@illuma-ai/agents 1.4.0-alpha.6 → 1.5.1

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 (653) hide show
  1. package/README.md +62 -0
  2. package/dist/cjs/agents/AgentContext.cjs +274 -67
  3. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  4. package/dist/cjs/common/enum.cjs +44 -13
  5. package/dist/cjs/common/enum.cjs.map +1 -1
  6. package/dist/cjs/graphs/Graph.cjs +182 -5
  7. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  8. package/dist/cjs/graphs/MultiAgentGraph.cjs +152 -1167
  9. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  10. package/dist/cjs/graphs/phases/memoryFlushPhase.cjs +1 -1
  11. package/dist/cjs/graphs/phases/memoryFlushPhase.cjs.map +1 -1
  12. package/dist/cjs/hooks/HookRegistry.cjs +162 -0
  13. package/dist/cjs/hooks/HookRegistry.cjs.map +1 -0
  14. package/dist/cjs/hooks/executeHooks.cjs +276 -0
  15. package/dist/cjs/hooks/executeHooks.cjs.map +1 -0
  16. package/dist/cjs/hooks/matchers.cjs +256 -0
  17. package/dist/cjs/hooks/matchers.cjs.map +1 -0
  18. package/dist/cjs/hooks/types.cjs +27 -0
  19. package/dist/cjs/hooks/types.cjs.map +1 -0
  20. package/dist/cjs/langchain/google-common.cjs +3 -0
  21. package/dist/cjs/langchain/google-common.cjs.map +1 -0
  22. package/dist/cjs/langchain/index.cjs +86 -0
  23. package/dist/cjs/langchain/index.cjs.map +1 -0
  24. package/dist/cjs/langchain/language_models/chat_models.cjs +3 -0
  25. package/dist/cjs/langchain/language_models/chat_models.cjs.map +1 -0
  26. package/dist/cjs/langchain/messages/tool.cjs +3 -0
  27. package/dist/cjs/langchain/messages/tool.cjs.map +1 -0
  28. package/dist/cjs/langchain/messages.cjs +51 -0
  29. package/dist/cjs/langchain/messages.cjs.map +1 -0
  30. package/dist/cjs/langchain/openai.cjs +3 -0
  31. package/dist/cjs/langchain/openai.cjs.map +1 -0
  32. package/dist/cjs/langchain/prompts.cjs +11 -0
  33. package/dist/cjs/langchain/prompts.cjs.map +1 -0
  34. package/dist/cjs/langchain/runnables.cjs +19 -0
  35. package/dist/cjs/langchain/runnables.cjs.map +1 -0
  36. package/dist/cjs/langchain/tools.cjs +23 -0
  37. package/dist/cjs/langchain/tools.cjs.map +1 -0
  38. package/dist/cjs/langchain/utils/env.cjs +11 -0
  39. package/dist/cjs/langchain/utils/env.cjs.map +1 -0
  40. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +5 -1
  41. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  42. package/dist/cjs/llm/bedrock/cacheSupport.cjs +55 -0
  43. package/dist/cjs/llm/bedrock/cacheSupport.cjs.map +1 -0
  44. package/dist/cjs/llm/bedrock/index.cjs +61 -33
  45. package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
  46. package/dist/cjs/llm/openai/index.cjs +1 -4
  47. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  48. package/dist/cjs/llm/openai/utils/index.cjs +27 -10
  49. package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
  50. package/dist/cjs/main.cjs +178 -127
  51. package/dist/cjs/main.cjs.map +1 -1
  52. package/dist/cjs/memory/citations.cjs +4 -4
  53. package/dist/cjs/memory/citations.cjs.map +1 -1
  54. package/dist/cjs/memory/constants.cjs +17 -17
  55. package/dist/cjs/memory/constants.cjs.map +1 -1
  56. package/dist/cjs/memory/mmr.cjs +1 -1
  57. package/dist/cjs/memory/mmr.cjs.map +1 -1
  58. package/dist/cjs/memory/paths.cjs +1 -1
  59. package/dist/cjs/memory/paths.cjs.map +1 -1
  60. package/dist/cjs/memory/recallTracking.cjs +3 -3
  61. package/dist/cjs/memory/recallTracking.cjs.map +1 -1
  62. package/dist/cjs/memory/temporalDecay.cjs +2 -2
  63. package/dist/cjs/memory/temporalDecay.cjs.map +1 -1
  64. package/dist/cjs/messages/cache.cjs +89 -0
  65. package/dist/cjs/messages/cache.cjs.map +1 -1
  66. package/dist/cjs/messages/contextPruning.cjs +156 -0
  67. package/dist/cjs/messages/contextPruning.cjs.map +1 -0
  68. package/dist/cjs/messages/contextPruningSettings.cjs +53 -0
  69. package/dist/cjs/messages/contextPruningSettings.cjs.map +1 -0
  70. package/dist/cjs/messages/format.cjs +144 -20
  71. package/dist/cjs/messages/format.cjs.map +1 -1
  72. package/dist/cjs/messages/prune.cjs +505 -4
  73. package/dist/cjs/messages/prune.cjs.map +1 -1
  74. package/dist/cjs/run.cjs +141 -1
  75. package/dist/cjs/run.cjs.map +1 -1
  76. package/dist/cjs/tools/BashExecutor.cjs +235 -0
  77. package/dist/cjs/tools/BashExecutor.cjs.map +1 -0
  78. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +297 -0
  79. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -0
  80. package/dist/cjs/tools/CodeExecutor.cjs +45 -47
  81. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  82. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +16 -11
  83. package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
  84. package/dist/cjs/tools/ReadFile.cjs +44 -0
  85. package/dist/cjs/tools/ReadFile.cjs.map +1 -0
  86. package/dist/cjs/tools/SkillTool.cjs +51 -0
  87. package/dist/cjs/tools/SkillTool.cjs.map +1 -0
  88. package/dist/cjs/tools/SubagentTool.cjs +93 -0
  89. package/dist/cjs/tools/SubagentTool.cjs.map +1 -0
  90. package/dist/cjs/tools/ToolNode.cjs +450 -24
  91. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  92. package/dist/cjs/tools/memory/memoryAppendTool.cjs +1 -1
  93. package/dist/cjs/tools/memory/memoryAppendTool.cjs.map +1 -1
  94. package/dist/cjs/tools/memory/memoryGetTool.cjs +2 -2
  95. package/dist/cjs/tools/memory/memoryGetTool.cjs.map +1 -1
  96. package/dist/cjs/tools/memory/memorySearchTool.cjs +3 -3
  97. package/dist/cjs/tools/memory/memorySearchTool.cjs.map +1 -1
  98. package/dist/cjs/tools/memory/shared.cjs +1 -1
  99. package/dist/cjs/tools/memory/shared.cjs.map +1 -1
  100. package/dist/cjs/tools/search/search.cjs +11 -3
  101. package/dist/cjs/tools/search/search.cjs.map +1 -1
  102. package/dist/cjs/tools/search/tavily-scraper.cjs +189 -0
  103. package/dist/cjs/tools/search/tavily-scraper.cjs.map +1 -0
  104. package/dist/cjs/tools/search/tavily-search.cjs +372 -0
  105. package/dist/cjs/tools/search/tavily-search.cjs.map +1 -0
  106. package/dist/cjs/tools/search/tool.cjs +28 -4
  107. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  108. package/dist/cjs/tools/search/utils.cjs +10 -3
  109. package/dist/cjs/tools/search/utils.cjs.map +1 -1
  110. package/dist/cjs/tools/skillCatalog.cjs +84 -0
  111. package/dist/cjs/tools/skillCatalog.cjs.map +1 -0
  112. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +512 -0
  113. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -0
  114. package/dist/cjs/tools/toolOutputReferences.cjs +670 -0
  115. package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -0
  116. package/dist/cjs/types/agent-cache.cjs +54 -0
  117. package/dist/cjs/types/agent-cache.cjs.map +1 -0
  118. package/dist/cjs/types/graph.cjs.map +1 -1
  119. package/dist/cjs/utils/truncation.cjs +135 -0
  120. package/dist/cjs/utils/truncation.cjs.map +1 -0
  121. package/dist/esm/agents/AgentContext.mjs +274 -67
  122. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  123. package/dist/esm/common/enum.mjs +44 -12
  124. package/dist/esm/common/enum.mjs.map +1 -1
  125. package/dist/esm/graphs/Graph.mjs +182 -5
  126. package/dist/esm/graphs/Graph.mjs.map +1 -1
  127. package/dist/esm/graphs/MultiAgentGraph.mjs +155 -1170
  128. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  129. package/dist/esm/graphs/phases/memoryFlushPhase.mjs +1 -1
  130. package/dist/esm/graphs/phases/memoryFlushPhase.mjs.map +1 -1
  131. package/dist/esm/hooks/HookRegistry.mjs +160 -0
  132. package/dist/esm/hooks/HookRegistry.mjs.map +1 -0
  133. package/dist/esm/hooks/executeHooks.mjs +273 -0
  134. package/dist/esm/hooks/executeHooks.mjs.map +1 -0
  135. package/dist/esm/hooks/matchers.mjs +251 -0
  136. package/dist/esm/hooks/matchers.mjs.map +1 -0
  137. package/dist/esm/hooks/types.mjs +25 -0
  138. package/dist/esm/hooks/types.mjs.map +1 -0
  139. package/dist/esm/langchain/google-common.mjs +2 -0
  140. package/dist/esm/langchain/google-common.mjs.map +1 -0
  141. package/dist/esm/langchain/index.mjs +5 -0
  142. package/dist/esm/langchain/language_models/chat_models.mjs +2 -0
  143. package/dist/esm/langchain/language_models/chat_models.mjs.map +1 -0
  144. package/dist/esm/langchain/messages/tool.mjs +2 -0
  145. package/dist/esm/langchain/messages/tool.mjs.map +1 -0
  146. package/dist/esm/langchain/messages.mjs +2 -0
  147. package/dist/esm/langchain/messages.mjs.map +1 -0
  148. package/dist/esm/langchain/openai.mjs +2 -0
  149. package/dist/esm/langchain/openai.mjs.map +1 -0
  150. package/dist/esm/langchain/prompts.mjs +2 -0
  151. package/dist/esm/langchain/prompts.mjs.map +1 -0
  152. package/dist/esm/langchain/runnables.mjs +2 -0
  153. package/dist/esm/langchain/runnables.mjs.map +1 -0
  154. package/dist/esm/langchain/tools.mjs +2 -0
  155. package/dist/esm/langchain/tools.mjs.map +1 -0
  156. package/dist/esm/langchain/utils/env.mjs +2 -0
  157. package/dist/esm/langchain/utils/env.mjs.map +1 -0
  158. package/dist/esm/llm/anthropic/utils/message_inputs.mjs +5 -1
  159. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  160. package/dist/esm/llm/bedrock/cacheSupport.mjs +52 -0
  161. package/dist/esm/llm/bedrock/cacheSupport.mjs.map +1 -0
  162. package/dist/esm/llm/bedrock/index.mjs +61 -34
  163. package/dist/esm/llm/bedrock/index.mjs.map +1 -1
  164. package/dist/esm/llm/openai/index.mjs +1 -4
  165. package/dist/esm/llm/openai/index.mjs.map +1 -1
  166. package/dist/esm/llm/openai/utils/index.mjs +27 -10
  167. package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
  168. package/dist/esm/main.mjs +21 -27
  169. package/dist/esm/main.mjs.map +1 -1
  170. package/dist/esm/memory/citations.mjs +4 -4
  171. package/dist/esm/memory/citations.mjs.map +1 -1
  172. package/dist/esm/memory/constants.mjs +17 -17
  173. package/dist/esm/memory/constants.mjs.map +1 -1
  174. package/dist/esm/memory/mmr.mjs +1 -1
  175. package/dist/esm/memory/mmr.mjs.map +1 -1
  176. package/dist/esm/memory/paths.mjs +1 -1
  177. package/dist/esm/memory/paths.mjs.map +1 -1
  178. package/dist/esm/memory/recallTracking.mjs +3 -3
  179. package/dist/esm/memory/recallTracking.mjs.map +1 -1
  180. package/dist/esm/memory/temporalDecay.mjs +2 -2
  181. package/dist/esm/memory/temporalDecay.mjs.map +1 -1
  182. package/dist/esm/messages/cache.mjs +89 -0
  183. package/dist/esm/messages/cache.mjs.map +1 -1
  184. package/dist/esm/messages/contextPruning.mjs +154 -0
  185. package/dist/esm/messages/contextPruning.mjs.map +1 -0
  186. package/dist/esm/messages/contextPruningSettings.mjs +50 -0
  187. package/dist/esm/messages/contextPruningSettings.mjs.map +1 -0
  188. package/dist/esm/messages/format.mjs +136 -12
  189. package/dist/esm/messages/format.mjs.map +1 -1
  190. package/dist/esm/messages/prune.mjs +504 -7
  191. package/dist/esm/messages/prune.mjs.map +1 -1
  192. package/dist/esm/run.mjs +141 -1
  193. package/dist/esm/run.mjs.map +1 -1
  194. package/dist/esm/tools/BashExecutor.mjs +227 -0
  195. package/dist/esm/tools/BashExecutor.mjs.map +1 -0
  196. package/dist/esm/tools/BashProgrammaticToolCalling.mjs +288 -0
  197. package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -0
  198. package/dist/esm/tools/CodeExecutor.mjs +45 -48
  199. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  200. package/dist/esm/tools/ProgrammaticToolCalling.mjs +17 -12
  201. package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
  202. package/dist/esm/tools/ReadFile.mjs +39 -0
  203. package/dist/esm/tools/ReadFile.mjs.map +1 -0
  204. package/dist/esm/tools/SkillTool.mjs +46 -0
  205. package/dist/esm/tools/SkillTool.mjs.map +1 -0
  206. package/dist/esm/tools/SubagentTool.mjs +86 -0
  207. package/dist/esm/tools/SubagentTool.mjs.map +1 -0
  208. package/dist/esm/tools/ToolNode.mjs +452 -26
  209. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  210. package/dist/esm/tools/memory/memoryAppendTool.mjs +1 -1
  211. package/dist/esm/tools/memory/memoryAppendTool.mjs.map +1 -1
  212. package/dist/esm/tools/memory/memoryGetTool.mjs +2 -2
  213. package/dist/esm/tools/memory/memoryGetTool.mjs.map +1 -1
  214. package/dist/esm/tools/memory/memorySearchTool.mjs +3 -3
  215. package/dist/esm/tools/memory/memorySearchTool.mjs.map +1 -1
  216. package/dist/esm/tools/memory/shared.mjs +1 -1
  217. package/dist/esm/tools/memory/shared.mjs.map +1 -1
  218. package/dist/esm/tools/search/search.mjs +11 -3
  219. package/dist/esm/tools/search/search.mjs.map +1 -1
  220. package/dist/esm/tools/search/tavily-scraper.mjs +186 -0
  221. package/dist/esm/tools/search/tavily-scraper.mjs.map +1 -0
  222. package/dist/esm/tools/search/tavily-search.mjs +370 -0
  223. package/dist/esm/tools/search/tavily-search.mjs.map +1 -0
  224. package/dist/esm/tools/search/tool.mjs +28 -4
  225. package/dist/esm/tools/search/tool.mjs.map +1 -1
  226. package/dist/esm/tools/search/utils.mjs +10 -3
  227. package/dist/esm/tools/search/utils.mjs.map +1 -1
  228. package/dist/esm/tools/skillCatalog.mjs +82 -0
  229. package/dist/esm/tools/skillCatalog.mjs.map +1 -0
  230. package/dist/esm/tools/subagent/SubagentExecutor.mjs +506 -0
  231. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -0
  232. package/dist/esm/tools/toolOutputReferences.mjs +662 -0
  233. package/dist/esm/tools/toolOutputReferences.mjs.map +1 -0
  234. package/dist/esm/types/agent-cache.mjs +52 -0
  235. package/dist/esm/types/agent-cache.mjs.map +1 -0
  236. package/dist/esm/types/graph.mjs.map +1 -1
  237. package/dist/esm/utils/truncation.mjs +128 -0
  238. package/dist/esm/utils/truncation.mjs.map +1 -0
  239. package/dist/types/agents/AgentContext.d.ts +101 -8
  240. package/dist/types/common/enum.d.ts +39 -12
  241. package/dist/types/common/index.d.ts +0 -1
  242. package/dist/types/graphs/Graph.d.ts +43 -0
  243. package/dist/types/graphs/MultiAgentGraph.d.ts +26 -150
  244. package/dist/types/graphs/index.d.ts +0 -1
  245. package/dist/types/graphs/phases/memoryFlushPhase.d.ts +2 -2
  246. package/dist/types/hooks/HookRegistry.d.ts +56 -0
  247. package/dist/types/hooks/executeHooks.d.ts +79 -0
  248. package/dist/types/hooks/index.d.ts +6 -0
  249. package/dist/types/hooks/matchers.d.ts +95 -0
  250. package/dist/types/hooks/types.d.ts +320 -0
  251. package/dist/types/index.d.ts +9 -9
  252. package/dist/types/langchain/google-common.d.ts +1 -0
  253. package/dist/types/langchain/index.d.ts +8 -0
  254. package/dist/types/langchain/language_models/chat_models.d.ts +1 -0
  255. package/dist/types/langchain/messages/tool.d.ts +1 -0
  256. package/dist/types/langchain/messages.d.ts +2 -0
  257. package/dist/types/langchain/openai.d.ts +1 -0
  258. package/dist/types/langchain/prompts.d.ts +1 -0
  259. package/dist/types/langchain/runnables.d.ts +2 -0
  260. package/dist/types/langchain/tools.d.ts +2 -0
  261. package/dist/types/langchain/utils/env.d.ts +1 -0
  262. package/dist/types/llm/bedrock/cacheSupport.d.ts +35 -0
  263. package/dist/types/llm/bedrock/index.d.ts +54 -1
  264. package/dist/types/llm/openai/index.d.ts +1 -1
  265. package/dist/types/memory/citations.d.ts +4 -4
  266. package/dist/types/memory/constants.d.ts +17 -17
  267. package/dist/types/memory/mmr.d.ts +3 -3
  268. package/dist/types/memory/paths.d.ts +1 -1
  269. package/dist/types/memory/temporalDecay.d.ts +2 -2
  270. package/dist/types/memory/types.d.ts +3 -3
  271. package/dist/types/messages/contextPruning.d.ts +42 -0
  272. package/dist/types/messages/contextPruningSettings.d.ts +44 -0
  273. package/dist/types/messages/format.d.ts +9 -1
  274. package/dist/types/messages/index.d.ts +2 -0
  275. package/dist/types/messages/prune.d.ts +91 -1
  276. package/dist/types/run.d.ts +2 -0
  277. package/dist/types/tools/BashExecutor.d.ts +76 -0
  278. package/dist/types/tools/BashProgrammaticToolCalling.d.ts +72 -0
  279. package/dist/types/tools/CodeExecutor.d.ts +8 -26
  280. package/dist/types/tools/ReadFile.d.ts +28 -0
  281. package/dist/types/tools/SkillTool.d.ts +40 -0
  282. package/dist/types/tools/SubagentTool.d.ts +36 -0
  283. package/dist/types/tools/ToolNode.d.ts +77 -5
  284. package/dist/types/tools/memory/shared.d.ts +1 -1
  285. package/dist/types/tools/search/tavily-scraper.d.ts +19 -0
  286. package/dist/types/tools/search/tavily-search.d.ts +4 -0
  287. package/dist/types/tools/search/types.d.ts +99 -5
  288. package/dist/types/tools/search/utils.d.ts +2 -2
  289. package/dist/types/tools/skillCatalog.d.ts +19 -0
  290. package/dist/types/tools/subagent/SubagentExecutor.d.ts +137 -0
  291. package/dist/types/tools/subagent/index.d.ts +2 -0
  292. package/dist/types/tools/subagent/types.d.ts +84 -0
  293. package/dist/types/tools/toolOutputReferences.d.ts +236 -0
  294. package/dist/types/types/agent-cache.d.ts +71 -0
  295. package/dist/types/types/graph.d.ts +163 -22
  296. package/dist/types/types/index.d.ts +3 -0
  297. package/dist/types/types/messages.d.ts +26 -0
  298. package/dist/types/types/run.d.ts +22 -0
  299. package/dist/types/types/skill.d.ts +9 -0
  300. package/dist/types/types/tools.d.ts +111 -0
  301. package/dist/types/utils/index.d.ts +1 -3
  302. package/dist/types/utils/truncation.d.ts +70 -0
  303. package/package.json +57 -17
  304. package/src/agents/AgentContext.ts +321 -78
  305. package/src/agents/__tests__/AgentContext.cacheTtl.live.test.ts +259 -0
  306. package/src/agents/__tests__/AgentContext.crossAgentTier1.live.test.ts +266 -0
  307. package/src/agents/__tests__/AgentContext.crossUserCache.live.test.ts +342 -0
  308. package/src/agents/__tests__/AgentContext.test.ts +632 -0
  309. package/src/common/__tests__/enum.test.ts +7 -17
  310. package/src/common/enum.ts +43 -12
  311. package/src/common/index.ts +0 -1
  312. package/src/graphs/Graph.ts +222 -2
  313. package/src/graphs/MultiAgentGraph.ts +154 -1466
  314. package/src/graphs/__tests__/MultiAgentGraph.test.ts +91 -0
  315. package/src/graphs/gapFeatures.test.ts +1 -1
  316. package/src/graphs/index.ts +0 -1
  317. package/src/graphs/phases/__tests__/memoryFlushPhase.test.ts +1 -1
  318. package/src/graphs/phases/memoryFlushPhase.ts +2 -2
  319. package/src/hooks/HookRegistry.ts +208 -0
  320. package/src/hooks/__tests__/HookRegistry.test.ts +190 -0
  321. package/src/hooks/__tests__/compactHooks.test.ts +214 -0
  322. package/src/hooks/__tests__/executeHooks.test.ts +1013 -0
  323. package/src/hooks/__tests__/integration.test.ts +337 -0
  324. package/src/hooks/__tests__/matchers.test.ts +238 -0
  325. package/src/hooks/__tests__/toolHooks.test.ts +665 -0
  326. package/src/hooks/executeHooks.ts +375 -0
  327. package/src/hooks/index.ts +57 -0
  328. package/src/hooks/matchers.ts +280 -0
  329. package/src/hooks/types.ts +404 -0
  330. package/src/index.ts +15 -24
  331. package/src/langchain/google-common.ts +1 -0
  332. package/src/langchain/index.ts +8 -0
  333. package/src/langchain/language_models/chat_models.ts +1 -0
  334. package/src/langchain/messages/tool.ts +5 -0
  335. package/src/langchain/messages.ts +21 -0
  336. package/src/langchain/openai.ts +1 -0
  337. package/src/langchain/prompts.ts +1 -0
  338. package/src/langchain/runnables.ts +7 -0
  339. package/src/langchain/tools.ts +8 -0
  340. package/src/langchain/utils/env.ts +1 -0
  341. package/src/llm/anthropic/utils/message_inputs.ts +10 -1
  342. package/src/llm/anthropic/utils/server-tool-inputs.test.ts +436 -0
  343. package/src/llm/bedrock/__tests__/bedrock-caching.test.ts +166 -18
  344. package/src/llm/bedrock/cacheSupport.test.ts +99 -0
  345. package/src/llm/bedrock/cacheSupport.ts +53 -0
  346. package/src/llm/bedrock/index.ts +116 -41
  347. package/src/llm/openai/index.ts +2 -2
  348. package/src/llm/openai/utils/index.ts +31 -14
  349. package/src/memory/citations.ts +4 -4
  350. package/src/memory/constants.ts +17 -17
  351. package/src/memory/mmr.ts +3 -3
  352. package/src/memory/paths.ts +1 -1
  353. package/src/memory/recallTracking.ts +3 -3
  354. package/src/memory/temporalDecay.ts +2 -2
  355. package/src/memory/types.ts +3 -3
  356. package/src/messages/__tests__/contextPruning.test.ts +228 -0
  357. package/src/messages/cache.test.ts +62 -24
  358. package/src/messages/cache.ts +112 -0
  359. package/src/messages/contextPruning.ts +191 -0
  360. package/src/messages/contextPruningSettings.ts +90 -0
  361. package/src/messages/ensureThinkingBlock.test.ts +1 -1
  362. package/src/messages/format.ts +164 -12
  363. package/src/messages/formatAgentMessages.skills.test.ts +413 -0
  364. package/src/messages/formatAgentMessages.test.ts +1 -1
  365. package/src/messages/index.ts +2 -0
  366. package/src/messages/prune.ts +661 -4
  367. package/src/run.ts +155 -1
  368. package/src/scripts/multi-agent-chain.ts +2 -2
  369. package/src/scripts/multi-agent-document-review-chain.ts +2 -2
  370. package/src/scripts/multi-agent-hybrid-flow.ts +4 -4
  371. package/src/scripts/multi-agent-parallel.ts +3 -3
  372. package/src/scripts/multi-agent-sequence.ts +3 -3
  373. package/src/scripts/multi-agent-subagent.ts +246 -0
  374. package/src/scripts/multi-agent-supervisor.ts +5 -5
  375. package/src/scripts/poc-multi-agent-comprehensive.ts +8 -8
  376. package/src/scripts/sequential-full-metadata-test.ts +2 -2
  377. package/src/scripts/subagent-event-driven-debug.ts +190 -0
  378. package/src/scripts/subagent-tools-debug.ts +160 -0
  379. package/src/scripts/test-custom-prompt-key.ts +3 -3
  380. package/src/scripts/test-handoff-input.ts +1 -1
  381. package/src/scripts/test-handoff-steering.ts +3 -3
  382. package/src/scripts/test-multi-agent-list-handoff.ts +1 -1
  383. package/src/scripts/test-parallel-agent-labeling.ts +3 -3
  384. package/src/scripts/test-parallel-handoffs.ts +2 -2
  385. package/src/scripts/test-thinking-handoff-bedrock.ts +1 -1
  386. package/src/scripts/test-thinking-handoff.ts +1 -1
  387. package/src/scripts/test-thinking-to-thinking-handoff-bedrock.ts +1 -1
  388. package/src/scripts/test-tool-before-handoff-role-order.ts +1 -1
  389. package/src/scripts/test-tools-before-handoff.ts +1 -1
  390. package/src/specs/agent-handoffs.test.ts +26 -483
  391. package/src/specs/anthropic.simple.test.ts +61 -0
  392. package/src/specs/multi-agent-summarization.test.ts +396 -0
  393. package/src/specs/prune.orphans.test.ts +248 -0
  394. package/src/specs/prune.test.ts +104 -16
  395. package/src/specs/thinking-handoff.test.ts +19 -19
  396. package/src/tools/BashExecutor.ts +281 -0
  397. package/src/tools/BashProgrammaticToolCalling.ts +397 -0
  398. package/src/tools/CodeExecutor.ts +63 -54
  399. package/src/tools/ProgrammaticToolCalling.ts +29 -14
  400. package/src/tools/ReadFile.ts +39 -0
  401. package/src/tools/SkillTool.ts +46 -0
  402. package/src/tools/SubagentTool.ts +100 -0
  403. package/src/tools/ToolNode.ts +548 -26
  404. package/src/tools/__tests__/BashExecutor.test.ts +49 -0
  405. package/src/tools/__tests__/CodeExecutor.test.ts +37 -36
  406. package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +60 -0
  407. package/src/tools/__tests__/ReadFile.test.ts +44 -0
  408. package/src/tools/__tests__/SkillTool.test.ts +442 -0
  409. package/src/tools/__tests__/SubagentExecutor.test.ts +1148 -0
  410. package/src/tools/__tests__/SubagentTool.test.ts +149 -0
  411. package/src/tools/__tests__/ToolNode.outputReferences.test.ts +1438 -0
  412. package/src/tools/__tests__/annotateMessagesForLLM.test.ts +479 -0
  413. package/src/tools/__tests__/skillCatalog.test.ts +161 -0
  414. package/src/tools/__tests__/subagentHooks.test.ts +210 -0
  415. package/src/tools/__tests__/toolOutputReferences.test.ts +415 -0
  416. package/src/tools/memory/memoryAppendTool.ts +1 -1
  417. package/src/tools/memory/memoryGetTool.ts +2 -2
  418. package/src/tools/memory/memorySearchTool.ts +3 -3
  419. package/src/tools/memory/shared.ts +1 -1
  420. package/src/tools/search/search.ts +12 -2
  421. package/src/tools/search/tavily-scraper.ts +235 -0
  422. package/src/tools/search/tavily-search.ts +424 -0
  423. package/src/tools/search/tavily.test.ts +965 -0
  424. package/src/tools/search/tool.ts +36 -2
  425. package/src/tools/search/types.ts +133 -8
  426. package/src/tools/search/utils.ts +13 -5
  427. package/src/tools/skillCatalog.ts +126 -0
  428. package/src/tools/subagent/SubagentExecutor.ts +676 -0
  429. package/src/tools/subagent/index.ts +13 -0
  430. package/src/tools/subagent/types.test.ts +70 -0
  431. package/src/tools/subagent/types.ts +115 -0
  432. package/src/tools/toolOutputReferences.ts +825 -0
  433. package/src/types/agent-cache.ts +74 -0
  434. package/src/types/graph.ts +172 -20
  435. package/src/types/index.ts +3 -0
  436. package/src/types/messages.ts +27 -0
  437. package/src/types/run.ts +22 -0
  438. package/src/types/skill.ts +11 -0
  439. package/src/types/tools.ts +118 -0
  440. package/src/utils/__tests__/truncation.test.ts +66 -0
  441. package/src/utils/index.ts +1 -3
  442. package/src/utils/truncation.ts +154 -0
  443. package/dist/cjs/common/spawnPath.cjs +0 -104
  444. package/dist/cjs/common/spawnPath.cjs.map +0 -1
  445. package/dist/cjs/content/ArtifactStore.cjs +0 -579
  446. package/dist/cjs/content/ArtifactStore.cjs.map +0 -1
  447. package/dist/cjs/content/ContentStore.cjs +0 -638
  448. package/dist/cjs/content/ContentStore.cjs.map +0 -1
  449. package/dist/cjs/content/contentAnalyzer.cjs +0 -91
  450. package/dist/cjs/content/contentAnalyzer.cjs.map +0 -1
  451. package/dist/cjs/content/index.cjs +0 -20
  452. package/dist/cjs/content/index.cjs.map +0 -1
  453. package/dist/cjs/content/mcpAutoCache.cjs +0 -115
  454. package/dist/cjs/content/mcpAutoCache.cjs.map +0 -1
  455. package/dist/cjs/graphs/HandoffRegistry.cjs +0 -143
  456. package/dist/cjs/graphs/HandoffRegistry.cjs.map +0 -1
  457. package/dist/cjs/providers/a2a/A2ACapabilityProvider.cjs +0 -288
  458. package/dist/cjs/providers/a2a/A2ACapabilityProvider.cjs.map +0 -1
  459. package/dist/cjs/providers/a2a/client.cjs +0 -92
  460. package/dist/cjs/providers/a2a/client.cjs.map +0 -1
  461. package/dist/cjs/providers/a2a/config.cjs +0 -38
  462. package/dist/cjs/providers/a2a/config.cjs.map +0 -1
  463. package/dist/cjs/providers/capabilityNaming.cjs +0 -43
  464. package/dist/cjs/providers/capabilityNaming.cjs.map +0 -1
  465. package/dist/cjs/providers/mcp/MCPCapabilityProvider.cjs +0 -244
  466. package/dist/cjs/providers/mcp/MCPCapabilityProvider.cjs.map +0 -1
  467. package/dist/cjs/providers/mcp/config.cjs +0 -42
  468. package/dist/cjs/providers/mcp/config.cjs.map +0 -1
  469. package/dist/cjs/providers/mcp/transport.cjs +0 -65
  470. package/dist/cjs/providers/mcp/transport.cjs.map +0 -1
  471. package/dist/cjs/providers/tools-server/ToolsServerCapabilityProvider.cjs +0 -128
  472. package/dist/cjs/providers/tools-server/ToolsServerCapabilityProvider.cjs.map +0 -1
  473. package/dist/cjs/providers/types.cjs +0 -51
  474. package/dist/cjs/providers/types.cjs.map +0 -1
  475. package/dist/cjs/tools/artifacts/schema.cjs +0 -86
  476. package/dist/cjs/tools/artifacts/schema.cjs.map +0 -1
  477. package/dist/cjs/tools/artifacts/tool.cjs +0 -219
  478. package/dist/cjs/tools/artifacts/tool.cjs.map +0 -1
  479. package/dist/cjs/tools/fileSearch/formatter.cjs +0 -93
  480. package/dist/cjs/tools/fileSearch/formatter.cjs.map +0 -1
  481. package/dist/cjs/tools/fileSearch/ragClient.cjs +0 -102
  482. package/dist/cjs/tools/fileSearch/ragClient.cjs.map +0 -1
  483. package/dist/cjs/tools/fileSearch/schema.cjs +0 -18
  484. package/dist/cjs/tools/fileSearch/schema.cjs.map +0 -1
  485. package/dist/cjs/tools/fileSearch/tool.cjs +0 -155
  486. package/dist/cjs/tools/fileSearch/tool.cjs.map +0 -1
  487. package/dist/cjs/tools/proxyTool.cjs +0 -102
  488. package/dist/cjs/tools/proxyTool.cjs.map +0 -1
  489. package/dist/cjs/utils/childAgentContext.cjs +0 -242
  490. package/dist/cjs/utils/childAgentContext.cjs.map +0 -1
  491. package/dist/cjs/utils/credentials.cjs +0 -142
  492. package/dist/cjs/utils/credentials.cjs.map +0 -1
  493. package/dist/cjs/utils/httpClient.cjs +0 -74
  494. package/dist/cjs/utils/httpClient.cjs.map +0 -1
  495. package/dist/cjs/utils/toolManifest.cjs +0 -100
  496. package/dist/cjs/utils/toolManifest.cjs.map +0 -1
  497. package/dist/esm/common/spawnPath.mjs +0 -95
  498. package/dist/esm/common/spawnPath.mjs.map +0 -1
  499. package/dist/esm/content/ArtifactStore.mjs +0 -576
  500. package/dist/esm/content/ArtifactStore.mjs.map +0 -1
  501. package/dist/esm/content/ContentStore.mjs +0 -635
  502. package/dist/esm/content/ContentStore.mjs.map +0 -1
  503. package/dist/esm/content/contentAnalyzer.mjs +0 -87
  504. package/dist/esm/content/contentAnalyzer.mjs.map +0 -1
  505. package/dist/esm/content/index.mjs +0 -5
  506. package/dist/esm/content/mcpAutoCache.mjs +0 -111
  507. package/dist/esm/content/mcpAutoCache.mjs.map +0 -1
  508. package/dist/esm/graphs/HandoffRegistry.mjs +0 -141
  509. package/dist/esm/graphs/HandoffRegistry.mjs.map +0 -1
  510. package/dist/esm/providers/a2a/A2ACapabilityProvider.mjs +0 -281
  511. package/dist/esm/providers/a2a/A2ACapabilityProvider.mjs.map +0 -1
  512. package/dist/esm/providers/a2a/client.mjs +0 -88
  513. package/dist/esm/providers/a2a/client.mjs.map +0 -1
  514. package/dist/esm/providers/a2a/config.mjs +0 -35
  515. package/dist/esm/providers/a2a/config.mjs.map +0 -1
  516. package/dist/esm/providers/capabilityNaming.mjs +0 -39
  517. package/dist/esm/providers/capabilityNaming.mjs.map +0 -1
  518. package/dist/esm/providers/mcp/MCPCapabilityProvider.mjs +0 -240
  519. package/dist/esm/providers/mcp/MCPCapabilityProvider.mjs.map +0 -1
  520. package/dist/esm/providers/mcp/config.mjs +0 -39
  521. package/dist/esm/providers/mcp/config.mjs.map +0 -1
  522. package/dist/esm/providers/mcp/transport.mjs +0 -63
  523. package/dist/esm/providers/mcp/transport.mjs.map +0 -1
  524. package/dist/esm/providers/tools-server/ToolsServerCapabilityProvider.mjs +0 -126
  525. package/dist/esm/providers/tools-server/ToolsServerCapabilityProvider.mjs.map +0 -1
  526. package/dist/esm/providers/types.mjs +0 -51
  527. package/dist/esm/providers/types.mjs.map +0 -1
  528. package/dist/esm/tools/artifacts/schema.mjs +0 -79
  529. package/dist/esm/tools/artifacts/schema.mjs.map +0 -1
  530. package/dist/esm/tools/artifacts/tool.mjs +0 -213
  531. package/dist/esm/tools/artifacts/tool.mjs.map +0 -1
  532. package/dist/esm/tools/fileSearch/formatter.mjs +0 -90
  533. package/dist/esm/tools/fileSearch/formatter.mjs.map +0 -1
  534. package/dist/esm/tools/fileSearch/ragClient.mjs +0 -98
  535. package/dist/esm/tools/fileSearch/ragClient.mjs.map +0 -1
  536. package/dist/esm/tools/fileSearch/schema.mjs +0 -15
  537. package/dist/esm/tools/fileSearch/schema.mjs.map +0 -1
  538. package/dist/esm/tools/fileSearch/tool.mjs +0 -152
  539. package/dist/esm/tools/fileSearch/tool.mjs.map +0 -1
  540. package/dist/esm/tools/proxyTool.mjs +0 -100
  541. package/dist/esm/tools/proxyTool.mjs.map +0 -1
  542. package/dist/esm/utils/childAgentContext.mjs +0 -237
  543. package/dist/esm/utils/childAgentContext.mjs.map +0 -1
  544. package/dist/esm/utils/credentials.mjs +0 -135
  545. package/dist/esm/utils/credentials.mjs.map +0 -1
  546. package/dist/esm/utils/httpClient.mjs +0 -70
  547. package/dist/esm/utils/httpClient.mjs.map +0 -1
  548. package/dist/esm/utils/toolManifest.mjs +0 -96
  549. package/dist/esm/utils/toolManifest.mjs.map +0 -1
  550. package/dist/types/common/spawnPath.d.ts +0 -59
  551. package/dist/types/content/ArtifactStore.d.ts +0 -223
  552. package/dist/types/content/ContentStore.d.ts +0 -140
  553. package/dist/types/content/contentAnalyzer.d.ts +0 -38
  554. package/dist/types/content/index.d.ts +0 -24
  555. package/dist/types/content/mcpAutoCache.d.ts +0 -89
  556. package/dist/types/content/types.d.ts +0 -75
  557. package/dist/types/graphs/HandoffRegistry.d.ts +0 -97
  558. package/dist/types/providers/a2a/A2ACapabilityProvider.d.ts +0 -89
  559. package/dist/types/providers/a2a/client.d.ts +0 -47
  560. package/dist/types/providers/a2a/config.d.ts +0 -18
  561. package/dist/types/providers/a2a/index.d.ts +0 -6
  562. package/dist/types/providers/a2a/types.d.ts +0 -173
  563. package/dist/types/providers/capabilityNaming.d.ts +0 -25
  564. package/dist/types/providers/index.d.ts +0 -12
  565. package/dist/types/providers/mcp/MCPCapabilityProvider.d.ts +0 -54
  566. package/dist/types/providers/mcp/config.d.ts +0 -20
  567. package/dist/types/providers/mcp/index.d.ts +0 -5
  568. package/dist/types/providers/mcp/transport.d.ts +0 -18
  569. package/dist/types/providers/mcp/types.d.ts +0 -112
  570. package/dist/types/providers/tools-server/ToolsServerCapabilityProvider.d.ts +0 -59
  571. package/dist/types/providers/tools-server/index.d.ts +0 -1
  572. package/dist/types/providers/types.d.ts +0 -184
  573. package/dist/types/tools/artifacts/index.d.ts +0 -3
  574. package/dist/types/tools/artifacts/schema.d.ts +0 -63
  575. package/dist/types/tools/artifacts/tool.d.ts +0 -16
  576. package/dist/types/tools/artifacts/types.d.ts +0 -127
  577. package/dist/types/tools/fileSearch/formatter.d.ts +0 -25
  578. package/dist/types/tools/fileSearch/index.d.ts +0 -5
  579. package/dist/types/tools/fileSearch/ragClient.d.ts +0 -32
  580. package/dist/types/tools/fileSearch/schema.d.ts +0 -13
  581. package/dist/types/tools/fileSearch/tool.d.ts +0 -18
  582. package/dist/types/tools/fileSearch/types.d.ts +0 -139
  583. package/dist/types/tools/proxyTool.d.ts +0 -62
  584. package/dist/types/tools/search/test.d.ts +0 -1
  585. package/dist/types/utils/childAgentContext.d.ts +0 -99
  586. package/dist/types/utils/credentials.d.ts +0 -77
  587. package/dist/types/utils/httpClient.d.ts +0 -46
  588. package/dist/types/utils/toolManifest.d.ts +0 -49
  589. package/src/common/__tests__/spawnPath.test.ts +0 -110
  590. package/src/common/spawnPath.ts +0 -101
  591. package/src/content/ArtifactStore.ts +0 -782
  592. package/src/content/ContentStore.ts +0 -753
  593. package/src/content/contentAnalyzer.ts +0 -105
  594. package/src/content/index.ts +0 -51
  595. package/src/content/mcpAutoCache.ts +0 -185
  596. package/src/content/types.ts +0 -82
  597. package/src/graphs/HandoffRegistry.ts +0 -199
  598. package/src/graphs/__tests__/HandoffRegistry.test.ts +0 -410
  599. package/src/graphs/__tests__/multi-agent-delegate.test.ts +0 -458
  600. package/src/graphs/__tests__/multi-agent-edges.test.ts +0 -276
  601. package/src/graphs/__tests__/multi-agent-nested-subgraph.test.ts +0 -221
  602. package/src/graphs/handoffValidation.test.ts +0 -353
  603. package/src/providers/__tests__/ToolsServerCapabilityProvider.integration.spec.ts +0 -79
  604. package/src/providers/__tests__/ToolsServerCapabilityProvider.test.ts +0 -271
  605. package/src/providers/__tests__/types.test.ts +0 -64
  606. package/src/providers/a2a/A2ACapabilityProvider.ts +0 -384
  607. package/src/providers/a2a/__tests__/A2ACapabilityProvider.integration.spec.ts +0 -345
  608. package/src/providers/a2a/__tests__/A2ACapabilityProvider.test.ts +0 -460
  609. package/src/providers/a2a/client.ts +0 -115
  610. package/src/providers/a2a/config.ts +0 -40
  611. package/src/providers/a2a/index.ts +0 -29
  612. package/src/providers/a2a/types.ts +0 -191
  613. package/src/providers/capabilityNaming.ts +0 -42
  614. package/src/providers/index.ts +0 -68
  615. package/src/providers/mcp/MCPCapabilityProvider.ts +0 -345
  616. package/src/providers/mcp/__tests__/MCPCapabilityProvider.integration.spec.ts +0 -386
  617. package/src/providers/mcp/__tests__/MCPCapabilityProvider.test.ts +0 -371
  618. package/src/providers/mcp/config.ts +0 -45
  619. package/src/providers/mcp/index.ts +0 -21
  620. package/src/providers/mcp/transport.ts +0 -76
  621. package/src/providers/mcp/types.ts +0 -139
  622. package/src/providers/tools-server/ToolsServerCapabilityProvider.ts +0 -249
  623. package/src/providers/tools-server/index.ts +0 -1
  624. package/src/providers/types.ts +0 -204
  625. package/src/scripts/test-bedrock-handoff-autonomous.ts +0 -267
  626. package/src/scripts/test-handoff-preamble.ts +0 -278
  627. package/src/specs/agent-handoffs-bedrock.integration.test.ts +0 -415
  628. package/src/tools/artifacts/__tests__/tool.test.ts +0 -259
  629. package/src/tools/artifacts/index.ts +0 -33
  630. package/src/tools/artifacts/schema.ts +0 -99
  631. package/src/tools/artifacts/tool.ts +0 -289
  632. package/src/tools/artifacts/types.ts +0 -162
  633. package/src/tools/fileSearch/__tests__/tool.test.ts +0 -261
  634. package/src/tools/fileSearch/formatter.ts +0 -129
  635. package/src/tools/fileSearch/index.ts +0 -23
  636. package/src/tools/fileSearch/ragClient.ts +0 -137
  637. package/src/tools/fileSearch/schema.ts +0 -19
  638. package/src/tools/fileSearch/tool.ts +0 -207
  639. package/src/tools/fileSearch/types.ts +0 -149
  640. package/src/tools/proxyTool.ts +0 -166
  641. package/src/tools/search/output.md +0 -2775
  642. package/src/tools/search/test.html +0 -884
  643. package/src/tools/search/test.md +0 -643
  644. package/src/tools/search/test.ts +0 -159
  645. package/src/utils/__tests__/childAgentContext.test.ts +0 -217
  646. package/src/utils/__tests__/credentials.test.ts +0 -130
  647. package/src/utils/__tests__/httpClient.test.ts +0 -75
  648. package/src/utils/__tests__/toolManifest.test.ts +0 -116
  649. package/src/utils/childAgentContext.ts +0 -259
  650. package/src/utils/credentials.ts +0 -157
  651. package/src/utils/httpClient.ts +0 -92
  652. package/src/utils/toolManifest.ts +0 -109
  653. /package/dist/esm/{content → langchain}/index.mjs.map +0 -0
@@ -1,782 +0,0 @@
1
- import type Keyv from 'keyv';
2
- import { ContentStore } from './ContentStore';
3
- import type {
4
- StoreEntry,
5
- StoredEntry,
6
- ContentMetadata,
7
- EditResult,
8
- ReadResult,
9
- ReadAllResult,
10
- SearchMatch,
11
- } from './types';
12
-
13
- /**
14
- * Minimal logger surface. Callers inject any winston/pino/console-like
15
- * logger that honors the four level methods; defaults to a no-op so the
16
- * library runs without a configured logger.
17
- */
18
- export interface Logger {
19
- debug(...args: unknown[]): void;
20
- info(...args: unknown[]): void;
21
- warn(...args: unknown[]): void;
22
- error(...args: unknown[]): void;
23
- }
24
-
25
- const noopLogger: Logger = {
26
- debug: () => {},
27
- info: () => {},
28
- warn: () => {},
29
- error: () => {},
30
- };
31
-
32
- /**
33
- * Callback interface for S3 operations.
34
- * Injected at construction so ArtifactStore stays host-agnostic — the
35
- * consumer wires this to its own S3 strategy / presigner.
36
- */
37
- export interface S3Strategy {
38
- /** Upload a buffer to S3, return the stored filepath (signed URL or key). */
39
- saveBuffer(params: {
40
- userId: string;
41
- buffer: Buffer;
42
- fileName: string;
43
- basePath: string;
44
- }): Promise<string>;
45
-
46
- /** Download file content from S3 as a readable stream. */
47
- getFileStream(filePath: string): Promise<NodeJS.ReadableStream>;
48
-
49
- /** Delete a file from S3. Requires userId for ownership validation. */
50
- deleteFile(userId: string, filePath: string): Promise<void>;
51
- }
52
-
53
- /**
54
- * Callback interface for MongoDB File model operations.
55
- * Injected to keep ArtifactStore decoupled from Mongoose models.
56
- */
57
- export interface FileModel {
58
- /** Create or upsert a File document. */
59
- createFile(
60
- data: Record<string, unknown>,
61
- disableTTL: boolean
62
- ): Promise<Record<string, unknown>>;
63
-
64
- /** Find a single File by filter. */
65
- findFile(
66
- filter: Record<string, unknown>
67
- ): Promise<Record<string, unknown> | null>;
68
-
69
- /** Find multiple Files by filter. */
70
- findFiles(
71
- filter: Record<string, unknown>
72
- ): Promise<Record<string, unknown>[]>;
73
-
74
- /** Update a File document (must include file_id). */
75
- updateFile(
76
- data: Record<string, unknown>
77
- ): Promise<Record<string, unknown> | null>;
78
-
79
- /** Delete a File by file_id. */
80
- deleteFile(fileId: string): Promise<Record<string, unknown> | null>;
81
-
82
- /**
83
- * Get the file_ids linked to a conversation via the Conversation.files array.
84
- * Returns an empty array if the conversation is not found or has no files.
85
- * This is the primary source of truth for "which files belong to this conversation".
86
- */
87
- getConversationFileIds(conversationId: string): Promise<string[]>;
88
-
89
- /**
90
- * Link file_ids to a conversation via $addToSet on Conversation.files.
91
- * Idempotent — calling with already-linked file_ids is a no-op.
92
- * Used after creating a File record to ensure it appears in "Files in Context".
93
- */
94
- addFilesToConversation(
95
- conversationId: string,
96
- fileIds: string[]
97
- ): Promise<void>;
98
- }
99
-
100
- /** S3 base path for all artifact files. */
101
- const ARTIFACTS_BASE_PATH = 'artifacts';
102
-
103
- /**
104
- * Sanitize a filename for safe S3 key usage.
105
- * Replaces non-alphanumeric characters (except . _ - /) with underscores.
106
- */
107
- export function sanitizeName(name: string): string {
108
- return name.replace(/[^a-zA-Z0-9._\-/]/g, '_');
109
- }
110
-
111
- /**
112
- * Constructs the canonical S3 file name for an artifact.
113
- * Format: `{contentId}__{sanitizedName}` — contentId prefix ensures uniqueness.
114
- */
115
- function buildS3FileName(contentId: string, name: string): string {
116
- return `${contentId}__${sanitizeName(name)}`;
117
- }
118
-
119
- /**
120
- * Constructs the S3 base path scoped to a conversation.
121
- * Pattern: `artifacts/{conversationId}`
122
- * The S3 strategy prepends userId internally via getS3Key().
123
- */
124
- function buildS3BasePath(conversationId: string): string {
125
- return `${ARTIFACTS_BASE_PATH}/${conversationId}`;
126
- }
127
-
128
- /**
129
- * File-backed artifact store extending ContentStore with S3 persistence.
130
- *
131
- * Every write immediately persists to Redis (fast cache) AND S3 (permanent store).
132
- * S3 writes are fire-and-forget async — the agent gets an instant response from Redis.
133
- * On Redis cache miss, content is transparently restored from S3 via MongoDB lookup.
134
- *
135
- * Key structure (consistent across all layers):
136
- * - Redis: `CONTENT_STORE::{conversationId}::{contentId}`
137
- * - S3: `artifacts/{conversationId}/{userId}/{contentId}__{name}`
138
- * - MongoDB: `file_id: "artifact-{contentId}"`, `metadata.contentId: "{contentId}"`
139
- *
140
- * @example
141
- * ```ts
142
- * import Keyv from 'keyv';
143
- * import { ArtifactStore, CONTENT_TTL_MS } from '@illuma-ai/agents/content';
144
- *
145
- * const cache = new Keyv({ namespace: `content-store::${conversationId}`, ttl: CONTENT_TTL_MS });
146
- * const store = new ArtifactStore(cache, conversationId, userId, s3Strategy, fileModel, logger);
147
- * const id = await store.store({ name: 'App.tsx', type: 'text/x-typescript', content: code, source: 'agent' });
148
- * // Content is in the cache immediately; S3 + the injected FileModel persist in background.
149
- * const result = await store.readLines(id, 1, 50);
150
- * ```
151
- */
152
- export class ArtifactStore extends ContentStore {
153
- protected logger: Logger;
154
-
155
- constructor(
156
- cache: Keyv,
157
- protected conversationId: string,
158
- protected userId: string,
159
- protected s3: S3Strategy,
160
- protected fileModel: FileModel,
161
- logger: Logger = noopLogger
162
- ) {
163
- super(cache);
164
- this.logger = logger;
165
- }
166
-
167
- /** File ID prefix for MongoDB file_id. Override in subclasses. */
168
- protected getFileIdPrefix(): string {
169
- return 'artifact-';
170
- }
171
-
172
- /** Context label stored on MongoDB File records. Override in subclasses. */
173
- protected getContextLabel(): string {
174
- return 'artifact';
175
- }
176
-
177
- /** S3 base path prefix. Override in subclasses. */
178
- protected getS3BasePath(): string {
179
- return buildS3BasePath(this.conversationId);
180
- }
181
-
182
- /** Build S3 file name. Override in subclasses. */
183
- protected getS3FileName(contentId: string, name: string): string {
184
- return buildS3FileName(contentId, name);
185
- }
186
-
187
- /** Build the canonical file_id for a content entry. */
188
- protected buildFileId(contentId: string): string {
189
- return `${this.getFileIdPrefix()}${contentId}`;
190
- }
191
-
192
- /**
193
- * Store new content in Redis and persist to S3 + MongoDB in background.
194
- * Returns immediately after Redis write — agent doesn't wait for S3.
195
- *
196
- * @param entry - The content to store.
197
- * @returns The generated content ID.
198
- */
199
- async store(entry: StoreEntry): Promise<string> {
200
- // 1. Fast path: store in Redis via parent (agent gets instant response)
201
- const contentId = await super.store(entry);
202
-
203
- // 2. Update Redis metadata with ownership info for S3 restore path
204
- const stored = await this.getStored(contentId);
205
- if (stored) {
206
- stored.metadata.userId = this.userId;
207
- stored.metadata.conversationId = this.conversationId;
208
- stored.metadata.fileId = this.buildFileId(contentId);
209
- await this.cache.set(contentId, JSON.stringify(stored));
210
-
211
- // Update index with enriched metadata
212
- const index = await this.getIndex();
213
- if (index[contentId]) {
214
- index[contentId] = stored.metadata;
215
- await this.cache.set(this.indexKey, JSON.stringify(index));
216
- }
217
- }
218
-
219
- // 3. Background: persist to S3 + MongoDB (fire-and-forget)
220
- this.persistToS3(contentId, entry).catch((err) => {
221
- this.logger.warn(
222
- `[ArtifactStore] S3 persist failed for ${contentId}:`,
223
- (err as Error).message
224
- );
225
- });
226
-
227
- return contentId;
228
- }
229
-
230
- /**
231
- * Overwrite content for an existing entry. Updates Redis + syncs to S3.
232
- *
233
- * @param contentId - The content entry ID.
234
- * @param content - New content to write.
235
- * @throws If content ID is not found in Redis or S3.
236
- */
237
- async write(contentId: string, content: string): Promise<void> {
238
- // Ensure content is loaded into Redis (may need S3 fallback)
239
- await this.ensureLoaded(contentId);
240
-
241
- // Update Redis via parent
242
- await super.write(contentId, content);
243
-
244
- // Background: sync updated content to S3
245
- this.syncToS3(contentId).catch((err) => {
246
- this.logger.warn(
247
- `[ArtifactStore] S3 sync failed for write on ${contentId}:`,
248
- (err as Error).message
249
- );
250
- });
251
- }
252
-
253
- /**
254
- * Surgical string replacement. Updates Redis + syncs to S3.
255
- *
256
- * @param contentId - The content entry ID.
257
- * @param oldStr - Exact string to find.
258
- * @param newStr - Replacement string.
259
- * @returns Edit result with diff and affected line info.
260
- */
261
- async strReplace(
262
- contentId: string,
263
- oldStr: string,
264
- newStr: string
265
- ): Promise<EditResult> {
266
- // Ensure content is loaded into Redis (may need S3 fallback)
267
- await this.ensureLoaded(contentId);
268
-
269
- // Edit in Redis via parent
270
- const result = await super.strReplace(contentId, oldStr, newStr);
271
-
272
- if (result.success) {
273
- // Background: sync updated content to S3
274
- this.syncToS3(contentId).catch((err) => {
275
- this.logger.warn(
276
- `[ArtifactStore] S3 sync failed for edit on ${contentId}:`,
277
- (err as Error).message
278
- );
279
- });
280
- }
281
-
282
- return result;
283
- }
284
-
285
- /**
286
- * Read lines with S3 fallback. If Redis has expired, loads from S3 first.
287
- *
288
- * @param contentId - The content entry ID.
289
- * @param startLine - First line to read (1-based).
290
- * @param endLine - Last line to read (inclusive).
291
- * @returns Read result or null if not found in any layer.
292
- */
293
- async readLines(
294
- contentId: string,
295
- startLine?: number,
296
- endLine?: number
297
- ): Promise<ReadResult | null> {
298
- // Try Redis first via parent
299
- let result = await super.readLines(contentId, startLine, endLine);
300
- if (result) {
301
- return result;
302
- }
303
-
304
- // Redis miss — try S3 fallback
305
- const restored = await this.restoreFromS3(contentId);
306
- if (!restored) {
307
- return null;
308
- }
309
-
310
- // Retry read from Redis (now populated)
311
- result = await super.readLines(contentId, startLine, endLine);
312
- return result;
313
- }
314
-
315
- /**
316
- * Read full content with S3 fallback. If Redis has expired, loads from S3 first.
317
- * No line cap — returns raw content for frontend display (e.g., CodeViz).
318
- *
319
- * @param contentId - The content entry ID.
320
- * @returns Raw content with total line/char counts, or null if not found in any layer.
321
- */
322
- async readAll(contentId: string): Promise<ReadAllResult | null> {
323
- // Try Redis first via parent
324
- let result = await super.readAll(contentId);
325
- if (result) {
326
- return result;
327
- }
328
-
329
- // Redis miss — try S3 fallback
330
- const restored = await this.restoreFromS3(contentId);
331
- if (!restored) {
332
- return null;
333
- }
334
-
335
- // Retry read from Redis (now populated)
336
- result = await super.readAll(contentId);
337
- return result;
338
- }
339
-
340
- /**
341
- * Search with S3 fallback. If Redis has expired, loads from S3 first.
342
- *
343
- * @param contentId - The content entry ID.
344
- * @param pattern - Text or regex pattern to match.
345
- * @param maxResults - Maximum matches to return.
346
- * @returns Array of matches or null if not found.
347
- */
348
- async search(
349
- contentId: string,
350
- pattern: string,
351
- maxResults?: number
352
- ): Promise<SearchMatch[] | null> {
353
- // Try Redis first via parent
354
- let result = await super.search(contentId, pattern, maxResults);
355
- if (result) {
356
- return result;
357
- }
358
-
359
- // Redis miss — try S3 fallback
360
- const restored = await this.restoreFromS3(contentId);
361
- if (!restored) {
362
- return null;
363
- }
364
-
365
- result = await super.search(contentId, pattern, maxResults);
366
- return result;
367
- }
368
-
369
- /**
370
- * Get metadata with S3 fallback.
371
- *
372
- * @param contentId - The content entry ID.
373
- * @returns Metadata or null if not found in any layer.
374
- */
375
- async info(contentId: string): Promise<ContentMetadata | null> {
376
- // Try Redis first via parent
377
- let result = await super.info(contentId);
378
- if (result) {
379
- return result;
380
- }
381
-
382
- // Redis miss — try S3 fallback
383
- const restored = await this.restoreFromS3(contentId);
384
- if (!restored) {
385
- return null;
386
- }
387
-
388
- result = await super.info(contentId);
389
- return result;
390
- }
391
-
392
- /**
393
- * Delete an artifact from all layers: Redis + S3 + MongoDB.
394
- *
395
- * @param contentId - The content entry ID.
396
- */
397
- async deleteFile(contentId: string): Promise<void> {
398
- // 1. Delete from Redis
399
- await super.delete(contentId);
400
-
401
- // 2. Delete from MongoDB + S3 (background, best-effort)
402
- const fileId = this.buildFileId(contentId);
403
- try {
404
- const fileRecord = await this.fileModel.findFile({
405
- file_id: fileId,
406
- user: this.userId,
407
- });
408
-
409
- if (fileRecord && fileRecord.filepath) {
410
- // Delete from S3
411
- try {
412
- await this.s3.deleteFile(this.userId, fileRecord.filepath as string);
413
- } catch (err) {
414
- this.logger.warn(
415
- `[ArtifactStore] S3 delete failed for ${contentId}:`,
416
- (err as Error).message
417
- );
418
- }
419
-
420
- // Delete from MongoDB
421
- await this.fileModel.deleteFile(fileId);
422
- }
423
- } catch (err) {
424
- this.logger.warn(
425
- `[ArtifactStore] MongoDB cleanup failed for ${contentId}:`,
426
- (err as Error).message
427
- );
428
- }
429
- }
430
-
431
- /**
432
- * List all files in this conversation. Merges Redis index with MongoDB File
433
- * records found via `Conversation.files` (the single source of truth).
434
- *
435
- * Query flow:
436
- * 1. Redis index — fast cache of recently-accessed content entries (in-memory, no DB hit)
437
- * 2. Conversation.files — canonical file_id list via `getConversationFileIds()`
438
- * SCALE: Single indexed `findOne` on `{ conversationId }` — O(1)
439
- * 3. Backward compat fallback — `File.find({ conversationId, user })` for pre-migration
440
- * data not yet in `Conversation.files`. Uses index `{ user, conversationId, updatedAt }`.
441
- * Can be removed once all File records are migrated.
442
- * 4. Batch fetch — `File.find({ file_id: { $in: mergedIds }, user })` to hydrate full
443
- * File documents. Uses index `{ file_id, user }`.
444
- *
445
- * Deduplication: Redis entries win — if a contentId is already in Redis, the MongoDB
446
- * record is skipped. Non-artifact files are keyed by `file:{file_id}` to avoid dupes.
447
- *
448
- * @returns Array of metadata for all files in this conversation.
449
- */
450
- async listFiles(): Promise<ContentMetadata[]> {
451
- // 1. Redis entries — fast cache of content store entries
452
- const redisEntries = await super.list();
453
- const seen = new Set<string>(redisEntries.map((e) => e.id));
454
-
455
- // 2. Conversation.files — the primary source of truth
456
- // SCALE: Single indexed findOne on { conversationId } — O(1)
457
- let convoFileIds: string[] = [];
458
- try {
459
- convoFileIds = await this.fileModel.getConversationFileIds(
460
- this.conversationId
461
- );
462
- } catch (err) {
463
- this.logger.warn(
464
- `[ArtifactStore] getConversationFileIds failed for ${this.conversationId}:`,
465
- (err as Error).message
466
- );
467
- }
468
- const convoFileIdSet = new Set(convoFileIds);
469
-
470
- // 3. Backward compat fallback — files with File.conversationId set directly
471
- // (pre-migration artifacts/code executor files not yet in Conversation.files).
472
- // SCALE: Uses compound index { user: 1, conversationId: 1, updatedAt: -1 }
473
- let fallbackFileIds: string[] = [];
474
- try {
475
- const directFiles = await this.fileModel.findFiles({
476
- conversationId: this.conversationId,
477
- user: this.userId,
478
- });
479
- fallbackFileIds = directFiles
480
- .map((f) => f.file_id as string)
481
- .filter((fid) => fid && !convoFileIdSet.has(fid));
482
- } catch (err) {
483
- this.logger.warn(
484
- `[ArtifactStore] Fallback conversationId query failed for ${this.conversationId}:`,
485
- (err as Error).message
486
- );
487
- }
488
-
489
- // 4. Merge into single set and batch fetch File records
490
- // SCALE: Uses compound index { file_id: 1, user: 1 }
491
- const allFileIds = [...new Set([...convoFileIds, ...fallbackFileIds])];
492
- if (allFileIds.length === 0) {
493
- return redisEntries;
494
- }
495
-
496
- try {
497
- const files = await this.fileModel.findFiles({
498
- file_id: { $in: allFileIds } as unknown,
499
- user: this.userId,
500
- });
501
-
502
- for (const file of files) {
503
- const existingContentId = file.metadata
504
- ? ((file.metadata as Record<string, unknown>).contentId as string)
505
- : undefined;
506
-
507
- // Artifact file (has contentId) — add as content entry if not already in Redis
508
- if (existingContentId) {
509
- if (seen.has(existingContentId)) {
510
- continue;
511
- }
512
- seen.add(existingContentId);
513
- redisEntries.push({
514
- id: existingContentId,
515
- name: (file.filename as string) || 'unknown',
516
- type: (file.type as string) || 'text/plain',
517
- source:
518
- ((file.metadata as Record<string, unknown>)
519
- .artifactSource as string) || 'unknown',
520
- totalLines: 0,
521
- totalChars: (file.bytes as number) || 0,
522
- createdAt: file.createdAt
523
- ? new Date(file.createdAt as string).getTime()
524
- : Date.now(),
525
- fileId: file.file_id as string,
526
- userId: this.userId,
527
- conversationId: this.conversationId,
528
- });
529
- continue;
530
- }
531
-
532
- // Non-artifact file (attachment, code executor output, etc.)
533
- const fileId = file.file_id as string;
534
- if (seen.has(`file:${fileId}`)) {
535
- continue;
536
- }
537
- seen.add(`file:${fileId}`);
538
-
539
- // Determine source label from file context/metadata
540
- const context = file.context as string | undefined;
541
- const hasFileIdentifier = !!(file.metadata as Record<string, unknown>)
542
- .fileIdentifier;
543
- let source = 'attachment';
544
- if (context === 'artifact') {
545
- source = 'agent';
546
- } else if (hasFileIdentifier) {
547
- source = 'code_executor';
548
- }
549
-
550
- const hasText = !!(file.text && (file.text as string).length > 0);
551
-
552
- redisEntries.push({
553
- id: `file:${fileId}`,
554
- name: (file.filename as string) || 'unknown',
555
- type: (file.type as string) || 'text/plain',
556
- source,
557
- totalLines: 0,
558
- totalChars: (file.bytes as number) || 0,
559
- createdAt: file.createdAt
560
- ? new Date(file.createdAt as string).getTime()
561
- : Date.now(),
562
- fileId,
563
- userId: this.userId,
564
- conversationId: this.conversationId,
565
- needsIngestion: hasText,
566
- });
567
- }
568
- } catch (err) {
569
- this.logger.warn(
570
- `[ArtifactStore] File batch fetch failed for ${this.conversationId}:`,
571
- (err as Error).message
572
- );
573
- }
574
-
575
- return redisEntries;
576
- }
577
-
578
- /**
579
- * Persist a new content entry to S3 and create a MongoDB File record.
580
- * Called in background after Redis store — agent doesn't wait for this.
581
- *
582
- * @param contentId - The content entry ID.
583
- * @param entry - The original store entry with content and metadata.
584
- */
585
- protected async persistToS3(
586
- contentId: string,
587
- entry: StoreEntry
588
- ): Promise<void> {
589
- const buffer = Buffer.from(entry.content, 'utf-8');
590
- const fileName = this.getS3FileName(contentId, entry.name);
591
- const basePath = this.getS3BasePath();
592
-
593
- const filepath = await this.s3.saveBuffer({
594
- userId: this.userId,
595
- buffer,
596
- fileName,
597
- basePath,
598
- });
599
-
600
- const fileId = this.buildFileId(contentId);
601
- await this.fileModel.createFile(
602
- {
603
- user: this.userId,
604
- file_id: fileId,
605
- conversationId: this.conversationId,
606
- filename: entry.name,
607
- filepath,
608
- type: entry.type || 'text/plain',
609
- bytes: buffer.length,
610
- source: 's3',
611
- context: this.getContextLabel(),
612
- object: 'file',
613
- usage: 0,
614
- metadata: {
615
- contentId,
616
- artifactSource: entry.source,
617
- },
618
- },
619
- /* disableTTL */ true
620
- );
621
-
622
- // Link artifact to Conversation.files — the single source of truth for
623
- // which files belong to a conversation. Fire-and-forget: non-critical
624
- // because the fallback query in listFiles() will still find via File.conversationId.
625
- try {
626
- await this.fileModel.addFilesToConversation(this.conversationId, [
627
- fileId,
628
- ]);
629
- } catch (err) {
630
- this.logger.warn(
631
- `[ArtifactStore] addFilesToConversation failed for ${fileId}:`,
632
- (err as Error).message
633
- );
634
- }
635
-
636
- // Update Redis metadata with the S3-backed fileId
637
- const stored = await this.getStored(contentId);
638
- if (stored) {
639
- stored.metadata.fileId = fileId;
640
- await this.cache.set(contentId, JSON.stringify(stored));
641
-
642
- // Update index
643
- const index = await this.getIndex();
644
- if (index[contentId]) {
645
- index[contentId] = stored.metadata;
646
- await this.cache.set(this.indexKey, JSON.stringify(index));
647
- }
648
- }
649
- }
650
-
651
- /**
652
- * Sync updated Redis content to S3 (overwrite same key).
653
- * Called in background after write/edit operations.
654
- *
655
- * @param contentId - The content entry ID to sync.
656
- */
657
- protected async syncToS3(contentId: string): Promise<void> {
658
- const stored = await this.getStored(contentId);
659
- if (!stored) {
660
- return;
661
- }
662
-
663
- const buffer = Buffer.from(stored.content, 'utf-8');
664
- const fileName = this.getS3FileName(contentId, stored.metadata.name);
665
- const basePath = this.getS3BasePath();
666
-
667
- const filepath = await this.s3.saveBuffer({
668
- userId: this.userId,
669
- buffer,
670
- fileName,
671
- basePath,
672
- });
673
-
674
- // Update MongoDB File record with new bytes and filepath
675
- const fileId = this.buildFileId(contentId);
676
- try {
677
- await this.fileModel.updateFile({
678
- file_id: fileId,
679
- bytes: buffer.length,
680
- filepath,
681
- });
682
- } catch (err) {
683
- this.logger.warn(
684
- `[ArtifactStore] MongoDB update failed for ${contentId}:`,
685
- (err as Error).message
686
- );
687
- }
688
- }
689
-
690
- /**
691
- * Restore content from S3 into Redis on cache miss.
692
- * Looks up the MongoDB File record to find the S3 path, downloads content,
693
- * and re-populates the Redis cache with the same key structure.
694
- *
695
- * @param contentId - The content entry ID to restore.
696
- * @returns The restored StoredEntry, or null if not found in S3/MongoDB.
697
- */
698
- protected async restoreFromS3(
699
- contentId: string
700
- ): Promise<StoredEntry | null> {
701
- const fileId = this.buildFileId(contentId);
702
-
703
- try {
704
- // Find the MongoDB record for this artifact
705
- const fileRecord = await this.fileModel.findFile({
706
- file_id: fileId,
707
- user: this.userId,
708
- });
709
-
710
- if (!fileRecord || !fileRecord.filepath) {
711
- return null;
712
- }
713
-
714
- // Download content from S3
715
- const stream = await this.s3.getFileStream(fileRecord.filepath as string);
716
- const chunks: Buffer[] = [];
717
- for await (const chunk of stream) {
718
- chunks.push(
719
- Buffer.isBuffer(chunk)
720
- ? chunk
721
- : Buffer.from(chunk as unknown as Uint8Array)
722
- );
723
- }
724
- const content = Buffer.concat(chunks).toString('utf-8');
725
-
726
- // Reconstruct metadata from MongoDB record + content
727
- const metadata: ContentMetadata = {
728
- id: contentId,
729
- name: (fileRecord.filename as string) || 'unknown',
730
- type: (fileRecord.type as string) || 'text/plain',
731
- source:
732
- ((fileRecord.metadata as Record<string, unknown>)
733
- .artifactSource as string) || 'unknown',
734
- totalLines: content.split('\n').length,
735
- totalChars: content.length,
736
- createdAt: fileRecord.createdAt
737
- ? new Date(fileRecord.createdAt as string).getTime()
738
- : Date.now(),
739
- fileId,
740
- userId: this.userId,
741
- conversationId: this.conversationId,
742
- };
743
-
744
- // Re-populate Redis cache
745
- const stored: StoredEntry = { content, metadata };
746
- await this.cache.set(contentId, JSON.stringify(stored));
747
-
748
- // Update index
749
- const index = await this.getIndex();
750
- index[contentId] = metadata;
751
- await this.cache.set(this.indexKey, JSON.stringify(index));
752
-
753
- return stored;
754
- } catch (err) {
755
- this.logger.warn(
756
- `[ArtifactStore] S3 restore failed for ${contentId}:`,
757
- (err as Error).message
758
- );
759
- return null;
760
- }
761
- }
762
-
763
- /**
764
- * Ensure content is loaded into Redis. If not in Redis, attempt S3 restore.
765
- * Used before write/edit operations that need content to be present.
766
- *
767
- * @param contentId - The content entry ID.
768
- * @throws If content is not found in Redis or S3.
769
- */
770
- protected async ensureLoaded(contentId: string): Promise<void> {
771
- const existing = await this.getStored(contentId);
772
- if (existing) {
773
- return;
774
- }
775
-
776
- // Try S3 restore
777
- const restored = await this.restoreFromS3(contentId);
778
- if (!restored) {
779
- throw new Error(`Content "${contentId}" not found in Redis or S3`);
780
- }
781
- }
782
- }