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,167 @@
1
+ //! OpenAI-compatible provider (Ollama, vLLM, LocalAI, etc.)
2
+ //!
3
+ //! This provider works with any service that follows the OpenAI API spec:
4
+ //! - Ollama (local models)
5
+ //! - vLLM (local inference server)
6
+ //! - LocalAI
7
+ //! - Any OpenAI-compatible endpoint
8
+ //!
9
+ //! ## Usage
10
+ //!
11
+ //! ```rust
12
+ //! use enact_providers::OpenAICompatible;
13
+ //!
14
+ //! // For Ollama (no API key needed)
15
+ //! let provider = OpenAICompatible::new(
16
+ //! "http://localhost:11434",
17
+ //! "llama3",
18
+ //! None,
19
+ //! );
20
+ //!
21
+ //! // For OpenAI or other services requiring API key
22
+ //! let provider = OpenAICompatible::new(
23
+ //! "https://api.openai.com",
24
+ //! "gpt-4",
25
+ //! Some("sk-...".to_string()),
26
+ //! );
27
+ //! ```
28
+
29
+ use crate::http::{HttpRequestSpec, post_json};
30
+ use enact_core::providers::{
31
+ ChatRequest, ChatResponse, EmbeddingRequest, EmbeddingResponse, ModelCapabilities, ModelProvider,
32
+ };
33
+ use async_trait::async_trait;
34
+ use reqwest::Client;
35
+ use std::time::Duration;
36
+
37
+ /// OpenAI-compatible provider
38
+ ///
39
+ /// Works with any service that follows the OpenAI API specification:
40
+ /// - Ollama (local models)
41
+ /// - vLLM (local inference server)
42
+ /// - LocalAI
43
+ /// - OpenAI API
44
+ /// - Any other OpenAI-compatible endpoint
45
+ pub struct OpenAICompatible {
46
+ client: Client,
47
+ base_url: String,
48
+ api_key: Option<String>,
49
+ model: String,
50
+ }
51
+
52
+ impl OpenAICompatible {
53
+ /// Create a new OpenAI-compatible provider
54
+ ///
55
+ /// # Arguments
56
+ ///
57
+ /// * `base_url` - Base URL of the API (e.g., "http://localhost:11434" for Ollama)
58
+ /// * `model` - Model name to use (e.g., "llama3", "gpt-4")
59
+ /// * `api_key` - Optional API key (Ollama doesn't need one, OpenAI does)
60
+ pub fn new(
61
+ base_url: impl Into<String>,
62
+ model: impl Into<String>,
63
+ api_key: Option<String>,
64
+ ) -> Self {
65
+ Self {
66
+ client: Client::new(),
67
+ base_url: base_url.into().trim_end_matches('/').to_string(),
68
+ api_key,
69
+ model: model.into(),
70
+ }
71
+ }
72
+
73
+ fn build_chat_url(&self) -> String {
74
+ format!("{}/v1/chat/completions", self.base_url)
75
+ }
76
+
77
+ fn build_embedding_url(&self) -> String {
78
+ format!("{}/v1/embeddings", self.base_url)
79
+ }
80
+
81
+ fn build_headers(&self) -> Vec<(String, String)> {
82
+ let mut headers = vec![
83
+ ("Content-Type".to_string(), "application/json".to_string()),
84
+ ];
85
+
86
+ if let Some(api_key) = &self.api_key {
87
+ headers.push(("Authorization".to_string(), format!("Bearer {}", api_key)));
88
+ }
89
+
90
+ headers
91
+ }
92
+ }
93
+
94
+ #[async_trait]
95
+ impl ModelProvider for OpenAICompatible {
96
+ fn name(&self) -> &str {
97
+ "openai-compatible"
98
+ }
99
+
100
+ fn model(&self) -> &str {
101
+ &self.model
102
+ }
103
+
104
+ fn capabilities(&self) -> ModelCapabilities {
105
+ ModelCapabilities {
106
+ max_tokens: 8192,
107
+ max_output_tokens: 4096,
108
+ supports_streaming: true,
109
+ supports_tools: true,
110
+ supports_vision: false, // Most local models don't support vision
111
+ supports_json_mode: true,
112
+ supports_embeddings: true,
113
+ pii_safe: false,
114
+ cost_per_1k_input: None, // Local models typically have no cost
115
+ cost_per_1k_output: None,
116
+ }
117
+ }
118
+
119
+ async fn chat(&self, request: ChatRequest) -> anyhow::Result<ChatResponse> {
120
+ let url = self.build_chat_url();
121
+
122
+ // Build request body with model
123
+ let mut body = serde_json::to_value(&request)?;
124
+ body["model"] = serde_json::Value::String(self.model.clone());
125
+
126
+ // Build HTTP request spec
127
+ let http_req = HttpRequestSpec {
128
+ url,
129
+ headers: self.build_headers(),
130
+ body,
131
+ timeout: Duration::from_secs(60), // Longer timeout for local models
132
+ };
133
+
134
+ // Execute request using HTTP helper
135
+ let json_response = post_json(&self.client, http_req).await?;
136
+
137
+ // Parse response
138
+ let chat_response: ChatResponse = serde_json::from_value(json_response)?;
139
+ Ok(chat_response)
140
+ }
141
+
142
+ async fn embed(&self, request: EmbeddingRequest) -> anyhow::Result<EmbeddingResponse> {
143
+ let url = self.build_embedding_url();
144
+
145
+ // Build request body with model
146
+ let mut body = serde_json::to_value(&request)?;
147
+ body["model"] = serde_json::Value::String(
148
+ request.model.clone().unwrap_or_else(|| self.model.clone())
149
+ );
150
+
151
+ // Build HTTP request spec
152
+ let http_req = HttpRequestSpec {
153
+ url,
154
+ headers: self.build_headers(),
155
+ body,
156
+ timeout: Duration::from_secs(60),
157
+ };
158
+
159
+ // Execute request using HTTP helper
160
+ let json_response = post_json(&self.client, http_req).await?;
161
+
162
+ // Parse response
163
+ let embedding_response: EmbeddingResponse = serde_json::from_value(json_response)?;
164
+ Ok(embedding_response)
165
+ }
166
+ }
167
+
@@ -0,0 +1,33 @@
1
+ //! OpenRouter provider
2
+ //!
3
+ //! **Status**: [planned]
4
+ //!
5
+ //! ## Implementation Notes
6
+ //!
7
+ //! This provider will implement the `ModelProvider` trait for OpenRouter's unified API.
8
+ //!
9
+ //! - **Endpoint**: HTTP POST to `https://openrouter.ai/api/v1/chat/completions`
10
+ //! - **Documentation**: https://openrouter.ai/docs
11
+ //! - **Authentication**: `Authorization: Bearer <api_key>` header
12
+ //!
13
+ //! ## Environment Variables
14
+ //!
15
+ //! - `OPENROUTER_API_KEY` (required) - Your OpenRouter API key
16
+ //! - `OPENROUTER_MODEL` (optional, default: "openai/gpt-4") - Model to use
17
+ //!
18
+ //! ## Important Notes
19
+ //!
20
+ //! Providers must be side-effect free outside HTTP calls. All retries, rate limiting,
21
+ //! and quotas are enforced by the kernel, not by the provider implementation.
22
+ //!
23
+ //! ## Example Usage (Future)
24
+ //!
25
+ //! ```rust,ignore
26
+ //! use enact_providers::{OpenRouter, ModelProvider};
27
+ //! use enact_config::Config;
28
+ //!
29
+ //! let config = Config::load()?;
30
+ //! let provider = OpenRouter::new(config)?;
31
+ //! let response = provider.chat(request).await?;
32
+ //! ```
33
+
@@ -0,0 +1,24 @@
1
+ [package]
2
+ name = "enact-runner"
3
+ version.workspace = true
4
+ edition.workspace = true
5
+ license.workspace = true
6
+ description = "Robust agent loop runner for Enact — retries, compaction, multi-format parsing"
7
+ repository.workspace = true
8
+ homepage.workspace = true
9
+ keywords = ["runner", "agent", "loop", "retry"]
10
+ categories.workspace = true
11
+
12
+ [dependencies]
13
+ enact-core = { workspace = true }
14
+
15
+ tokio.workspace = true
16
+ async-trait.workspace = true
17
+ serde.workspace = true
18
+ serde_json.workspace = true
19
+ tracing.workspace = true
20
+ anyhow.workspace = true
21
+ regex.workspace = true
22
+
23
+ [dev-dependencies]
24
+ tokio = { workspace = true, features = ["test-util"] }
@@ -0,0 +1,76 @@
1
+ # enact-runner
2
+
3
+ > Robust agent loop runner for Enact — retries, compaction, multi-format parsing.
4
+
5
+ ## What Is This?
6
+
7
+ `enact-runner` is the **"missing middle"** between the apps (`cli`, `api`) and `enact-core`'s deterministic kernel. It implements the robust agent loop mandated by the technical specs but never built.
8
+
9
+ ## Quick Start
10
+
11
+ ```rust
12
+ use enact_runner::{AgentRunner, DefaultAgentRunner, RunnerConfig, LoopOutcome};
13
+
14
+ // Default config (max 25 iterations, compaction at 40 messages)
15
+ let mut runner = DefaultAgentRunner::default_new()
16
+ .add_tool(my_search_tool)
17
+ .add_tool(my_read_file_tool);
18
+
19
+ let outcome = runner.run(&my_llm_callable, "user input").await?;
20
+
21
+ match outcome {
22
+ LoopOutcome::Completed(output) => println!("Done: {}", output),
23
+ LoopOutcome::MaxIterationsReached { .. } => println!("Hit limit"),
24
+ LoopOutcome::Cancelled => println!("Cancelled"),
25
+ LoopOutcome::TimedOut { .. } => println!("Timed out"),
26
+ }
27
+ ```
28
+
29
+ ## Presets
30
+
31
+ ```rust
32
+ // Short interactive sessions (10 iterations, 2 min timeout)
33
+ let config = RunnerConfig::interactive();
34
+
35
+ // Long-running background agents (100 iterations, 1 hour timeout)
36
+ let config = RunnerConfig::long_running();
37
+ ```
38
+
39
+ ## Features
40
+
41
+ | Feature | Description |
42
+ |---|---|
43
+ | **Multi-format parsing** | Parses tool calls from JSON, XML, and Markdown |
44
+ | **Retry with backoff** | Exponential backoff for rate-limits and transient errors |
45
+ | **Error classification** | Distinguishes retryable (rate-limit, network) from fatal (auth, invalid) |
46
+ | **Auto-compaction** | Summarizes older messages when history exceeds threshold |
47
+ | **Checkpointing** | Saves state at configurable intervals |
48
+ | **Cancel/Pause** | Delegates to `enact-core::Runner` for cancel/pause signals |
49
+ | **Stream events** | Emits `StreamEvent`s for real-time observability |
50
+
51
+ ## Module Structure
52
+
53
+ ```
54
+ src/
55
+ ├── lib.rs # Module root + re-exports
56
+ ├── config.rs # RunnerConfig, RetryConfig, presets
57
+ ├── loop_driver.rs # AgentRunner::run() — the core loop
58
+ ├── parser.rs # Multi-format tool call parsing
59
+ ├── compaction.rs # Auto context summarization
60
+ └── retry.rs # Error classification + backoff
61
+ tests/
62
+ └── integration.rs # Full loop integration tests
63
+ ```
64
+
65
+ ## Testing
66
+
67
+ ```bash
68
+ # All tests (31 total)
69
+ cargo test -p enact-runner
70
+
71
+ # Only integration tests
72
+ cargo test -p enact-runner --test integration
73
+
74
+ # Specific test
75
+ cargo test -p enact-runner test_retry_on_transient_error
76
+ ```
@@ -0,0 +1,225 @@
1
+ //! Context compaction for long-running agent loops
2
+ //!
3
+ //! When message history exceeds a threshold, older messages are summarized
4
+ //! into a single context message to prevent context window overflow.
5
+ //!
6
+ //! Ported from zeroclaw's `auto_compact_history` which uses the LLM itself
7
+ //! to generate a summary of older conversation history.
8
+
9
+ use enact_core::callable::Callable;
10
+
11
+ /// A message in the conversation history.
12
+ #[derive(Debug, Clone)]
13
+ pub struct HistoryMessage {
14
+ /// Role: "system", "user", "assistant", "tool"
15
+ pub role: String,
16
+ /// Message content
17
+ pub content: String,
18
+ }
19
+
20
+ impl HistoryMessage {
21
+ pub fn system(content: impl Into<String>) -> Self {
22
+ Self {
23
+ role: "system".to_string(),
24
+ content: content.into(),
25
+ }
26
+ }
27
+
28
+ pub fn user(content: impl Into<String>) -> Self {
29
+ Self {
30
+ role: "user".to_string(),
31
+ content: content.into(),
32
+ }
33
+ }
34
+
35
+ pub fn assistant(content: impl Into<String>) -> Self {
36
+ Self {
37
+ role: "assistant".to_string(),
38
+ content: content.into(),
39
+ }
40
+ }
41
+
42
+ pub fn tool_result(name: &str, content: impl Into<String>) -> Self {
43
+ Self {
44
+ role: "tool".to_string(),
45
+ content: format!("[{}]: {}", name, content.into()),
46
+ }
47
+ }
48
+ }
49
+
50
+ /// Check if compaction is needed based on message count.
51
+ pub fn needs_compaction(history: &[HistoryMessage], threshold: usize) -> bool {
52
+ history.len() > threshold
53
+ }
54
+
55
+ /// Compact the conversation history by summarizing older messages.
56
+ ///
57
+ /// Keeps the system message (index 0) and the `keep_recent` most recent messages.
58
+ /// Everything in between is summarized into a single "context summary" message.
59
+ ///
60
+ /// # Arguments
61
+ /// * `history` — mutable reference to the message history
62
+ /// * `summarizer` — a Callable used to generate the summary (typically the LLM itself)
63
+ /// * `keep_recent` — how many recent messages to preserve verbatim
64
+ ///
65
+ /// # Returns
66
+ /// `true` if compaction was performed, `false` if history was too short.
67
+ pub async fn compact_history(
68
+ history: &mut Vec<HistoryMessage>,
69
+ summarizer: &dyn Callable,
70
+ keep_recent: usize,
71
+ ) -> anyhow::Result<bool> {
72
+ // Need at least: system + some old messages + keep_recent
73
+ if history.len() <= keep_recent + 2 {
74
+ return Ok(false);
75
+ }
76
+
77
+ // Split: [system] [old messages to summarize] [recent messages to keep]
78
+ let split_point = history.len() - keep_recent;
79
+
80
+ // Build a transcript of the old messages (skip system at index 0)
81
+ let old_messages = &history[1..split_point];
82
+
83
+ if old_messages.is_empty() {
84
+ return Ok(false);
85
+ }
86
+
87
+ let transcript = old_messages
88
+ .iter()
89
+ .map(|m| format!("{}: {}", m.role, m.content))
90
+ .collect::<Vec<_>>()
91
+ .join("\n");
92
+
93
+ // Ask the LLM to summarize the old conversation
94
+ let summary_prompt = format!(
95
+ "Summarize the following conversation history into a concise context summary. \
96
+ Preserve key facts, decisions, tool results, and any state that would be needed \
97
+ to continue the conversation. Be concise but complete.\n\n\
98
+ CONVERSATION:\n{}\n\n\
99
+ SUMMARY:",
100
+ transcript
101
+ );
102
+
103
+ let summary = summarizer.run(&summary_prompt).await?;
104
+
105
+ tracing::info!(
106
+ old_messages = old_messages.len(),
107
+ summary_len = summary.len(),
108
+ "Compacted conversation history"
109
+ );
110
+
111
+ // Reconstruct history: [system] [summary] [recent messages]
112
+ let system_msg = history[0].clone();
113
+ let recent_messages: Vec<HistoryMessage> = history[split_point..].to_vec();
114
+
115
+ history.clear();
116
+ history.push(system_msg);
117
+ history.push(HistoryMessage {
118
+ role: "system".to_string(),
119
+ content: format!(
120
+ "[Context Summary from earlier conversation]\n{}",
121
+ summary
122
+ ),
123
+ });
124
+ history.extend(recent_messages);
125
+
126
+ Ok(true)
127
+ }
128
+
129
+ #[cfg(test)]
130
+ mod tests {
131
+ use super::*;
132
+
133
+ #[test]
134
+ fn test_needs_compaction() {
135
+ let history: Vec<HistoryMessage> = (0..50)
136
+ .map(|i| HistoryMessage::user(format!("msg {}", i)))
137
+ .collect();
138
+
139
+ assert!(needs_compaction(&history, 40));
140
+ assert!(!needs_compaction(&history, 50));
141
+ assert!(!needs_compaction(&history, 100));
142
+ }
143
+
144
+ #[test]
145
+ fn test_history_message_constructors() {
146
+ let sys = HistoryMessage::system("You are helpful");
147
+ assert_eq!(sys.role, "system");
148
+
149
+ let user = HistoryMessage::user("Hello");
150
+ assert_eq!(user.role, "user");
151
+
152
+ let asst = HistoryMessage::assistant("Hi there");
153
+ assert_eq!(asst.role, "assistant");
154
+
155
+ let tool = HistoryMessage::tool_result("search", "found 5 results");
156
+ assert_eq!(tool.role, "tool");
157
+ assert!(tool.content.contains("[search]"));
158
+ }
159
+
160
+ #[tokio::test]
161
+ async fn test_compact_short_history_is_noop() {
162
+ use async_trait::async_trait;
163
+
164
+ struct MockSummarizer;
165
+
166
+ #[async_trait]
167
+ impl Callable for MockSummarizer {
168
+ fn name(&self) -> &str {
169
+ "mock"
170
+ }
171
+ async fn run(&self, _input: &str) -> anyhow::Result<String> {
172
+ Ok("summary".to_string())
173
+ }
174
+ }
175
+
176
+ let mut history = vec![
177
+ HistoryMessage::system("system"),
178
+ HistoryMessage::user("hello"),
179
+ ];
180
+
181
+ let result = compact_history(&mut history, &MockSummarizer, 10).await.unwrap();
182
+ assert!(!result, "Should not compact when history is short");
183
+ assert_eq!(history.len(), 2);
184
+ }
185
+
186
+ #[tokio::test]
187
+ async fn test_compact_long_history() {
188
+ use async_trait::async_trait;
189
+
190
+ struct MockSummarizer;
191
+
192
+ #[async_trait]
193
+ impl Callable for MockSummarizer {
194
+ fn name(&self) -> &str {
195
+ "mock"
196
+ }
197
+ async fn run(&self, _input: &str) -> anyhow::Result<String> {
198
+ Ok("Summarized: user asked about Rust, assistant explained ownership.".to_string())
199
+ }
200
+ }
201
+
202
+ let mut history = vec![HistoryMessage::system("Be helpful")];
203
+ // Add 30 old messages
204
+ for i in 0..30 {
205
+ history.push(HistoryMessage::user(format!("question {}", i)));
206
+ history.push(HistoryMessage::assistant(format!("answer {}", i)));
207
+ }
208
+
209
+ let original_len = history.len(); // 61
210
+
211
+ let result = compact_history(&mut history, &MockSummarizer, 5).await.unwrap();
212
+ assert!(result, "Should have compacted");
213
+
214
+ // Should now be: system + summary + 5 recent = 7
215
+ assert_eq!(history.len(), 7);
216
+ assert!(history.len() < original_len);
217
+
218
+ // First should still be system
219
+ assert_eq!(history[0].role, "system");
220
+ assert_eq!(history[0].content, "Be helpful");
221
+
222
+ // Second should be the context summary
223
+ assert!(history[1].content.contains("[Context Summary"));
224
+ }
225
+ }
@@ -0,0 +1,118 @@
1
+ //! Runner configuration
2
+ //!
3
+ //! Defines `RunnerConfig` — the knobs that control the robust agent loop.
4
+ //! Ported from zeroclaw's iteration limits, compaction thresholds, and retry policies.
5
+
6
+ use std::time::Duration;
7
+
8
+ /// Configuration for the `AgentRunner` loop.
9
+ ///
10
+ /// Controls iteration limits, context compaction, retry behavior,
11
+ /// and checkpointing intervals.
12
+ #[derive(Debug, Clone)]
13
+ pub struct RunnerConfig {
14
+ /// Maximum number of tool-call iterations before the loop terminates.
15
+ /// Prevents runaway executions.
16
+ /// Default: 25 (zeroclaw uses configurable `max_tool_iterations`)
17
+ pub max_iterations: usize,
18
+
19
+ /// Maximum wall-clock duration for the entire run.
20
+ /// Default: 10 minutes
21
+ pub max_duration: Duration,
22
+
23
+ /// Number of messages in history before auto-compaction triggers.
24
+ /// When exceeded, older messages are summarized into a single context message.
25
+ /// Default: 40 messages
26
+ pub compaction_threshold: usize,
27
+
28
+ /// How many messages to keep verbatim after compaction.
29
+ /// The rest are summarized.
30
+ /// Default: 10 (keep the 10 most recent messages)
31
+ pub compaction_keep_recent: usize,
32
+
33
+ /// Retry configuration for transient errors.
34
+ pub retry: RetryConfig,
35
+
36
+ /// Checkpoint every N steps. `None` disables periodic checkpointing.
37
+ /// Default: Some(5)
38
+ pub checkpoint_interval: Option<usize>,
39
+
40
+ /// Whether to emit verbose stream events for each iteration.
41
+ /// Default: true
42
+ pub emit_events: bool,
43
+ }
44
+
45
+ /// Retry configuration for transient errors.
46
+ #[derive(Debug, Clone)]
47
+ pub struct RetryConfig {
48
+ /// Maximum number of retries for a single operation.
49
+ /// Default: 3
50
+ pub max_retries: u32,
51
+
52
+ /// Initial delay before the first retry.
53
+ /// Default: 1 second
54
+ pub initial_delay: Duration,
55
+
56
+ /// Maximum delay between retries (caps exponential growth).
57
+ /// Default: 30 seconds
58
+ pub max_delay: Duration,
59
+
60
+ /// Multiplier for exponential backoff.
61
+ /// Default: 2.0
62
+ pub backoff_multiplier: f64,
63
+ }
64
+
65
+ impl Default for RunnerConfig {
66
+ fn default() -> Self {
67
+ Self {
68
+ max_iterations: 25,
69
+ max_duration: Duration::from_secs(600),
70
+ compaction_threshold: 40,
71
+ compaction_keep_recent: 10,
72
+ retry: RetryConfig::default(),
73
+ checkpoint_interval: Some(5),
74
+ emit_events: true,
75
+ }
76
+ }
77
+ }
78
+
79
+ impl Default for RetryConfig {
80
+ fn default() -> Self {
81
+ Self {
82
+ max_retries: 3,
83
+ initial_delay: Duration::from_secs(1),
84
+ max_delay: Duration::from_secs(30),
85
+ backoff_multiplier: 2.0,
86
+ }
87
+ }
88
+ }
89
+
90
+ impl RunnerConfig {
91
+ /// Create a config tuned for short, interactive sessions.
92
+ pub fn interactive() -> Self {
93
+ Self {
94
+ max_iterations: 10,
95
+ max_duration: Duration::from_secs(120),
96
+ compaction_threshold: 20,
97
+ compaction_keep_recent: 6,
98
+ checkpoint_interval: None,
99
+ ..Default::default()
100
+ }
101
+ }
102
+
103
+ /// Create a config tuned for long-running background agents.
104
+ pub fn long_running() -> Self {
105
+ Self {
106
+ max_iterations: 100,
107
+ max_duration: Duration::from_secs(3600),
108
+ compaction_threshold: 60,
109
+ compaction_keep_recent: 15,
110
+ checkpoint_interval: Some(10),
111
+ retry: RetryConfig {
112
+ max_retries: 5,
113
+ ..Default::default()
114
+ },
115
+ ..Default::default()
116
+ }
117
+ }
118
+ }