@rudderjs/ai 1.17.3 → 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,903 +0,0 @@
1
- import { base64ToUtf8 } from '../base64.js';
2
- import { buildGoogleCacheKey, splitContentsAtCache, durationToGoogleTtl, _internals as _registryInternals, } from './google-cache-registry.js';
3
- export class GoogleProvider {
4
- name = 'google';
5
- config;
6
- cacheRegistry;
7
- constructor(config, cacheRegistry) {
8
- this.config = config;
9
- if (cacheRegistry)
10
- this.cacheRegistry = cacheRegistry;
11
- }
12
- create(model) {
13
- return new GoogleAdapter(this.config, model, this.cacheRegistry);
14
- }
15
- createEmbedding(model) {
16
- return new GoogleEmbeddingAdapter(this.config, model);
17
- }
18
- createImage(model) {
19
- return new GoogleImageAdapter(this.config, model);
20
- }
21
- createFiles() {
22
- return new GoogleFileAdapter(this.config);
23
- }
24
- createVectorStores() {
25
- return new GoogleVectorStoreAdapter(this.config);
26
- }
27
- }
28
- // ─── Adapter ──────────────────────────────────────────────
29
- export class GoogleAdapter {
30
- config;
31
- model;
32
- cacheRegistry;
33
- client = null;
34
- constructor(config, model, cacheRegistry) {
35
- this.config = config;
36
- this.model = model;
37
- this.cacheRegistry = cacheRegistry;
38
- }
39
- async getClient() {
40
- if (this.client)
41
- return this.client;
42
- const sdk = await import(/* @vite-ignore */ '@google/genai');
43
- const GoogleGenAI = sdk.GoogleGenAI ?? sdk.default;
44
- this.client = new GoogleGenAI({ apiKey: this.config.apiKey });
45
- return this.client;
46
- }
47
- /**
48
- * Build the request payload, consulting the cache registry if `options.cache`
49
- * is set. Returns the payload for `generateContent` / `generateContentStream`
50
- * plus the cache key (so the caller can `forget()` it on a 404 stale-cache
51
- * retry).
52
- */
53
- async buildPayload(options) {
54
- const client = await this.getClient();
55
- const { system, contents } = toGeminiContents(options.messages);
56
- // `toGeminiTools` returns the already-wrapped top-level array
57
- // ({functionDeclarations: [...]} + any native blocks like google_search).
58
- const geminiTools = options.tools?.length ? toGeminiTools(options.tools) : undefined;
59
- const config = {};
60
- if (options.maxTokens)
61
- config['maxOutputTokens'] = options.maxTokens;
62
- if (options.temperature !== undefined)
63
- config['temperature'] = options.temperature;
64
- if (options.topP !== undefined)
65
- config['topP'] = options.topP;
66
- if (options.stop)
67
- config['stopSequences'] = options.stop;
68
- if (geminiTools && geminiTools.length > 0)
69
- config['tools'] = geminiTools;
70
- if (options.toolChoice)
71
- config['toolConfig'] = toGeminiToolConfig(options.toolChoice);
72
- // The Gemini SDK reads abortSignal from the config block.
73
- if (options.signal)
74
- config['abortSignal'] = options.signal;
75
- let cacheName = null;
76
- let cacheKey;
77
- if (this.cacheRegistry && options.cache) {
78
- cacheKey = buildGoogleCacheKey(this.model, options.cache, system, contents, geminiTools);
79
- if (cacheKey) {
80
- const { cached: cachedSlice } = splitContentsAtCache(contents, options.cache);
81
- cacheName = await this.cacheRegistry.resolve({
82
- client,
83
- model: this.model,
84
- cacheKey,
85
- ...(options.cache.instructions && system ? { systemInstruction: { parts: [{ text: system }] } } : {}),
86
- ...(cachedSlice.length > 0 ? { contents: cachedSlice } : {}),
87
- ...(options.cache.tools && geminiTools && geminiTools.length > 0 ? { tools: geminiTools } : {}),
88
- ...(options.cache.ttl ? { ttl: durationToGoogleTtl(options.cache.ttl) } : {}),
89
- });
90
- }
91
- }
92
- if (cacheName) {
93
- // Drop tools / system from the request — they're inherited from the cache resource.
94
- const { fresh } = splitContentsAtCache(contents, options.cache);
95
- const configForCachedRequest = { ...config };
96
- delete configForCachedRequest['tools'];
97
- configForCachedRequest['cachedContent'] = cacheName;
98
- return {
99
- payload: { model: this.model, contents: fresh, config: configForCachedRequest },
100
- cacheKey,
101
- };
102
- }
103
- return {
104
- payload: {
105
- model: this.model,
106
- contents,
107
- ...(system ? { systemInstruction: { parts: [{ text: system }] } } : {}),
108
- config,
109
- },
110
- cacheKey,
111
- };
112
- }
113
- async generate(options) {
114
- const { payload, cacheKey } = await this.buildPayload(options);
115
- const client = await this.getClient();
116
- try {
117
- const response = await client.models.generateContent(payload);
118
- return fromGeminiResponse(response);
119
- }
120
- catch (err) {
121
- if (cacheKey && this.cacheRegistry && _registryInternals.isNotFoundError(err)) {
122
- // Stale `cachedContent` resource — drop and retry once with a fresh build.
123
- await this.cacheRegistry.forget(cacheKey);
124
- const { payload: retryPayload } = await this.buildPayload(options);
125
- const response = await client.models.generateContent(retryPayload);
126
- return fromGeminiResponse(response);
127
- }
128
- throw err;
129
- }
130
- }
131
- async *stream(options) {
132
- let payloadAndKey = await this.buildPayload(options);
133
- const client = await this.getClient();
134
- let response;
135
- try {
136
- response = await client.models.generateContentStream(payloadAndKey.payload);
137
- }
138
- catch (err) {
139
- if (payloadAndKey.cacheKey && this.cacheRegistry && _registryInternals.isNotFoundError(err)) {
140
- await this.cacheRegistry.forget(payloadAndKey.cacheKey);
141
- payloadAndKey = await this.buildPayload(options);
142
- response = await client.models.generateContentStream(payloadAndKey.payload);
143
- }
144
- else {
145
- throw err;
146
- }
147
- }
148
- for await (const chunk of response) {
149
- const candidate = chunk.candidates?.[0];
150
- if (!candidate)
151
- continue;
152
- for (const part of candidate.content?.parts ?? []) {
153
- if (part.text) {
154
- yield { type: 'text-delta', text: part.text };
155
- }
156
- if (part.functionCall) {
157
- yield {
158
- type: 'tool-call',
159
- toolCall: {
160
- id: `call_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
161
- name: part.functionCall.name,
162
- arguments: part.functionCall.args ?? {},
163
- },
164
- };
165
- }
166
- }
167
- if (candidate.finishReason) {
168
- yield {
169
- type: 'finish',
170
- finishReason: candidate.finishReason === 'STOP' ? 'stop' : 'tool_calls',
171
- usage: chunk.usageMetadata ? {
172
- promptTokens: chunk.usageMetadata.promptTokenCount ?? 0,
173
- completionTokens: chunk.usageMetadata.candidatesTokenCount ?? 0,
174
- totalTokens: chunk.usageMetadata.totalTokenCount ?? 0,
175
- } : undefined,
176
- };
177
- }
178
- }
179
- }
180
- }
181
- // ─── Conversion Helpers ──────────────────────────────────
182
- function contentToString(content) {
183
- if (typeof content === 'string')
184
- return content;
185
- return content.filter(p => p.type === 'text').map(p => p.text).join('');
186
- }
187
- function contentToGeminiParts(content) {
188
- if (typeof content === 'string')
189
- return [{ text: content }];
190
- return content.map(p => {
191
- if (p.type === 'text')
192
- return { text: p.text };
193
- if (p.type === 'image')
194
- return { inlineData: { mimeType: p.mimeType, data: p.data } };
195
- // document — inline data for PDFs, text for text-based
196
- if (p.mimeType === 'application/pdf') {
197
- return { inlineData: { mimeType: p.mimeType, data: p.data } };
198
- }
199
- return { text: base64ToUtf8(p.data) };
200
- });
201
- }
202
- export function toGeminiContents(messages) {
203
- const systemMsgs = messages.filter(m => m.role === 'system');
204
- const rest = messages.filter(m => m.role !== 'system');
205
- const system = systemMsgs.length > 0
206
- ? systemMsgs.map(m => contentToString(m.content)).join('\n\n')
207
- : undefined;
208
- // Gemini's `functionResponse.name` must match the originating `functionCall.name`
209
- // (the function name like "search"), not the synthetic call id the adapter
210
- // generates per stream. Pre-build a (toolCallId → name) lookup by walking
211
- // every prior assistant message's `toolCalls`. Without this the receiving
212
- // model sees `name: "call_1234_abc"` and can't pair the result with the call.
213
- const toolNameByCallId = new Map();
214
- for (const m of rest) {
215
- if (m.role === 'assistant' && m.toolCalls?.length) {
216
- for (const tc of m.toolCalls)
217
- toolNameByCallId.set(tc.id, tc.name);
218
- }
219
- }
220
- const contents = rest.map(m => {
221
- if (m.role === 'assistant' && m.toolCalls?.length) {
222
- const text = contentToString(m.content);
223
- return {
224
- role: 'model',
225
- parts: [
226
- ...(text ? [{ text }] : []),
227
- ...m.toolCalls.map(tc => ({
228
- functionCall: { name: tc.name, args: tc.arguments },
229
- })),
230
- ],
231
- };
232
- }
233
- if (m.role === 'tool') {
234
- const callId = m.toolCallId;
235
- const name = (callId && toolNameByCallId.get(callId)) ?? 'unknown';
236
- return {
237
- role: 'user',
238
- parts: [{
239
- functionResponse: {
240
- name,
241
- response: typeof m.content === 'string' ? { result: m.content } : m.content,
242
- },
243
- }],
244
- };
245
- }
246
- return {
247
- role: m.role === 'assistant' ? 'model' : 'user',
248
- parts: contentToGeminiParts(m.content),
249
- };
250
- });
251
- return { system, contents };
252
- }
253
- /**
254
- * Build Gemini's `tools` array. The Gemini API accepts a mixed array where
255
- * function declarations live under one wrapper entry and provider-native
256
- * blocks (e.g. `{ google_search: {} }`) sit as separate top-level entries:
257
- *
258
- * tools: [
259
- * { functionDeclarations: [...] },
260
- * { google_search: {} },
261
- * ]
262
- *
263
- * Tools tagged with a recognized `providerHint.type` are emitted as their
264
- * native top-level block; everything else collects into one
265
- * `functionDeclarations` entry. Tools with unrecognized hints fall through
266
- * to the function-declaration shape — the input schema's still there, so
267
- * the worst case is the model treats it as a regular function-call tool.
268
- */
269
- function toGeminiTools(tools) {
270
- const fnDecls = [];
271
- const blocks = [];
272
- for (const t of tools) {
273
- if (t.providerHint?.type === 'web-search') {
274
- // Gemini's native search tool. The block's `google_search: {}` form is
275
- // intentional — Gemini doesn't accept allowed_domains / max_uses on
276
- // this block, so the WebSearch.domains() / .maxResults() opts are
277
- // ignored on this provider (documented on WebSearch).
278
- blocks.push({ google_search: {} });
279
- continue;
280
- }
281
- if (t.providerHint?.type === 'file-search') {
282
- // Gemini's native FileSearch tool (#B8.5). The OpenAI-shaped hint
283
- // (`vector_store_ids` + typed `filters`) is translated to Gemini's
284
- // shape (`fileSearchStoreNames` + `metadataFilter` string). `topK`
285
- // mirrors OpenAI's `max_num_results`.
286
- const storeNames = t.providerHint['vector_store_ids'] ?? [];
287
- const fileSearchConfig = {
288
- fileSearchStoreNames: storeNames,
289
- };
290
- const filters = t.providerHint['filters'];
291
- if (filters !== undefined) {
292
- fileSearchConfig['metadataFilter'] = filterToGeminiString(filters);
293
- }
294
- const maxNumResults = t.providerHint['max_num_results'];
295
- if (maxNumResults !== undefined) {
296
- fileSearchConfig['topK'] = maxNumResults;
297
- }
298
- blocks.push({ fileSearch: fileSearchConfig });
299
- continue;
300
- }
301
- fnDecls.push({
302
- name: t.name,
303
- description: t.description,
304
- parameters: t.parameters,
305
- });
306
- }
307
- if (fnDecls.length > 0)
308
- blocks.unshift({ functionDeclarations: fnDecls });
309
- return blocks;
310
- }
311
- /**
312
- * Translate a typed `FileSearchFilter` (OpenAI-shaped) into Gemini's
313
- * `metadataFilter` string syntax (#B8.5).
314
- *
315
- * - `{ type: 'eq', key, value }` → `key = value`
316
- * - `{ type: 'ne', key, value }` → `key != value`
317
- * - `{ type: 'gt', key, value }` → `key > value`
318
- * - `{ type: 'gte', key, value }` → `key >= value`
319
- * - `{ type: 'lt', key, value }` → `key < value`
320
- * - `{ type: 'lte', key, value }` → `key <= value`
321
- * - `{ type: 'and', filters }` → `(f1) AND (f2) AND ...`
322
- * - `{ type: 'or', filters }` → `(f1) OR (f2) OR ...`
323
- *
324
- * String values are wrapped in double quotes with `"` and `\` escaped.
325
- * Numbers and booleans render bare.
326
- *
327
- * Exported for unit testing — see `google-vector-stores.test.ts`.
328
- *
329
- * @internal
330
- */
331
- export function filterToGeminiString(filter) {
332
- switch (filter.type) {
333
- case 'eq':
334
- case 'ne':
335
- case 'gt':
336
- case 'gte':
337
- case 'lt':
338
- case 'lte': {
339
- const op = GEMINI_FILTER_OP[filter.type];
340
- return `${filter.key} ${op} ${formatGeminiValue(filter.value)}`;
341
- }
342
- case 'and':
343
- case 'or': {
344
- if (filter.filters.length === 0) {
345
- throw new Error(`[Rudder AI] Gemini metadataFilter: ${filter.type.toUpperCase()} requires at least one sub-filter.`);
346
- }
347
- const joiner = filter.type === 'and' ? ' AND ' : ' OR ';
348
- return filter.filters.map(f => `(${filterToGeminiString(f)})`).join(joiner);
349
- }
350
- }
351
- }
352
- const GEMINI_FILTER_OP = {
353
- eq: '=',
354
- ne: '!=',
355
- gt: '>',
356
- gte: '>=',
357
- lt: '<',
358
- lte: '<=',
359
- };
360
- function formatGeminiValue(value) {
361
- if (typeof value === 'string') {
362
- return `"${value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
363
- }
364
- return String(value);
365
- }
366
- function toGeminiToolConfig(choice) {
367
- if (choice === 'auto')
368
- return { functionCallingConfig: { mode: 'AUTO' } };
369
- if (choice === 'required')
370
- return { functionCallingConfig: { mode: 'ANY' } };
371
- if (choice === 'none')
372
- return { functionCallingConfig: { mode: 'NONE' } };
373
- if (typeof choice === 'object' && 'name' in choice) {
374
- return { functionCallingConfig: { mode: 'ANY', allowedFunctionNames: [choice.name] } };
375
- }
376
- return { functionCallingConfig: { mode: 'AUTO' } };
377
- }
378
- function fromGeminiResponse(response) {
379
- const candidate = response.candidates?.[0];
380
- const toolCalls = [];
381
- let text = '';
382
- for (const part of candidate?.content?.parts ?? []) {
383
- if (part.text)
384
- text += part.text;
385
- if (part.functionCall) {
386
- toolCalls.push({
387
- id: `call_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
388
- name: part.functionCall.name,
389
- arguments: part.functionCall.args ?? {},
390
- });
391
- }
392
- }
393
- return {
394
- message: {
395
- role: 'assistant',
396
- content: text,
397
- ...(toolCalls.length > 0 ? { toolCalls } : {}),
398
- },
399
- usage: {
400
- promptTokens: response.usageMetadata?.promptTokenCount ?? 0,
401
- completionTokens: response.usageMetadata?.candidatesTokenCount ?? 0,
402
- totalTokens: response.usageMetadata?.totalTokenCount ?? 0,
403
- },
404
- finishReason: toolCalls.length > 0 ? 'tool_calls' : 'stop',
405
- };
406
- }
407
- // ─── Embedding Adapter ──────────────────────────────────
408
- class GoogleEmbeddingAdapter {
409
- config;
410
- model;
411
- client = null;
412
- constructor(config, model) {
413
- this.config = config;
414
- this.model = model;
415
- }
416
- async getClient() {
417
- if (this.client)
418
- return this.client;
419
- const sdk = await import(/* @vite-ignore */ '@google/genai');
420
- const GoogleGenAI = sdk.GoogleGenAI ?? sdk.default;
421
- this.client = new GoogleGenAI({ apiKey: this.config.apiKey });
422
- return this.client;
423
- }
424
- async embed(input) {
425
- const client = await this.getClient();
426
- const inputs = Array.isArray(input) ? input : [input];
427
- const results = await Promise.all(inputs.map(text => client.models.embedContent({
428
- model: this.model,
429
- content: { parts: [{ text }] },
430
- })));
431
- const embeddings = results.map((r) => r.embedding?.values ?? []);
432
- return {
433
- embeddings,
434
- usage: { promptTokens: 0, totalTokens: 0 },
435
- };
436
- }
437
- }
438
- // ─── Image Generation Adapter (Imagen) ──────────────────
439
- const GOOGLE_IMAGE_SIZE_MAP = {
440
- square: '1024x1024',
441
- landscape: '1792x1024',
442
- portrait: '1024x1792',
443
- };
444
- class GoogleImageAdapter {
445
- config;
446
- model;
447
- constructor(config, model) {
448
- this.config = config;
449
- this.model = model;
450
- }
451
- async generate(options) {
452
- const size = options.size
453
- ? (GOOGLE_IMAGE_SIZE_MAP[options.size] ?? options.size)
454
- : '1024x1024';
455
- const [width, height] = size.split('x').map(Number);
456
- const body = {
457
- instances: [{ prompt: options.prompt }],
458
- parameters: {
459
- sampleCount: options.n ?? 1,
460
- ...(width && height ? { aspectRatio: `${width}:${height}` } : {}),
461
- },
462
- };
463
- const endpoint = `https://generativelanguage.googleapis.com/v1beta/models/${this.model}:predict?key=${this.config.apiKey}`;
464
- const res = await fetch(endpoint, {
465
- method: 'POST',
466
- headers: { 'Content-Type': 'application/json' },
467
- body: JSON.stringify(body),
468
- });
469
- if (!res.ok) {
470
- throw new Error(`[Rudder AI] Google image generation error: ${res.status} ${await res.text()}`);
471
- }
472
- const data = await res.json();
473
- return {
474
- images: (data.predictions ?? []).map((p) => ({
475
- ...(p.bytesBase64Encoded ? { base64: p.bytesBase64Encoded } : {}),
476
- })),
477
- model: this.model,
478
- };
479
- }
480
- }
481
- // ─── Files ──────────────────────────────────────────────
482
- class GoogleFileAdapter {
483
- config;
484
- client = null;
485
- constructor(config) {
486
- this.config = config;
487
- }
488
- async getClient() {
489
- if (this.client)
490
- return this.client;
491
- const sdk = await import(/* @vite-ignore */ '@google/genai');
492
- const GoogleGenAI = sdk.GoogleGenAI ?? sdk.default;
493
- this.client = new GoogleGenAI({ apiKey: this.config.apiKey });
494
- return this.client;
495
- }
496
- async upload(options) {
497
- const client = await this.getClient();
498
- const { readFile, stat } = await import(/* @vite-ignore */ 'node:fs/promises');
499
- const { basename } = await import(/* @vite-ignore */ 'node:path');
500
- const data = await readFile(options.filePath);
501
- const stats = await stat(options.filePath);
502
- const filename = basename(options.filePath);
503
- const response = await client.files.upload({
504
- file: new Blob([data]),
505
- config: { displayName: filename },
506
- });
507
- return {
508
- id: response.name ?? response.uri,
509
- filename,
510
- bytes: stats.size,
511
- };
512
- }
513
- async list() {
514
- const client = await this.getClient();
515
- const response = await client.files.list();
516
- const files = [];
517
- for (const f of response.files ?? response ?? []) {
518
- files.push({
519
- id: f.name ?? f.uri,
520
- filename: f.displayName ?? f.name ?? '',
521
- bytes: Number(f.sizeBytes ?? 0),
522
- });
523
- }
524
- return { files };
525
- }
526
- async delete(fileId) {
527
- const client = await this.getClient();
528
- await client.files.delete({ name: fileId });
529
- }
530
- }
531
- // ─── Vector Stores (Gemini FileSearchStores, #B8.5) ──────
532
- //
533
- // Gemini's hosted RAG surface is `ai.fileSearchStores.*` — a direct
534
- // OpenAI-equivalent that handles ingestion, chunking, embedding, and
535
- // retrieval server-side. NOT available on Vertex AI; the underlying SDK
536
- // methods throw for Vertex clients.
537
- //
538
- // Mapping decisions:
539
- // - `VectorStoreInfo.id` is the full Gemini resource name
540
- // (`fileSearchStores/foo-bar`). Apps pass it back verbatim to `get` /
541
- // `delete` / `addFile`.
542
- // - `VectorStoreInfo.name` is `displayName`. The OpenAI adapter populates
543
- // it from the store's name field; we use the user-supplied display name
544
- // to keep `create('Knowledge Base')` round-trip-able.
545
- // - `createdAt` is parsed from ISO 8601 to Unix seconds for parity with
546
- // OpenAI's `created_at`.
547
- // - `fileCount` sums `activeDocumentsCount + pendingDocumentsCount` (both
548
- // string-encoded). `failedDocumentsCount` is dropped — it's surfaced
549
- // per-file via `addFile`'s status when polling.
550
- // - `bytesUsed` is parsed from `sizeBytes` (string-encoded).
551
- // - Store-level `metadata` and `expiresAfter` are NOT supported by Gemini.
552
- // Passing them throws fail-loud so apps don't silently lose data.
553
- //
554
- // `addFile` paths:
555
- // - `{ fileId }` → `importFile` (re-uses an existing Files API file).
556
- // - `{ filePath | fileBuffer }` → `uploadToFileSearchStore` (single-shot
557
- // upload). Both paths return long-running operations; default
558
- // `wait: true` polls `client.operations.get` until `done`.
559
- // - `attributes` (Record<string, primitive>) → Gemini's `customMetadata`
560
- // array shape; booleans coerce to `stringValue: 'true' | 'false'`.
561
- class GoogleVectorStoreAdapter {
562
- config;
563
- client = null;
564
- constructor(config) {
565
- this.config = config;
566
- }
567
- async getClient() {
568
- if (this.client)
569
- return this.client;
570
- const sdk = await import(/* @vite-ignore */ '@google/genai');
571
- const GoogleGenAI = sdk.GoogleGenAI ?? sdk.default;
572
- this.client = new GoogleGenAI({ apiKey: this.config.apiKey });
573
- return this.client;
574
- }
575
- async create(opts) {
576
- if (opts.metadata) {
577
- throw new Error('[Rudder AI] Gemini FileSearchStores does not support store-level metadata. ' +
578
- 'Attach searchable metadata per-document via addFile({ attributes }).');
579
- }
580
- if (opts.expiresAfter) {
581
- throw new Error('[Rudder AI] Gemini FileSearchStores does not support expiresAfter. ' +
582
- 'Stores persist until explicitly deleted via VectorStores.delete().');
583
- }
584
- const client = await this.getClient();
585
- const response = await client.fileSearchStores.create({
586
- config: { displayName: opts.name },
587
- });
588
- return fromGeminiFileSearchStore(response, opts.name);
589
- }
590
- async list(opts) {
591
- const client = await this.getClient();
592
- const config = {};
593
- if (opts?.limit !== undefined)
594
- config['pageSize'] = opts.limit;
595
- if (opts?.after !== undefined)
596
- config['pageToken'] = opts.after;
597
- // Gemini paginates forward via pageToken only — `before` has no
598
- // equivalent. Drop it silently (matches OpenAI when `before` is unset).
599
- const pager = await client.fileSearchStores.list({ config });
600
- const items = Array.isArray(pager?.page) ? pager.page : [];
601
- return { stores: items.map(item => fromGeminiFileSearchStore(item)) };
602
- }
603
- async get(id) {
604
- const client = await this.getClient();
605
- const response = await client.fileSearchStores.get({ name: id });
606
- return fromGeminiFileSearchStore(response);
607
- }
608
- async delete(id) {
609
- const client = await this.getClient();
610
- // `force: true` mirrors OpenAI's behavior — deleting a store also
611
- // drops attached documents. Without `force`, Gemini returns
612
- // FAILED_PRECONDITION when the store has any documents.
613
- await client.fileSearchStores.delete({ name: id, config: { force: true } });
614
- }
615
- async addFile(storeId, opts) {
616
- const client = await this.getClient();
617
- const customMetadata = opts.attributes ? attributesToCustomMetadata(opts.attributes) : undefined;
618
- // Path 1: re-use an existing Files API file.
619
- if (opts.fileId) {
620
- const importConfig = {};
621
- if (customMetadata)
622
- importConfig['customMetadata'] = customMetadata;
623
- if (opts.chunkingStrategy)
624
- importConfig['chunkingConfig'] = opts.chunkingStrategy;
625
- const op = await client.fileSearchStores.importFile({
626
- fileSearchStoreName: storeId,
627
- fileName: opts.fileId,
628
- config: importConfig,
629
- });
630
- return finishVectorStoreOperation(client, op, storeId, opts);
631
- }
632
- // Path 2: upload a local file directly. Either `filePath` or
633
- // `fileBuffer` is required — Gemini's SDK accepts a path string OR a
634
- // Blob. For `filePath`, the SDK infers mimeType from the extension;
635
- // for `fileBuffer`, it reads `blob.type` which is empty on a
636
- // untyped `new Blob([data])`, so we forward an explicit `mimeType`
637
- // derived from `filename` to avoid `Can not determine mimeType`.
638
- if (opts.filePath || opts.fileBuffer) {
639
- const uploadConfig = {};
640
- if (customMetadata)
641
- uploadConfig['customMetadata'] = customMetadata;
642
- if (opts.chunkingStrategy)
643
- uploadConfig['chunkingConfig'] = opts.chunkingStrategy;
644
- if (opts.fileBuffer?.filename)
645
- uploadConfig['displayName'] = opts.fileBuffer.filename;
646
- if (opts.fileBuffer?.filename) {
647
- const mimeType = mimeTypeFromFilename(opts.fileBuffer.filename);
648
- if (mimeType)
649
- uploadConfig['mimeType'] = mimeType;
650
- }
651
- const file = opts.filePath ?? new Blob([opts.fileBuffer.data]);
652
- const op = await client.fileSearchStores.uploadToFileSearchStore({
653
- fileSearchStoreName: storeId,
654
- file,
655
- config: uploadConfig,
656
- });
657
- return finishVectorStoreOperation(client, op, storeId, opts);
658
- }
659
- throw new Error('[Rudder AI] addFile requires fileId, filePath, or fileBuffer. ' +
660
- 'Pass an existing Gemini Files API id via { fileId } (e.g. `files/abc-123`) or ' +
661
- 'a local source via { filePath } / { fileBuffer }.');
662
- }
663
- async removeFile(storeId, fileId) {
664
- const client = await this.getClient();
665
- // Document resource names are `fileSearchStores/<store>/documents/<doc>`.
666
- // Apps that pass the full path use it verbatim; apps that pass only
667
- // the document id get the store prefix joined for them.
668
- const name = fileId.includes('/documents/') ? fileId : `${storeId}/documents/${fileId}`;
669
- await client.fileSearchStores.documents.delete({ name });
670
- }
671
- async listFiles(storeId, opts) {
672
- const client = await this.getClient();
673
- const config = {};
674
- if (opts?.limit !== undefined)
675
- config['pageSize'] = opts.limit;
676
- if (opts?.after !== undefined)
677
- config['pageToken'] = opts.after;
678
- const pager = await client.fileSearchStores.documents.list({ parent: storeId, config });
679
- const items = Array.isArray(pager?.page) ? pager.page : [];
680
- return { files: items.map(doc => fromGeminiDocument(doc, storeId)) };
681
- }
682
- }
683
- /**
684
- * Wait for a long-running file ingestion operation to finish and map the
685
- * result into `VectorStoreFileInfo`. Honors `wait`/`pollInterval`/
686
- * `pollTimeout` from `VectorStoreAddOptions` (defaults: wait=true,
687
- * interval=1000ms, timeout=120_000ms).
688
- *
689
- * The terminal state of a Gemini ingestion op is exposed two ways:
690
- * - `op.error?: { code, message }` when ingestion failed.
691
- * - `op.response?: { documentName: 'fileSearchStores/.../documents/...' }`
692
- * when successful.
693
- *
694
- * On success we follow up with a single `documents.get` to fetch
695
- * `state` / `sizeBytes` / `createTime`. On failure we surface the error
696
- * message via `lastError` and the status flips to `'failed'`.
697
- */
698
- async function finishVectorStoreOperation(client, initialOp, storeId, opts) {
699
- if (opts.wait === false) {
700
- return {
701
- id: initialOp?.name ?? `${storeId}/documents/pending-${Date.now()}`,
702
- vectorStoreId: storeId,
703
- status: 'in_progress',
704
- createdAt: Math.floor(Date.now() / 1000),
705
- ...(opts.attributes ? { attributes: opts.attributes } : {}),
706
- };
707
- }
708
- const pollInterval = opts.pollInterval ?? 1000;
709
- const pollTimeout = opts.pollTimeout ?? 120_000;
710
- const deadline = Date.now() + pollTimeout;
711
- let current = initialOp;
712
- while (!current?.done) {
713
- if (Date.now() > deadline) {
714
- throw new Error(`[Rudder AI] Gemini FileSearchStore ingestion timed out after ${pollTimeout}ms ` +
715
- `(store=${storeId}). Increase pollTimeout or set wait: false for fire-and-forget.`);
716
- }
717
- await sleep(pollInterval);
718
- current = await client.operations.get({ operation: current });
719
- }
720
- if (current.error) {
721
- const errMessage = current.error.message ?? 'unknown error';
722
- return {
723
- id: current.name ?? `${storeId}/documents/failed-${Date.now()}`,
724
- vectorStoreId: storeId,
725
- status: 'failed',
726
- createdAt: Math.floor(Date.now() / 1000),
727
- lastError: errMessage,
728
- ...(opts.attributes ? { attributes: opts.attributes } : {}),
729
- };
730
- }
731
- const documentName = current.response?.documentName;
732
- if (!documentName) {
733
- // Op done, no error, no documentName — surface as completed without
734
- // follow-up details rather than failing.
735
- return {
736
- id: current.name ?? `${storeId}/documents/unknown-${Date.now()}`,
737
- vectorStoreId: storeId,
738
- status: 'completed',
739
- createdAt: Math.floor(Date.now() / 1000),
740
- ...(opts.attributes ? { attributes: opts.attributes } : {}),
741
- };
742
- }
743
- // Follow up with documents.get to surface real createdAt + sizeBytes.
744
- // Best-effort: if the get fails (rare race), fall back to the op data.
745
- try {
746
- const doc = await client.fileSearchStores.documents.get({ name: documentName });
747
- const info = fromGeminiDocument(doc, storeId);
748
- if (opts.attributes && !info.attributes)
749
- info.attributes = opts.attributes;
750
- return info;
751
- }
752
- catch {
753
- return {
754
- id: documentName,
755
- vectorStoreId: storeId,
756
- status: 'completed',
757
- createdAt: Math.floor(Date.now() / 1000),
758
- ...(opts.attributes ? { attributes: opts.attributes } : {}),
759
- };
760
- }
761
- }
762
- /**
763
- * Map a Gemini `FileSearchStore` resource into the framework's
764
- * `VectorStoreInfo` shape. `displayNameOverride` lets `create()` populate
765
- * the human-friendly name from the user-supplied value when the API
766
- * response omits it (some response variants do).
767
- *
768
- * @internal
769
- */
770
- export function fromGeminiFileSearchStore(raw, displayNameOverride) {
771
- const r = raw;
772
- const id = r.name ?? '';
773
- const active = Number(r.activeDocumentsCount ?? 0) || 0;
774
- const pending = Number(r.pendingDocumentsCount ?? 0) || 0;
775
- const result = {
776
- id,
777
- name: r.displayName ?? displayNameOverride ?? id,
778
- createdAt: r.createTime ? Math.floor(Date.parse(r.createTime) / 1000) : Math.floor(Date.now() / 1000),
779
- fileCount: active + pending,
780
- };
781
- if (r.sizeBytes !== undefined) {
782
- const bytes = Number(r.sizeBytes);
783
- if (Number.isFinite(bytes))
784
- result.bytesUsed = bytes;
785
- }
786
- return result;
787
- }
788
- /**
789
- * Map a Gemini `Document` resource into the framework's
790
- * `VectorStoreFileInfo` shape. `DocumentState` enum values flatten to the
791
- * shared `'in_progress' | 'completed' | 'failed' | 'cancelled'` union.
792
- *
793
- * @internal
794
- */
795
- export function fromGeminiDocument(raw, storeId) {
796
- const r = raw;
797
- const status = mapGeminiDocumentState(r.state);
798
- const result = {
799
- id: r.name ?? `${storeId}/documents/unknown`,
800
- vectorStoreId: storeId,
801
- status,
802
- createdAt: r.createTime ? Math.floor(Date.parse(r.createTime) / 1000) : Math.floor(Date.now() / 1000),
803
- };
804
- if (r.sizeBytes !== undefined) {
805
- const bytes = Number(r.sizeBytes);
806
- if (Number.isFinite(bytes))
807
- result.bytes = bytes;
808
- }
809
- if (r.customMetadata && r.customMetadata.length > 0) {
810
- result.attributes = customMetadataToAttributes(r.customMetadata);
811
- }
812
- return result;
813
- }
814
- function mapGeminiDocumentState(state) {
815
- switch (state) {
816
- case 'STATE_ACTIVE': return 'completed';
817
- case 'STATE_FAILED': return 'failed';
818
- case 'STATE_PENDING': return 'in_progress';
819
- default: return 'in_progress';
820
- }
821
- }
822
- /**
823
- * Convert the framework's flat attribute map to Gemini's `CustomMetadata`
824
- * array shape. Strings → `stringValue`, numbers → `numericValue`,
825
- * booleans → `stringValue: 'true' | 'false'` (Gemini has no boolean
826
- * variant — string is the safe lossless choice; filter-builders can
827
- * still match on `key = "true"`).
828
- *
829
- * @internal
830
- */
831
- export function attributesToCustomMetadata(attrs) {
832
- return Object.entries(attrs).map(([key, value]) => {
833
- if (typeof value === 'number')
834
- return { key, numericValue: value };
835
- if (typeof value === 'boolean')
836
- return { key, stringValue: value ? 'true' : 'false' };
837
- return { key, stringValue: value };
838
- });
839
- }
840
- /**
841
- * Inverse of {@link attributesToCustomMetadata}. Drops `stringListValue`
842
- * variants (no flat-attribute representation; apps that need lists
843
- * should read the raw Document via the SDK).
844
- *
845
- * @internal
846
- */
847
- export function customMetadataToAttributes(metadata) {
848
- const out = {};
849
- for (const entry of metadata) {
850
- if (!entry.key)
851
- continue;
852
- if (entry.numericValue !== undefined)
853
- out[entry.key] = entry.numericValue;
854
- else if (entry.stringValue !== undefined) {
855
- // Round-trip booleans encoded by attributesToCustomMetadata.
856
- if (entry.stringValue === 'true')
857
- out[entry.key] = true;
858
- else if (entry.stringValue === 'false')
859
- out[entry.key] = false;
860
- else
861
- out[entry.key] = entry.stringValue;
862
- }
863
- // stringListValue intentionally dropped.
864
- }
865
- return out;
866
- }
867
- function sleep(ms) {
868
- return new Promise(resolve => setTimeout(resolve, ms));
869
- }
870
- /**
871
- * Best-effort MIME type from a filename extension. Gemini's
872
- * `uploadToFileSearchStore` requires a mimeType on Blob uploads (it
873
- * reads `blob.type`, which is empty on untyped `new Blob([data])`).
874
- *
875
- * Coverage matches Gemini's supported FileSearchStore document formats.
876
- * Unknown extensions return `''` — the caller drops the field so the
877
- * Gemini SDK's own error fires loudly rather than silently picking a
878
- * wrong type.
879
- *
880
- * @internal
881
- */
882
- export function mimeTypeFromFilename(filename) {
883
- const ext = filename.toLowerCase().split('.').pop() ?? '';
884
- switch (ext) {
885
- case 'txt': return 'text/plain';
886
- case 'md': return 'text/markdown';
887
- case 'pdf': return 'application/pdf';
888
- case 'html':
889
- case 'htm': return 'text/html';
890
- case 'json': return 'application/json';
891
- case 'csv': return 'text/csv';
892
- case 'tsv': return 'text/tab-separated-values';
893
- case 'xml': return 'application/xml';
894
- case 'rtf': return 'application/rtf';
895
- case 'doc': return 'application/msword';
896
- case 'docx': return 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
897
- case 'js': return 'text/javascript';
898
- case 'ts': return 'text/x-typescript';
899
- case 'py': return 'text/x-python';
900
- default: return '';
901
- }
902
- }
903
- //# sourceMappingURL=google.js.map