autonomous-agent-algos 0.1.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 (206) hide show
  1. autonomous_agent_algos-0.1.0/.github/workflows/ci.yml +103 -0
  2. autonomous_agent_algos-0.1.0/.github/workflows/docs.yml +63 -0
  3. autonomous_agent_algos-0.1.0/.github/workflows/release.yml +111 -0
  4. autonomous_agent_algos-0.1.0/.gitignore +7 -0
  5. autonomous_agent_algos-0.1.0/LICENSE +21 -0
  6. autonomous_agent_algos-0.1.0/PKG-INFO +276 -0
  7. autonomous_agent_algos-0.1.0/README.md +229 -0
  8. autonomous_agent_algos-0.1.0/docs/about/changelog.md +81 -0
  9. autonomous_agent_algos-0.1.0/docs/about/contributing.md +89 -0
  10. autonomous_agent_algos-0.1.0/docs/about/design-decisions.md +79 -0
  11. autonomous_agent_algos-0.1.0/docs/about/license.md +7 -0
  12. autonomous_agent_algos-0.1.0/docs/about/limitations.md +102 -0
  13. autonomous_agent_algos-0.1.0/docs/concepts/architecture.md +76 -0
  14. autonomous_agent_algos-0.1.0/docs/concepts/data-model.md +95 -0
  15. autonomous_agent_algos-0.1.0/docs/concepts/delivery-and-idempotency.md +57 -0
  16. autonomous_agent_algos-0.1.0/docs/concepts/events-and-the-log.md +105 -0
  17. autonomous_agent_algos-0.1.0/docs/concepts/projections-and-snapshots.md +100 -0
  18. autonomous_agent_algos-0.1.0/docs/concepts/runs-and-the-engine.md +134 -0
  19. autonomous_agent_algos-0.1.0/docs/getting-started/installation.md +72 -0
  20. autonomous_agent_algos-0.1.0/docs/getting-started/mental-model.md +66 -0
  21. autonomous_agent_algos-0.1.0/docs/getting-started/quickstart.md +99 -0
  22. autonomous_agent_algos-0.1.0/docs/guides/algorithms/custom.md +84 -0
  23. autonomous_agent_algos-0.1.0/docs/guides/algorithms/ensembles-rag.md +64 -0
  24. autonomous_agent_algos-0.1.0/docs/guides/algorithms/index.md +61 -0
  25. autonomous_agent_algos-0.1.0/docs/guides/algorithms/plan-and-execute.md +81 -0
  26. autonomous_agent_algos-0.1.0/docs/guides/algorithms/refine.md +92 -0
  27. autonomous_agent_algos-0.1.0/docs/guides/algorithms/router-supervisor.md +74 -0
  28. autonomous_agent_algos-0.1.0/docs/guides/algorithms/tool-loop-react.md +104 -0
  29. autonomous_agent_algos-0.1.0/docs/guides/algorithms/workflow-fsm.md +80 -0
  30. autonomous_agent_algos-0.1.0/docs/guides/clusters.md +151 -0
  31. autonomous_agent_algos-0.1.0/docs/guides/context.md +81 -0
  32. autonomous_agent_algos-0.1.0/docs/guides/extending.md +93 -0
  33. autonomous_agent_algos-0.1.0/docs/guides/human-approval.md +67 -0
  34. autonomous_agent_algos-0.1.0/docs/guides/large-payloads.md +61 -0
  35. autonomous_agent_algos-0.1.0/docs/guides/llm-gateways.md +196 -0
  36. autonomous_agent_algos-0.1.0/docs/guides/mcp.md +110 -0
  37. autonomous_agent_algos-0.1.0/docs/guides/memory.md +194 -0
  38. autonomous_agent_algos-0.1.0/docs/guides/persistence.md +90 -0
  39. autonomous_agent_algos-0.1.0/docs/guides/privacy.md +170 -0
  40. autonomous_agent_algos-0.1.0/docs/guides/streaming.md +50 -0
  41. autonomous_agent_algos-0.1.0/docs/guides/testing.md +122 -0
  42. autonomous_agent_algos-0.1.0/docs/guides/tool-guard.md +157 -0
  43. autonomous_agent_algos-0.1.0/docs/guides/tools.md +128 -0
  44. autonomous_agent_algos-0.1.0/docs/index.md +107 -0
  45. autonomous_agent_algos-0.1.0/docs/operations/configuration.md +81 -0
  46. autonomous_agent_algos-0.1.0/docs/operations/deployment.md +63 -0
  47. autonomous_agent_algos-0.1.0/docs/operations/performance.md +60 -0
  48. autonomous_agent_algos-0.1.0/docs/operations/security.md +77 -0
  49. autonomous_agent_algos-0.1.0/docs/operations/troubleshooting.md +113 -0
  50. autonomous_agent_algos-0.1.0/docs/reference/api/algos.md +56 -0
  51. autonomous_agent_algos-0.1.0/docs/reference/api/context.md +35 -0
  52. autonomous_agent_algos-0.1.0/docs/reference/api/core.md +43 -0
  53. autonomous_agent_algos-0.1.0/docs/reference/api/data.md +43 -0
  54. autonomous_agent_algos-0.1.0/docs/reference/api/events.md +59 -0
  55. autonomous_agent_algos-0.1.0/docs/reference/api/index.md +18 -0
  56. autonomous_agent_algos-0.1.0/docs/reference/api/llm.md +68 -0
  57. autonomous_agent_algos-0.1.0/docs/reference/api/mcp.md +15 -0
  58. autonomous_agent_algos-0.1.0/docs/reference/api/memory.md +55 -0
  59. autonomous_agent_algos-0.1.0/docs/reference/api/runtime.md +37 -0
  60. autonomous_agent_algos-0.1.0/docs/reference/api/tools.md +27 -0
  61. autonomous_agent_algos-0.1.0/docs/reference/event-catalog.md +82 -0
  62. autonomous_agent_algos-0.1.0/docs/reference/outcomes-and-errors.md +56 -0
  63. autonomous_agent_algos-0.1.0/examples/cluster_client.py +30 -0
  64. autonomous_agent_algos-0.1.0/examples/cluster_worker.py +38 -0
  65. autonomous_agent_algos-0.1.0/examples/context_management.py +66 -0
  66. autonomous_agent_algos-0.1.0/examples/custom_algorithm.py +77 -0
  67. autonomous_agent_algos-0.1.0/examples/data_codecs.py +56 -0
  68. autonomous_agent_algos-0.1.0/examples/ensembles.py +35 -0
  69. autonomous_agent_algos-0.1.0/examples/generate_test_repair.py +42 -0
  70. autonomous_agent_algos-0.1.0/examples/inspect_log.py +35 -0
  71. autonomous_agent_algos-0.1.0/examples/large_payloads.py +42 -0
  72. autonomous_agent_algos-0.1.0/examples/llm_gateways.py +53 -0
  73. autonomous_agent_algos-0.1.0/examples/mcp_tools.py +71 -0
  74. autonomous_agent_algos-0.1.0/examples/memory_agent.py +63 -0
  75. autonomous_agent_algos-0.1.0/examples/model_router.py +58 -0
  76. autonomous_agent_algos-0.1.0/examples/persistence_recovery.py +69 -0
  77. autonomous_agent_algos-0.1.0/examples/plan_and_execute.py +56 -0
  78. autonomous_agent_algos-0.1.0/examples/privacy_tenancy.py +67 -0
  79. autonomous_agent_algos-0.1.0/examples/quickstart.py +38 -0
  80. autonomous_agent_algos-0.1.0/examples/rag_agent.py +43 -0
  81. autonomous_agent_algos-0.1.0/examples/router_supervisor.py +66 -0
  82. autonomous_agent_algos-0.1.0/examples/streaming.py +26 -0
  83. autonomous_agent_algos-0.1.0/examples/testing_replay.py +41 -0
  84. autonomous_agent_algos-0.1.0/examples/tool_approval.py +47 -0
  85. autonomous_agent_algos-0.1.0/examples/tool_guard.py +59 -0
  86. autonomous_agent_algos-0.1.0/examples/workflow_fsm.py +70 -0
  87. autonomous_agent_algos-0.1.0/mkdocs.yml +130 -0
  88. autonomous_agent_algos-0.1.0/pyproject.toml +67 -0
  89. autonomous_agent_algos-0.1.0/scripts/bench_growth.py +82 -0
  90. autonomous_agent_algos-0.1.0/scripts/live_smoke.py +445 -0
  91. autonomous_agent_algos-0.1.0/src/aaa/__init__.py +10 -0
  92. autonomous_agent_algos-0.1.0/src/aaa/algos/__init__.py +26 -0
  93. autonomous_agent_algos-0.1.0/src/aaa/algos/base.py +78 -0
  94. autonomous_agent_algos-0.1.0/src/aaa/algos/control.py +183 -0
  95. autonomous_agent_algos-0.1.0/src/aaa/algos/ensemble.py +173 -0
  96. autonomous_agent_algos-0.1.0/src/aaa/algos/loops.py +333 -0
  97. autonomous_agent_algos-0.1.0/src/aaa/algos/plan.py +265 -0
  98. autonomous_agent_algos-0.1.0/src/aaa/algos/refine.py +163 -0
  99. autonomous_agent_algos-0.1.0/src/aaa/algos/route.py +93 -0
  100. autonomous_agent_algos-0.1.0/src/aaa/context/__init__.py +30 -0
  101. autonomous_agent_algos-0.1.0/src/aaa/context/policy.py +199 -0
  102. autonomous_agent_algos-0.1.0/src/aaa/context/strategies.py +353 -0
  103. autonomous_agent_algos-0.1.0/src/aaa/context/tokens.py +115 -0
  104. autonomous_agent_algos-0.1.0/src/aaa/core/__init__.py +33 -0
  105. autonomous_agent_algos-0.1.0/src/aaa/core/aio.py +50 -0
  106. autonomous_agent_algos-0.1.0/src/aaa/core/errors.py +30 -0
  107. autonomous_agent_algos-0.1.0/src/aaa/core/ids.py +32 -0
  108. autonomous_agent_algos-0.1.0/src/aaa/core/outcome.py +30 -0
  109. autonomous_agent_algos-0.1.0/src/aaa/core/retry.py +152 -0
  110. autonomous_agent_algos-0.1.0/src/aaa/data/__init__.py +27 -0
  111. autonomous_agent_algos-0.1.0/src/aaa/data/blob.py +87 -0
  112. autonomous_agent_algos-0.1.0/src/aaa/data/capabilities.py +40 -0
  113. autonomous_agent_algos-0.1.0/src/aaa/data/codec.py +102 -0
  114. autonomous_agent_algos-0.1.0/src/aaa/data/index.py +115 -0
  115. autonomous_agent_algos-0.1.0/src/aaa/data/item.py +41 -0
  116. autonomous_agent_algos-0.1.0/src/aaa/events/__init__.py +33 -0
  117. autonomous_agent_algos-0.1.0/src/aaa/events/bus.py +277 -0
  118. autonomous_agent_algos-0.1.0/src/aaa/events/cloudevents.py +78 -0
  119. autonomous_agent_algos-0.1.0/src/aaa/events/distributed.py +500 -0
  120. autonomous_agent_algos-0.1.0/src/aaa/events/event.py +81 -0
  121. autonomous_agent_algos-0.1.0/src/aaa/events/guard.py +67 -0
  122. autonomous_agent_algos-0.1.0/src/aaa/events/postgres.py +428 -0
  123. autonomous_agent_algos-0.1.0/src/aaa/events/projection.py +95 -0
  124. autonomous_agent_algos-0.1.0/src/aaa/events/redis.py +361 -0
  125. autonomous_agent_algos-0.1.0/src/aaa/events/schema.py +55 -0
  126. autonomous_agent_algos-0.1.0/src/aaa/events/snapshot.py +24 -0
  127. autonomous_agent_algos-0.1.0/src/aaa/events/sqlite.py +222 -0
  128. autonomous_agent_algos-0.1.0/src/aaa/events/store.py +157 -0
  129. autonomous_agent_algos-0.1.0/src/aaa/llm/__init__.py +45 -0
  130. autonomous_agent_algos-0.1.0/src/aaa/llm/client.py +26 -0
  131. autonomous_agent_algos-0.1.0/src/aaa/llm/config.py +39 -0
  132. autonomous_agent_algos-0.1.0/src/aaa/llm/embedder.py +14 -0
  133. autonomous_agent_algos-0.1.0/src/aaa/llm/errors.py +41 -0
  134. autonomous_agent_algos-0.1.0/src/aaa/llm/factory.py +30 -0
  135. autonomous_agent_algos-0.1.0/src/aaa/llm/fake.py +93 -0
  136. autonomous_agent_algos-0.1.0/src/aaa/llm/gateways.py +75 -0
  137. autonomous_agent_algos-0.1.0/src/aaa/llm/handler.py +257 -0
  138. autonomous_agent_algos-0.1.0/src/aaa/llm/litellm_client.py +119 -0
  139. autonomous_agent_algos-0.1.0/src/aaa/llm/middleware.py +113 -0
  140. autonomous_agent_algos-0.1.0/src/aaa/llm/openai_compat.py +261 -0
  141. autonomous_agent_algos-0.1.0/src/aaa/llm/streaming.py +36 -0
  142. autonomous_agent_algos-0.1.0/src/aaa/llm/types.py +70 -0
  143. autonomous_agent_algos-0.1.0/src/aaa/mcp/__init__.py +6 -0
  144. autonomous_agent_algos-0.1.0/src/aaa/mcp/client.py +364 -0
  145. autonomous_agent_algos-0.1.0/src/aaa/mcp/memory.py +125 -0
  146. autonomous_agent_algos-0.1.0/src/aaa/memory/__init__.py +46 -0
  147. autonomous_agent_algos-0.1.0/src/aaa/memory/base.py +96 -0
  148. autonomous_agent_algos-0.1.0/src/aaa/memory/callable.py +152 -0
  149. autonomous_agent_algos-0.1.0/src/aaa/memory/fake.py +116 -0
  150. autonomous_agent_algos-0.1.0/src/aaa/memory/graphiti.py +180 -0
  151. autonomous_agent_algos-0.1.0/src/aaa/memory/handler.py +226 -0
  152. autonomous_agent_algos-0.1.0/src/aaa/memory/langgraph.py +179 -0
  153. autonomous_agent_algos-0.1.0/src/aaa/memory/mem0.py +158 -0
  154. autonomous_agent_algos-0.1.0/src/aaa/memory/native.py +177 -0
  155. autonomous_agent_algos-0.1.0/src/aaa/memory/supermemory.py +264 -0
  156. autonomous_agent_algos-0.1.0/src/aaa/memory/tools.py +76 -0
  157. autonomous_agent_algos-0.1.0/src/aaa/memory/types.py +138 -0
  158. autonomous_agent_algos-0.1.0/src/aaa/privacy.py +264 -0
  159. autonomous_agent_algos-0.1.0/src/aaa/py.typed +0 -0
  160. autonomous_agent_algos-0.1.0/src/aaa/runtime/__init__.py +18 -0
  161. autonomous_agent_algos-0.1.0/src/aaa/runtime/budget.py +57 -0
  162. autonomous_agent_algos-0.1.0/src/aaa/runtime/engine.py +834 -0
  163. autonomous_agent_algos-0.1.0/src/aaa/runtime/recovery.py +136 -0
  164. autonomous_agent_algos-0.1.0/src/aaa/runtime/retention.py +171 -0
  165. autonomous_agent_algos-0.1.0/src/aaa/runtime/tenancy.py +106 -0
  166. autonomous_agent_algos-0.1.0/src/aaa/tools/__init__.py +29 -0
  167. autonomous_agent_algos-0.1.0/src/aaa/tools/guard.py +104 -0
  168. autonomous_agent_algos-0.1.0/src/aaa/tools/handler.py +436 -0
  169. autonomous_agent_algos-0.1.0/src/aaa/tools/rag.py +28 -0
  170. autonomous_agent_algos-0.1.0/src/aaa/tools/tool.py +225 -0
  171. autonomous_agent_algos-0.1.0/src/aaa/validate/__init__.py +79 -0
  172. autonomous_agent_algos-0.1.0/tests/cluster.py +101 -0
  173. autonomous_agent_algos-0.1.0/tests/conftest.py +219 -0
  174. autonomous_agent_algos-0.1.0/tests/helpers/mcp_server.py +93 -0
  175. autonomous_agent_algos-0.1.0/tests/helpers/memory_stubs.py +382 -0
  176. autonomous_agent_algos-0.1.0/tests/helpers/victim.py +46 -0
  177. autonomous_agent_algos-0.1.0/tests/helpers/worker.py +70 -0
  178. autonomous_agent_algos-0.1.0/tests/unit/test_aio.py +96 -0
  179. autonomous_agent_algos-0.1.0/tests/unit/test_algos.py +372 -0
  180. autonomous_agent_algos-0.1.0/tests/unit/test_cluster_engine.py +222 -0
  181. autonomous_agent_algos-0.1.0/tests/unit/test_context.py +423 -0
  182. autonomous_agent_algos-0.1.0/tests/unit/test_data.py +49 -0
  183. autonomous_agent_algos-0.1.0/tests/unit/test_distributed_bus.py +288 -0
  184. autonomous_agent_algos-0.1.0/tests/unit/test_docs_snippets.py +40 -0
  185. autonomous_agent_algos-0.1.0/tests/unit/test_engine.py +95 -0
  186. autonomous_agent_algos-0.1.0/tests/unit/test_events.py +104 -0
  187. autonomous_agent_algos-0.1.0/tests/unit/test_examples.py +163 -0
  188. autonomous_agent_algos-0.1.0/tests/unit/test_growth.py +276 -0
  189. autonomous_agent_algos-0.1.0/tests/unit/test_llm.py +313 -0
  190. autonomous_agent_algos-0.1.0/tests/unit/test_loops.py +216 -0
  191. autonomous_agent_algos-0.1.0/tests/unit/test_mcp.py +267 -0
  192. autonomous_agent_algos-0.1.0/tests/unit/test_memory_adapters.py +253 -0
  193. autonomous_agent_algos-0.1.0/tests/unit/test_memory_contract.py +250 -0
  194. autonomous_agent_algos-0.1.0/tests/unit/test_memory_runtime.py +278 -0
  195. autonomous_agent_algos-0.1.0/tests/unit/test_memory_signatures.py +137 -0
  196. autonomous_agent_algos-0.1.0/tests/unit/test_multiprocess.py +235 -0
  197. autonomous_agent_algos-0.1.0/tests/unit/test_privacy.py +327 -0
  198. autonomous_agent_algos-0.1.0/tests/unit/test_recovery.py +353 -0
  199. autonomous_agent_algos-0.1.0/tests/unit/test_servers_smoke.py +10 -0
  200. autonomous_agent_algos-0.1.0/tests/unit/test_snapshots.py +172 -0
  201. autonomous_agent_algos-0.1.0/tests/unit/test_storage.py +50 -0
  202. autonomous_agent_algos-0.1.0/tests/unit/test_store_contract.py +267 -0
  203. autonomous_agent_algos-0.1.0/tests/unit/test_store_outage.py +373 -0
  204. autonomous_agent_algos-0.1.0/tests/unit/test_store_outage_cluster.py +211 -0
  205. autonomous_agent_algos-0.1.0/tests/unit/test_tool_guard.py +445 -0
  206. autonomous_agent_algos-0.1.0/uv.lock +4340 -0
@@ -0,0 +1,103 @@
1
+ name: ci
2
+
3
+ # Lint + type-check, then the full test suite against REAL Postgres and Redis, on Python 3.11 and 3.12.
4
+ # (Docs have their own workflow, docs.yml, which also runs the docs tests before publishing.)
5
+
6
+ on:
7
+ push:
8
+ branches: [master]
9
+ pull_request:
10
+ workflow_dispatch:
11
+ schedule:
12
+ - cron: "17 5 * * 1" # weekly: do the memory libraries' newest releases still match our adapters?
13
+
14
+ permissions:
15
+ contents: read
16
+
17
+ concurrency:
18
+ group: ci-${{ github.ref }}
19
+ cancel-in-progress: true
20
+
21
+ jobs:
22
+ lint:
23
+ runs-on: ubuntu-latest
24
+ timeout-minutes: 10
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+ - uses: astral-sh/setup-uv@v5
28
+ with:
29
+ enable-cache: true
30
+ - run: uv sync --frozen
31
+ - name: ruff (lint)
32
+ run: uv run ruff check .
33
+ - name: ruff (format)
34
+ run: uv run ruff format --check .
35
+ - name: pyright (src, examples, scripts)
36
+ run: uv run pyright
37
+
38
+ test:
39
+ runs-on: ubuntu-latest
40
+ timeout-minutes: 15
41
+ strategy:
42
+ fail-fast: false
43
+ matrix:
44
+ python: ["3.11", "3.12"]
45
+ services:
46
+ postgres:
47
+ image: postgres:16
48
+ env:
49
+ POSTGRES_PASSWORD: aaa
50
+ ports: ["5432:5432"]
51
+ options: >-
52
+ --health-cmd "pg_isready -U postgres"
53
+ --health-interval 5s
54
+ --health-timeout 5s
55
+ --health-retries 10
56
+ redis:
57
+ image: redis:7
58
+ ports: ["6379:6379"]
59
+ options: >-
60
+ --health-cmd "redis-cli ping"
61
+ --health-interval 5s
62
+ --health-timeout 5s
63
+ --health-retries 10
64
+ env:
65
+ # The suite creates a throwaway database per test and isolates Redis by key prefix.
66
+ AAA_TEST_POSTGRES_URL: postgresql://postgres:aaa@localhost:5432/postgres
67
+ AAA_TEST_REDIS_URL: redis://localhost:6379/0
68
+ steps:
69
+ - uses: actions/checkout@v4
70
+ - uses: astral-sh/setup-uv@v5
71
+ with:
72
+ enable-cache: true
73
+ python-version: ${{ matrix.python }}
74
+ - run: uv sync --frozen
75
+ - name: tests
76
+ # -v names every test, and a test stuck for 2 minutes dumps all thread stacks, so a hang is
77
+ # diagnosable from the log instead of just a cancelled job.
78
+ run: uv run pytest -v -p no:cacheprovider -o faulthandler_timeout=120
79
+
80
+ adapters:
81
+ # The memory adapters are tested against stand-ins; this job replays their calls against the REAL
82
+ # Mem0, Graphiti and LangGraph signatures (tests/unit/test_memory_signatures.py), which are skipped
83
+ # in the main job because those libraries are not dev dependencies.
84
+ runs-on: ubuntu-latest
85
+ timeout-minutes: 15
86
+ steps:
87
+ - uses: actions/checkout@v4
88
+ - uses: astral-sh/setup-uv@v5
89
+ with:
90
+ enable-cache: true
91
+ - name: Locked versions
92
+ run: |
93
+ uv sync --frozen --extra mem0 --extra graphiti --extra langgraph --extra langmem --extra mcp
94
+ uv run pytest -v -p no:cacheprovider tests/unit/test_memory_signatures.py tests/unit/test_memory_adapters.py tests/unit/test_memory_contract.py tests/unit/test_mcp.py tests/unit/test_examples.py -k "not cluster"
95
+ - name: MCP SDK 1.x (the lock resolves 2.x; both are supported)
96
+ run: |
97
+ uv pip install "mcp<2"
98
+ uv run --no-sync pytest -v -p no:cacheprovider tests/unit/test_mcp.py
99
+ - name: Newest releases (scheduled and manual runs only)
100
+ if: github.event_name != 'pull_request' && github.event_name != 'push'
101
+ run: |
102
+ uv pip install --upgrade mem0ai graphiti-core langgraph langmem mcp
103
+ uv run --no-sync pytest -v -p no:cacheprovider tests/unit/test_memory_signatures.py tests/unit/test_mcp.py
@@ -0,0 +1,63 @@
1
+ name: docs
2
+
3
+ # Builds the documentation (strictly) and publishes it to GitHub Pages on every push to master that
4
+ # touches the docs, the examples they embed, the source their API reference is generated from, or
5
+ # this workflow. A broken example or an invalid fragment blocks publishing.
6
+
7
+ on:
8
+ push:
9
+ branches: [master]
10
+ paths:
11
+ - "docs/**"
12
+ - "examples/**"
13
+ - "src/**"
14
+ - "mkdocs.yml"
15
+ - "pyproject.toml"
16
+ - "uv.lock"
17
+ - "LICENSE"
18
+ - ".github/workflows/docs.yml"
19
+ workflow_dispatch:
20
+
21
+ permissions:
22
+ contents: read
23
+ pages: write
24
+ id-token: write
25
+
26
+ concurrency:
27
+ group: pages
28
+ cancel-in-progress: false
29
+
30
+ jobs:
31
+ build:
32
+ runs-on: ubuntu-latest
33
+ steps:
34
+ - uses: actions/checkout@v4
35
+
36
+ - uses: astral-sh/setup-uv@v5
37
+ with:
38
+ enable-cache: true
39
+
40
+ - name: Install (docs extra + dev group)
41
+ run: uv sync --extra docs --frozen
42
+
43
+ - name: Every embedded example runs, and every inline fragment is valid Python
44
+ run: uv run pytest -q -p no:cacheprovider tests/unit/test_examples.py tests/unit/test_docs_snippets.py
45
+
46
+ - name: "Build (strict - warnings fail the build)"
47
+ run: uv run mkdocs build --strict
48
+
49
+ - uses: actions/configure-pages@v5
50
+
51
+ - uses: actions/upload-pages-artifact@v3
52
+ with:
53
+ path: site
54
+
55
+ deploy:
56
+ needs: build
57
+ runs-on: ubuntu-latest
58
+ environment:
59
+ name: github-pages
60
+ url: ${{ steps.deployment.outputs.page_url }}
61
+ steps:
62
+ - id: deployment
63
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,111 @@
1
+ name: release
2
+
3
+ # Publishes to PyPI when a GitHub Release is published, using PyPI "Trusted Publishing" (OIDC): no API
4
+ # token is stored in this repository. One-time setup is described in docs/about/contributing.md.
5
+ #
6
+ # * publish a GitHub Release tagged vX.Y.Z -> builds, verifies, publishes to PyPI
7
+ # * run manually (workflow_dispatch) -> builds, verifies, publishes to TestPyPI (a dry run)
8
+
9
+ on:
10
+ release:
11
+ types: [published]
12
+ workflow_dispatch:
13
+
14
+ permissions:
15
+ contents: read
16
+
17
+ jobs:
18
+ build:
19
+ runs-on: ubuntu-latest
20
+ timeout-minutes: 15
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+ - uses: astral-sh/setup-uv@v5
24
+ - name: Tag matches the package version
25
+ if: github.event_name == 'release'
26
+ run: |
27
+ tag="${GITHUB_REF_NAME#v}"
28
+ version="$(uv run --no-project python -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")"
29
+ if [ "$tag" != "$version" ]; then
30
+ echo "::error::release tag '$GITHUB_REF_NAME' does not match pyproject version '$version'"
31
+ exit 1
32
+ fi
33
+ - name: Build sdist and wheel
34
+ run: uv build
35
+ - name: Check metadata and README rendering
36
+ run: uvx twine check --strict dist/*
37
+ - name: The built wheel installs and runs in a clean environment
38
+ run: |
39
+ uv venv /tmp/smoke --python 3.12
40
+ uv pip install --python /tmp/smoke/bin/python dist/*.whl
41
+ /tmp/smoke/bin/python -I examples/quickstart.py | grep -q "success - 17 x 23 = 391"
42
+ /tmp/smoke/bin/python -I -c "import aaa; print('aaa', aaa.__version__)"
43
+ - uses: actions/upload-artifact@v4
44
+ with:
45
+ name: dist
46
+ path: dist/
47
+ if-no-files-found: error
48
+
49
+ test:
50
+ # The release gate: the same checks as CI, on the commit being released.
51
+ needs: build
52
+ runs-on: ubuntu-latest
53
+ timeout-minutes: 20
54
+ services:
55
+ postgres:
56
+ image: postgres:16
57
+ env:
58
+ POSTGRES_PASSWORD: aaa
59
+ ports: ["5432:5432"]
60
+ options: >-
61
+ --health-cmd "pg_isready -U postgres" --health-interval 5s --health-timeout 5s --health-retries 10
62
+ redis:
63
+ image: redis:7
64
+ ports: ["6379:6379"]
65
+ options: >-
66
+ --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 5s --health-retries 10
67
+ env:
68
+ AAA_TEST_POSTGRES_URL: postgresql://postgres:aaa@localhost:5432/postgres
69
+ AAA_TEST_REDIS_URL: redis://localhost:6379/0
70
+ steps:
71
+ - uses: actions/checkout@v4
72
+ - uses: astral-sh/setup-uv@v5
73
+ with:
74
+ enable-cache: true
75
+ - run: uv sync --frozen
76
+ - run: uv run ruff check . && uv run ruff format --check . && uv run pyright
77
+ - run: uv run pytest -v -p no:cacheprovider -o faulthandler_timeout=120
78
+
79
+ publish-pypi:
80
+ if: github.event_name == 'release'
81
+ needs: [build, test]
82
+ runs-on: ubuntu-latest
83
+ environment:
84
+ name: pypi
85
+ url: https://pypi.org/p/autonomous-agent-algos
86
+ permissions:
87
+ id-token: write # required for Trusted Publishing
88
+ steps:
89
+ - uses: actions/download-artifact@v4
90
+ with:
91
+ name: dist
92
+ path: dist/
93
+ - uses: pypa/gh-action-pypi-publish@release/v1
94
+
95
+ publish-testpypi:
96
+ if: github.event_name == 'workflow_dispatch'
97
+ needs: [build, test]
98
+ runs-on: ubuntu-latest
99
+ environment:
100
+ name: testpypi
101
+ url: https://test.pypi.org/p/autonomous-agent-algos
102
+ permissions:
103
+ id-token: write
104
+ steps:
105
+ - uses: actions/download-artifact@v4
106
+ with:
107
+ name: dist
108
+ path: dist/
109
+ - uses: pypa/gh-action-pypi-publish@release/v1
110
+ with:
111
+ repository-url: https://test.pypi.org/legacy/
@@ -0,0 +1,7 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.egg-info/
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ site/
7
+ dist/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Innerkore Technologies
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,276 @@
1
+ Metadata-Version: 2.4
2
+ Name: autonomous-agent-algos
3
+ Version: 0.1.0
4
+ Summary: Async, event-driven library of production-deployable agent algorithms over arbitrary data.
5
+ Project-URL: Homepage, https://github.com/innerkorehq/AutonomousAgentAlgos
6
+ Project-URL: Documentation, https://innerkorehq.github.io/AutonomousAgentAlgos/
7
+ Project-URL: Source, https://github.com/innerkorehq/AutonomousAgentAlgos
8
+ Project-URL: Issues, https://github.com/innerkorehq/AutonomousAgentAlgos/issues
9
+ Author: Innerkore Technologies
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: agents,asyncio,event-sourcing,llm,planning,react,tool-calling,workflow
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Framework :: AsyncIO
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.11
22
+ Requires-Dist: anyio>=4.4
23
+ Requires-Dist: httpx>=0.27
24
+ Requires-Dist: pydantic>=2.7
25
+ Provides-Extra: docs
26
+ Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
27
+ Requires-Dist: mkdocs<2,>=1.6; extra == 'docs'
28
+ Requires-Dist: mkdocstrings[python]>=0.26; extra == 'docs'
29
+ Provides-Extra: graphiti
30
+ Requires-Dist: graphiti-core>=0.30; extra == 'graphiti'
31
+ Provides-Extra: langgraph
32
+ Requires-Dist: langgraph>=1.0; extra == 'langgraph'
33
+ Provides-Extra: langmem
34
+ Requires-Dist: langgraph>=1.0; extra == 'langmem'
35
+ Requires-Dist: langmem>=0.0.30; extra == 'langmem'
36
+ Provides-Extra: litellm
37
+ Requires-Dist: litellm; extra == 'litellm'
38
+ Provides-Extra: mcp
39
+ Requires-Dist: mcp<3,>=1.12; extra == 'mcp'
40
+ Provides-Extra: mem0
41
+ Requires-Dist: mem0ai>=2.0; extra == 'mem0'
42
+ Provides-Extra: postgres
43
+ Requires-Dist: asyncpg>=0.29; extra == 'postgres'
44
+ Provides-Extra: redis
45
+ Requires-Dist: redis>=5.0; extra == 'redis'
46
+ Description-Content-Type: text/markdown
47
+
48
+ # AutonomousAgentAlgos (AAA)
49
+
50
+ Async, **event-driven** library of production-deployable agent algorithms that run over
51
+ **arbitrary user data**, with a pluggable LLM gateway layer.
52
+
53
+ **Documentation: <https://innerkorehq.github.io/AutonomousAgentAlgos/>** — quickstart, concepts, guides for every
54
+ algorithm, clustering, the tool execution guard, operations, security, API reference, and an honest
55
+ [status and limitations](https://innerkorehq.github.io/AutonomousAgentAlgos/about/limitations/) page.
56
+ The README below is a condensed overview; the docs are the reference.
57
+
58
+ ```python
59
+ async with Engine() as eng:
60
+ LLMHandler(build_client(gateways.portkey("gpt-4o"))).attach(eng)
61
+ ToolHandler(registry).attach(eng)
62
+ outcome = await eng.run(
63
+ ToolLoop(registry), {"task": "..."}, budget=Budget(max_cost=0.50, deadline_s=60)
64
+ )
65
+ ```
66
+
67
+ ## Design decisions (data first)
68
+ 1. **The event log is the source of truth.** Every run is an append-only stream of immutable
69
+ CloudEvents-compatible `Event`s. State, plans, conversation, spend are folds of the log.
70
+ Algorithms hold *no* run state, so runs replay, resume and audit by construction.
71
+ 2. **User data is a payload, never the algorithm's type.** `Item[T]` + per-`kind` `Codec`
72
+ (Pydantic / dataclass / dict / str / custom `FunctionCodec`) render, serialize and
73
+ fingerprint any type. Algorithms ask only for the capabilities they need.
74
+ 3. **Large payloads are claim-checked** into a content-addressed `BlobStore`; events stay small.
75
+ Handlers and algorithms see hydrated data transparently.
76
+ 4. **Failures are facts, not exceptions.** `aaa.llm.failed`, `aaa.tool.failed` are events the
77
+ algorithm reasons about. Outcomes are distinct: success / no_solution / timeout /
78
+ budget_exceeded / invalid_input / cancelled / failed.
79
+ 5. **Safety lives outside the model**: budgets, deadlines, approval gates, and idempotency are
80
+ enforced by the Engine/ToolHandler, not by prompts.
81
+ 6. **Ordering**: each algorithm sees its events serially in log order; delivery is in-process
82
+ at-most-once (distributed at-least-once adapters are future work).
83
+ 7. **Durable and crash-resumable.** `SQLiteEventStore` (stdlib, WAL, atomic OCC append,
84
+ idempotent on event id) persists the log. After a crash, `engine.recover([...algorithms])`
85
+ rebuilds budgets, spend and deadlines from the log, then redelivers events nothing reacted to.
86
+ This is safe because algorithms decide from folded state, and every derived event has a
87
+ deterministic id, so a repeated reaction is absorbed by the store instead of duplicating.
88
+
89
+ ## MCP and context management
90
+ `aaa.mcp.MCPClient` connects to any MCP server (stdio, HTTP, or your own session; mcp SDK 1.x and 2.x) and turns its tools into guarded AAA tools,
91
+ with MCP's annotations driving the retry/approval policy. `LLMHandler(client, context=ContextPolicy(max_input_tokens=...))` keeps long runs inside the
92
+ model's window by clearing old tool output, summarizing old turns (summaries are persisted events) or dropping them, without rewriting the log.
93
+
94
+ ## Long-term memory
95
+ `aaa.memory` gives agents memory across runs behind one small protocol, with adapters for **Mem0**, **Graphiti** (Zep's engine),
96
+ **Supermemory** and **LangGraph/LangMem** stores, a built-in `NativeMemory`, and `CallableMemory` to wrap any other library.
97
+ Memory is scoped by the run's tenant and user (never by model output), goes through the event log (replayable, redacted), and
98
+ is erasable per user.
99
+ ```python
100
+ MemoryHandler(Mem0Memory(AsyncMemory()), write_back=WriteBack()).attach(engine)
101
+ algo = ToolLoop(registry, recall=True) # recall before the first model call
102
+ await engine.tenant("acme").run(algo, {"task": "..."}, user="ann")
103
+ ```
104
+
105
+ ## Layout
106
+ `core` ids/outcomes/errors · `events` envelope, stores (memory/SQLite/Postgres/Redis), buses (in-process/distributed), projections+snapshots, schemas,
107
+ CloudEvents · `data` Item/Codec/BlobStore/Index · `llm` client protocol, OpenAI-compatible
108
+ adapter + gateway presets, LiteLLM, retry/breaker, streaming, fakes · `tools` typed registry +
109
+ handler · `validate` deterministic validators · `runtime` Engine/Budget · `algos`.
110
+
111
+ ## Algorithms (v0.1)
112
+ ToolLoop, ReAct, PlanAndExecute (DAG, parallel child runs, replan), Router, GenerateTestRepair,
113
+ GeneratorCritic, WorkflowGraph (deterministic DAG), FSM, SelfConsistency, RAGAgent, Supervisor.
114
+
115
+ ## Persistence, snapshots, and running as a cluster
116
+
117
+ | Store | Use for | Notes |
118
+ |---|---|---|
119
+ | `InMemoryEventStore` | tests, notebooks | nothing survives the process |
120
+ | `SQLiteEventStore` | one machine, durable | stdlib, WAL; single engine process |
121
+ | `PostgresEventStore` | production system of record | `pip install autonomous-agent-algos[postgres]` |
122
+ | `RedisEventStore` | low-latency, ephemeral-ish logs | `[redis]`; durability = your Redis AOF settings |
123
+
124
+ **Single process, restart safe** (`InProcessBus` + a durable store):
125
+ ```python
126
+ async with Engine(store=SQLiteEventStore("agent.db")) as eng:
127
+ LLMHandler(client).attach(eng)
128
+ ToolHandler(registry).attach(eng)
129
+ handles = await eng.recover([ToolLoop(registry), PlanAndExecute(...)]) # after a crash
130
+ ```
131
+
132
+ **Multi-process** (`DistributedBus` over Postgres or Redis; run the same worker code N times):
133
+ ```python
134
+ store = await PostgresEventStore.create(DSN, partitions=16) # or RedisEventStore.create(URL, ...)
135
+ bus = DistributedBus(store.bus_backend())
136
+ async with Engine(store=store, bus=bus, sweep_interval_s=5) as eng:
137
+ LLMHandler(client).attach(eng)
138
+ ToolHandler(registry).attach(eng)
139
+ eng.register(ToolLoop(registry))
140
+ await asyncio.Event().wait() # a worker
141
+ # anywhere else (API server, CLI): submit and observe only
142
+ client = Engine(store=store, bus=ClientBus())
143
+ outcome = await client.run(ToolLoop(registry), {"task": "..."})
144
+ ```
145
+ How it works: an event is appended to the store *and* the bus outbox in one atomic step (a
146
+ transaction in Postgres, one Lua script in Redis), so nothing stored can fail to be published. Events
147
+ go to partition `crc32(run_id) % P`. Within a consumer *group* (an algorithm, the LLM handler, the
148
+ tool handler...) each partition is owned by exactly one process at a time, consumed in order, and
149
+ acknowledged with a cursor; processes joining or dying rebalance partitions. Delivery is
150
+ at-least-once; derived events have deterministic ids and results are one-per-request
151
+ (`<request id>:result`), so repeats are absorbed by the store's idempotent append. Any process can
152
+ host any run: engine state (spend, completion, open children) is a fold of the log, rebuilt on
153
+ demand from a snapshot plus the tail.
154
+
155
+ **Snapshots**: every algorithm's state is an incremental `Projection`; state is snapshotted every 64
156
+ events and a load costs O(new events). A 40-turn run does ~16x fewer state folds, and the gap
157
+ grows with run length. A snapshot is derived data: a corrupt, stale-versioned, or too-new one is
158
+ ignored and the state is replayed from the log. Bump a projection's `version` if you change its fold.
159
+
160
+ ### Tool execution guard (stalled and crashed workers)
161
+ Bus delivery is at-least-once, and a worker can die or stall (GC pause, VM freeze, network partition)
162
+ while a tool call is running. Three layers protect against a repeated side effect; each is configurable.
163
+
164
+ | Layer | What it does |
165
+ |---|---|
166
+ | **Durable ack** | The request stays unacknowledged on the bus until the tool finishes, so a worker that dies mid-call has the call redelivered to another. |
167
+ | **Exclusion** | A per-call execution lease with a heartbeat: two workers never run the same call concurrently while the first is alive. |
168
+ | **Fencing** | Every run is a numbered attempt recorded *before* it executes (`aaa.tool.started`, id `<request>:attempt:<n>`). A worker that loses its lease cancels its tool and records nothing; a result from a superseded attempt is rejected (`aaa.tool.stale_result`). |
169
+ | **Effect safety** | The tool receives `ctx.idempotency_key` (stable across attempts and workers), `ctx.attempt` and `ctx.fence` to make the external effect idempotent. |
170
+
171
+ ```python
172
+ from aaa.tools import GuardConfig, ToolContext, ToolHandler, tool
173
+
174
+ # global default for every tool
175
+ ToolHandler(registry, guard=GuardConfig(lease_ttl_s=30, max_attempts=3)).attach(engine)
176
+
177
+
178
+ @tool # inherits the default: re-run a lost call, up to 3 attempts
179
+ async def search(q: str) -> list: ...
180
+
181
+
182
+ @tool(delivery="at_most_once") # never re-run once an attempt started
183
+ async def send_email(to: str, body: str, ctx: ToolContext) -> str:
184
+ return await ses.send(to, body, dedupe_key=ctx.idempotency_key)
185
+
186
+
187
+ @tool(
188
+ idempotency_key=lambda a: f"refund:{a['order_id']}", # business-level key, stable across
189
+ guard={"max_attempts": 1, "lease_ttl_s": 60},
190
+ ) # the model re-issuing the call
191
+ async def refund(order_id: str, ctx: ToolContext) -> str: ...
192
+ ```
193
+
194
+ | `GuardConfig` field | Default | Meaning |
195
+ |---|---|---|
196
+ | `enabled` | `True` | `False`: no lease, no attempt records (the bus still redelivers a lost request, so a tool can run twice and nothing notices). |
197
+ | `delivery` | `at_least_once` | `at_least_once`: re-run a lost call up to `max_attempts`. `at_most_once`: a lost attempt becomes an `OutcomeUnknown` failure (the effect may or may not have happened) for the algorithm or a human to reconcile. |
198
+ | `max_attempts` | `3` | Cap on executions of one call; beyond it the call fails with `ExecutionAbandoned` (a poison call must not loop forever). |
199
+ | `lease_ttl_s` / `heartbeat_s` | `15` / `ttl/3` | How long a silent worker keeps its claim / how often it renews. Lower = faster takeover but more false positives from slow heartbeats. |
200
+ | `wait_poll_s` | `0.5` | How often a worker that found the call busy re-checks. |
201
+ | `on_lost_lease` | `cancel` | `cancel`: a worker that wakes up and finds it lost the lease stops its tool. `finish`: let it complete (its result is still fenced). |
202
+ | `fence_results` | `True` | Reject (and audit) a result from a superseded attempt. `False`: the first finisher wins. |
203
+
204
+ Per-tool settings override the handler default; inconsistent combinations (e.g. `heartbeat_s >= lease_ttl_s`)
205
+ fail at startup. **Backend semantics differ**: Redis and in-memory leases expire by TTL, so a *frozen*
206
+ worker is replaced after `lease_ttl_s`. Postgres leases are advisory locks bound to the database session:
207
+ a worker that crashes or loses its connection frees them instantly, but one that is frozen *and still
208
+ connected* keeps them, so nobody takes over until it resumes or the connection dies (use TCP keepalives /
209
+ `idle_session_timeout`, or Redis, if you need TTL takeover of frozen processes). The fence check
210
+ (`has(attempt n+1)` then append) is not one atomic store operation; its residual window is microseconds
211
+ and the result id is first-writer-wins, so the worst case is one recorded result, never two.
212
+
213
+ ### Guarantees and caveats (read these)
214
+ - **Tool execution is guarded, and the guard is configurable** (next section). The library makes a
215
+ call run *at most once at a time* and *record exactly one result*; it cannot make an arbitrary
216
+ external effect (an email, a payment) exactly-once. That part belongs to the tool, via the
217
+ idempotency key the guard hands it.
218
+ - **Partition count is fixed** for the life of a cluster (checked on connect). Changing it needs a new
219
+ cluster or migration. Pick headroom (default 16).
220
+ - **Algorithm names must be unique and identical on every worker**, and every worker in a group must
221
+ register the same tools. Heterogeneous worker pools are not supported yet.
222
+ - **Outbox growth**: the bus log is not trimmed automatically. Call `store.trim_outbox(keep_last=...)`
223
+ from a periodic job, sized to your longest tolerable consumer outage.
224
+ - **Postgres**: a dropped LISTEN connection degrades latency to polling, never correctness. Appends to
225
+ the same partition serialize on one row lock (P-way write parallelism).
226
+ - **Redis**: with no persistence a restart loses the log. Works with Redis Cluster (hash-tagged keys)
227
+ but is only tested on a single node.
228
+ - Each consumer group scans all events of its partitions (read amplification ~ number of groups).
229
+ - Algorithms' `Engine.sweep()` (set `sweep_interval_s`) enforces deadlines of dead owners and repairs
230
+ lost child announcements; without it a run with a deadline whose host died waits for its next event.
231
+ - Tested with real separate OS processes and `SIGKILL` (including mid-tool-call) on Postgres and Redis;
232
+ not yet load tested.
233
+
234
+ ## Scaling with run length
235
+ A continuing LLM request stores only the *new* messages plus a pointer to the previous request
236
+ (`conv: {prev, delta}`); algorithm state holds a request id, not the transcript. The LLM handler
237
+ rebuilds the full transcript the provider needs from an in-memory cache, falling back to one pass
238
+ over the run's log after a restart/failover/different worker. Tool-call idempotency is an O(1)
239
+ `store.has(stream, id)` lookup. `scripts/bench_growth.py` (SQLite, fake LLM, ~400-byte tool results):
240
+
241
+ | turns | log size before -> after | wall time before -> after |
242
+ |---|---|---|
243
+ | 50 | 999 KB -> 170 KB | 0.22 s -> 0.07 s |
244
+ | 100 | 3,667 KB -> 337 KB | 1.17 s -> 0.14 s |
245
+ | 200 | 14,032 KB -> 673 KB | 7.53 s -> 0.28 s |
246
+ | 400 | (not measured) -> 1,344 KB | -> 0.56 s |
247
+
248
+ Log size, state size and per-turn work are now constant per turn (doubling the turns doubles the
249
+ totals). What is *not* reduced is the provider payload itself: each call must still send the whole
250
+ transcript, so token cost per call grows with the conversation. Use provider prompt caching or
251
+ summarization for very long conversations. Custom algorithms should build continuing requests with
252
+ `llm_request(..., prev=<previous request id>)` and pass only the new messages.
253
+
254
+ ## Live gateway smoke test
255
+ `scripts/live_smoke.py` checks the library against a real OpenAI-compatible endpoint: completion +
256
+ usage, streaming, structured output, native tool calls (also streamed), a full ToolLoop through the
257
+ Engine, PlanAndExecute with a real planner, generate-test-repair, delta events, and error mapping
258
+ (unknown model, bad key, unreachable host). It spends a few thousand tokens. Configure with env vars:
259
+ ```bash
260
+ AAA_LIVE_BASE_URL=http://127.0.0.1:11434/v1 AAA_LIVE_MODEL=gemma4:latest uv run python scripts/live_smoke.py
261
+ # a cloud gateway: use the base URL / headers from aaa.llm.gateways, e.g. Portkey
262
+ AAA_LIVE_BASE_URL=https://api.portkey.ai/v1 AAA_LIVE_MODEL=gpt-4o-mini AAA_LIVE_API_KEY=$OPENAI_API_KEY \
263
+ AAA_LIVE_HEADERS='{"x-portkey-api-key": "...", "x-portkey-provider": "openai"}' uv run python scripts/live_smoke.py
264
+ ```
265
+ Verified so far: a local Ollama (`gemma4:latest`, 8B) — 11/11 applicable checks. Not yet verified
266
+ against any hosted gateway (Portkey, Cloudflare, Vercel, Bifrost, Kong, MLflow, LiteLLM proxy): their
267
+ base URLs and headers follow vendor docs and are covered only by mocked-transport tests.
268
+
269
+ ## Known limitations
270
+ - No sandboxed code-execution validator is shipped (deliberately).
271
+ - Structured-output `strict` mode may need schema adjustments per provider.
272
+ - Only a local Ollama has been tested live; hosted gateways are untested (see above).
273
+
274
+ ## License
275
+
276
+ [MIT](https://github.com/innerkorehq/AutonomousAgentAlgos/blob/master/LICENSE) © 2026 Innerkore Technologies.