agentomatic 0.1.1__tar.gz → 0.2.0__tar.gz

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 (175) hide show
  1. {agentomatic-0.1.1 → agentomatic-0.2.0}/CHANGELOG.md +22 -0
  2. {agentomatic-0.1.1 → agentomatic-0.2.0}/PKG-INFO +1 -1
  3. agentomatic-0.2.0/docs/guide/platform-features.md +339 -0
  4. {agentomatic-0.1.1 → agentomatic-0.2.0}/docs/guide/prompts.md +5 -4
  5. {agentomatic-0.1.1 → agentomatic-0.2.0}/docs/guide/storage.md +10 -0
  6. {agentomatic-0.1.1 → agentomatic-0.2.0}/docs/index.md +15 -15
  7. {agentomatic-0.1.1 → agentomatic-0.2.0}/mkdocs.yml +1 -0
  8. {agentomatic-0.1.1 → agentomatic-0.2.0}/pyproject.toml +2 -1
  9. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/_version.py +1 -1
  10. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/core/platform.py +8 -0
  11. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/core/registry.py +3 -0
  12. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/core/router_factory.py +300 -4
  13. agentomatic-0.2.0/src/agentomatic/providers/llm.py +194 -0
  14. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/storage/__init__.py +6 -2
  15. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/storage/base.py +91 -0
  16. agentomatic-0.2.0/src/agentomatic/storage/checkpointer.py +230 -0
  17. agentomatic-0.2.0/src/agentomatic/storage/memory.py +329 -0
  18. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/storage/models.py +54 -0
  19. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/storage/sqlalchemy.py +239 -1
  20. {agentomatic-0.1.1 → agentomatic-0.2.0}/tests/test_agentomatic.py +191 -1
  21. {agentomatic-0.1.1 → agentomatic-0.2.0}/tests/test_integration.py +54 -5
  22. agentomatic-0.2.0/tests/test_platform_features.py +622 -0
  23. {agentomatic-0.1.1 → agentomatic-0.2.0}/uv.lock +1 -1
  24. agentomatic-0.1.1/src/agentomatic/providers/llm.py +0 -116
  25. agentomatic-0.1.1/src/agentomatic/storage/memory.py +0 -167
  26. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/config.toml +0 -0
  27. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/translations/ar-SA.json +0 -0
  28. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/translations/bn.json +0 -0
  29. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/translations/da-DK.json +0 -0
  30. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/translations/de-DE.json +0 -0
  31. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/translations/el-GR.json +0 -0
  32. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/translations/en-US.json +0 -0
  33. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/translations/es.json +0 -0
  34. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/translations/fr-FR.json +0 -0
  35. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/translations/gu.json +0 -0
  36. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/translations/he-IL.json +0 -0
  37. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/translations/hi.json +0 -0
  38. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/translations/it.json +0 -0
  39. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/translations/ja.json +0 -0
  40. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/translations/kn.json +0 -0
  41. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/translations/ko.json +0 -0
  42. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/translations/ml.json +0 -0
  43. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/translations/mr.json +0 -0
  44. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/translations/nl.json +0 -0
  45. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/translations/pt-PT.json +0 -0
  46. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/translations/ta.json +0 -0
  47. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/translations/te.json +0 -0
  48. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/translations/zh-CN.json +0 -0
  49. {agentomatic-0.1.1 → agentomatic-0.2.0}/.chainlit/translations/zh-TW.json +0 -0
  50. {agentomatic-0.1.1 → agentomatic-0.2.0}/.dockerignore +0 -0
  51. {agentomatic-0.1.1 → agentomatic-0.2.0}/.env.example +0 -0
  52. {agentomatic-0.1.1 → agentomatic-0.2.0}/.github/FUNDING.yml +0 -0
  53. {agentomatic-0.1.1 → agentomatic-0.2.0}/.github/workflows/ci.yml +0 -0
  54. {agentomatic-0.1.1 → agentomatic-0.2.0}/.github/workflows/docs.yml +0 -0
  55. {agentomatic-0.1.1 → agentomatic-0.2.0}/.github/workflows/manual-docs.yml +0 -0
  56. {agentomatic-0.1.1 → agentomatic-0.2.0}/.github/workflows/manual-pypi.yml +0 -0
  57. {agentomatic-0.1.1 → agentomatic-0.2.0}/.github/workflows/pr-checks.yml +0 -0
  58. {agentomatic-0.1.1 → agentomatic-0.2.0}/.github/workflows/release.yml +0 -0
  59. {agentomatic-0.1.1 → agentomatic-0.2.0}/.gitignore +0 -0
  60. {agentomatic-0.1.1 → agentomatic-0.2.0}/.pre-commit-config.yaml +0 -0
  61. {agentomatic-0.1.1 → agentomatic-0.2.0}/.vscode-upload.json +0 -0
  62. {agentomatic-0.1.1 → agentomatic-0.2.0}/CONTRIBUTING.md +0 -0
  63. {agentomatic-0.1.1 → agentomatic-0.2.0}/Dockerfile +0 -0
  64. {agentomatic-0.1.1 → agentomatic-0.2.0}/Dockerfile.distroless +0 -0
  65. {agentomatic-0.1.1 → agentomatic-0.2.0}/LICENSE +0 -0
  66. {agentomatic-0.1.1 → agentomatic-0.2.0}/Makefile +0 -0
  67. {agentomatic-0.1.1 → agentomatic-0.2.0}/README.md +0 -0
  68. {agentomatic-0.1.1 → agentomatic-0.2.0}/TODO.md +0 -0
  69. {agentomatic-0.1.1 → agentomatic-0.2.0}/assets/logo.png +0 -0
  70. {agentomatic-0.1.1 → agentomatic-0.2.0}/docker-compose.yml +0 -0
  71. {agentomatic-0.1.1 → agentomatic-0.2.0}/docs/FRONTEND_API_GUIDE.md +0 -0
  72. {agentomatic-0.1.1 → agentomatic-0.2.0}/docs/architecture/api-reference.md +0 -0
  73. {agentomatic-0.1.1 → agentomatic-0.2.0}/docs/architecture/overview.md +0 -0
  74. {agentomatic-0.1.1 → agentomatic-0.2.0}/docs/assets/architecture_diagram.png +0 -0
  75. {agentomatic-0.1.1 → agentomatic-0.2.0}/docs/assets/logo.png +0 -0
  76. {agentomatic-0.1.1 → agentomatic-0.2.0}/docs/assets/optimization_flow.png +0 -0
  77. {agentomatic-0.1.1 → agentomatic-0.2.0}/docs/changelog.md +0 -0
  78. {agentomatic-0.1.1 → agentomatic-0.2.0}/docs/cli/commands.md +0 -0
  79. {agentomatic-0.1.1 → agentomatic-0.2.0}/docs/contributing.md +0 -0
  80. {agentomatic-0.1.1 → agentomatic-0.2.0}/docs/getting-started/first-agent.md +0 -0
  81. {agentomatic-0.1.1 → agentomatic-0.2.0}/docs/getting-started/installation.md +0 -0
  82. {agentomatic-0.1.1 → agentomatic-0.2.0}/docs/getting-started/quickstart.md +0 -0
  83. {agentomatic-0.1.1 → agentomatic-0.2.0}/docs/guide/agent-structure.md +0 -0
  84. {agentomatic-0.1.1 → agentomatic-0.2.0}/docs/guide/configuration.md +0 -0
  85. {agentomatic-0.1.1 → agentomatic-0.2.0}/docs/guide/debug-ui.md +0 -0
  86. {agentomatic-0.1.1 → agentomatic-0.2.0}/docs/guide/middleware.md +0 -0
  87. {agentomatic-0.1.1 → agentomatic-0.2.0}/docs/guide/optimization.md +0 -0
  88. {agentomatic-0.1.1 → agentomatic-0.2.0}/docs/guide/schemas.md +0 -0
  89. {agentomatic-0.1.1 → agentomatic-0.2.0}/docs/guide/telemetry.md +0 -0
  90. {agentomatic-0.1.1 → agentomatic-0.2.0}/docs/guide/templates.md +0 -0
  91. {agentomatic-0.1.1 → agentomatic-0.2.0}/examples/full_agent/README.md +0 -0
  92. {agentomatic-0.1.1 → agentomatic-0.2.0}/examples/full_agent/agents/weather/__init__.py +0 -0
  93. {agentomatic-0.1.1 → agentomatic-0.2.0}/examples/full_agent/agents/weather/api.py +0 -0
  94. {agentomatic-0.1.1 → agentomatic-0.2.0}/examples/full_agent/agents/weather/config.py +0 -0
  95. {agentomatic-0.1.1 → agentomatic-0.2.0}/examples/full_agent/agents/weather/graph.py +0 -0
  96. {agentomatic-0.1.1 → agentomatic-0.2.0}/examples/full_agent/agents/weather/langgraph.json +0 -0
  97. {agentomatic-0.1.1 → agentomatic-0.2.0}/examples/full_agent/agents/weather/nodes.py +0 -0
  98. {agentomatic-0.1.1 → agentomatic-0.2.0}/examples/full_agent/agents/weather/prompts.json +0 -0
  99. {agentomatic-0.1.1 → agentomatic-0.2.0}/examples/full_agent/agents/weather/schemas.py +0 -0
  100. {agentomatic-0.1.1 → agentomatic-0.2.0}/examples/full_agent/agents/weather/tools.py +0 -0
  101. {agentomatic-0.1.1 → agentomatic-0.2.0}/examples/full_agent/main.py +0 -0
  102. {agentomatic-0.1.1 → agentomatic-0.2.0}/examples/hello_agent/agents/hello/__init__.py +0 -0
  103. {agentomatic-0.1.1 → agentomatic-0.2.0}/examples/hello_agent/agents/hello/graph.py +0 -0
  104. {agentomatic-0.1.1 → agentomatic-0.2.0}/examples/hello_agent/agents/hello/nodes.py +0 -0
  105. {agentomatic-0.1.1 → agentomatic-0.2.0}/examples/hello_agent/main.py +0 -0
  106. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/__init__.py +0 -0
  107. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/__init__.py +0 -0
  108. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/cli/__init__.py +0 -0
  109. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/cli/commands.py +0 -0
  110. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/cli/templates.py +0 -0
  111. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/config/__init__.py +0 -0
  112. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/config/defaults.py +0 -0
  113. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/config/settings.py +0 -0
  114. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/core/__init__.py +0 -0
  115. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/core/lifespan.py +0 -0
  116. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/core/manifest.py +0 -0
  117. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/core/state.py +0 -0
  118. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/middleware/__init__.py +0 -0
  119. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/middleware/auth.py +0 -0
  120. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/middleware/feedback.py +0 -0
  121. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/middleware/logging.py +0 -0
  122. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/middleware/metrics.py +0 -0
  123. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/middleware/rate_limit.py +0 -0
  124. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/observability/__init__.py +0 -0
  125. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/observability/concurrency.py +0 -0
  126. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/observability/metrics.py +0 -0
  127. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/observability/telemetry.py +0 -0
  128. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/optimize/__init__.py +0 -0
  129. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/optimize/dataset.py +0 -0
  130. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/optimize/loop.py +0 -0
  131. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/optimize/metrics.py +0 -0
  132. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/optimize/optimizer.py +0 -0
  133. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/optimize/report.py +0 -0
  134. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/optimize/runner.py +0 -0
  135. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/optimize/strategies.py +0 -0
  136. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/optimize/synthesizer.py +0 -0
  137. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/prompts/__init__.py +0 -0
  138. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/prompts/manager.py +0 -0
  139. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/protocols/__init__.py +0 -0
  140. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/protocols/decorators.py +0 -0
  141. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/providers/__init__.py +0 -0
  142. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/providers/embeddings.py +0 -0
  143. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/py.typed +0 -0
  144. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/ui/.chainlit/config.toml +0 -0
  145. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/ui/__init__.py +0 -0
  146. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agentomatic/ui/chat.py +0 -0
  147. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agents/__init__.py +0 -0
  148. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agents/alpha/__init__.py +0 -0
  149. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agents/alpha/agent.py +0 -0
  150. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agents/alpha/api.py +0 -0
  151. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agents/alpha/config.py +0 -0
  152. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agents/alpha/prompts.json +0 -0
  153. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agents/alpha/schemas.py +0 -0
  154. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agents/alpha/state.py +0 -0
  155. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agents/beta/__init__.py +0 -0
  156. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agents/beta/agent.py +0 -0
  157. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agents/beta/api.py +0 -0
  158. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agents/beta/config.py +0 -0
  159. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agents/beta/prompts.json +0 -0
  160. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agents/beta/schemas.py +0 -0
  161. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/agents/beta/state.py +0 -0
  162. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/app/__init__.py +0 -0
  163. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/app/api.py +0 -0
  164. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/app/dependencies.py +0 -0
  165. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/app/main.py +0 -0
  166. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/app/settings.py +0 -0
  167. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/common/__init__.py +0 -0
  168. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/common/agent_state.py +0 -0
  169. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/common/api_decorators.py +0 -0
  170. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/common/base_agent.py +0 -0
  171. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/common/llm_factory.py +0 -0
  172. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/common/prompt_manager.py +0 -0
  173. {agentomatic-0.1.1 → agentomatic-0.2.0}/src/common/utilities.py +0 -0
  174. {agentomatic-0.1.1 → agentomatic-0.2.0}/tests/test_cli.py +0 -0
  175. {agentomatic-0.1.1 → agentomatic-0.2.0}/tests/test_optimize.py +0 -0
@@ -1,6 +1,28 @@
1
1
  # CHANGELOG
2
2
 
3
3
 
4
+ ## v0.2.0 (2026-06-14)
5
+
6
+ ### Documentation
7
+
8
+ - Add telemetry and feedback correlation notes for A/B testing
9
+ ([`2c27a86`](https://github.com/UnicoLab/agentomatic/commit/2c27a86ac83b44a022e5d002d88316953f01ab35))
10
+
11
+ ### Features
12
+
13
+ - Implement advanced platform features (HITL, checkpointer, structured output, fork, A/B routing,
14
+ fallbacks, hooks) and update documentation
15
+ ([`c1a55c3`](https://github.com/UnicoLab/agentomatic/commit/c1a55c39b1efd24084f1453946df27a830d3d7ec))
16
+
17
+ - Increase core test coverage over 85% and enhance homepage aesthetics
18
+ ([`98f28f5`](https://github.com/UnicoLab/agentomatic/commit/98f28f56308b7540d642149aa2a7edc20b2eeafb))
19
+
20
+ ### Testing
21
+
22
+ - Enhance unit test coverage for sqlalchemy store, sync checkpointers, and structured fallbacks
23
+ ([`91ab042`](https://github.com/UnicoLab/agentomatic/commit/91ab04254a623fb4fbd108303265ad8d4b3aeba5))
24
+
25
+
4
26
  ## v0.1.1 (2026-06-13)
5
27
 
6
28
  ### Bug Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentomatic
3
- Version: 0.1.1
3
+ Version: 0.2.0
4
4
  Summary: Drop agents, not code — zero-code multi-agent API platform framework
5
5
  Project-URL: Homepage, https://github.com/UnicoLab/agentomatic
6
6
  Project-URL: Documentation, https://unicolab.github.io/agentomatic
@@ -0,0 +1,339 @@
1
+ # Advanced Platform Features
2
+
3
+ <div align="center">
4
+ <img src="../assets/logo.png" width="200" alt="agentomatic logo">
5
+ <h3>Enterprise-Grade Orchestration & Core Capabilities</h3>
6
+ </div>
7
+
8
+ ---
9
+
10
+ Agentomatic provides a suite of advanced platform capabilities designed to make multi-agent systems production-ready. These features solve common real-world challenges around human-in-the-loop validation, schema enforcement, prompt routing, checkpointer persistence, and service resilience.
11
+
12
+ ---
13
+
14
+ ## 🚦 1. Human-in-the-Loop (HITL) Protocol
15
+
16
+ In complex multi-agent architectures, agents often require human validation before executing sensitive actions (e.g., executing a transaction, sending an email, or performing a destructive write).
17
+
18
+ Agentomatic provides a built-in suspension/resume mechanism that allows nodes or graphs to halt execution, serialize their state snapshots to the storage backend, and resume or abort dynamically when approved/rejected via HTTP.
19
+
20
+ ```
21
+ ┌──────────────────────┐
22
+ │ Agent Execution │
23
+ └──────────┬───────────┘
24
+
25
+ Node raises AgentSuspendedException
26
+
27
+
28
+ ┌──────────────────────┐
29
+ │ Serializes state snapshot │
30
+ │ Saves to database │
31
+ │ Returns HTTP 202 │
32
+ └──────────────────────┘
33
+
34
+ ┌───────────┴───────────┐
35
+ ▼ ▼
36
+ POST /approve POST /reject
37
+ │ │
38
+ Merges human context Deletes snapshot
39
+ Resumes execution Aborts execution
40
+ │ │
41
+ ▼ ▼
42
+ ┌──────────────────┐ ┌──────────────────┐
43
+ │ Completes graph│ │ Returns 200 OK │
44
+ └──────────────────┘ └──────────────────┘
45
+ ```
46
+
47
+ ### Suspending Execution
48
+
49
+ To suspend execution, raise `AgentSuspendedException` from anywhere inside your node function or LangGraph node:
50
+
51
+ ```python
52
+ from agentomatic.core.router_factory import AgentSuspendedException
53
+
54
+ async def financial_transfer_node(state: dict):
55
+ metadata = state.get("metadata") or {}
56
+
57
+ # Check if we already have approval
58
+ if metadata.get("hitl_approved"):
59
+ return {
60
+ "response": f"Successfully transferred ${state['amount']}",
61
+ "metadata": metadata
62
+ }
63
+
64
+ # Otherwise, suspend and wait for human confirmation
65
+ raise AgentSuspendedException(
66
+ approval_id=f"tx_{state['transaction_id']}",
67
+ node_name="financial_transfer_node",
68
+ state_snapshot=state,
69
+ message="Transaction requires human approval."
70
+ )
71
+ ```
72
+
73
+ When this exception is thrown:
74
+ 1. Agentomatic intercepts the execution.
75
+ 2. The current `state_snapshot` is stored in the persistent database under `SuspendedStateModel`.
76
+ 3. The API immediately returns a `202 Accepted` status code with the approval details.
77
+
78
+ **Response payload:**
79
+ ```json
80
+ {
81
+ "detail": {
82
+ "status": "suspended",
83
+ "approval_id": "tx_984712",
84
+ "node_name": "financial_transfer_node",
85
+ "message": "Transaction requires human approval."
86
+ }
87
+ }
88
+ ```
89
+
90
+ ### REST Endpoints for Approvals
91
+
92
+ Each registered agent automatically exposes three endpoints to manage suspended states:
93
+
94
+ #### A. List Pending Approvals
95
+ Retrieve all currently suspended states for a specific thread.
96
+
97
+ * **Method:** `GET`
98
+ * **Path:** `/api/v1/{agent_slug}/threads/{thread_id}/pending`
99
+ * **Response:**
100
+ ```json
101
+ {
102
+ "thread_id": "thread_abc123",
103
+ "count": 1,
104
+ "pending": [
105
+ {
106
+ "id": "tx_984712",
107
+ "node_name": "financial_transfer_node",
108
+ "state_snapshot": { ... },
109
+ "created_at": "2026-06-13T22:50:34"
110
+ }
111
+ ]
112
+ }
113
+ ```
114
+
115
+ #### B. Approve and Resume Execution
116
+ Approve the suspension, optionally merge new parameters (e.g., corrections or decisions), and resume the agent's execution from that exact step.
117
+
118
+ * **Method:** `POST`
119
+ * **Path:** `/api/v1/{agent_slug}/threads/{thread_id}/approve`
120
+ * **Payload:**
121
+ ```json
122
+ {
123
+ "approval_id": "tx_984712",
124
+ "context": {
125
+ "approved_limit": 500
126
+ }
127
+ }
128
+ ```
129
+ * **Behavior:** Deletes the pending suspended snapshot, merges the request's `context` into the state, marks `state.metadata.hitl_approved = True`, and resumes the graph execution synchronously. It returns the final agent execution output.
130
+
131
+ #### C. Reject and Abort Execution
132
+ Reject the transaction and discard the execution context.
133
+
134
+ * **Method:** `POST`
135
+ * **Path:** `/api/v1/{agent_slug}/threads/{thread_id}/reject`
136
+ * **Payload:**
137
+ ```json
138
+ {
139
+ "approval_id": "tx_984712",
140
+ "reason": "Risk score too high"
141
+ }
142
+ ```
143
+ * **Response:**
144
+ ```json
145
+ {
146
+ "status": "rejected",
147
+ "approval_id": "tx_984712",
148
+ "reason": "Risk score too high"
149
+ }
150
+ ```
151
+
152
+ ---
153
+
154
+ ## 💾 2. LangGraph Checkpointer (`AgentomaticCheckpointer`)
155
+
156
+ If you are building your agents using **LangGraph**, you need a checkpoint saver to persist the graph's memory across invocations. Agentomatic provides a native adapter: `AgentomaticCheckpointer`.
157
+
158
+ This checkpointer implements LangGraph's `BaseCheckpointSaver` and delegates storage operations directly to your configured Agentomatic `BaseStore` (e.g., `SQLAlchemyStore` or `MemoryStore`). This ensures that thread states, checkpoint namespaces, and historical tuples are stored consistently without needing a separate database.
159
+
160
+ ### Usage Example
161
+
162
+ ```python
163
+ from langgraph.graph import StateGraph
164
+ from agentomatic.storage import SQLAlchemyStore
165
+ from agentomatic.storage.checkpointer import AgentomaticCheckpointer
166
+
167
+ # 1. Setup your database store
168
+ store = SQLAlchemyStore("postgresql+asyncpg://postgres:secret@localhost:5432/agent_db")
169
+
170
+ # 2. Wrap it with the LangGraph checkpointer adapter
171
+ checkpointer = AgentomaticCheckpointer(store)
172
+
173
+ # 3. Create and compile your LangGraph with the checkpointer
174
+ builder = StateGraph(MyStateClass)
175
+ # ... build graph nodes ...
176
+
177
+ graph = builder.compile(checkpointer=checkpointer)
178
+ ```
179
+
180
+ All LangGraph checkpoints are automatically persisted in your database and can be fetched or updated using the standard LangGraph runtime config.
181
+
182
+ ---
183
+
184
+ ## 🎯 3. Structured Output Enforcer
185
+
186
+ Ensuring that LLM outputs strictly match validation schemas is critical for reliable API integration. Agentomatic makes structured output enforcement seamless:
187
+
188
+ 1. **Auto-bind Schemas**: Under the hood, Agentomatic leverages LangChain's `.with_structured_output()` to bind Pydantic schemas directly to the LLM runtime.
189
+ 2. **Fallback Parser**: If the provider or mock model does not support native schema enforcement (e.g., mock/fake models in test environments), Agentomatic automatically intercepts the output and applies a robust parsing and default-fallback generator wrapper.
190
+
191
+ ### Factory Method
192
+
193
+ Use `get_structured_llm` to create a model bound to a Pydantic schema:
194
+
195
+ ```python
196
+ from pydantic import BaseModel, Field
197
+ from agentomatic.providers.llm import get_structured_llm
198
+
199
+ class TranslationOutput(BaseModel):
200
+ detected_language: str
201
+ translated_text: str
202
+ confidence: float = Field(default=0.0)
203
+
204
+ # Build an LLM instance that returns parsed instances of TranslationOutput
205
+ structured_model = get_structured_llm(
206
+ response_model=TranslationOutput,
207
+ provider="openai",
208
+ model="gpt-4o",
209
+ temperature=0.0
210
+ )
211
+
212
+ result = structured_model.invoke("Translate 'Bonjour tout le monde' to English")
213
+ # 'result' is guaranteed to be a TranslationOutput object
214
+ print(result.translated_text) # "Hello everyone"
215
+ ```
216
+
217
+ ---
218
+
219
+ ## 🗃️ 4. Thread Forking & Cloning
220
+
221
+ Debugging agent failures or performing A/B evaluation of system prompt prompts requires the ability to fork history. Agentomatic supports **Thread Forking** at the API and database levels.
222
+
223
+ You can clone a parent thread starting at a specific message index. This creates a brand new thread containing a copy of all messages up to and including that index, allowing subsequent interactions to diverge without altering the parent thread's history.
224
+
225
+ * **Method:** `POST`
226
+ * **Path:** `/api/v1/{agent_slug}/threads/{thread_id}/fork`
227
+ * **Payload:**
228
+ ```json
229
+ {
230
+ "message_index": 2,
231
+ "new_thread_id": "fork_thread_99",
232
+ "title": "A/B Test Variant B"
233
+ }
234
+ ```
235
+ * **Response:** Returns the new thread dictionary:
236
+ ```json
237
+ {
238
+ "id": "fork_thread_99",
239
+ "user_id": "user_id_12",
240
+ "agent_name": "support_agent",
241
+ "title": "A/B Test Variant B",
242
+ "message_count": 3,
243
+ "metadata": {}
244
+ }
245
+ ```
246
+
247
+ ---
248
+
249
+ ## 📊 5. A/B Test Prompt Router
250
+
251
+ Agentomatic enables you to easily conduct prompt version testing in production. You can configure routing splits between different system prompts directly inside your agent configuration.
252
+
253
+ ### Configuration
254
+
255
+ Add `prompt_ab_tests` with fractional weights inside your agent's config settings:
256
+
257
+ ```json
258
+ {
259
+ "prompt_ab_tests": {
260
+ "v1": 0.7,
261
+ "v2": 0.3
262
+ }
263
+ }
264
+ ```
265
+
266
+ ### Execution Flow
267
+
268
+ 1. When a client invokes the agent without specifying a `prompt_version` (or when set to `"v1"`), Agentomatic performs a **weighted random choice** based on the configured split (in the example above: 70% traffic to `v1`, 30% traffic to `v2`).
269
+ 2. The chosen version is automatically stored in the invocation state under `state["prompt_version"]`.
270
+ 3. Your agent nodes can read `prompt_version` from the state to load the correct prompt template.
271
+ 4. The chosen version is returned in the response metadata (`metadata.prompt_version`) so that you can trace and analyze performance.
272
+
273
+ ### Telemetry & Feedback Correlation
274
+
275
+ To measure the performance and quality of different prompt variants:
276
+ 1. **Response Tracking**: Read `metadata.prompt_version` from the `/invoke` or `/chat` JSON response payload.
277
+ 2. **Feedback Logging**: When calling the `POST /api/v1/{agent}/feedback` endpoint, pass the active prompt version in the request metadata payload:
278
+ ```json
279
+ {
280
+ "thread_id": "thread_123",
281
+ "rating": 5,
282
+ "comment": "Highly accurate answer!",
283
+ "metadata": {
284
+ "prompt_version": "v2"
285
+ }
286
+ }
287
+ ```
288
+ This associates ratings and comments directly with each version, allowing you to run analytical breakdowns of user satisfaction metrics per prompt variant.
289
+
290
+ > [!NOTE]
291
+ > Clients can explicitly override the A/B router by passing a specific `prompt_version` parameter in the invoke request (e.g. `{"prompt_version": "v2"}`).
292
+
293
+ ---
294
+
295
+ ## 🛡️ 6. LLM Failover & Fallbacks
296
+
297
+ LLM APIs can suffer from outages, rate limiting (HTTP 429), or transient network errors. To ensure high availability, Agentomatic lets you define chainable fallback providers.
298
+
299
+ ### Configuration
300
+
301
+ Pass a list of provider slugs in the `fallbacks` parameter of `get_llm()`:
302
+
303
+ ```python
304
+ from agentomatic.providers.llm import get_llm
305
+
306
+ llm = get_llm(
307
+ provider="openai",
308
+ model="gpt-4",
309
+ fallbacks=["azure", "ollama"]
310
+ )
311
+ ```
312
+
313
+ If the primary provider (`openai`) raises an exception during execution, LangChain's fallback mechanism automatically routes the request to the next available backup in the list (`azure`, then `ollama`), shielding clients from upstream downtime.
314
+
315
+ ---
316
+
317
+ ## 🔌 7. State-Level Hook Middleware (Interceptors)
318
+
319
+ For custom telemetry, audit logging, or real-time security scanning, you can register **state-level node hooks**. These are run instantly before and after every agent node invocation.
320
+
321
+ ```python
322
+ from agentomatic import AgentPlatform
323
+
324
+ platform = AgentPlatform.from_folder("agents/")
325
+
326
+ # 1. Register a before-node interceptor
327
+ def audit_input_hook(agent_name: str, state: dict):
328
+ print(f"[Hook] Agent '{agent_name}' is about to run. Query: {state.get('current_query')}")
329
+ # You can inspect or modify the state inline before execution starts
330
+ state["metadata"]["audit_logged"] = True
331
+
332
+ platform.register_before_node_hook(audit_input_hook)
333
+
334
+ # 2. Register an after-node interceptor
335
+ def audit_output_hook(agent_name: str, result: dict):
336
+ print(f"[Hook] Agent '{agent_name}' completed. Response snippet: {result.get('response')[:30]}")
337
+
338
+ platform.register_after_node_hook(audit_output_hook)
339
+ ```
@@ -99,8 +99,7 @@ If you write a custom router using `api.py` and want to load prompt templates dy
99
99
 
100
100
  ```python
101
101
  from fastapi import APIRouter
102
- from agentomatic import APIResponse, handle_api_errors
103
- from rac.agents._registry import get_registry
102
+ from agentomatic import APIResponse, handle_api_errors, AgentRegistry
104
103
 
105
104
  router = APIRouter()
106
105
 
@@ -108,8 +107,10 @@ router = APIRouter()
108
107
  @handle_api_errors
109
108
  async def custom_chat(query: str) -> APIResponse:
110
109
  # Retrieve the agent instance from the registry
111
- agent = get_registry().get_agent("my_agent")
112
-
110
+ agent = AgentRegistry().get("my_agent")
111
+ if not agent:
112
+ return APIResponse(success=False, message="Agent not found")
113
+
113
114
  # Format user prompt
114
115
  user_prompt = agent.prompt_manager.format_prompt(
115
116
  version=agent.config.prompt_version,
@@ -192,3 +192,13 @@ Every storage adapter implements the following async interface methods:
192
192
  | `async def get_messages(id) -> list[dict]` | **Required** | Fetch chronological chat histories |
193
193
  | `async def add_feedback(...) -> dict` | Optional | Save user scores and comment metrics |
194
194
  | `async def list_feedback(...) -> list[dict]` | Optional | Search feedback records |
195
+ | `async def save_suspended_state(...) -> dict` | Optional | Save execution state for human approval |
196
+ | `async def get_suspended_state(id) -> dict \| None` | Optional | Retrieve a suspended state |
197
+ | `async def list_suspended_states(...) -> list[dict]` | Optional | List all pending suspended states |
198
+ | `async def delete_suspended_state(id) -> bool` | Optional | Delete suspended state on completion |
199
+ | `async def fork_thread(...) -> dict \| None` | Optional | Fork a conversation history up to index |
200
+ | `async def save_checkpoint(...) -> None` | Optional | Save a LangGraph checkpoint state |
201
+ | `async def get_checkpoint(...) -> dict \| None` | Optional | Retrieve a LangGraph checkpoint state |
202
+ | `async def list_checkpoints(...) -> list[dict]` | Optional | List checkpoints for a thread namespace |
203
+
204
+ > 🚦 *For details on how checkpointer, thread forking, and human-in-the-loop suspension integrate with these storage methods, see the [Advanced Platform Features Guide](platform-features.md).*
@@ -10,20 +10,20 @@ hide:
10
10
  <img src="assets/logo.png" width="300" alt="agentomatic logo">
11
11
  </p>
12
12
 
13
- <h3>Drop agents, not code. ⚡</h3>
13
+ <h3>Drop agents, not code. :octicons-zap-24:</h3>
14
14
  <p><b>The zero-code multi-agent API platform framework.</b> Turn any agent script or graph into a secure, resilient, enterprise-grade microservice with auto-discovery, SSE streaming, thread persistence, and prompt optimization — in 3 lines of code.</p>
15
15
 
16
16
  <p>
17
17
  <a href="https://pypi.org/project/agentomatic/"><img src="https://img.shields.io/pypi/v/agentomatic.svg" alt="PyPI version"></a>
18
18
  <img src="https://img.shields.io/badge/python-3.11%2B-blue.svg" alt="Python 3.11+">
19
19
  <img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License: MIT">
20
- <img src="https://img.shields.io/badge/tests-161%20passing-brightgreen.svg" alt="Tests passing">
20
+ <img src="https://img.shields.io/badge/tests-175%20passing-brightgreen.svg" alt="Tests passing">
21
21
  </p>
22
22
  </div>
23
23
 
24
24
  ---
25
25
 
26
- ## What is Agentomatic?
26
+ ## :octicons-zap-24: What is Agentomatic?
27
27
 
28
28
  **Agentomatic** acts as a production-ready application server for AI agents. Whether you write raw Python functions, build complex multi-agent orchestrations with **LangGraph**, or chain tools together with **LangChain**, Agentomatic auto-discovers your code and mounts a complete FastAPI application with standard REST routes, server-sent events (SSE) streaming, database adapters, telemetry, and rate limiting.
29
29
 
@@ -41,41 +41,41 @@ Run with `uvicorn main:app --reload` and visit `/docs` for a fully documented Op
41
41
 
42
42
  ---
43
43
 
44
- ## 🏗️ Platform Architecture
44
+ ## :material-sitemap: Platform Architecture
45
45
 
46
- Agentomatic's core principle is **Convention over Configuration**. By dividing agents into isolated directories containing a manifest, configuration, and a execution graph, the framework automatically maps directory files to API endpoints, database adapters, and prompt templates.
46
+ Agentomatic's core principle is **Convention over Configuration**. By dividing agents into isolated directories containing a manifest, configuration, and an execution graph, the framework automatically maps directory files to API endpoints, database adapters, and prompt templates.
47
47
 
48
48
  ![Agentomatic Architecture](assets/architecture_diagram.png)
49
49
 
50
50
  ---
51
51
 
52
- ## 🚀 Key Features
52
+ ## :octicons-star-fill-24: Key Features
53
53
 
54
- ### 🔍 1. Auto-Discovery & Hot Reloading
54
+ ### :material-flash: 1. Auto-Discovery & Hot Reloading
55
55
  Drop a directory containing an `__init__.py` file (which exports an `AgentManifest` and execution function) into your `agents/` folder. Agentomatic automatically spins up a custom FastAPI router, parses your input/output schemas, and mounts a complete suite of **12+ REST endpoints** for that specific agent.
56
56
 
57
- ### 🌊 2. Synchronous & SSE Streaming
57
+ ### :material-waves: 2. Synchronous & SSE Streaming
58
58
  Standardize how clients talk to your agents. Every agent gets a synchronous `/invoke` endpoint and an asynchronous `/invoke/stream` Server-Sent Events (SSE) streaming endpoint that streams intermediate agent thought steps, tool calls, and final answers in real-time.
59
59
 
60
- ### 🗄️ 3. Session-Aware Chat & Persistence
60
+ ### :material-database: 3. Session-Aware Chat & Persistence
61
61
  The `/chat` endpoint manages full context history automatically. By passing a `thread_id`, Agentomatic reads the conversation log, formats it as history, and executes your agent. Swappable database adapters (**MemoryStore**, **SQLAlchemyStore**) let you persist user messages to PostgreSQL, MySQL, or SQLite out of the box.
62
62
 
63
- ### 🛡️ 4. Enterprise-Grade Middleware
63
+ ### :material-shield-key: 4. Enterprise-Grade Middleware
64
64
  Keep your agents safe and monitored. Toggle middleware filters globally or per-agent:
65
65
  - **API Key Auth**: Secured endpoints with customizable key authorization.
66
66
  - **Token Bucket Rate Limiting**: Prevent abuse by limiting queries per IP/User.
67
67
  - **Prometheus Metrics**: Monitor latency, request counts, and active connections at `/metrics`.
68
68
  - **Structured Logging**: Context-scoped loguru logs tracking execution durations and exceptions.
69
69
 
70
- ### 📊 5. Prompt Tuning & Optimization (DSPy-inspired)
70
+ ### :material-tune-vertical: 5. Prompt Tuning & Optimization (DSPy-inspired)
71
71
  Tune prompts like hyper-parameters. Agentomatic includes a prompt optimization module with **7 optimization strategies** (e.g. `iterative_rewrite`, `few_shot_bootstrap`) and **8 evaluation metrics** (answer relevancy, faithfulness, toxic speech check, etc.). Generate synthetic datasets with a single command and track prompt version history with side-by-side HTML reports.
72
72
 
73
- ### 🎨 6. ChatGPT-like Debug UI
73
+ ### :material-palette: 6. ChatGPT-like Debug UI
74
74
  No frontend development required. Run `agentomatic run --with-ui` to launch a built-in, production-quality **Chainlit** chat interface where you can test agents, select prompt versions, inspect step-by-step tool invocations, and submit feedback ratings.
75
75
 
76
76
  ---
77
77
 
78
- ## 🗺️ How does it compare?
78
+ ## :material-swap-horizontal: How does it compare?
79
79
 
80
80
  | Feature | Raw FastAPI + LangChain | Agentomatic Platform |
81
81
  | :--- | :--- | :--- |
@@ -88,7 +88,7 @@ No frontend development required. Run `agentomatic run --with-ui` to launch a bu
88
88
 
89
89
  ---
90
90
 
91
- ## 🏁 Quick Installation
91
+ ## :material-download: Quick Installation
92
92
 
93
93
  Install Agentomatic and all its production components (including optimizer and web UI) using `pip` or `uv`:
94
94
 
@@ -102,7 +102,7 @@ uv add agentomatic --extra all
102
102
 
103
103
  ---
104
104
 
105
- ## 🛠️ Create Your First Agent
105
+ ## :material-play: Create Your First Agent
106
106
 
107
107
  Scaffold a basic chatbot and start the local API platform with two terminal commands:
108
108
 
@@ -90,6 +90,7 @@ nav:
90
90
  - Configuration: guide/configuration.md
91
91
  - Storage Backends: guide/storage.md
92
92
  - Middleware: guide/middleware.md
93
+ - Advanced Platform Features: guide/platform-features.md
93
94
  - Prompt Optimization: guide/optimization.md
94
95
  - Telemetry & Feedback: guide/telemetry.md
95
96
  - Debug UI: guide/debug-ui.md
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agentomatic"
3
- version = "0.1.1"
3
+ version = "0.2.0"
4
4
  description = "Drop agents, not code — zero-code multi-agent API platform framework"
5
5
  readme = "README.md"
6
6
  license = {text = "MIT"}
@@ -81,6 +81,7 @@ Changelog = "https://github.com/UnicoLab/agentomatic/blob/main/CHANGELOG.md"
81
81
 
82
82
 
83
83
 
84
+
84
85
  [dependency-groups]
85
86
  dev = [
86
87
  "pytest>=8",
@@ -2,4 +2,4 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- __version__ = "0.1.1"
5
+ __version__ = "0.2.0"
@@ -171,6 +171,14 @@ class AgentPlatform:
171
171
  """Set the storage backend."""
172
172
  self._store = value
173
173
 
174
+ def register_before_node_hook(self, hook: Callable[[str, dict[str, Any]], None]) -> None:
175
+ """Register a hook to execute before any agent node/graph runs."""
176
+ self._registry.before_node_hooks.append(hook)
177
+
178
+ def register_after_node_hook(self, hook: Callable[[str, dict[str, Any]], None]) -> None:
179
+ """Register a hook to execute after any agent node/graph runs."""
180
+ self._registry.after_node_hooks.append(hook)
181
+
174
182
  # ------------------------------------------------------------------
175
183
  # Programmatic registration
176
184
  # ------------------------------------------------------------------
@@ -3,6 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import importlib
6
+ from collections.abc import Callable
6
7
  from pathlib import Path
7
8
  from typing import Any
8
9
 
@@ -25,6 +26,8 @@ class AgentRegistry:
25
26
 
26
27
  def __init__(self) -> None:
27
28
  self._agents: dict[str, RegisteredAgent] = {}
29
+ self.before_node_hooks: list[Callable[[str, dict[str, Any]], None]] = []
30
+ self.after_node_hooks: list[Callable[[str, dict[str, Any]], None]] = []
28
31
 
29
32
  @property
30
33
  def count(self) -> int: