@rudderjs/ai 1.17.2 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (377) hide show
  1. package/README.md +19 -1274
  2. package/dist/budget-orm/index.d.ts +1 -95
  3. package/dist/budget-orm/index.d.ts.map +1 -1
  4. package/dist/budget-orm/index.js +4 -176
  5. package/dist/budget-orm/index.js.map +1 -1
  6. package/dist/chat-mentions.d.ts +1 -58
  7. package/dist/chat-mentions.d.ts.map +1 -1
  8. package/dist/chat-mentions.js +4 -80
  9. package/dist/chat-mentions.js.map +1 -1
  10. package/dist/commands/ai-eval.d.ts +1 -92
  11. package/dist/commands/ai-eval.d.ts.map +1 -1
  12. package/dist/commands/ai-eval.js +4 -377
  13. package/dist/commands/ai-eval.js.map +1 -1
  14. package/dist/commands/make-agent.d.ts +1 -2
  15. package/dist/commands/make-agent.d.ts.map +1 -1
  16. package/dist/commands/make-agent.js +4 -22
  17. package/dist/commands/make-agent.js.map +1 -1
  18. package/dist/computer-use/index.d.ts +1 -52
  19. package/dist/computer-use/index.d.ts.map +1 -1
  20. package/dist/computer-use/index.js +4 -50
  21. package/dist/computer-use/index.js.map +1 -1
  22. package/dist/conversation-orm/index.d.ts +1 -108
  23. package/dist/conversation-orm/index.d.ts.map +1 -1
  24. package/dist/conversation-orm/index.js +4 -214
  25. package/dist/conversation-orm/index.js.map +1 -1
  26. package/dist/doctor.d.ts +1 -1
  27. package/dist/doctor.d.ts.map +1 -1
  28. package/dist/doctor.js +4 -65
  29. package/dist/doctor.js.map +1 -1
  30. package/dist/eval/index.d.ts +1 -270
  31. package/dist/eval/index.d.ts.map +1 -1
  32. package/dist/eval/index.js +4 -509
  33. package/dist/eval/index.js.map +1 -1
  34. package/dist/gateway/index.d.ts +1 -10
  35. package/dist/gateway/index.d.ts.map +1 -1
  36. package/dist/gateway/index.js +4 -10
  37. package/dist/gateway/index.js.map +1 -1
  38. package/dist/index.d.ts +1 -66
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +4 -78
  41. package/dist/index.js.map +1 -1
  42. package/dist/mcp/index.d.ts +1 -15
  43. package/dist/mcp/index.d.ts.map +1 -1
  44. package/dist/mcp/index.js +4 -14
  45. package/dist/mcp/index.js.map +1 -1
  46. package/dist/memory-embedding/index.d.ts +1 -120
  47. package/dist/memory-embedding/index.d.ts.map +1 -1
  48. package/dist/memory-embedding/index.js +4 -228
  49. package/dist/memory-embedding/index.js.map +1 -1
  50. package/dist/memory-orm/index.d.ts +1 -117
  51. package/dist/memory-orm/index.d.ts.map +1 -1
  52. package/dist/memory-orm/index.js +4 -186
  53. package/dist/memory-orm/index.js.map +1 -1
  54. package/dist/node/index.d.ts +1 -2
  55. package/dist/node/index.d.ts.map +1 -1
  56. package/dist/node/index.js +4 -2
  57. package/dist/node/index.js.map +1 -1
  58. package/dist/observers.d.ts +1 -129
  59. package/dist/observers.d.ts.map +1 -1
  60. package/dist/observers.js +4 -39
  61. package/dist/observers.js.map +1 -1
  62. package/dist/react/index.d.ts +1 -15
  63. package/dist/react/index.d.ts.map +1 -1
  64. package/dist/react/index.js +4 -15
  65. package/dist/react/index.js.map +1 -1
  66. package/dist/server/index.d.ts +1 -1
  67. package/dist/server/index.d.ts.map +1 -1
  68. package/dist/server/index.js +4 -1
  69. package/dist/server/index.js.map +1 -1
  70. package/package.json +9 -13
  71. package/boost/guidelines.md +0 -260
  72. package/boost/skills/ai-agents/SKILL.md +0 -240
  73. package/boost/skills/ai-tools/SKILL.md +0 -260
  74. package/dist/agent-run-store.d.ts +0 -161
  75. package/dist/agent-run-store.d.ts.map +0 -1
  76. package/dist/agent-run-store.js +0 -98
  77. package/dist/agent-run-store.js.map +0 -1
  78. package/dist/agent-sse.d.ts +0 -153
  79. package/dist/agent-sse.d.ts.map +0 -1
  80. package/dist/agent-sse.js +0 -282
  81. package/dist/agent-sse.js.map +0 -1
  82. package/dist/agent.d.ts +0 -508
  83. package/dist/agent.d.ts.map +0 -1
  84. package/dist/agent.js +0 -1538
  85. package/dist/agent.js.map +0 -1
  86. package/dist/attachment.d.ts +0 -31
  87. package/dist/attachment.d.ts.map +0 -1
  88. package/dist/attachment.js +0 -89
  89. package/dist/attachment.js.map +0 -1
  90. package/dist/audio.d.ts +0 -45
  91. package/dist/audio.d.ts.map +0 -1
  92. package/dist/audio.js +0 -93
  93. package/dist/audio.js.map +0 -1
  94. package/dist/base64.d.ts +0 -7
  95. package/dist/base64.d.ts.map +0 -1
  96. package/dist/base64.js +0 -39
  97. package/dist/base64.js.map +0 -1
  98. package/dist/budget/pricing.d.ts +0 -124
  99. package/dist/budget/pricing.d.ts.map +0 -1
  100. package/dist/budget/pricing.js +0 -175
  101. package/dist/budget/pricing.js.map +0 -1
  102. package/dist/budget/storage.d.ts +0 -104
  103. package/dist/budget/storage.d.ts.map +0 -1
  104. package/dist/budget/storage.js +0 -0
  105. package/dist/budget/storage.js.map +0 -1
  106. package/dist/budget/with-budget.d.ts +0 -119
  107. package/dist/budget/with-budget.d.ts.map +0 -1
  108. package/dist/budget/with-budget.js +0 -175
  109. package/dist/budget/with-budget.js.map +0 -1
  110. package/dist/cached-embedding.d.ts +0 -14
  111. package/dist/cached-embedding.d.ts.map +0 -1
  112. package/dist/cached-embedding.js +0 -44
  113. package/dist/cached-embedding.js.map +0 -1
  114. package/dist/computer-use/actions.d.ts +0 -214
  115. package/dist/computer-use/actions.d.ts.map +0 -1
  116. package/dist/computer-use/actions.js +0 -48
  117. package/dist/computer-use/actions.js.map +0 -1
  118. package/dist/computer-use/errors.d.ts +0 -57
  119. package/dist/computer-use/errors.d.ts.map +0 -1
  120. package/dist/computer-use/errors.js +0 -76
  121. package/dist/computer-use/errors.js.map +0 -1
  122. package/dist/computer-use/playwright.d.ts +0 -76
  123. package/dist/computer-use/playwright.d.ts.map +0 -1
  124. package/dist/computer-use/playwright.js +0 -270
  125. package/dist/computer-use/playwright.js.map +0 -1
  126. package/dist/computer-use/tool.d.ts +0 -154
  127. package/dist/computer-use/tool.d.ts.map +0 -1
  128. package/dist/computer-use/tool.js +0 -210
  129. package/dist/computer-use/tool.js.map +0 -1
  130. package/dist/continuation-validation.d.ts +0 -85
  131. package/dist/continuation-validation.d.ts.map +0 -1
  132. package/dist/continuation-validation.js +0 -166
  133. package/dist/continuation-validation.js.map +0 -1
  134. package/dist/conversation-persistence.d.ts +0 -46
  135. package/dist/conversation-persistence.d.ts.map +0 -1
  136. package/dist/conversation-persistence.js +0 -176
  137. package/dist/conversation-persistence.js.map +0 -1
  138. package/dist/conversation.d.ts +0 -11
  139. package/dist/conversation.d.ts.map +0 -1
  140. package/dist/conversation.js +0 -55
  141. package/dist/conversation.js.map +0 -1
  142. package/dist/eval/fixtures.d.ts +0 -65
  143. package/dist/eval/fixtures.d.ts.map +0 -1
  144. package/dist/eval/fixtures.js +0 -110
  145. package/dist/eval/fixtures.js.map +0 -1
  146. package/dist/eval/html-reporter.d.ts +0 -25
  147. package/dist/eval/html-reporter.d.ts.map +0 -1
  148. package/dist/eval/html-reporter.js +0 -209
  149. package/dist/eval/html-reporter.js.map +0 -1
  150. package/dist/eval/json-reporter.d.ts +0 -43
  151. package/dist/eval/json-reporter.d.ts.map +0 -1
  152. package/dist/eval/json-reporter.js +0 -40
  153. package/dist/eval/json-reporter.js.map +0 -1
  154. package/dist/facade.d.ts +0 -96
  155. package/dist/facade.d.ts.map +0 -1
  156. package/dist/facade.js +0 -146
  157. package/dist/facade.js.map +0 -1
  158. package/dist/fake.d.ts +0 -201
  159. package/dist/fake.d.ts.map +0 -1
  160. package/dist/fake.js +0 -428
  161. package/dist/fake.js.map +0 -1
  162. package/dist/file-search.d.ts +0 -168
  163. package/dist/file-search.d.ts.map +0 -1
  164. package/dist/file-search.js +0 -158
  165. package/dist/file-search.js.map +0 -1
  166. package/dist/files.d.ts +0 -27
  167. package/dist/files.d.ts.map +0 -1
  168. package/dist/files.js +0 -44
  169. package/dist/files.js.map +0 -1
  170. package/dist/gateway/http-gateway-adapter.d.ts +0 -94
  171. package/dist/gateway/http-gateway-adapter.d.ts.map +0 -1
  172. package/dist/gateway/http-gateway-adapter.js +0 -106
  173. package/dist/gateway/http-gateway-adapter.js.map +0 -1
  174. package/dist/gateway/sse.d.ts +0 -28
  175. package/dist/gateway/sse.d.ts.map +0 -1
  176. package/dist/gateway/sse.js +0 -78
  177. package/dist/gateway/sse.js.map +0 -1
  178. package/dist/handoff.d.ts +0 -95
  179. package/dist/handoff.d.ts.map +0 -1
  180. package/dist/handoff.js +0 -78
  181. package/dist/handoff.js.map +0 -1
  182. package/dist/handoffs-driver.d.ts +0 -58
  183. package/dist/handoffs-driver.d.ts.map +0 -1
  184. package/dist/handoffs-driver.js +0 -103
  185. package/dist/handoffs-driver.js.map +0 -1
  186. package/dist/image.d.ts +0 -40
  187. package/dist/image.d.ts.map +0 -1
  188. package/dist/image.js +0 -109
  189. package/dist/image.js.map +0 -1
  190. package/dist/mcp/client-tools.d.ts +0 -39
  191. package/dist/mcp/client-tools.d.ts.map +0 -1
  192. package/dist/mcp/client-tools.js +0 -147
  193. package/dist/mcp/client-tools.js.map +0 -1
  194. package/dist/mcp/server-from-agent.d.ts +0 -24
  195. package/dist/mcp/server-from-agent.d.ts.map +0 -1
  196. package/dist/mcp/server-from-agent.js +0 -113
  197. package/dist/mcp/server-from-agent.js.map +0 -1
  198. package/dist/mcp/types.d.ts +0 -64
  199. package/dist/mcp/types.d.ts.map +0 -1
  200. package/dist/mcp/types.js +0 -6
  201. package/dist/mcp/types.js.map +0 -1
  202. package/dist/memory-extract.d.ts +0 -60
  203. package/dist/memory-extract.d.ts.map +0 -1
  204. package/dist/memory-extract.js +0 -163
  205. package/dist/memory-extract.js.map +0 -1
  206. package/dist/memory-inject.d.ts +0 -39
  207. package/dist/memory-inject.d.ts.map +0 -1
  208. package/dist/memory-inject.js +0 -135
  209. package/dist/memory-inject.js.map +0 -1
  210. package/dist/memory.d.ts +0 -55
  211. package/dist/memory.d.ts.map +0 -1
  212. package/dist/memory.js +0 -132
  213. package/dist/memory.js.map +0 -1
  214. package/dist/middleware.d.ts +0 -18
  215. package/dist/middleware.d.ts.map +0 -1
  216. package/dist/middleware.js +0 -72
  217. package/dist/middleware.js.map +0 -1
  218. package/dist/node/attachment.d.ts +0 -6
  219. package/dist/node/attachment.d.ts.map +0 -1
  220. package/dist/node/attachment.js +0 -35
  221. package/dist/node/attachment.js.map +0 -1
  222. package/dist/node/transcription.d.ts +0 -4
  223. package/dist/node/transcription.d.ts.map +0 -1
  224. package/dist/node/transcription.js +0 -8
  225. package/dist/node/transcription.js.map +0 -1
  226. package/dist/output.d.ts +0 -22
  227. package/dist/output.d.ts.map +0 -1
  228. package/dist/output.js +0 -60
  229. package/dist/output.js.map +0 -1
  230. package/dist/provider-tools.d.ts +0 -87
  231. package/dist/provider-tools.d.ts.map +0 -1
  232. package/dist/provider-tools.js +0 -189
  233. package/dist/provider-tools.js.map +0 -1
  234. package/dist/providers/anthropic.d.ts +0 -24
  235. package/dist/providers/anthropic.d.ts.map +0 -1
  236. package/dist/providers/anthropic.js +0 -405
  237. package/dist/providers/anthropic.js.map +0 -1
  238. package/dist/providers/azure.d.ts +0 -13
  239. package/dist/providers/azure.d.ts.map +0 -1
  240. package/dist/providers/azure.js +0 -15
  241. package/dist/providers/azure.js.map +0 -1
  242. package/dist/providers/bedrock.d.ts +0 -75
  243. package/dist/providers/bedrock.d.ts.map +0 -1
  244. package/dist/providers/bedrock.js +0 -181
  245. package/dist/providers/bedrock.js.map +0 -1
  246. package/dist/providers/cohere.d.ts +0 -13
  247. package/dist/providers/cohere.d.ts.map +0 -1
  248. package/dist/providers/cohere.js +0 -87
  249. package/dist/providers/cohere.js.map +0 -1
  250. package/dist/providers/deepseek.d.ts +0 -12
  251. package/dist/providers/deepseek.d.ts.map +0 -1
  252. package/dist/providers/deepseek.js +0 -15
  253. package/dist/providers/deepseek.js.map +0 -1
  254. package/dist/providers/elevenlabs.d.ts +0 -98
  255. package/dist/providers/elevenlabs.d.ts.map +0 -1
  256. package/dist/providers/elevenlabs.js +0 -229
  257. package/dist/providers/elevenlabs.js.map +0 -1
  258. package/dist/providers/google-cache-registry.d.ts +0 -132
  259. package/dist/providers/google-cache-registry.d.ts.map +0 -1
  260. package/dist/providers/google-cache-registry.js +0 -209
  261. package/dist/providers/google-cache-registry.js.map +0 -1
  262. package/dist/providers/google.d.ts +0 -38
  263. package/dist/providers/google.d.ts.map +0 -1
  264. package/dist/providers/google.js +0 -903
  265. package/dist/providers/google.js.map +0 -1
  266. package/dist/providers/groq.d.ts +0 -12
  267. package/dist/providers/groq.d.ts.map +0 -1
  268. package/dist/providers/groq.js +0 -15
  269. package/dist/providers/groq.js.map +0 -1
  270. package/dist/providers/jina.d.ts +0 -13
  271. package/dist/providers/jina.d.ts.map +0 -1
  272. package/dist/providers/jina.js +0 -90
  273. package/dist/providers/jina.js.map +0 -1
  274. package/dist/providers/mistral.d.ts +0 -13
  275. package/dist/providers/mistral.d.ts.map +0 -1
  276. package/dist/providers/mistral.js +0 -46
  277. package/dist/providers/mistral.js.map +0 -1
  278. package/dist/providers/ollama.d.ts +0 -11
  279. package/dist/providers/ollama.d.ts.map +0 -1
  280. package/dist/providers/ollama.js +0 -15
  281. package/dist/providers/ollama.js.map +0 -1
  282. package/dist/providers/openai.d.ts +0 -79
  283. package/dist/providers/openai.d.ts.map +0 -1
  284. package/dist/providers/openai.js +0 -792
  285. package/dist/providers/openai.js.map +0 -1
  286. package/dist/providers/openrouter.d.ts +0 -43
  287. package/dist/providers/openrouter.d.ts.map +0 -1
  288. package/dist/providers/openrouter.js +0 -21
  289. package/dist/providers/openrouter.js.map +0 -1
  290. package/dist/providers/voyage.d.ts +0 -91
  291. package/dist/providers/voyage.d.ts.map +0 -1
  292. package/dist/providers/voyage.js +0 -166
  293. package/dist/providers/voyage.js.map +0 -1
  294. package/dist/providers/xai.d.ts +0 -12
  295. package/dist/providers/xai.d.ts.map +0 -1
  296. package/dist/providers/xai.js +0 -15
  297. package/dist/providers/xai.js.map +0 -1
  298. package/dist/queue-job.d.ts +0 -100
  299. package/dist/queue-job.d.ts.map +0 -1
  300. package/dist/queue-job.js +0 -185
  301. package/dist/queue-job.js.map +0 -1
  302. package/dist/react/agent-run.d.ts +0 -111
  303. package/dist/react/agent-run.d.ts.map +0 -1
  304. package/dist/react/agent-run.js +0 -107
  305. package/dist/react/agent-run.js.map +0 -1
  306. package/dist/react/useAgentRun.d.ts +0 -68
  307. package/dist/react/useAgentRun.d.ts.map +0 -1
  308. package/dist/react/useAgentRun.js +0 -125
  309. package/dist/react/useAgentRun.js.map +0 -1
  310. package/dist/registry.d.ts +0 -45
  311. package/dist/registry.d.ts.map +0 -1
  312. package/dist/registry.js +0 -131
  313. package/dist/registry.js.map +0 -1
  314. package/dist/rerank.d.ts +0 -20
  315. package/dist/rerank.d.ts.map +0 -1
  316. package/dist/rerank.js +0 -40
  317. package/dist/rerank.js.map +0 -1
  318. package/dist/resume-approval.d.ts +0 -30
  319. package/dist/resume-approval.d.ts.map +0 -1
  320. package/dist/resume-approval.js +0 -147
  321. package/dist/resume-approval.js.map +0 -1
  322. package/dist/sanitize-conversation.d.ts +0 -43
  323. package/dist/sanitize-conversation.d.ts.map +0 -1
  324. package/dist/sanitize-conversation.js +0 -85
  325. package/dist/sanitize-conversation.js.map +0 -1
  326. package/dist/scoped-tool.d.ts +0 -98
  327. package/dist/scoped-tool.d.ts.map +0 -1
  328. package/dist/scoped-tool.js +0 -174
  329. package/dist/scoped-tool.js.map +0 -1
  330. package/dist/server/provider.d.ts +0 -22
  331. package/dist/server/provider.d.ts.map +0 -1
  332. package/dist/server/provider.js +0 -194
  333. package/dist/server/provider.js.map +0 -1
  334. package/dist/similarity-search.d.ts +0 -163
  335. package/dist/similarity-search.d.ts.map +0 -1
  336. package/dist/similarity-search.js +0 -147
  337. package/dist/similarity-search.js.map +0 -1
  338. package/dist/sub-agent-run-store.d.ts +0 -157
  339. package/dist/sub-agent-run-store.d.ts.map +0 -1
  340. package/dist/sub-agent-run-store.js +0 -87
  341. package/dist/sub-agent-run-store.js.map +0 -1
  342. package/dist/tool-execution.d.ts +0 -16
  343. package/dist/tool-execution.d.ts.map +0 -1
  344. package/dist/tool-execution.js +0 -498
  345. package/dist/tool-execution.js.map +0 -1
  346. package/dist/tool-helpers.d.ts +0 -77
  347. package/dist/tool-helpers.d.ts.map +0 -1
  348. package/dist/tool-helpers.js +0 -117
  349. package/dist/tool-helpers.js.map +0 -1
  350. package/dist/tool.d.ts +0 -216
  351. package/dist/tool.d.ts.map +0 -1
  352. package/dist/tool.js +0 -175
  353. package/dist/tool.js.map +0 -1
  354. package/dist/transcription.d.ts +0 -42
  355. package/dist/transcription.d.ts.map +0 -1
  356. package/dist/transcription.js +0 -77
  357. package/dist/transcription.js.map +0 -1
  358. package/dist/types.d.ts +0 -1020
  359. package/dist/types.d.ts.map +0 -1
  360. package/dist/types.js +0 -2
  361. package/dist/types.js.map +0 -1
  362. package/dist/util/hash.d.ts +0 -11
  363. package/dist/util/hash.d.ts.map +0 -1
  364. package/dist/util/hash.js +0 -23
  365. package/dist/util/hash.js.map +0 -1
  366. package/dist/vector-stores/index.d.ts +0 -96
  367. package/dist/vector-stores/index.d.ts.map +0 -1
  368. package/dist/vector-stores/index.js +0 -153
  369. package/dist/vector-stores/index.js.map +0 -1
  370. package/dist/vercel-protocol.d.ts +0 -18
  371. package/dist/vercel-protocol.d.ts.map +0 -1
  372. package/dist/vercel-protocol.js +0 -75
  373. package/dist/vercel-protocol.js.map +0 -1
  374. package/dist/zod-to-json-schema.d.ts +0 -16
  375. package/dist/zod-to-json-schema.d.ts.map +0 -1
  376. package/dist/zod-to-json-schema.js +0 -17
  377. package/dist/zod-to-json-schema.js.map +0 -1
@@ -1,792 +0,0 @@
1
- import { cyrb53Hex } from '../util/hash.js';
2
- import { base64ToUtf8 } from '../base64.js';
3
- export class OpenAIProvider {
4
- name = 'openai';
5
- config;
6
- constructor(config) {
7
- this.config = config;
8
- }
9
- create(model) {
10
- return new OpenAIAdapter(this.config, model);
11
- }
12
- createEmbedding(model) {
13
- return new OpenAIEmbeddingAdapter(this.config, model);
14
- }
15
- createImage(model) {
16
- return new OpenAIImageAdapter(this.config, model);
17
- }
18
- createTts(model) {
19
- return new OpenAITtsAdapter(this.config, model);
20
- }
21
- createStt(model) {
22
- return new OpenAISttAdapter(this.config, model);
23
- }
24
- createFiles() {
25
- return new OpenAIFileAdapter(this.config);
26
- }
27
- createVectorStores() {
28
- return new OpenAIVectorStoreAdapter(this.config);
29
- }
30
- }
31
- // ─── Adapter (also reused by Ollama) ─────────────────────
32
- export class OpenAIAdapter {
33
- config;
34
- model;
35
- client = null;
36
- constructor(config, model) {
37
- this.config = config;
38
- this.model = model;
39
- }
40
- async getClient() {
41
- if (this.client)
42
- return this.client;
43
- const sdk = await import(/* @vite-ignore */ 'openai');
44
- const OpenAI = sdk.default ?? sdk.OpenAI;
45
- this.client = new OpenAI({
46
- apiKey: this.config.apiKey,
47
- ...(this.config.baseUrl ? { baseURL: this.config.baseUrl } : {}),
48
- ...(this.config.organization ? { organization: this.config.organization } : {}),
49
- ...(this.config.defaultHeaders ? { defaultHeaders: this.config.defaultHeaders } : {}),
50
- });
51
- return this.client;
52
- }
53
- async generate(options) {
54
- const client = await this.getClient();
55
- const messages = toOpenAIMessages(options.messages);
56
- const tools = options.tools?.length ? toOpenAITools(options.tools) : undefined;
57
- const params = {
58
- model: this.model,
59
- messages,
60
- };
61
- if (options.maxTokens)
62
- params['max_tokens'] = options.maxTokens;
63
- if (options.temperature !== undefined)
64
- params['temperature'] = options.temperature;
65
- if (options.topP !== undefined)
66
- params['top_p'] = options.topP;
67
- if (options.stop)
68
- params['stop'] = options.stop;
69
- if (tools)
70
- params['tools'] = tools;
71
- if (options.toolChoice)
72
- params['tool_choice'] = toOpenAIToolChoice(options.toolChoice);
73
- const cacheKey = buildPromptCacheKey(messages, tools, options.cache);
74
- if (cacheKey)
75
- params['prompt_cache_key'] = cacheKey;
76
- const response = await client.chat.completions.create(params, options.signal ? { signal: options.signal } : undefined);
77
- return fromOpenAIResponse(response);
78
- }
79
- async *stream(options) {
80
- const client = await this.getClient();
81
- const messages = toOpenAIMessages(options.messages);
82
- const tools = options.tools?.length ? toOpenAITools(options.tools) : undefined;
83
- const params = {
84
- model: this.model,
85
- messages,
86
- stream: true,
87
- };
88
- if (options.maxTokens)
89
- params['max_tokens'] = options.maxTokens;
90
- if (options.temperature !== undefined)
91
- params['temperature'] = options.temperature;
92
- if (options.topP !== undefined)
93
- params['top_p'] = options.topP;
94
- if (options.stop)
95
- params['stop'] = options.stop;
96
- if (tools)
97
- params['tools'] = tools;
98
- if (options.toolChoice)
99
- params['tool_choice'] = toOpenAIToolChoice(options.toolChoice);
100
- const cacheKey = buildPromptCacheKey(messages, tools, options.cache);
101
- if (cacheKey)
102
- params['prompt_cache_key'] = cacheKey;
103
- const stream = await client.chat.completions.create(params, options.signal ? { signal: options.signal } : undefined);
104
- for await (const chunk of stream) {
105
- const choice = chunk.choices?.[0];
106
- if (!choice)
107
- continue;
108
- const delta = choice.delta;
109
- if (delta?.content) {
110
- yield { type: 'text-delta', text: delta.content };
111
- }
112
- if (delta?.tool_calls?.length) {
113
- for (const tc of delta.tool_calls) {
114
- // OpenAI guarantees `index` on every tool_calls delta — it's the
115
- // only stable correlator across the start-delta (carries `id`) and
116
- // subsequent arg-only deltas. We thread it through StreamChunk so
117
- // the agent loop can route arg fragments to the right partial
118
- // under parallel tool calls.
119
- const index = typeof tc.index === 'number' ? tc.index : undefined;
120
- if (tc.id) {
121
- yield {
122
- type: 'tool-call-delta',
123
- toolCall: { id: tc.id, name: tc.function?.name },
124
- ...(index !== undefined ? { toolCallIndex: index } : {}),
125
- };
126
- }
127
- if (tc.function?.arguments) {
128
- yield {
129
- type: 'tool-call-delta',
130
- text: tc.function.arguments,
131
- ...(index !== undefined ? { toolCallIndex: index } : {}),
132
- };
133
- }
134
- }
135
- }
136
- if (choice.finish_reason) {
137
- yield {
138
- type: 'finish',
139
- finishReason: choice.finish_reason === 'tool_calls' ? 'tool_calls' : 'stop',
140
- usage: chunk.usage ? {
141
- promptTokens: chunk.usage.prompt_tokens ?? 0,
142
- completionTokens: chunk.usage.completion_tokens ?? 0,
143
- totalTokens: chunk.usage.total_tokens ?? 0,
144
- } : undefined,
145
- };
146
- }
147
- }
148
- }
149
- }
150
- // ─── Conversion Helpers ──────────────────────────────────
151
- function contentToString(content) {
152
- if (typeof content === 'string')
153
- return content;
154
- return content.filter(p => p.type === 'text').map(p => p.text).join('');
155
- }
156
- function contentToOpenAIParts(content) {
157
- if (typeof content === 'string')
158
- return content;
159
- return content.map(p => {
160
- if (p.type === 'text')
161
- return { type: 'text', text: p.text };
162
- if (p.type === 'image')
163
- return { type: 'image_url', image_url: { url: `data:${p.mimeType};base64,${p.data}` } };
164
- // document — for text-based docs, decode to text; for PDFs, send as image_url (GPT-4o supports)
165
- if (p.mimeType === 'application/pdf') {
166
- return { type: 'file', file: { data: p.data, mime_type: p.mimeType } };
167
- }
168
- return { type: 'text', text: base64ToUtf8(p.data) };
169
- });
170
- }
171
- /**
172
- * Repair tool-call ↔ tool-result adjacency before serializing for an
173
- * OpenAI-compatible provider.
174
- *
175
- * Anthropic carries tool results as content blocks inside user turns, so a
176
- * loosely-ordered transcript round-trips fine. The OpenAI wire protocol (and
177
- * strict implementers like DeepSeek) enforce two hard rules:
178
- *
179
- * 1. every `role:'tool'` message must immediately follow the `assistant`
180
- * message whose `tool_calls` declares its `tool_call_id`, and
181
- * 2. every `tool_calls` entry on an assistant message must be answered by a
182
- * following `role:'tool'` message before the next assistant/user turn.
183
- *
184
- * A persist→resume cycle (client-tool pause, approval round-trip, or an app
185
- * that re-stores assistant turns without their `toolCalls`) can violate
186
- * either rule, yielding `400 Messages with role 'tool' must be a response to
187
- * a preceding message with 'tool_calls'` — or its mirror, an unanswered
188
- * `tool_calls`. See `docs/plans/2026-06-11-deepseek-tool-transcript-400.md`.
189
- *
190
- * This pass enforces BOTH directions:
191
- * - **Detached / out-of-order results** are pulled up to sit immediately
192
- * after their parent assistant, in `tool_calls` order.
193
- * - **Unanswered `tool_calls`** get a synthesized stub result so the
194
- * request is well-formed (mirrors the placeholder strategy in
195
- * `resumePendingToolCalls`).
196
- * - **Orphan tool results** — whose `tool_call_id` is declared by no
197
- * assistant message anywhere — are dropped; they can never be valid on
198
- * the wire. (Lossy only when the app already discarded the parent's
199
- * `toolCalls`; the framework can't reconstruct a deleted call.)
200
- *
201
- * Transcripts that already satisfy the invariant pass through unchanged
202
- * (same message object references), so the common single-run path pays only
203
- * a linear scan.
204
- */
205
- export function normalizeToolTranscript(messages) {
206
- // Index tool results by the call id they answer (a FIFO queue per id
207
- // tolerates pathological duplicate ids without dropping a message), and
208
- // collect every call id any assistant message declares.
209
- const resultsByCallId = new Map();
210
- const declaredCallIds = new Set();
211
- for (const m of messages) {
212
- if (m.role === 'tool' && m.toolCallId) {
213
- const queue = resultsByCallId.get(m.toolCallId);
214
- if (queue)
215
- queue.push(m);
216
- else
217
- resultsByCallId.set(m.toolCallId, [m]);
218
- }
219
- else if (m.role === 'assistant' && m.toolCalls?.length) {
220
- for (const tc of m.toolCalls)
221
- declaredCallIds.add(tc.id);
222
- }
223
- }
224
- const out = [];
225
- for (const m of messages) {
226
- if (m.role === 'assistant' && m.toolCalls?.length) {
227
- out.push(m);
228
- // Emit each declared call's answer adjacent + in declaration order,
229
- // claiming the real result wherever it sat or synthesizing a stub.
230
- for (const tc of m.toolCalls) {
231
- const real = resultsByCallId.get(tc.id)?.shift();
232
- if (real) {
233
- out.push(real);
234
- }
235
- else {
236
- out.push({
237
- role: 'tool',
238
- toolCallId: tc.id,
239
- content: '[Rudder] tool result missing — synthesized to satisfy the OpenAI tool-call/tool-result protocol.',
240
- });
241
- }
242
- }
243
- continue;
244
- }
245
- // A tool message is emitted only by its parent assistant block above —
246
- // here it is either already-claimed (skip) or an orphan with no declaring
247
- // assistant (drop). Either way, never emit it standalone.
248
- if (m.role === 'tool')
249
- continue;
250
- out.push(m);
251
- }
252
- return out;
253
- }
254
- export function toOpenAIMessages(messages) {
255
- return normalizeToolTranscript(messages).map(m => {
256
- if (m.role === 'assistant' && m.toolCalls?.length) {
257
- return {
258
- role: 'assistant',
259
- content: contentToString(m.content) || null,
260
- tool_calls: m.toolCalls.map(tc => ({
261
- id: tc.id,
262
- type: 'function',
263
- function: { name: tc.name, arguments: JSON.stringify(tc.arguments) },
264
- })),
265
- };
266
- }
267
- if (m.role === 'tool') {
268
- return {
269
- role: 'tool',
270
- tool_call_id: m.toolCallId,
271
- content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content),
272
- };
273
- }
274
- // User messages with attachments → content array
275
- if (Array.isArray(m.content)) {
276
- return { role: m.role, content: contentToOpenAIParts(m.content) };
277
- }
278
- return { role: m.role, content: m.content };
279
- });
280
- }
281
- export function toOpenAITools(tools) {
282
- return tools.map(t => {
283
- // Provider-native tool blocks: when a tool carries a recognized
284
- // `providerHint`, emit OpenAI's native shape instead of the standard
285
- // function-call schema. Currently:
286
- // - 'file-search' → { type: 'file_search', vector_store_ids, filters?,
287
- // max_num_results? }. The model is trained on the
288
- // native tool — quality is dramatically better
289
- // than wrapping it as a function call, and the
290
- // provider runs the search server-side so no
291
- // client-side execute is needed.
292
- if (t.providerHint?.type === 'file-search') {
293
- const vectorStoreIds = t.providerHint['vector_store_ids'] ?? [];
294
- const block = {
295
- type: 'file_search',
296
- vector_store_ids: vectorStoreIds,
297
- };
298
- if (t.providerHint['filters'] !== undefined)
299
- block['filters'] = t.providerHint['filters'];
300
- if (t.providerHint['max_num_results'] !== undefined)
301
- block['max_num_results'] = t.providerHint['max_num_results'];
302
- return block;
303
- }
304
- return {
305
- type: 'function',
306
- function: { name: t.name, description: t.description, parameters: t.parameters },
307
- };
308
- });
309
- }
310
- function toOpenAIToolChoice(choice) {
311
- if (choice === 'auto')
312
- return 'auto';
313
- if (choice === 'required')
314
- return 'required';
315
- if (choice === 'none')
316
- return 'none';
317
- if (typeof choice === 'object' && 'name' in choice)
318
- return { type: 'function', function: { name: choice.name } };
319
- return 'auto';
320
- }
321
- // ─── Prompt-cache key ────────────────────────────────────
322
- //
323
- // OpenAI caches prompts automatically once they exceed 1024 tokens. The only
324
- // SDK knob is `prompt_cache_key`: an opaque string that gives OpenAI a routing
325
- // hint so requests with the same cacheable prefix land on the same backend
326
- // (which has the prefix already cached). Stable hashing is the goal — not
327
- // cryptographic strength — so we use cyrb53 over canonical JSON of the
328
- // regions the agent declared as `cacheable()`.
329
- //
330
- // Spec: https://platform.openai.com/docs/guides/prompt-caching
331
- /**
332
- * Build a stable `prompt_cache_key` from the regions the agent marked as
333
- * cacheable. Returns `undefined` if no markers apply (request goes out
334
- * without a cache key — OpenAI still caches automatically above 1024
335
- * tokens, just without routing affinity).
336
- *
337
- * Exported for unit testing.
338
- */
339
- export function buildPromptCacheKey(messages, tools, cache) {
340
- if (!cache)
341
- return undefined;
342
- const parts = [];
343
- if (cache.instructions) {
344
- const sys = messages.find(m => m.role === 'system');
345
- if (sys)
346
- parts.push({ s: sys.content });
347
- }
348
- if (cache.tools && tools && tools.length > 0) {
349
- parts.push({ t: tools });
350
- }
351
- if (cache.messages && cache.messages > 0) {
352
- const conv = messages.filter(m => m.role !== 'system');
353
- const sliced = conv.slice(0, cache.messages);
354
- if (sliced.length > 0)
355
- parts.push({ m: sliced });
356
- }
357
- if (parts.length === 0)
358
- return undefined;
359
- return cyrb53Hex(JSON.stringify(parts));
360
- }
361
- function fromOpenAIResponse(response) {
362
- const choice = response.choices?.[0];
363
- const message = choice?.message;
364
- const toolCalls = (message?.tool_calls ?? []).map((tc) => ({
365
- id: tc.id,
366
- name: tc.function.name,
367
- arguments: JSON.parse(tc.function.arguments),
368
- }));
369
- return {
370
- message: {
371
- role: 'assistant',
372
- content: message?.content ?? '',
373
- ...(toolCalls.length > 0 ? { toolCalls } : {}),
374
- },
375
- usage: {
376
- promptTokens: response.usage?.prompt_tokens ?? 0,
377
- completionTokens: response.usage?.completion_tokens ?? 0,
378
- totalTokens: response.usage?.total_tokens ?? 0,
379
- },
380
- finishReason: choice?.finish_reason === 'tool_calls' ? 'tool_calls' : 'stop',
381
- };
382
- }
383
- // ─── Embedding Adapter ────────────────────────────────────
384
- class OpenAIEmbeddingAdapter {
385
- config;
386
- model;
387
- constructor(config, model) {
388
- this.config = config;
389
- this.model = model;
390
- }
391
- async embed(input) {
392
- const baseUrl = this.config.baseUrl ?? 'https://api.openai.com/v1';
393
- const inputs = Array.isArray(input) ? input : [input];
394
- const res = await fetch(`${baseUrl}/embeddings`, {
395
- method: 'POST',
396
- headers: {
397
- 'Authorization': `Bearer ${this.config.apiKey}`,
398
- 'Content-Type': 'application/json',
399
- ...(this.config.organization ? { 'OpenAI-Organization': this.config.organization } : {}),
400
- ...(this.config.defaultHeaders ?? {}),
401
- },
402
- body: JSON.stringify({ model: this.model, input: inputs }),
403
- });
404
- if (!res.ok)
405
- throw new Error(`[Rudder AI] OpenAI embeddings error: ${res.status} ${await res.text()}`);
406
- const data = await res.json();
407
- return {
408
- embeddings: data.data.map(d => d.embedding),
409
- usage: { promptTokens: data.usage.prompt_tokens, totalTokens: data.usage.total_tokens },
410
- };
411
- }
412
- }
413
- // ─── Image Generation Adapter ────────────────────────────
414
- const IMAGE_SIZE_MAP = {
415
- square: '1024x1024',
416
- landscape: '1792x1024',
417
- portrait: '1024x1792',
418
- };
419
- class OpenAIImageAdapter {
420
- config;
421
- model;
422
- client = null;
423
- constructor(config, model) {
424
- this.config = config;
425
- this.model = model;
426
- }
427
- async getClient() {
428
- if (this.client)
429
- return this.client;
430
- const sdk = await import(/* @vite-ignore */ 'openai');
431
- const OpenAI = sdk.default ?? sdk.OpenAI;
432
- this.client = new OpenAI({
433
- apiKey: this.config.apiKey,
434
- ...(this.config.baseUrl ? { baseURL: this.config.baseUrl } : {}),
435
- ...(this.config.organization ? { organization: this.config.organization } : {}),
436
- ...(this.config.defaultHeaders ? { defaultHeaders: this.config.defaultHeaders } : {}),
437
- });
438
- return this.client;
439
- }
440
- async generate(options) {
441
- const client = await this.getClient();
442
- const size = options.size
443
- ? (IMAGE_SIZE_MAP[options.size] ?? options.size)
444
- : '1024x1024';
445
- const params = {
446
- model: this.model,
447
- prompt: options.prompt,
448
- size,
449
- response_format: 'b64_json',
450
- };
451
- if (options.n !== undefined)
452
- params['n'] = options.n;
453
- if (options.quality)
454
- params['quality'] = options.quality;
455
- if (options.style)
456
- params['style'] = options.style;
457
- const response = await client.images.generate(params);
458
- return {
459
- images: (response.data ?? []).map((img) => ({
460
- ...(img.b64_json ? { base64: img.b64_json } : {}),
461
- ...(img.url ? { url: img.url } : {}),
462
- ...(img.revised_prompt ? { revisedPrompt: img.revised_prompt } : {}),
463
- })),
464
- model: this.model,
465
- };
466
- }
467
- }
468
- // ─── TTS Adapter ─────────────────────────────────────────
469
- class OpenAITtsAdapter {
470
- config;
471
- model;
472
- client = null;
473
- constructor(config, model) {
474
- this.config = config;
475
- this.model = model;
476
- }
477
- async getClient() {
478
- if (this.client)
479
- return this.client;
480
- const sdk = await import(/* @vite-ignore */ 'openai');
481
- const OpenAI = sdk.default ?? sdk.OpenAI;
482
- this.client = new OpenAI({
483
- apiKey: this.config.apiKey,
484
- ...(this.config.baseUrl ? { baseURL: this.config.baseUrl } : {}),
485
- ...(this.config.organization ? { organization: this.config.organization } : {}),
486
- ...(this.config.defaultHeaders ? { defaultHeaders: this.config.defaultHeaders } : {}),
487
- });
488
- return this.client;
489
- }
490
- async generate(options) {
491
- const client = await this.getClient();
492
- const format = options.format ?? 'mp3';
493
- const params = {
494
- model: this.model,
495
- input: options.text,
496
- voice: options.voice ?? 'alloy',
497
- };
498
- if (options.speed !== undefined)
499
- params['speed'] = options.speed;
500
- if (options.format)
501
- params['response_format'] = options.format;
502
- const response = await client.audio.speech.create(params);
503
- const arrayBuffer = await response.arrayBuffer();
504
- return {
505
- audio: Buffer.from(arrayBuffer),
506
- format,
507
- model: this.model,
508
- };
509
- }
510
- }
511
- // ─── STT Adapter ─────────────────────────────────────────
512
- class OpenAISttAdapter {
513
- config;
514
- model;
515
- client = null;
516
- constructor(config, model) {
517
- this.config = config;
518
- this.model = model;
519
- }
520
- async getClient() {
521
- if (this.client)
522
- return this.client;
523
- const sdk = await import(/* @vite-ignore */ 'openai');
524
- const OpenAI = sdk.default ?? sdk.OpenAI;
525
- this.client = new OpenAI({
526
- apiKey: this.config.apiKey,
527
- ...(this.config.baseUrl ? { baseURL: this.config.baseUrl } : {}),
528
- ...(this.config.organization ? { organization: this.config.organization } : {}),
529
- ...(this.config.defaultHeaders ? { defaultHeaders: this.config.defaultHeaders } : {}),
530
- });
531
- return this.client;
532
- }
533
- async transcribe(options) {
534
- const client = await this.getClient();
535
- const file = new File([options.audio], 'audio.mp3', { type: 'audio/mpeg' });
536
- const params = {
537
- model: this.model,
538
- file,
539
- response_format: 'verbose_json',
540
- };
541
- if (options.language)
542
- params['language'] = options.language;
543
- if (options.prompt)
544
- params['prompt'] = options.prompt;
545
- const response = await client.audio.transcriptions.create(params);
546
- return {
547
- text: response.text,
548
- language: response.language,
549
- duration: response.duration,
550
- model: this.model,
551
- };
552
- }
553
- }
554
- // ─── Files ──────────────────────────────────────────────
555
- class OpenAIFileAdapter {
556
- config;
557
- client = null;
558
- constructor(config) {
559
- this.config = config;
560
- }
561
- async getClient() {
562
- if (this.client)
563
- return this.client;
564
- const sdk = await import(/* @vite-ignore */ 'openai');
565
- const OpenAI = sdk.default ?? sdk.OpenAI;
566
- this.client = new OpenAI({
567
- apiKey: this.config.apiKey,
568
- ...(this.config.baseUrl ? { baseURL: this.config.baseUrl } : {}),
569
- ...(this.config.organization ? { organization: this.config.organization } : {}),
570
- ...(this.config.defaultHeaders ? { defaultHeaders: this.config.defaultHeaders } : {}),
571
- });
572
- return this.client;
573
- }
574
- async upload(options) {
575
- const client = await this.getClient();
576
- const { createReadStream } = await import(/* @vite-ignore */ 'node:fs');
577
- const file = createReadStream(options.filePath);
578
- const response = await client.files.create({
579
- file,
580
- purpose: options.purpose ?? 'assistants',
581
- });
582
- return {
583
- id: response.id,
584
- filename: response.filename,
585
- bytes: response.bytes,
586
- purpose: response.purpose,
587
- };
588
- }
589
- async list() {
590
- const client = await this.getClient();
591
- const response = await client.files.list();
592
- const files = [];
593
- for await (const f of response) {
594
- files.push({
595
- id: f.id,
596
- filename: f.filename,
597
- bytes: f.bytes,
598
- purpose: f.purpose,
599
- });
600
- }
601
- return { files };
602
- }
603
- async delete(fileId) {
604
- const client = await this.getClient();
605
- await client.files.del(fileId);
606
- }
607
- async retrieve(fileId) {
608
- const client = await this.getClient();
609
- const response = await client.files.content(fileId);
610
- const buffer = Buffer.from(await response.arrayBuffer());
611
- return { data: buffer, mimeType: 'application/octet-stream' };
612
- }
613
- }
614
- // ─── OpenAI Vector Stores (#B8 Phase 1) ──────────────────
615
- /**
616
- * OpenAI hosted vector store adapter. Wraps `client.vectorStores.*` and
617
- * `client.vectorStores.files.*` from the v4+ SDK. Lazy SDK load mirrors
618
- * the rest of the OpenAI provider.
619
- *
620
- * `addFile` defaults to polling until the file is fully indexed
621
- * (`status === 'completed'`). Pass `{ wait: false }` to fire-and-forget.
622
- *
623
- * Local file paths route through OpenAI's Files API first
624
- * (`client.files.create({ purpose: 'assistants' })`); the resulting
625
- * `file_id` then attaches to the vector store. Apps that already have
626
- * a file id pass `{ fileId }` directly.
627
- */
628
- class OpenAIVectorStoreAdapter {
629
- config;
630
- client = null;
631
- constructor(config) {
632
- this.config = config;
633
- }
634
- async getClient() {
635
- if (this.client)
636
- return this.client;
637
- const sdk = await import(/* @vite-ignore */ 'openai');
638
- const OpenAI = sdk.default ?? sdk.OpenAI;
639
- this.client = new OpenAI({
640
- apiKey: this.config.apiKey,
641
- ...(this.config.baseUrl ? { baseURL: this.config.baseUrl } : {}),
642
- ...(this.config.organization ? { organization: this.config.organization } : {}),
643
- ...(this.config.defaultHeaders ? { defaultHeaders: this.config.defaultHeaders } : {}),
644
- });
645
- return this.client;
646
- }
647
- async create(opts) {
648
- const client = await this.getClient();
649
- const params = { name: opts.name };
650
- if (opts.metadata)
651
- params['metadata'] = opts.metadata;
652
- if (opts.expiresAfter)
653
- params['expires_after'] = opts.expiresAfter;
654
- const response = await client.vectorStores.create(params);
655
- return fromOpenAIVectorStore(response);
656
- }
657
- async list(opts) {
658
- const client = await this.getClient();
659
- const params = {};
660
- if (opts?.limit !== undefined)
661
- params['limit'] = opts.limit;
662
- if (opts?.after !== undefined)
663
- params['after'] = opts.after;
664
- if (opts?.before !== undefined)
665
- params['before'] = opts.before;
666
- const response = await client.vectorStores.list(params);
667
- const data = (response.data ?? []);
668
- return { stores: data.map(d => fromOpenAIVectorStore(d)) };
669
- }
670
- async get(id) {
671
- const client = await this.getClient();
672
- const response = await client.vectorStores.retrieve(id);
673
- return fromOpenAIVectorStore(response);
674
- }
675
- async delete(id) {
676
- const client = await this.getClient();
677
- await client.vectorStores.del(id);
678
- }
679
- async addFile(storeId, opts) {
680
- const client = await this.getClient();
681
- // Step 1: resolve the file id. If the user passed an existing one we
682
- // skip the upload; otherwise upload via the standard Files API and
683
- // reuse the resulting id.
684
- const fileId = opts.fileId ?? await this.uploadAndGetId(client, opts);
685
- // Step 2: attach to the store. OpenAI splits attribute + chunking
686
- // config from the file payload so we pass them as a sibling object.
687
- const attachParams = { file_id: fileId };
688
- if (opts.attributes)
689
- attachParams['attributes'] = opts.attributes;
690
- if (opts.chunkingStrategy)
691
- attachParams['chunking_strategy'] = opts.chunkingStrategy;
692
- const attached = await client.vectorStores.files.create(storeId, attachParams);
693
- if (opts.wait === false) {
694
- return fromOpenAIVectorStoreFile(attached, storeId);
695
- }
696
- // Step 3: poll until `completed` / `failed` / timeout. Default 2-min
697
- // budget — enough for typical PDFs but small enough that runaway
698
- // batch uploads surface a clear error fast.
699
- const pollInterval = opts.pollInterval ?? 1000;
700
- const pollTimeout = opts.pollTimeout ?? 120_000;
701
- const deadline = Date.now() + pollTimeout;
702
- let current = attached;
703
- while (true) {
704
- const info = fromOpenAIVectorStoreFile(current, storeId);
705
- if (info.status === 'completed' || info.status === 'failed' || info.status === 'cancelled') {
706
- return info;
707
- }
708
- if (Date.now() > deadline) {
709
- throw new Error(`[Rudder AI] vector-store file ingestion timed out after ${pollTimeout}ms ` +
710
- `(store=${storeId}, file=${fileId}, status=${info.status}). ` +
711
- 'Increase pollTimeout or set wait: false for fire-and-forget.');
712
- }
713
- await sleep(pollInterval);
714
- current = await client.vectorStores.files.retrieve(storeId, fileId);
715
- }
716
- }
717
- async removeFile(storeId, fileId) {
718
- const client = await this.getClient();
719
- await client.vectorStores.files.del(storeId, fileId);
720
- }
721
- async listFiles(storeId, opts) {
722
- const client = await this.getClient();
723
- const params = {};
724
- if (opts?.limit !== undefined)
725
- params['limit'] = opts.limit;
726
- if (opts?.after !== undefined)
727
- params['after'] = opts.after;
728
- if (opts?.before !== undefined)
729
- params['before'] = opts.before;
730
- const response = await client.vectorStores.files.list(storeId, params);
731
- const data = (response.data ?? []);
732
- return { files: data.map(d => fromOpenAIVectorStoreFile(d, storeId)) };
733
- }
734
- /** @internal — upload a local file via the Files API and return the
735
- * provider's file id. Used when the user passes `filePath` or
736
- * `fileBuffer` to `addFile` instead of an existing `fileId`. */
737
- async uploadAndGetId(client, opts) {
738
- if (opts.filePath) {
739
- const { createReadStream } = await import(/* @vite-ignore */ 'node:fs');
740
- const file = createReadStream(opts.filePath);
741
- const uploaded = await client.files.create({ file, purpose: 'assistants' });
742
- return uploaded.id;
743
- }
744
- if (opts.fileBuffer) {
745
- const { toFile } = await import(/* @vite-ignore */ 'openai/uploads');
746
- const file = await toFile(opts.fileBuffer.data, opts.fileBuffer.filename);
747
- const uploaded = await client.files.create({ file, purpose: 'assistants' });
748
- return uploaded.id;
749
- }
750
- throw new Error('[Rudder AI] addFile requires fileId, filePath, or fileBuffer. ' +
751
- 'Pass an existing OpenAI file id via { fileId } or a local source via { filePath }.');
752
- }
753
- }
754
- function fromOpenAIVectorStore(raw) {
755
- const r = raw;
756
- const fileCount = r.file_counts?.total ??
757
- (r.file_counts ? (r.file_counts.in_progress ?? 0) + (r.file_counts.completed ?? 0) + (r.file_counts.failed ?? 0) + (r.file_counts.cancelled ?? 0) : 0);
758
- const result = {
759
- id: r.id,
760
- name: r.name,
761
- createdAt: r.created_at,
762
- fileCount,
763
- };
764
- if (r.usage_bytes !== undefined)
765
- result.bytesUsed = r.usage_bytes;
766
- if (r.metadata !== undefined)
767
- result.metadata = r.metadata;
768
- return result;
769
- }
770
- function fromOpenAIVectorStoreFile(raw, storeId) {
771
- const r = raw;
772
- const status = r.status === 'completed' || r.status === 'failed' || r.status === 'cancelled' || r.status === 'in_progress'
773
- ? r.status
774
- : 'in_progress';
775
- const result = {
776
- id: r.id,
777
- vectorStoreId: storeId,
778
- status,
779
- createdAt: r.created_at,
780
- };
781
- if (r.usage_bytes !== undefined)
782
- result.bytes = r.usage_bytes;
783
- if (r.attributes !== undefined)
784
- result.attributes = r.attributes;
785
- if (r.last_error?.message !== undefined)
786
- result.lastError = r.last_error.message;
787
- return result;
788
- }
789
- function sleep(ms) {
790
- return new Promise(resolve => setTimeout(resolve, ms));
791
- }
792
- //# sourceMappingURL=openai.js.map