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,511 @@
1
+ //! Trigger System for Background Callables
2
+ //!
3
+ //! Triggers enable event-based callable invocation. A trigger watches for
4
+ //! specific events and spawns background executions when conditions are met.
5
+ //!
6
+ //! ## Trigger Types
7
+ //!
8
+ //! - **Event**: Fired by execution/step events
9
+ //! - **Schedule**: Fired by cron/interval schedules
10
+ //! - **Webhook**: Fired by external webhooks
11
+ //! - **Threshold**: Fired when metrics cross thresholds
12
+ //! - **Lifecycle**: Fired by thread/user lifecycle events
13
+ //!
14
+ //! @see packages/enact-schemas/src/execution.schemas.ts
15
+
16
+ use chrono::{DateTime, Utc};
17
+ use serde::{Deserialize, Serialize};
18
+ use std::collections::HashMap;
19
+ use svix_ksuid::KsuidLike;
20
+
21
+ use crate::kernel::ids::{ExecutionId, TenantId};
22
+
23
+ /// TriggerId - Unique identifier for a trigger
24
+ /// Format: trigger_[27-char KSUID]
25
+ #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
26
+ #[serde(transparent)]
27
+ pub struct TriggerId(String);
28
+
29
+ impl TriggerId {
30
+ /// Create a new TriggerId
31
+ pub fn new() -> Self {
32
+ Self(format!("trigger_{}", svix_ksuid::Ksuid::new(None, None)))
33
+ }
34
+
35
+ /// Create from string (for deserialization)
36
+ pub fn from_string(s: String) -> Self {
37
+ Self(s)
38
+ }
39
+
40
+ /// Get the inner string
41
+ pub fn as_str(&self) -> &str {
42
+ &self.0
43
+ }
44
+ }
45
+
46
+ impl Default for TriggerId {
47
+ fn default() -> Self {
48
+ Self::new()
49
+ }
50
+ }
51
+
52
+ impl std::fmt::Display for TriggerId {
53
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54
+ write!(f, "{}", self.0)
55
+ }
56
+ }
57
+
58
+ /// TriggerType - What kind of trigger this is
59
+ /// @see packages/enact-schemas/src/execution.schemas.ts - triggerTypeSchema
60
+ #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
61
+ #[serde(rename_all = "snake_case")]
62
+ pub enum TriggerType {
63
+ /// Fired by an event (e.g., execution.completed, step.failed)
64
+ Event,
65
+ /// Fired by a schedule (cron, interval)
66
+ Schedule,
67
+ /// Fired by an external webhook
68
+ Webhook,
69
+ /// Fired when a metric crosses a threshold
70
+ Threshold,
71
+ /// Fired manually by user
72
+ Manual,
73
+ /// Fired by lifecycle events (thread.created, user.signup)
74
+ Lifecycle,
75
+ }
76
+
77
+ /// TriggerStatus - Current status of a trigger
78
+ /// @see packages/enact-schemas/src/execution.schemas.ts - triggerStatusSchema
79
+ #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
80
+ #[serde(rename_all = "snake_case")]
81
+ pub enum TriggerStatus {
82
+ /// Trigger is active and will fire
83
+ #[default]
84
+ Active,
85
+ /// Trigger is paused (won't fire)
86
+ Paused,
87
+ /// Trigger is disabled (won't fire, hidden)
88
+ Disabled,
89
+ /// Trigger has fired (for one-shot triggers)
90
+ Fired,
91
+ /// Trigger has expired (past end_at)
92
+ Expired,
93
+ }
94
+
95
+ /// ThresholdOperator - Comparison operator for threshold triggers
96
+ #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
97
+ #[serde(rename_all = "snake_case")]
98
+ pub enum ThresholdOperator {
99
+ Gt,
100
+ Gte,
101
+ Lt,
102
+ Lte,
103
+ Eq,
104
+ Neq,
105
+ }
106
+
107
+ /// TriggerCondition - When the trigger should fire
108
+ /// @see packages/enact-schemas/src/execution.schemas.ts - triggerConditionSchema
109
+ #[derive(Debug, Clone, Default, Serialize, Deserialize)]
110
+ #[serde(rename_all = "camelCase")]
111
+ pub struct TriggerCondition {
112
+ /// Event type to match (for event triggers)
113
+ #[serde(skip_serializing_if = "Option::is_none")]
114
+ pub event_type: Option<String>,
115
+
116
+ /// Pattern to match against event data
117
+ #[serde(skip_serializing_if = "Option::is_none")]
118
+ pub event_pattern: Option<HashMap<String, serde_json::Value>>,
119
+
120
+ /// Cron expression (for schedule triggers)
121
+ #[serde(skip_serializing_if = "Option::is_none")]
122
+ pub cron_expression: Option<String>,
123
+
124
+ /// Interval in seconds (for schedule triggers)
125
+ #[serde(skip_serializing_if = "Option::is_none")]
126
+ pub interval_seconds: Option<u64>,
127
+
128
+ /// Metric name (for threshold triggers)
129
+ #[serde(skip_serializing_if = "Option::is_none")]
130
+ pub metric_name: Option<String>,
131
+
132
+ /// Threshold value (for threshold triggers)
133
+ #[serde(skip_serializing_if = "Option::is_none")]
134
+ pub threshold_value: Option<f64>,
135
+
136
+ /// Threshold operator
137
+ #[serde(skip_serializing_if = "Option::is_none")]
138
+ pub threshold_operator: Option<ThresholdOperator>,
139
+ }
140
+
141
+ /// RetryConfig - Configuration for retry behavior
142
+ #[derive(Debug, Clone, Serialize, Deserialize)]
143
+ #[serde(rename_all = "camelCase")]
144
+ pub struct RetryConfig {
145
+ /// Maximum number of retry attempts
146
+ #[serde(default = "default_max_attempts")]
147
+ pub max_attempts: u32,
148
+
149
+ /// Initial backoff in milliseconds
150
+ #[serde(default = "default_backoff_ms")]
151
+ pub backoff_ms: u64,
152
+
153
+ /// Backoff multiplier for exponential backoff
154
+ #[serde(default = "default_backoff_multiplier")]
155
+ pub backoff_multiplier: f64,
156
+ }
157
+
158
+ fn default_max_attempts() -> u32 {
159
+ 3
160
+ }
161
+
162
+ fn default_backoff_ms() -> u64 {
163
+ 1000
164
+ }
165
+
166
+ fn default_backoff_multiplier() -> f64 {
167
+ 2.0
168
+ }
169
+
170
+ impl Default for RetryConfig {
171
+ fn default() -> Self {
172
+ Self {
173
+ max_attempts: default_max_attempts(),
174
+ backoff_ms: default_backoff_ms(),
175
+ backoff_multiplier: default_backoff_multiplier(),
176
+ }
177
+ }
178
+ }
179
+
180
+ /// TargetBindingConfig - Where to write the result
181
+ #[derive(Debug, Clone, Serialize, Deserialize)]
182
+ #[serde(rename_all = "camelCase")]
183
+ pub struct TargetBindingConfig {
184
+ /// Target type (where to write the result)
185
+ pub target_type: TargetBindingType,
186
+
187
+ /// Custom target path (for custom target type)
188
+ #[serde(skip_serializing_if = "Option::is_none")]
189
+ pub target_path: Option<String>,
190
+ }
191
+
192
+ /// TargetBindingType - What kind of target to bind to
193
+ /// @see packages/enact-schemas/src/execution.schemas.ts - targetBindingTypeSchema
194
+ #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
195
+ #[serde(rename_all = "snake_case")]
196
+ pub enum TargetBindingType {
197
+ /// Set thread title
198
+ #[serde(rename = "thread.title")]
199
+ ThreadTitle,
200
+ /// Set thread summary
201
+ #[serde(rename = "thread.summary")]
202
+ ThreadSummary,
203
+ /// Set execution summary
204
+ #[serde(rename = "execution.summary")]
205
+ ExecutionSummary,
206
+ /// Add to message metadata
207
+ #[serde(rename = "message.metadata")]
208
+ MessageMetadata,
209
+ /// Create an artifact
210
+ #[serde(rename = "artifact.create")]
211
+ ArtifactCreate,
212
+ /// Write to memory
213
+ #[serde(rename = "memory.write")]
214
+ MemoryWrite,
215
+ /// Custom target (requires targetPath)
216
+ Custom,
217
+ }
218
+
219
+ /// TriggerAction - What to do when the trigger fires
220
+ /// @see packages/enact-schemas/src/execution.schemas.ts - triggerActionSchema
221
+ #[derive(Debug, Clone, Serialize, Deserialize)]
222
+ #[serde(rename_all = "camelCase")]
223
+ pub struct TriggerAction {
224
+ /// Callable to invoke
225
+ pub callable_name: String,
226
+
227
+ /// Input to pass to the callable
228
+ #[serde(skip_serializing_if = "Option::is_none")]
229
+ pub input: Option<String>,
230
+
231
+ /// Context to pass
232
+ #[serde(skip_serializing_if = "Option::is_none")]
233
+ pub context: Option<HashMap<String, String>>,
234
+
235
+ /// System prompt override
236
+ #[serde(skip_serializing_if = "Option::is_none")]
237
+ pub system_prompt: Option<String>,
238
+
239
+ /// Target binding for the result
240
+ #[serde(skip_serializing_if = "Option::is_none")]
241
+ pub target_binding: Option<TargetBindingConfig>,
242
+
243
+ /// Execute in background (fire-and-forget)
244
+ #[serde(default = "default_background")]
245
+ pub background: bool,
246
+
247
+ /// Retry configuration
248
+ #[serde(skip_serializing_if = "Option::is_none")]
249
+ pub retry: Option<RetryConfig>,
250
+ }
251
+
252
+ fn default_background() -> bool {
253
+ true
254
+ }
255
+
256
+ /// Trigger - Event-based callable invocation definition
257
+ /// @see packages/enact-schemas/src/execution.schemas.ts - triggerSchema
258
+ #[derive(Debug, Clone, Serialize, Deserialize)]
259
+ #[serde(rename_all = "camelCase")]
260
+ pub struct Trigger {
261
+ /// Unique trigger identifier
262
+ pub trigger_id: TriggerId,
263
+
264
+ /// Tenant that owns this trigger
265
+ pub tenant_id: TenantId,
266
+
267
+ /// Human-readable name
268
+ pub name: String,
269
+
270
+ /// Optional description
271
+ #[serde(skip_serializing_if = "Option::is_none")]
272
+ pub description: Option<String>,
273
+
274
+ /// Trigger type
275
+ #[serde(rename = "type")]
276
+ pub trigger_type: TriggerType,
277
+
278
+ /// Current status
279
+ #[serde(default)]
280
+ pub status: TriggerStatus,
281
+
282
+ /// Condition (when to fire)
283
+ pub condition: TriggerCondition,
284
+
285
+ /// Action (what to do when fired)
286
+ pub action: TriggerAction,
287
+
288
+ /// When to start listening
289
+ #[serde(skip_serializing_if = "Option::is_none")]
290
+ pub start_at: Option<DateTime<Utc>>,
291
+
292
+ /// When to stop (expire)
293
+ #[serde(skip_serializing_if = "Option::is_none")]
294
+ pub end_at: Option<DateTime<Utc>>,
295
+
296
+ /// Max times to fire (None = unlimited)
297
+ #[serde(skip_serializing_if = "Option::is_none")]
298
+ pub max_fires: Option<u32>,
299
+
300
+ /// Times fired so far
301
+ #[serde(default)]
302
+ pub fire_count: u32,
303
+
304
+ /// Cooldown in milliseconds (prevent rapid re-firing)
305
+ #[serde(skip_serializing_if = "Option::is_none")]
306
+ pub cooldown_ms: Option<u64>,
307
+
308
+ /// Last time this trigger fired
309
+ #[serde(skip_serializing_if = "Option::is_none")]
310
+ pub last_fired_at: Option<DateTime<Utc>>,
311
+
312
+ /// When the trigger was created
313
+ pub created_at: DateTime<Utc>,
314
+
315
+ /// When the trigger was last updated
316
+ pub updated_at: DateTime<Utc>,
317
+ }
318
+
319
+ impl Trigger {
320
+ /// Create a new trigger
321
+ pub fn new(
322
+ tenant_id: TenantId,
323
+ name: impl Into<String>,
324
+ trigger_type: TriggerType,
325
+ condition: TriggerCondition,
326
+ action: TriggerAction,
327
+ ) -> Self {
328
+ let now = Utc::now();
329
+ Self {
330
+ trigger_id: TriggerId::new(),
331
+ tenant_id,
332
+ name: name.into(),
333
+ description: None,
334
+ trigger_type,
335
+ status: TriggerStatus::Active,
336
+ condition,
337
+ action,
338
+ start_at: None,
339
+ end_at: None,
340
+ max_fires: None,
341
+ fire_count: 0,
342
+ cooldown_ms: None,
343
+ last_fired_at: None,
344
+ created_at: now,
345
+ updated_at: now,
346
+ }
347
+ }
348
+
349
+ /// Check if the trigger can fire right now
350
+ pub fn can_fire(&self) -> bool {
351
+ // Must be active
352
+ if self.status != TriggerStatus::Active {
353
+ return false;
354
+ }
355
+
356
+ let now = Utc::now();
357
+
358
+ // Check start_at
359
+ if let Some(start_at) = self.start_at {
360
+ if now < start_at {
361
+ return false;
362
+ }
363
+ }
364
+
365
+ // Check end_at
366
+ if let Some(end_at) = self.end_at {
367
+ if now > end_at {
368
+ return false;
369
+ }
370
+ }
371
+
372
+ // Check max_fires
373
+ if let Some(max_fires) = self.max_fires {
374
+ if self.fire_count >= max_fires {
375
+ return false;
376
+ }
377
+ }
378
+
379
+ // Check cooldown
380
+ if let (Some(cooldown_ms), Some(last_fired_at)) = (self.cooldown_ms, self.last_fired_at) {
381
+ let cooldown = chrono::Duration::milliseconds(cooldown_ms as i64);
382
+ if now < last_fired_at + cooldown {
383
+ return false;
384
+ }
385
+ }
386
+
387
+ true
388
+ }
389
+
390
+ /// Record that the trigger fired
391
+ pub fn record_fire(&mut self) {
392
+ self.fire_count += 1;
393
+ self.last_fired_at = Some(Utc::now());
394
+ self.updated_at = Utc::now();
395
+
396
+ // Check if we've hit max_fires
397
+ if let Some(max_fires) = self.max_fires {
398
+ if self.fire_count >= max_fires {
399
+ self.status = TriggerStatus::Fired;
400
+ }
401
+ }
402
+ }
403
+
404
+ /// Pause the trigger
405
+ pub fn pause(&mut self) {
406
+ self.status = TriggerStatus::Paused;
407
+ self.updated_at = Utc::now();
408
+ }
409
+
410
+ /// Resume the trigger
411
+ pub fn resume(&mut self) {
412
+ if self.status == TriggerStatus::Paused {
413
+ self.status = TriggerStatus::Active;
414
+ self.updated_at = Utc::now();
415
+ }
416
+ }
417
+
418
+ /// Disable the trigger
419
+ pub fn disable(&mut self) {
420
+ self.status = TriggerStatus::Disabled;
421
+ self.updated_at = Utc::now();
422
+ }
423
+ }
424
+
425
+ /// TriggerFiredEvent - Emitted when a trigger fires
426
+ /// @see packages/enact-schemas/src/execution.schemas.ts - triggerFiredEventSchema
427
+ #[derive(Debug, Clone, Serialize, Deserialize)]
428
+ #[serde(rename_all = "camelCase")]
429
+ pub struct TriggerFiredEvent {
430
+ pub trigger_id: TriggerId,
431
+ pub trigger_name: String,
432
+ pub trigger_type: TriggerType,
433
+ pub execution_id: ExecutionId,
434
+ pub fired_at: DateTime<Utc>,
435
+ pub trigger_source: serde_json::Value,
436
+ }
437
+
438
+ #[cfg(test)]
439
+ mod tests {
440
+ use super::*;
441
+
442
+ #[test]
443
+ fn test_trigger_id_generation() {
444
+ let id = TriggerId::new();
445
+ assert!(id.as_str().starts_with("trigger_"));
446
+ assert_eq!(id.as_str().len(), 35); // "trigger_" + 27 chars
447
+ }
448
+
449
+ #[test]
450
+ fn test_trigger_can_fire() {
451
+ let tenant_id = TenantId::new();
452
+ let condition = TriggerCondition {
453
+ event_type: Some("execution.completed".to_string()),
454
+ ..Default::default()
455
+ };
456
+ let action = TriggerAction {
457
+ callable_name: "summarizer".to_string(),
458
+ input: None,
459
+ context: None,
460
+ system_prompt: None,
461
+ target_binding: Some(TargetBindingConfig {
462
+ target_type: TargetBindingType::ThreadTitle,
463
+ target_path: None,
464
+ }),
465
+ background: true,
466
+ retry: None,
467
+ };
468
+
469
+ let mut trigger = Trigger::new(
470
+ tenant_id,
471
+ "Auto-title",
472
+ TriggerType::Event,
473
+ condition,
474
+ action,
475
+ );
476
+
477
+ assert!(trigger.can_fire());
478
+
479
+ // Record fire and check again
480
+ trigger.record_fire();
481
+ assert_eq!(trigger.fire_count, 1);
482
+ assert!(trigger.last_fired_at.is_some());
483
+ }
484
+
485
+ #[test]
486
+ fn test_trigger_max_fires() {
487
+ let tenant_id = TenantId::new();
488
+ let mut trigger = Trigger::new(
489
+ tenant_id,
490
+ "One-shot",
491
+ TriggerType::Event,
492
+ TriggerCondition::default(),
493
+ TriggerAction {
494
+ callable_name: "task".to_string(),
495
+ input: None,
496
+ context: None,
497
+ system_prompt: None,
498
+ target_binding: None,
499
+ background: true,
500
+ retry: None,
501
+ },
502
+ );
503
+
504
+ trigger.max_fires = Some(1);
505
+
506
+ assert!(trigger.can_fire());
507
+ trigger.record_fire();
508
+ assert!(!trigger.can_fire());
509
+ assert_eq!(trigger.status, TriggerStatus::Fired);
510
+ }
511
+ }
@@ -0,0 +1,152 @@
1
+ //! Callable trait definition
2
+ //!
3
+ //! The core abstraction for anything that can be invoked.
4
+
5
+ use async_trait::async_trait;
6
+ use std::sync::Arc;
7
+
8
+ /// Core Callable trait - the fundamental execution unit
9
+ ///
10
+ /// Everything that can be "run" implements this trait:
11
+ /// - LLM agents
12
+ /// - Graph nodes
13
+ /// - Tools (when wrapped)
14
+ /// - Flow compositions
15
+ ///
16
+ /// ## Design Principles
17
+ ///
18
+ /// 1. **Simple**: Just run with input, get output
19
+ /// 2. **Async**: All execution is async by default
20
+ /// 3. **Named**: Every callable has a name for logging/debugging
21
+ /// 4. **Composable**: Callables can wrap other callables
22
+ #[async_trait]
23
+ pub trait Callable: Send + Sync {
24
+ /// Callable logical name (for logging, debugging, UI)
25
+ fn name(&self) -> &str;
26
+
27
+ /// Callable description (optional, for documentation)
28
+ fn description(&self) -> Option<&str> {
29
+ None
30
+ }
31
+
32
+ /// Execute the callable with the given input
33
+ ///
34
+ /// This is the core execution method. Implementations should:
35
+ /// - Be idempotent when possible
36
+ /// - Handle their own retries if needed
37
+ /// - Return meaningful error messages
38
+ async fn run(&self, input: &str) -> anyhow::Result<String>;
39
+ }
40
+
41
+ /// Boxed callable for dynamic dispatch
42
+ ///
43
+ /// Use this when you need to store heterogeneous callables together
44
+ /// or pass them through dynamic boundaries.
45
+ pub type DynCallable = Arc<dyn Callable>;
46
+
47
+ /// A simple function-based callable
48
+ ///
49
+ /// Wraps a closure to implement Callable.
50
+ #[allow(dead_code)]
51
+ pub struct FnCallable<F>
52
+ where
53
+ F: Fn(&str) -> anyhow::Result<String> + Send + Sync,
54
+ {
55
+ name: String,
56
+ description: Option<String>,
57
+ func: F,
58
+ }
59
+
60
+ #[allow(dead_code)]
61
+ impl<F> FnCallable<F>
62
+ where
63
+ F: Fn(&str) -> anyhow::Result<String> + Send + Sync,
64
+ {
65
+ /// Create a new function-based callable
66
+ pub fn new(name: impl Into<String>, func: F) -> Self {
67
+ Self {
68
+ name: name.into(),
69
+ description: None,
70
+ func,
71
+ }
72
+ }
73
+
74
+ /// Add a description
75
+ pub fn with_description(mut self, desc: impl Into<String>) -> Self {
76
+ self.description = Some(desc.into());
77
+ self
78
+ }
79
+ }
80
+
81
+ #[async_trait]
82
+ impl<F> Callable for FnCallable<F>
83
+ where
84
+ F: Fn(&str) -> anyhow::Result<String> + Send + Sync,
85
+ {
86
+ fn name(&self) -> &str {
87
+ &self.name
88
+ }
89
+
90
+ fn description(&self) -> Option<&str> {
91
+ self.description.as_deref()
92
+ }
93
+
94
+ async fn run(&self, input: &str) -> anyhow::Result<String> {
95
+ (self.func)(input)
96
+ }
97
+ }
98
+
99
+ /// Create a callable from an async function
100
+ #[allow(dead_code)]
101
+ pub struct AsyncFnCallable<F, Fut>
102
+ where
103
+ F: Fn(String) -> Fut + Send + Sync,
104
+ Fut: std::future::Future<Output = anyhow::Result<String>> + Send + Sync,
105
+ {
106
+ name: String,
107
+ description: Option<String>,
108
+ func: F,
109
+ _phantom: std::marker::PhantomData<fn() -> Fut>,
110
+ }
111
+
112
+ #[allow(dead_code)]
113
+ impl<F, Fut> AsyncFnCallable<F, Fut>
114
+ where
115
+ F: Fn(String) -> Fut + Send + Sync,
116
+ Fut: std::future::Future<Output = anyhow::Result<String>> + Send + Sync,
117
+ {
118
+ /// Create a new async function-based callable
119
+ pub fn new(name: impl Into<String>, func: F) -> Self {
120
+ Self {
121
+ name: name.into(),
122
+ description: None,
123
+ func,
124
+ _phantom: std::marker::PhantomData,
125
+ }
126
+ }
127
+
128
+ /// Add a description
129
+ pub fn with_description(mut self, desc: impl Into<String>) -> Self {
130
+ self.description = Some(desc.into());
131
+ self
132
+ }
133
+ }
134
+
135
+ #[async_trait]
136
+ impl<F, Fut> Callable for AsyncFnCallable<F, Fut>
137
+ where
138
+ F: Fn(String) -> Fut + Send + Sync,
139
+ Fut: std::future::Future<Output = anyhow::Result<String>> + Send + Sync,
140
+ {
141
+ fn name(&self) -> &str {
142
+ &self.name
143
+ }
144
+
145
+ fn description(&self) -> Option<&str> {
146
+ self.description.as_deref()
147
+ }
148
+
149
+ async fn run(&self, input: &str) -> anyhow::Result<String> {
150
+ (self.func)(input.to_string()).await
151
+ }
152
+ }