enya-agent 0.1.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 (389) hide show
  1. package/.env.example +20 -0
  2. package/.github/workflows/ci.yml +70 -0
  3. package/.github/workflows/publish.yml +250 -0
  4. package/.gitmodules +3 -0
  5. package/Cargo.lock +3584 -0
  6. package/Cargo.toml +97 -0
  7. package/crates/enact/Cargo.toml +27 -0
  8. package/crates/enact/src/lib.rs +60 -0
  9. package/crates/enact-a2a/Cargo.toml +25 -0
  10. package/crates/enact-a2a/src/lib.rs +411 -0
  11. package/crates/enact-channels/Cargo.toml +64 -0
  12. package/crates/enact-channels/examples/README.md +80 -0
  13. package/crates/enact-channels/examples/channel_bot.rs +169 -0
  14. package/crates/enact-channels/examples/telegram-echo.rs +34 -0
  15. package/crates/enact-channels/examples/whatsapp-echo.rs +142 -0
  16. package/crates/enact-channels/src/config.rs +213 -0
  17. package/crates/enact-channels/src/lib.rs +25 -0
  18. package/crates/enact-channels/src/runtime.rs +237 -0
  19. package/crates/enact-channels/src/security/mod.rs +5 -0
  20. package/crates/enact-channels/src/security/pairing.rs +205 -0
  21. package/crates/enact-channels/src/teams.rs +601 -0
  22. package/crates/enact-channels/src/telegram.rs +2833 -0
  23. package/crates/enact-channels/src/traits.rs +200 -0
  24. package/crates/enact-channels/src/webhook.rs +262 -0
  25. package/crates/enact-channels/src/whatsapp.rs +310 -0
  26. package/crates/enact-cli/Cargo.toml +40 -0
  27. package/crates/enact-cli/src/commands/doctor.rs +62 -0
  28. package/crates/enact-cli/src/commands/mod.rs +3 -0
  29. package/crates/enact-cli/src/commands/run.rs +69 -0
  30. package/crates/enact-cli/src/commands/serve.rs +81 -0
  31. package/crates/enact-cli/src/config.rs +2 -0
  32. package/crates/enact-cli/src/main.rs +79 -0
  33. package/crates/enact-config/Cargo.toml +36 -0
  34. package/crates/enact-config/ENV_VAR_MAPPING.md +135 -0
  35. package/crates/enact-config/QUICK_REFERENCE.md +92 -0
  36. package/crates/enact-config/README.md +107 -0
  37. package/crates/enact-config/TESTING.md +161 -0
  38. package/crates/enact-config/examples/test-env-vars.rs +100 -0
  39. package/crates/enact-config/src/config.rs +399 -0
  40. package/crates/enact-config/src/encrypted_store.rs +211 -0
  41. package/crates/enact-config/src/lib.rs +298 -0
  42. package/crates/enact-config/src/secrets.rs +149 -0
  43. package/crates/enact-config/src/sync.rs +260 -0
  44. package/crates/enact-config/test-env-vars.sh +34 -0
  45. package/crates/enact-config/tests/README.md +99 -0
  46. package/crates/enact-config/tests/config_integration_test.rs +202 -0
  47. package/crates/enact-config/tests/security_test.rs +140 -0
  48. package/crates/enact-context/Cargo.toml +41 -0
  49. package/crates/enact-context/src/budget.rs +314 -0
  50. package/crates/enact-context/src/calibrator.rs +535 -0
  51. package/crates/enact-context/src/compactor.rs +392 -0
  52. package/crates/enact-context/src/condenser.rs +826 -0
  53. package/crates/enact-context/src/lib.rs +94 -0
  54. package/crates/enact-context/src/segment.rs +238 -0
  55. package/crates/enact-context/src/step_context.rs +645 -0
  56. package/crates/enact-context/src/token_counter.rs +148 -0
  57. package/crates/enact-context/src/window.rs +372 -0
  58. package/crates/enact-core/Cargo.toml +42 -0
  59. package/crates/enact-core/README.md +98 -0
  60. package/crates/enact-core/src/background/executor.rs +524 -0
  61. package/crates/enact-core/src/background/mod.rs +48 -0
  62. package/crates/enact-core/src/background/target_binding.rs +390 -0
  63. package/crates/enact-core/src/background/trigger.rs +511 -0
  64. package/crates/enact-core/src/callable/callable.rs +152 -0
  65. package/crates/enact-core/src/callable/composite.rs +817 -0
  66. package/crates/enact-core/src/callable/graph.rs +104 -0
  67. package/crates/enact-core/src/callable/llm.rs +211 -0
  68. package/crates/enact-core/src/callable/mod.rs +64 -0
  69. package/crates/enact-core/src/callable/registry.rs +206 -0
  70. package/crates/enact-core/src/context/execution_context.rs +757 -0
  71. package/crates/enact-core/src/context/invocation.rs +99 -0
  72. package/crates/enact-core/src/context/mod.rs +50 -0
  73. package/crates/enact-core/src/context/tenant.rs +175 -0
  74. package/crates/enact-core/src/context/trace.rs +127 -0
  75. package/crates/enact-core/src/flow/conditional.rs +293 -0
  76. package/crates/enact-core/src/flow/mod.rs +43 -0
  77. package/crates/enact-core/src/flow/parallel.rs +437 -0
  78. package/crates/enact-core/src/flow/repeat.rs +534 -0
  79. package/crates/enact-core/src/flow/sequential.rs +248 -0
  80. package/crates/enact-core/src/graph/checkpoint.rs +79 -0
  81. package/crates/enact-core/src/graph/checkpoint_store.rs +76 -0
  82. package/crates/enact-core/src/graph/compiled.rs +189 -0
  83. package/crates/enact-core/src/graph/edge.rs +59 -0
  84. package/crates/enact-core/src/graph/graph_schema.rs +218 -0
  85. package/crates/enact-core/src/graph/loader.rs +155 -0
  86. package/crates/enact-core/src/graph/mod.rs +18 -0
  87. package/crates/enact-core/src/graph/node/function.rs +49 -0
  88. package/crates/enact-core/src/graph/node/mod.rs +48 -0
  89. package/crates/enact-core/src/graph/schema.rs +62 -0
  90. package/crates/enact-core/src/inbox/message.rs +405 -0
  91. package/crates/enact-core/src/inbox/mod.rs +31 -0
  92. package/crates/enact-core/src/inbox/store.rs +355 -0
  93. package/crates/enact-core/src/kernel/artifact/filesystem.rs +546 -0
  94. package/crates/enact-core/src/kernel/artifact/metadata.rs +283 -0
  95. package/crates/enact-core/src/kernel/artifact/mod.rs +27 -0
  96. package/crates/enact-core/src/kernel/artifact/store.rs +427 -0
  97. package/crates/enact-core/src/kernel/enforcement.rs +1315 -0
  98. package/crates/enact-core/src/kernel/error.rs +1200 -0
  99. package/crates/enact-core/src/kernel/event.rs +1394 -0
  100. package/crates/enact-core/src/kernel/execution_model.rs +831 -0
  101. package/crates/enact-core/src/kernel/execution_state.rs +189 -0
  102. package/crates/enact-core/src/kernel/execution_strategy.rs +117 -0
  103. package/crates/enact-core/src/kernel/ids.rs +2086 -0
  104. package/crates/enact-core/src/kernel/interrupt.rs +125 -0
  105. package/crates/enact-core/src/kernel/kernel.rs +1283 -0
  106. package/crates/enact-core/src/kernel/mod.rs +205 -0
  107. package/crates/enact-core/src/kernel/persistence/event_store.rs +270 -0
  108. package/crates/enact-core/src/kernel/persistence/message_store.rs +908 -0
  109. package/crates/enact-core/src/kernel/persistence/mod.rs +102 -0
  110. package/crates/enact-core/src/kernel/persistence/state_store.rs +228 -0
  111. package/crates/enact-core/src/kernel/persistence/vector_store.rs +299 -0
  112. package/crates/enact-core/src/kernel/reducer.rs +808 -0
  113. package/crates/enact-core/src/kernel/replay.rs +153 -0
  114. package/crates/enact-core/src/lib.rs +413 -0
  115. package/crates/enact-core/src/memory/episodic.rs +0 -0
  116. package/crates/enact-core/src/memory/mod.rs +6 -0
  117. package/crates/enact-core/src/memory/semantic.rs +0 -0
  118. package/crates/enact-core/src/memory/trait.rs +0 -0
  119. package/crates/enact-core/src/memory/vector_db.rs +0 -0
  120. package/crates/enact-core/src/memory/working.rs +0 -0
  121. package/crates/enact-core/src/policy/execution_policy.rs +292 -0
  122. package/crates/enact-core/src/policy/filters.rs +458 -0
  123. package/crates/enact-core/src/policy/input_processor.rs +407 -0
  124. package/crates/enact-core/src/policy/long_running.rs +134 -0
  125. package/crates/enact-core/src/policy/mod.rs +193 -0
  126. package/crates/enact-core/src/policy/pii_input.rs +274 -0
  127. package/crates/enact-core/src/policy/tenant_policy.rs +453 -0
  128. package/crates/enact-core/src/policy/tool_policy.rs +407 -0
  129. package/crates/enact-core/src/providers/mod.rs +63 -0
  130. package/crates/enact-core/src/providers/trait.rs +292 -0
  131. package/crates/enact-core/src/runner/callbacks.rs +6 -0
  132. package/crates/enact-core/src/runner/execution_runner.rs +476 -0
  133. package/crates/enact-core/src/runner/loop.rs +117 -0
  134. package/crates/enact-core/src/runner/mod.rs +58 -0
  135. package/crates/enact-core/src/runner/protected_runner.rs +280 -0
  136. package/crates/enact-core/src/signal/inmemory.rs +231 -0
  137. package/crates/enact-core/src/signal/mod.rs +108 -0
  138. package/crates/enact-core/src/streaming/event_logger.rs +195 -0
  139. package/crates/enact-core/src/streaming/event_stream.rs +1423 -0
  140. package/crates/enact-core/src/streaming/mod.rs +108 -0
  141. package/crates/enact-core/src/streaming/pause_cancel.rs +0 -0
  142. package/crates/enact-core/src/streaming/protected_emitter.rs +173 -0
  143. package/crates/enact-core/src/streaming/protection/context.rs +136 -0
  144. package/crates/enact-core/src/streaming/protection/encryption.rs +289 -0
  145. package/crates/enact-core/src/streaming/protection/mod.rs +43 -0
  146. package/crates/enact-core/src/streaming/protection/pii_protection.rs +243 -0
  147. package/crates/enact-core/src/streaming/protection/processor.rs +166 -0
  148. package/crates/enact-core/src/streaming/sse.rs +0 -0
  149. package/crates/enact-core/src/telemetry/exporter.rs +0 -0
  150. package/crates/enact-core/src/telemetry/init.rs +0 -0
  151. package/crates/enact-core/src/telemetry/mod.rs +49 -0
  152. package/crates/enact-core/src/telemetry/spans.rs +245 -0
  153. package/crates/enact-core/src/tool/agent_tool.rs +177 -0
  154. package/crates/enact-core/src/tool/browser/mod.rs +0 -0
  155. package/crates/enact-core/src/tool/browser/webdriver.rs +0 -0
  156. package/crates/enact-core/src/tool/cost.rs +247 -0
  157. package/crates/enact-core/src/tool/discovery.rs +0 -0
  158. package/crates/enact-core/src/tool/dispatcher.rs +347 -0
  159. package/crates/enact-core/src/tool/filesystem.rs +231 -0
  160. package/crates/enact-core/src/tool/function.rs +99 -0
  161. package/crates/enact-core/src/tool/git.rs +162 -0
  162. package/crates/enact-core/src/tool/http.rs +214 -0
  163. package/crates/enact-core/src/tool/mcp/client.rs +0 -0
  164. package/crates/enact-core/src/tool/mcp/mod.rs +0 -0
  165. package/crates/enact-core/src/tool/mod.rs +51 -0
  166. package/crates/enact-core/src/tool/reasoning/debugging.rs +0 -0
  167. package/crates/enact-core/src/tool/reasoning/mcts.rs +0 -0
  168. package/crates/enact-core/src/tool/reasoning/mod.rs +0 -0
  169. package/crates/enact-core/src/tool/reasoning/sequential.rs +0 -0
  170. package/crates/enact-core/src/tool/sandbox/dagger.rs +0 -0
  171. package/crates/enact-core/src/tool/sandbox/mod.rs +0 -0
  172. package/crates/enact-core/src/tool/shell.rs +147 -0
  173. package/crates/enact-core/src/tool/trait.rs +33 -0
  174. package/crates/enact-core/src/tool/web_search.rs +277 -0
  175. package/crates/enact-core/src/util/config.rs +0 -0
  176. package/crates/enact-core/src/util/errors.rs +0 -0
  177. package/crates/enact-core/src/util/mod.rs +6 -0
  178. package/crates/enact-core/tests/airgapped_e2e_test.rs +291 -0
  179. package/crates/enact-core/tests/e2e_agentic_loop.rs +119 -0
  180. package/crates/enact-core/tests/e2e_test.rs +259 -0
  181. package/crates/enact-core/tests/graph_test.rs +130 -0
  182. package/crates/enact-core/tests/stream_event_id_validation.rs +435 -0
  183. package/crates/enact-cron/Cargo.toml +28 -0
  184. package/crates/enact-cron/src/lib.rs +44 -0
  185. package/crates/enact-cron/src/schedule.rs +156 -0
  186. package/crates/enact-cron/src/store.rs +589 -0
  187. package/crates/enact-cron/src/types.rs +148 -0
  188. package/crates/enact-gateway/Cargo.toml +31 -0
  189. package/crates/enact-gateway/README.md +30 -0
  190. package/crates/enact-gateway/examples/whatsapp-gateway-runner-mock.rs +59 -0
  191. package/crates/enact-gateway/examples/whatsapp-gateway.rs +42 -0
  192. package/crates/enact-gateway/src/lib.rs +582 -0
  193. package/crates/enact-mcp/Cargo.toml +24 -0
  194. package/crates/enact-mcp/src/lib.rs +178 -0
  195. package/crates/enact-memory/Cargo.toml +25 -0
  196. package/crates/enact-memory/src/backend.rs +20 -0
  197. package/crates/enact-memory/src/chunker.rs +230 -0
  198. package/crates/enact-memory/src/embeddings.rs +221 -0
  199. package/crates/enact-memory/src/lib.rs +67 -0
  200. package/crates/enact-memory/src/markdown.rs +127 -0
  201. package/crates/enact-memory/src/none.rs +61 -0
  202. package/crates/enact-memory/src/sqlite.rs +276 -0
  203. package/crates/enact-memory/src/traits.rs +65 -0
  204. package/crates/enact-memory/src/vector.rs +198 -0
  205. package/crates/enact-oauth/Cargo.toml +27 -0
  206. package/crates/enact-oauth/src/lib.rs +584 -0
  207. package/crates/enact-observability/Cargo.toml +22 -0
  208. package/crates/enact-observability/src/lib.rs +197 -0
  209. package/crates/enact-providers/Cargo.toml +33 -0
  210. package/crates/enact-providers/examples/hello-agent.rs +33 -0
  211. package/crates/enact-providers/src/anthropic.rs +182 -0
  212. package/crates/enact-providers/src/azure.rs +96 -0
  213. package/crates/enact-providers/src/bridge.rs +221 -0
  214. package/crates/enact-providers/src/gemini.rs +227 -0
  215. package/crates/enact-providers/src/http.rs +78 -0
  216. package/crates/enact-providers/src/lib.rs +53 -0
  217. package/crates/enact-providers/src/openai_compatible.rs +167 -0
  218. package/crates/enact-providers/src/openrouter.rs +33 -0
  219. package/crates/enact-runner/Cargo.toml +24 -0
  220. package/crates/enact-runner/README.md +76 -0
  221. package/crates/enact-runner/src/compaction.rs +225 -0
  222. package/crates/enact-runner/src/config.rs +118 -0
  223. package/crates/enact-runner/src/lib.rs +63 -0
  224. package/crates/enact-runner/src/loop_driver.rs +414 -0
  225. package/crates/enact-runner/src/parser.rs +421 -0
  226. package/crates/enact-runner/src/retry.rs +262 -0
  227. package/crates/enact-runner/tests/integration.rs +278 -0
  228. package/crates/enact-security/Cargo.toml +22 -0
  229. package/crates/enact-security/src/audit.rs +375 -0
  230. package/crates/enact-security/src/lib.rs +37 -0
  231. package/crates/enact-security/src/policy.rs +406 -0
  232. package/crates/enact-skills/Cargo.toml +25 -0
  233. package/crates/enact-skills/src/lib.rs +506 -0
  234. package/crates/enact-tools/Cargo.toml +22 -0
  235. package/crates/enact-tools/src/file_read.rs +166 -0
  236. package/crates/enact-tools/src/file_write.rs +216 -0
  237. package/crates/enact-tools/src/git_operations.rs +513 -0
  238. package/crates/enact-tools/src/http_request.rs +417 -0
  239. package/crates/enact-tools/src/lib.rs +104 -0
  240. package/crates/enact-tools/src/security.rs +227 -0
  241. package/crates/enact-tools/src/shell.rs +191 -0
  242. package/crates/enact-tools/src/traits.rs +159 -0
  243. package/docs/Makefile +74 -0
  244. package/docs/config.toml +62 -0
  245. package/docs/content/_index.md +174 -0
  246. package/docs/content/a2a/_index.md +431 -0
  247. package/docs/content/api/_index.md +323 -0
  248. package/docs/content/channels/_index.md +160 -0
  249. package/docs/content/channels/teams.md +205 -0
  250. package/docs/content/channels/telegram.md +182 -0
  251. package/docs/content/channels/webhook.md +423 -0
  252. package/docs/content/channels/whatsapp.md +240 -0
  253. package/docs/content/cli/_index.md +261 -0
  254. package/docs/content/concepts/_index.md +273 -0
  255. package/docs/content/configuration/_index.md +241 -0
  256. package/docs/content/cron/_index.md +248 -0
  257. package/docs/content/developers/_index.md +278 -0
  258. package/docs/content/getting-started/_index.md +180 -0
  259. package/docs/content/installation/_index.md +186 -0
  260. package/docs/content/installation/uninstall.md +101 -0
  261. package/docs/content/installation/updating.md +120 -0
  262. package/docs/content/mcp/_index.md +215 -0
  263. package/docs/content/memory/_index.md +163 -0
  264. package/docs/content/oauth/_index.md +515 -0
  265. package/docs/content/providers/_index.md +206 -0
  266. package/docs/content/roadmap/_index.md +199 -0
  267. package/docs/content/security/_index.md +219 -0
  268. package/docs/content/skills/_index.md +228 -0
  269. package/docs/content/tools/_index.md +485 -0
  270. package/docs/content/troubleshooting/_index.md +259 -0
  271. package/docs/content/yaml-schema/_index.md +294 -0
  272. package/docs/static/giallo-dark.css +91 -0
  273. package/docs/static/giallo-light.css +91 -0
  274. package/docs/themes/tanuki/.github/workflows/deploy.yml +44 -0
  275. package/docs/themes/tanuki/LICENSE +21 -0
  276. package/docs/themes/tanuki/README.md +166 -0
  277. package/docs/themes/tanuki/examples/blog/config.toml +58 -0
  278. package/docs/themes/tanuki/examples/blog/content/_index.md +4 -0
  279. package/docs/themes/tanuki/examples/blog/content/about.md +33 -0
  280. package/docs/themes/tanuki/examples/blog/content/blog/_index.md +7 -0
  281. package/docs/themes/tanuki/examples/blog/content/blog/api-design-best-practices.md +245 -0
  282. package/docs/themes/tanuki/examples/blog/content/blog/building-accessible-websites.md +147 -0
  283. package/docs/themes/tanuki/examples/blog/content/blog/css-grid-vs-flexbox.md +165 -0
  284. package/docs/themes/tanuki/examples/blog/content/blog/customizing-catppuccin-colors.md +137 -0
  285. package/docs/themes/tanuki/examples/blog/content/blog/dark-mode-best-practices.md +82 -0
  286. package/docs/themes/tanuki/examples/blog/content/blog/docker-essentials.md +301 -0
  287. package/docs/themes/tanuki/examples/blog/content/blog/getting-started-with-zola.md +129 -0
  288. package/docs/themes/tanuki/examples/blog/content/blog/git-workflow-for-content.md +112 -0
  289. package/docs/themes/tanuki/examples/blog/content/blog/introduction-to-webassembly.md +183 -0
  290. package/docs/themes/tanuki/examples/blog/content/blog/modern-javascript-features.md +234 -0
  291. package/docs/themes/tanuki/examples/blog/content/blog/testing-strategies.md +311 -0
  292. package/docs/themes/tanuki/examples/blog/content/blog/typography-for-developers.md +104 -0
  293. package/docs/themes/tanuki/examples/blog/content/blog/welcome-to-tanuki.md +67 -0
  294. package/docs/themes/tanuki/examples/blog/content/blog/why-static-sites.md +85 -0
  295. package/docs/themes/tanuki/examples/blog/content/projects.md +64 -0
  296. package/docs/themes/tanuki/examples/book/config.toml +17 -0
  297. package/docs/themes/tanuki/examples/book/content/_index.md +12 -0
  298. package/docs/themes/tanuki/examples/book/content/chapter-1.md +90 -0
  299. package/docs/themes/tanuki/examples/book/content/chapter-2.md +143 -0
  300. package/docs/themes/tanuki/examples/book/content/chapter-3.md +217 -0
  301. package/docs/themes/tanuki/examples/book/content/chapter-4.md +224 -0
  302. package/docs/themes/tanuki/examples/book/content/chapter-5.md +297 -0
  303. package/docs/themes/tanuki/examples/book/content/print.md +6 -0
  304. package/docs/themes/tanuki/examples/docs/config.toml +28 -0
  305. package/docs/themes/tanuki/examples/docs/content/_index.md +20 -0
  306. package/docs/themes/tanuki/examples/docs/content/components.md +156 -0
  307. package/docs/themes/tanuki/examples/docs/content/configuration.md +94 -0
  308. package/docs/themes/tanuki/examples/docs/content/customization.md +202 -0
  309. package/docs/themes/tanuki/examples/docs/content/deployment.md +204 -0
  310. package/docs/themes/tanuki/examples/docs/content/installation.md +59 -0
  311. package/docs/themes/tanuki/examples/docs/content/print.md +6 -0
  312. package/docs/themes/tanuki/examples/docs/static/img/tanuki-icon.avif +0 -0
  313. package/docs/themes/tanuki/examples/index.html +2104 -0
  314. package/docs/themes/tanuki/mise.toml +108 -0
  315. package/docs/themes/tanuki/sass/base/_catppuccin.scss +164 -0
  316. package/docs/themes/tanuki/sass/base/_fonts.scss +64 -0
  317. package/docs/themes/tanuki/sass/base/_reset.scss +152 -0
  318. package/docs/themes/tanuki/sass/base/_typography.scss +523 -0
  319. package/docs/themes/tanuki/sass/components/_buttons.scss +209 -0
  320. package/docs/themes/tanuki/sass/components/_code.scss +457 -0
  321. package/docs/themes/tanuki/sass/components/_landing.scss +633 -0
  322. package/docs/themes/tanuki/sass/components/_layout.scss +294 -0
  323. package/docs/themes/tanuki/sass/components/_navigation.scss +1200 -0
  324. package/docs/themes/tanuki/sass/components/_print.scss +237 -0
  325. package/docs/themes/tanuki/sass/components/_search.scss +224 -0
  326. package/docs/themes/tanuki/sass/components/_sidebar.scss +473 -0
  327. package/docs/themes/tanuki/sass/components/_theme-toggle.scss +186 -0
  328. package/docs/themes/tanuki/sass/modes/_blog.scss +366 -0
  329. package/docs/themes/tanuki/sass/modes/_product.scss +875 -0
  330. package/docs/themes/tanuki/sass/modes/_raskell.scss +1696 -0
  331. package/docs/themes/tanuki/sass/patterns/_buttons.scss +183 -0
  332. package/docs/themes/tanuki/sass/patterns/_cards.scss +144 -0
  333. package/docs/themes/tanuki/sass/patterns/_index.scss +9 -0
  334. package/docs/themes/tanuki/sass/patterns/_lists.scss +259 -0
  335. package/docs/themes/tanuki/sass/patterns/_sections.scss +243 -0
  336. package/docs/themes/tanuki/sass/style.scss +47 -0
  337. package/docs/themes/tanuki/sass/tokens/_colors.scss +139 -0
  338. package/docs/themes/tanuki/sass/tokens/_spacing.scss +100 -0
  339. package/docs/themes/tanuki/sass/tokens/_typography.scss +186 -0
  340. package/docs/themes/tanuki/screenshot.png +0 -0
  341. package/docs/themes/tanuki/sentinel.kdl +59 -0
  342. package/docs/themes/tanuki/static/elasticlunr.min.js +10 -0
  343. package/docs/themes/tanuki/static/fonts/GEIST-LICENSE.txt +92 -0
  344. package/docs/themes/tanuki/static/fonts/Geist-Variable.woff2 +0 -0
  345. package/docs/themes/tanuki/static/fonts/GeistMono-Variable.woff2 +0 -0
  346. package/docs/themes/tanuki/static/img/tanuki-icon.avif +0 -0
  347. package/docs/themes/tanuki/static/img/tanuki-icon.png +0 -0
  348. package/docs/themes/tanuki/static/js/anchors.js +18 -0
  349. package/docs/themes/tanuki/static/js/app.js +274 -0
  350. package/docs/themes/tanuki/static/js/code.js +394 -0
  351. package/docs/themes/tanuki/static/js/navigation.js +778 -0
  352. package/docs/themes/tanuki/static/js/scroll-to-top.js +33 -0
  353. package/docs/themes/tanuki/static/js/search-raskell.js +240 -0
  354. package/docs/themes/tanuki/static/js/search.js +215 -0
  355. package/docs/themes/tanuki/static/js/theme.js +169 -0
  356. package/docs/themes/tanuki/static/syntax-dark.css +151 -0
  357. package/docs/themes/tanuki/static/syntax-light.css +151 -0
  358. package/docs/themes/tanuki/static/wasm/sentinel_playground_wasm.js +486 -0
  359. package/docs/themes/tanuki/static/wasm/sentinel_playground_wasm_bg.wasm +0 -0
  360. package/docs/themes/tanuki/templates/404.html +52 -0
  361. package/docs/themes/tanuki/templates/base.html +428 -0
  362. package/docs/themes/tanuki/templates/blog.html +66 -0
  363. package/docs/themes/tanuki/templates/home.html +108 -0
  364. package/docs/themes/tanuki/templates/index.html +178 -0
  365. package/docs/themes/tanuki/templates/landing.html +168 -0
  366. package/docs/themes/tanuki/templates/macros/nav.html +128 -0
  367. package/docs/themes/tanuki/templates/macros/posts.html +101 -0
  368. package/docs/themes/tanuki/templates/macros/ui.html +159 -0
  369. package/docs/themes/tanuki/templates/page.html +135 -0
  370. package/docs/themes/tanuki/templates/partials/footer.html +38 -0
  371. package/docs/themes/tanuki/templates/partials/header.html +366 -0
  372. package/docs/themes/tanuki/templates/partials/nav-buttons.html +55 -0
  373. package/docs/themes/tanuki/templates/partials/nav-overlay.html +81 -0
  374. package/docs/themes/tanuki/templates/partials/page-toc-panel.html +43 -0
  375. package/docs/themes/tanuki/templates/partials/search.html +52 -0
  376. package/docs/themes/tanuki/templates/partials/sidebar.html +107 -0
  377. package/docs/themes/tanuki/templates/partials/theme-toggle.html +35 -0
  378. package/docs/themes/tanuki/templates/partials/toc-overlay.html +146 -0
  379. package/docs/themes/tanuki/templates/partials/version-picker.html +38 -0
  380. package/docs/themes/tanuki/templates/print.html +244 -0
  381. package/docs/themes/tanuki/templates/section.html +186 -0
  382. package/docs/themes/tanuki/templates/taxonomy_list.html +18 -0
  383. package/docs/themes/tanuki/templates/taxonomy_single.html +31 -0
  384. package/docs/themes/tanuki/theme.toml +58 -0
  385. package/examples/hello-agent.rs +55 -0
  386. package/package.json +36 -0
  387. package/proto/config.proto +60 -0
  388. package/proto/events.proto +0 -0
  389. package/proto/runtime.proto +215 -0
@@ -0,0 +1,546 @@
1
+ //! Filesystem Artifact Store - Local storage with zstd compression
2
+ //!
3
+ //! This implementation stores artifacts on the local filesystem with:
4
+ //! - zstd compression for space efficiency
5
+ //! - SHA-256 content hashing for integrity
6
+ //! - Metadata stored as JSON sidecar files
7
+ //!
8
+ //! ## Directory Structure
9
+ //!
10
+ //! ```text
11
+ //! base_path/
12
+ //! {execution_id}/
13
+ //! {artifact_id}.zst # Compressed content
14
+ //! {artifact_id}.meta.json # Metadata
15
+ //! ```
16
+
17
+ use super::metadata::{ArtifactMetadata, CompressionType};
18
+ use super::store::{
19
+ ArtifactStore, ArtifactStoreError, GetArtifactResponse,
20
+ ListArtifactsQuery, PutArtifactRequest, PutArtifactResponse,
21
+ };
22
+ use crate::kernel::ids::{ArtifactId, ExecutionId};
23
+ use async_trait::async_trait;
24
+ use sha2::{Digest, Sha256};
25
+ use std::io::{Read, Write};
26
+ use std::path::{Path, PathBuf};
27
+ use tokio::fs;
28
+
29
+ /// Filesystem-based artifact store
30
+ ///
31
+ /// Stores artifacts on local disk with optional compression.
32
+ /// Uses zstd for compression by default.
33
+ pub struct FilesystemArtifactStore {
34
+ /// Base directory for artifact storage
35
+ base_path: PathBuf,
36
+ /// Compression level (1-22, default 3)
37
+ compression_level: i32,
38
+ /// Whether compression is enabled
39
+ compression_enabled: bool,
40
+ }
41
+
42
+ impl FilesystemArtifactStore {
43
+ /// Create a new filesystem artifact store
44
+ pub fn new(base_path: impl Into<PathBuf>) -> Self {
45
+ Self {
46
+ base_path: base_path.into(),
47
+ compression_level: 3, // Default zstd level
48
+ compression_enabled: true,
49
+ }
50
+ }
51
+
52
+ /// Set compression level (1-22, higher = better compression but slower)
53
+ pub fn with_compression_level(mut self, level: i32) -> Self {
54
+ self.compression_level = level.clamp(1, 22);
55
+ self
56
+ }
57
+
58
+ /// Disable compression
59
+ pub fn without_compression(mut self) -> Self {
60
+ self.compression_enabled = false;
61
+ self
62
+ }
63
+
64
+ /// Get the path for an execution's artifact directory
65
+ fn execution_path(&self, execution_id: &ExecutionId) -> PathBuf {
66
+ self.base_path.join(execution_id.as_str())
67
+ }
68
+
69
+ /// Get the path for an artifact's content file
70
+ fn artifact_content_path(&self, execution_id: &ExecutionId, artifact_id: &ArtifactId) -> PathBuf {
71
+ let ext = if self.compression_enabled { ".zst" } else { "" };
72
+ self.execution_path(execution_id)
73
+ .join(format!("{}{}", artifact_id.as_str(), ext))
74
+ }
75
+
76
+ /// Get the path for an artifact's metadata file
77
+ fn artifact_metadata_path(&self, execution_id: &ExecutionId, artifact_id: &ArtifactId) -> PathBuf {
78
+ self.execution_path(execution_id)
79
+ .join(format!("{}.meta.json", artifact_id.as_str()))
80
+ }
81
+
82
+ /// Compress content using zstd
83
+ fn compress(&self, data: &[u8]) -> Result<Vec<u8>, ArtifactStoreError> {
84
+ if !self.compression_enabled {
85
+ return Ok(data.to_vec());
86
+ }
87
+
88
+ // Use pure Rust zstd encoder
89
+ let mut encoder = zstd_encoder(self.compression_level)?;
90
+ encoder.write_all(data).map_err(|e| {
91
+ ArtifactStoreError::Compression(format!("Failed to write to encoder: {}", e))
92
+ })?;
93
+ encoder.finish().map_err(|e| {
94
+ ArtifactStoreError::Compression(format!("Failed to finish compression: {}", e))
95
+ })
96
+ }
97
+
98
+ /// Decompress content using zstd
99
+ fn decompress(&self, data: &[u8]) -> Result<Vec<u8>, ArtifactStoreError> {
100
+ if !self.compression_enabled {
101
+ return Ok(data.to_vec());
102
+ }
103
+
104
+ let mut decoder = zstd_decoder(data)?;
105
+ let mut result = Vec::new();
106
+ decoder.read_to_end(&mut result).map_err(|e| {
107
+ ArtifactStoreError::Compression(format!("Failed to decompress: {}", e))
108
+ })?;
109
+ Ok(result)
110
+ }
111
+
112
+ /// Calculate SHA-256 hash of content
113
+ fn hash_content(data: &[u8]) -> String {
114
+ let mut hasher = Sha256::new();
115
+ hasher.update(data);
116
+ format!("{:x}", hasher.finalize())
117
+ }
118
+
119
+ /// Load metadata from file
120
+ async fn load_metadata(&self, path: &Path) -> Result<ArtifactMetadata, ArtifactStoreError> {
121
+ let content = fs::read_to_string(path).await?;
122
+ let metadata: ArtifactMetadata = serde_json::from_str(&content)?;
123
+ Ok(metadata)
124
+ }
125
+
126
+ /// Save metadata to file
127
+ async fn save_metadata(&self, path: &Path, metadata: &ArtifactMetadata) -> Result<(), ArtifactStoreError> {
128
+ let content = serde_json::to_string_pretty(metadata)?;
129
+ fs::write(path, content).await?;
130
+ Ok(())
131
+ }
132
+ }
133
+
134
+ // =============================================================================
135
+ // Compression Helpers (Simple implementation without external zstd crate)
136
+ // =============================================================================
137
+
138
+ /// Create a zstd encoder
139
+ /// This is a simple wrapper that uses the flate2 crate as a fallback
140
+ /// In production, you would use the zstd crate directly
141
+ fn zstd_encoder(level: i32) -> Result<ZstdEncoder, ArtifactStoreError> {
142
+ Ok(ZstdEncoder::new(level))
143
+ }
144
+
145
+ /// Create a zstd decoder
146
+ fn zstd_decoder(data: &[u8]) -> Result<ZstdDecoder, ArtifactStoreError> {
147
+ Ok(ZstdDecoder::new(data))
148
+ }
149
+
150
+ /// Simple zstd-like encoder using miniz_oxide for compression
151
+ /// In production, replace with actual zstd crate
152
+ struct ZstdEncoder {
153
+ level: i32,
154
+ buffer: Vec<u8>,
155
+ }
156
+
157
+ impl ZstdEncoder {
158
+ fn new(level: i32) -> Self {
159
+ Self {
160
+ level,
161
+ buffer: Vec::new(),
162
+ }
163
+ }
164
+
165
+ fn finish(self) -> Result<Vec<u8>, std::io::Error> {
166
+ // Simple compression using miniz_oxide (deflate)
167
+ // In production, use the zstd crate for actual zstd compression
168
+
169
+ // For now, we use a simple framing format:
170
+ // [4 bytes: original length][compressed data]
171
+ let original_len = self.buffer.len() as u32;
172
+ let compressed = miniz_oxide::deflate::compress_to_vec(&self.buffer, self.level as u8);
173
+
174
+ let mut result = Vec::with_capacity(4 + compressed.len());
175
+ result.extend_from_slice(&original_len.to_le_bytes());
176
+ result.extend_from_slice(&compressed);
177
+ Ok(result)
178
+ }
179
+ }
180
+
181
+ impl Write for ZstdEncoder {
182
+ fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
183
+ self.buffer.extend_from_slice(buf);
184
+ Ok(buf.len())
185
+ }
186
+
187
+ fn flush(&mut self) -> std::io::Result<()> {
188
+ Ok(())
189
+ }
190
+ }
191
+
192
+ /// Simple zstd-like decoder
193
+ struct ZstdDecoder {
194
+ data: Vec<u8>,
195
+ position: usize,
196
+ }
197
+
198
+ impl ZstdDecoder {
199
+ fn new(data: &[u8]) -> Self {
200
+ Self {
201
+ data: data.to_vec(),
202
+ position: 0,
203
+ }
204
+ }
205
+ }
206
+
207
+ impl Read for ZstdDecoder {
208
+ fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
209
+ if self.position == 0 && self.data.len() > 4 {
210
+ // First read - decompress
211
+ let _original_len = u32::from_le_bytes([
212
+ self.data[0], self.data[1], self.data[2], self.data[3]
213
+ ]) as usize;
214
+
215
+ let decompressed = miniz_oxide::inflate::decompress_to_vec(&self.data[4..])
216
+ .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, format!("{:?}", e)))?;
217
+
218
+ self.data = decompressed;
219
+ }
220
+
221
+ let remaining = self.data.len() - self.position;
222
+ let to_read = std::cmp::min(remaining, buf.len());
223
+
224
+ if to_read > 0 {
225
+ buf[..to_read].copy_from_slice(&self.data[self.position..self.position + to_read]);
226
+ self.position += to_read;
227
+ }
228
+
229
+ Ok(to_read)
230
+ }
231
+ }
232
+
233
+ // =============================================================================
234
+ // ArtifactStore Implementation
235
+ // =============================================================================
236
+
237
+ #[async_trait]
238
+ impl ArtifactStore for FilesystemArtifactStore {
239
+ async fn put(&self, request: PutArtifactRequest) -> Result<PutArtifactResponse, ArtifactStoreError> {
240
+ let artifact_id = ArtifactId::new();
241
+ let original_size = request.content.len() as u64;
242
+
243
+ // Ensure execution directory exists
244
+ let exec_path = self.execution_path(&request.execution_id);
245
+ fs::create_dir_all(&exec_path).await?;
246
+
247
+ // Compress content
248
+ let compressed = self.compress(&request.content)?;
249
+ let compressed_size = compressed.len() as u64;
250
+
251
+ // Calculate content hash
252
+ let content_hash = Self::hash_content(&request.content);
253
+
254
+ // Create metadata
255
+ let content_path = self.artifact_content_path(&request.execution_id, &artifact_id);
256
+ let metadata = ArtifactMetadata::new(
257
+ artifact_id.clone(),
258
+ request.execution_id.clone(),
259
+ request.step_id,
260
+ request.name,
261
+ request.artifact_type,
262
+ )
263
+ .with_original_size(original_size)
264
+ .with_compressed_size(compressed_size)
265
+ .with_compression(if self.compression_enabled { CompressionType::Zstd } else { CompressionType::None })
266
+ .with_content_hash(content_hash)
267
+ .with_storage_uri(content_path.to_string_lossy().to_string())
268
+ .with_content_type(request.content_type.unwrap_or_else(|| request.artifact_type.default_content_type().to_string()));
269
+
270
+ // Write content file
271
+ fs::write(&content_path, &compressed).await?;
272
+
273
+ // Write metadata file
274
+ let metadata_path = self.artifact_metadata_path(&request.execution_id, &artifact_id);
275
+ self.save_metadata(&metadata_path, &metadata).await?;
276
+
277
+ Ok(PutArtifactResponse {
278
+ artifact_id,
279
+ metadata,
280
+ compressed_size,
281
+ original_size,
282
+ })
283
+ }
284
+
285
+ async fn get(&self, artifact_id: &ArtifactId) -> Result<GetArtifactResponse, ArtifactStoreError> {
286
+ // We need to find the execution ID from metadata
287
+ // Search all execution directories
288
+ let mut entries = fs::read_dir(&self.base_path).await?;
289
+
290
+ while let Some(entry) = entries.next_entry().await? {
291
+ if entry.file_type().await?.is_dir() {
292
+ let exec_id = ExecutionId::from(entry.file_name().to_string_lossy().as_ref());
293
+ let metadata_path = self.artifact_metadata_path(&exec_id, artifact_id);
294
+
295
+ if metadata_path.exists() {
296
+ let metadata = self.load_metadata(&metadata_path).await?;
297
+ let content_path = self.artifact_content_path(&exec_id, artifact_id);
298
+
299
+ let compressed = fs::read(&content_path).await?;
300
+ let content = self.decompress(&compressed)?;
301
+
302
+ return Ok(GetArtifactResponse { metadata, content });
303
+ }
304
+ }
305
+ }
306
+
307
+ Err(ArtifactStoreError::NotFound(artifact_id.clone()))
308
+ }
309
+
310
+ async fn exists(&self, artifact_id: &ArtifactId) -> Result<bool, ArtifactStoreError> {
311
+ // Search all execution directories
312
+ let mut entries = fs::read_dir(&self.base_path).await?;
313
+
314
+ while let Some(entry) = entries.next_entry().await? {
315
+ if entry.file_type().await?.is_dir() {
316
+ let exec_id = ExecutionId::from(entry.file_name().to_string_lossy().as_ref());
317
+ let metadata_path = self.artifact_metadata_path(&exec_id, artifact_id);
318
+
319
+ if metadata_path.exists() {
320
+ return Ok(true);
321
+ }
322
+ }
323
+ }
324
+
325
+ Ok(false)
326
+ }
327
+
328
+ async fn delete(&self, artifact_id: &ArtifactId) -> Result<(), ArtifactStoreError> {
329
+ // Search all execution directories
330
+ let mut entries = fs::read_dir(&self.base_path).await?;
331
+
332
+ while let Some(entry) = entries.next_entry().await? {
333
+ if entry.file_type().await?.is_dir() {
334
+ let exec_id = ExecutionId::from(entry.file_name().to_string_lossy().as_ref());
335
+ let metadata_path = self.artifact_metadata_path(&exec_id, artifact_id);
336
+
337
+ if metadata_path.exists() {
338
+ let content_path = self.artifact_content_path(&exec_id, artifact_id);
339
+
340
+ // Delete both files
341
+ if content_path.exists() {
342
+ fs::remove_file(&content_path).await?;
343
+ }
344
+ fs::remove_file(&metadata_path).await?;
345
+
346
+ return Ok(());
347
+ }
348
+ }
349
+ }
350
+
351
+ Err(ArtifactStoreError::NotFound(artifact_id.clone()))
352
+ }
353
+
354
+ async fn list(&self, query: ListArtifactsQuery) -> Result<Vec<ArtifactMetadata>, ArtifactStoreError> {
355
+ let mut results = Vec::new();
356
+
357
+ // If execution_id is specified, only search that directory
358
+ let exec_dirs = if let Some(ref exec_id) = query.execution_id {
359
+ vec![self.execution_path(exec_id)]
360
+ } else {
361
+ // Search all execution directories
362
+ let mut dirs = Vec::new();
363
+ let mut entries = fs::read_dir(&self.base_path).await?;
364
+ while let Some(entry) = entries.next_entry().await? {
365
+ if entry.file_type().await?.is_dir() {
366
+ dirs.push(entry.path());
367
+ }
368
+ }
369
+ dirs
370
+ };
371
+
372
+ for exec_path in exec_dirs {
373
+ if !exec_path.exists() {
374
+ continue;
375
+ }
376
+
377
+ let mut entries = fs::read_dir(&exec_path).await?;
378
+ while let Some(entry) = entries.next_entry().await? {
379
+ let path = entry.path();
380
+ if path.extension().map(|e| e == "json").unwrap_or(false)
381
+ && path.to_string_lossy().contains(".meta.")
382
+ {
383
+ if let Ok(metadata) = self.load_metadata(&path).await {
384
+ // Apply filters
385
+ if let Some(ref step_id) = query.step_id {
386
+ if metadata.step_id != *step_id {
387
+ continue;
388
+ }
389
+ }
390
+ if let Some(ref artifact_type) = query.artifact_type {
391
+ if metadata.artifact_type != *artifact_type {
392
+ continue;
393
+ }
394
+ }
395
+ results.push(metadata);
396
+ }
397
+ }
398
+ }
399
+ }
400
+
401
+ // Sort by creation time
402
+ results.sort_by(|a, b| a.created_at.cmp(&b.created_at));
403
+
404
+ // Apply pagination
405
+ if let Some(offset) = query.offset {
406
+ results = results.into_iter().skip(offset).collect();
407
+ }
408
+ if let Some(limit) = query.limit {
409
+ results.truncate(limit);
410
+ }
411
+
412
+ Ok(results)
413
+ }
414
+
415
+ async fn get_metadata(&self, artifact_id: &ArtifactId) -> Result<ArtifactMetadata, ArtifactStoreError> {
416
+ // Search all execution directories
417
+ let mut entries = fs::read_dir(&self.base_path).await?;
418
+
419
+ while let Some(entry) = entries.next_entry().await? {
420
+ if entry.file_type().await?.is_dir() {
421
+ let exec_id = ExecutionId::from(entry.file_name().to_string_lossy().as_ref());
422
+ let metadata_path = self.artifact_metadata_path(&exec_id, artifact_id);
423
+
424
+ if metadata_path.exists() {
425
+ return self.load_metadata(&metadata_path).await;
426
+ }
427
+ }
428
+ }
429
+
430
+ Err(ArtifactStoreError::NotFound(artifact_id.clone()))
431
+ }
432
+
433
+ async fn get_execution_size(&self, execution_id: &ExecutionId) -> Result<u64, ArtifactStoreError> {
434
+ let exec_path = self.execution_path(execution_id);
435
+
436
+ if !exec_path.exists() {
437
+ return Ok(0);
438
+ }
439
+
440
+ let mut total: u64 = 0;
441
+ let mut entries = fs::read_dir(&exec_path).await?;
442
+
443
+ while let Some(entry) = entries.next_entry().await? {
444
+ if let Ok(metadata) = entry.metadata().await {
445
+ total += metadata.len();
446
+ }
447
+ }
448
+
449
+ Ok(total)
450
+ }
451
+ }
452
+
453
+ // =============================================================================
454
+ // Tests
455
+ // =============================================================================
456
+
457
+ #[cfg(test)]
458
+ mod tests {
459
+ use super::*;
460
+ use super::super::metadata::ArtifactType;
461
+ use crate::kernel::ids::StepId;
462
+ use tempfile::TempDir;
463
+
464
+ #[tokio::test]
465
+ async fn test_filesystem_store_put_get() {
466
+ let temp_dir = TempDir::new().unwrap();
467
+ let store = FilesystemArtifactStore::new(temp_dir.path());
468
+
469
+ let exec_id = ExecutionId::new();
470
+ let step_id = StepId::new();
471
+ let content = b"Hello, World! This is a test artifact.".to_vec();
472
+
473
+ let request = PutArtifactRequest::new(
474
+ exec_id.clone(),
475
+ step_id,
476
+ "test.txt",
477
+ ArtifactType::Text,
478
+ content.clone(),
479
+ );
480
+
481
+ let response = store.put(request).await.unwrap();
482
+ assert!(response.artifact_id.as_str().starts_with("artifact_"));
483
+ assert!(response.compressed_size > 0);
484
+ assert_eq!(response.original_size, content.len() as u64);
485
+
486
+ // Retrieve and verify
487
+ let get_response = store.get(&response.artifact_id).await.unwrap();
488
+ assert_eq!(get_response.content, content);
489
+ assert_eq!(get_response.metadata.name, "test.txt");
490
+ }
491
+
492
+ #[tokio::test]
493
+ async fn test_filesystem_store_compression() {
494
+ let temp_dir = TempDir::new().unwrap();
495
+ let store = FilesystemArtifactStore::new(temp_dir.path());
496
+
497
+ let exec_id = ExecutionId::new();
498
+ let step_id = StepId::new();
499
+
500
+ // Create repetitive content that compresses well
501
+ let content = "Hello, World! ".repeat(1000).into_bytes();
502
+
503
+ let request = PutArtifactRequest::new(
504
+ exec_id,
505
+ step_id,
506
+ "repetitive.txt",
507
+ ArtifactType::Text,
508
+ content.clone(),
509
+ );
510
+
511
+ let response = store.put(request).await.unwrap();
512
+
513
+ // Compressed should be smaller than original for repetitive data
514
+ assert!(response.compressed_size < response.original_size);
515
+
516
+ // Verify content is preserved
517
+ let get_response = store.get(&response.artifact_id).await.unwrap();
518
+ assert_eq!(get_response.content, content);
519
+ }
520
+
521
+ #[tokio::test]
522
+ async fn test_filesystem_store_list() {
523
+ let temp_dir = TempDir::new().unwrap();
524
+ let store = FilesystemArtifactStore::new(temp_dir.path());
525
+
526
+ let exec_id = ExecutionId::new();
527
+ let step_id = StepId::new();
528
+
529
+ // Store multiple artifacts
530
+ for i in 0..3 {
531
+ let request = PutArtifactRequest::new(
532
+ exec_id.clone(),
533
+ step_id.clone(),
534
+ format!("file{}.txt", i),
535
+ ArtifactType::Text,
536
+ format!("Content {}", i).into_bytes(),
537
+ );
538
+ store.put(request).await.unwrap();
539
+ }
540
+
541
+ // List all for execution
542
+ let query = ListArtifactsQuery::for_execution(exec_id);
543
+ let results = store.list(query).await.unwrap();
544
+ assert_eq!(results.len(), 3);
545
+ }
546
+ }