agentforge-py 0.2.3__tar.gz → 0.3.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 (240) hide show
  1. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/.gitignore +10 -0
  2. agentforge_py-0.3.0/PKG-INFO +158 -0
  3. agentforge_py-0.3.0/pyproject.toml +189 -0
  4. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/_tools/decorator.py +9 -1
  5. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/agent.py +10 -1
  6. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/_build.py +168 -19
  7. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/_shared_scaffold.py +3 -1
  8. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/config_cmd.py +9 -0
  9. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/db_cmd.py +1 -1
  10. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/debug_cmd.py +1 -1
  11. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/health_cmd.py +3 -0
  12. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/module_cmd.py +52 -4
  13. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/new_cmd.py +7 -2
  14. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/run_cmd.py +28 -3
  15. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/strategies/_base.py +22 -11
  16. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/strategies/react.py +17 -2
  17. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/AGENTS.md.tmpl +3 -2
  18. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/02-add-a-tool.md +5 -0
  19. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/13-configure-multi-provider.md +39 -0
  20. agentforge_py-0.3.0/tests/conftest.py +25 -0
  21. agentforge_py-0.3.0/tests/integration/test_add_module_uv_live.py +101 -0
  22. agentforge_py-0.3.0/tests/integration/test_configured_runtime_e2e.py +107 -0
  23. agentforge_py-0.3.0/tests/unit/test_cli_build.py +495 -0
  24. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_cli_config.py +56 -0
  25. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_cli_run.py +46 -0
  26. agentforge_py-0.3.0/tests/unit/test_example_swap_smoke.py +35 -0
  27. agentforge_py-0.3.0/tests/unit/test_extras_chain.py +103 -0
  28. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_module_cmd.py +85 -0
  29. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_new_cmd.py +22 -1
  30. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_react_stream.py +23 -0
  31. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_strategies_react.py +28 -0
  32. agentforge_py-0.2.3/PKG-INFO +0 -158
  33. agentforge_py-0.2.3/pyproject.toml +0 -187
  34. agentforge_py-0.2.3/tests/conftest.py +0 -3
  35. agentforge_py-0.2.3/tests/unit/test_cli_build.py +0 -227
  36. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/LICENSE +0 -0
  37. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/README.md +0 -0
  38. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/__init__.py +0 -0
  39. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/_testing/__init__.py +0 -0
  40. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/_testing/fake_llm.py +0 -0
  41. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/_testing/fake_tool.py +0 -0
  42. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/_tools/__init__.py +0 -0
  43. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/_tools/calculator.py +0 -0
  44. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/_tools/file_read.py +0 -0
  45. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/_tools/shell.py +0 -0
  46. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/_tools/web_search.py +0 -0
  47. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/auth.py +0 -0
  48. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/__init__.py +0 -0
  49. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/_scaffold_state.py +0 -0
  50. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/docs_cmd.py +0 -0
  51. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/eval_cmd.py +0 -0
  52. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/list_modules.py +0 -0
  53. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/main.py +0 -0
  54. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/manifest_apply.py +0 -0
  55. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/upgrade_cmd.py +0 -0
  56. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/config/__init__.py +0 -0
  57. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/eval/__init__.py +0 -0
  58. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/eval/consistency.py +0 -0
  59. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/eval/coverage.py +0 -0
  60. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/eval/format_compliance.py +0 -0
  61. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/eval/regression.py +0 -0
  62. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/findings.py +0 -0
  63. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/guardrails/__init__.py +0 -0
  64. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/guardrails/allowlist.py +0 -0
  65. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/guardrails/capability_check.py +0 -0
  66. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/guardrails/engine.py +0 -0
  67. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/guardrails/pii_redact_basic.py +0 -0
  68. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/guardrails/prompt_injection_basic.py +0 -0
  69. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/memory/__init__.py +0 -0
  70. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/memory/in_memory.py +0 -0
  71. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/memory/in_memory_graph.py +0 -0
  72. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/memory/in_memory_vector.py +0 -0
  73. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/pipeline/__init__.py +0 -0
  74. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/pipeline/engine.py +0 -0
  75. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/pipeline/errors.py +0 -0
  76. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/pipeline/tool.py +0 -0
  77. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/py.typed +0 -0
  78. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/recording.py +0 -0
  79. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/renderers/__init__.py +0 -0
  80. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/renderers/_defaults.py +0 -0
  81. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/renderers/markdown.py +0 -0
  82. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/renderers/patch_applier.py +0 -0
  83. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/renderers/registry.py +0 -0
  84. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/renderers/scorecard.py +0 -0
  85. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/renderers/span_table.py +0 -0
  86. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/replay.py +0 -0
  87. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/resolver_register.py +0 -0
  88. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/retrieval.py +0 -0
  89. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/runtime.py +0 -0
  90. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/strategies/__init__.py +0 -0
  91. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/strategies/_plan.py +0 -0
  92. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/strategies/multi_agent.py +0 -0
  93. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/strategies/plan_execute.py +0 -0
  94. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/strategies/tot.py +0 -0
  95. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/.cursorrules +0 -0
  96. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/.github/copilot-instructions.md +0 -0
  97. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/.gitkeep +0 -0
  98. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/CLAUDE.md +0 -0
  99. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/01-set-up-new-agent.md.tmpl +0 -0
  100. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/03-add-a-pipeline-task.md +0 -0
  101. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/04-pick-reasoning-strategy.md +0 -0
  102. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/05-write-prompts.md +0 -0
  103. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/06-test-your-agent.md +0 -0
  104. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/07-debug-a-run.md +0 -0
  105. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/08-add-memory.md +0 -0
  106. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/09-add-mcp.md +0 -0
  107. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/10-add-evaluators.md +0 -0
  108. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/11-add-safety-guardrails.md +0 -0
  109. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/12-add-observability.md +0 -0
  110. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/14-deploy-your-agent.md +0 -0
  111. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/15-upgrade-your-agent.md +0 -0
  112. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/16-configuration-reference.md +0 -0
  113. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/17-add-reranker.md +0 -0
  114. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/18-add-hybrid-search.md +0 -0
  115. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/19-add-graphrag.md +0 -0
  116. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/20-apply-schema-migrations.md +0 -0
  117. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/21-use-streaming-guardrails.md +0 -0
  118. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/README.md.tmpl +0 -0
  119. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/code-reviewer/.env.example +0 -0
  120. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/code-reviewer/.gitignore +0 -0
  121. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/code-reviewer/README.md +0 -0
  122. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/code-reviewer/agentforge.yaml +0 -0
  123. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/code-reviewer/copier.yml +0 -0
  124. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/code-reviewer/pyproject.toml +0 -0
  125. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/code-reviewer/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
  126. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/code-reviewer/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
  127. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/docs-qa/.env.example +0 -0
  128. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/docs-qa/.gitignore +0 -0
  129. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/docs-qa/README.md +0 -0
  130. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/docs-qa/agentforge.yaml +0 -0
  131. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/docs-qa/copier.yml +0 -0
  132. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/docs-qa/pyproject.toml +0 -0
  133. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/docs-qa/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
  134. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/docs-qa/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
  135. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/minimal/.env.example +0 -0
  136. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/minimal/.gitignore +0 -0
  137. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/minimal/README.md +0 -0
  138. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/minimal/agentforge.yaml +0 -0
  139. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/minimal/copier.yml +0 -0
  140. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/minimal/pyproject.toml +0 -0
  141. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/minimal/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
  142. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/minimal/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
  143. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/patch-bot/.env.example +0 -0
  144. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/patch-bot/.gitignore +0 -0
  145. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/patch-bot/README.md +0 -0
  146. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/patch-bot/agentforge.yaml +0 -0
  147. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/patch-bot/copier.yml +0 -0
  148. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/patch-bot/pyproject.toml +0 -0
  149. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/patch-bot/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
  150. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/patch-bot/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
  151. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/research/.env.example +0 -0
  152. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/research/.gitignore +0 -0
  153. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/research/README.md +0 -0
  154. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/research/agentforge.yaml +0 -0
  155. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/research/copier.yml +0 -0
  156. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/research/pyproject.toml +0 -0
  157. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/research/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
  158. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/research/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
  159. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/triage/.env.example +0 -0
  160. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/triage/.gitignore +0 -0
  161. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/triage/README.md +0 -0
  162. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/triage/agentforge.yaml +0 -0
  163. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/triage/copier.yml +0 -0
  164. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/triage/pyproject.toml +0 -0
  165. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/triage/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
  166. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/triage/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
  167. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/testing/__init__.py +0 -0
  168. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/testing/conformance.py +0 -0
  169. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/testing/factory.py +0 -0
  170. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/testing/fixtures.py +0 -0
  171. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/testing/llm.py +0 -0
  172. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/testing/recording.py +0 -0
  173. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/tools/__init__.py +0 -0
  174. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/integration/test_web_search_live.py +0 -0
  175. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/.gitkeep +0 -0
  176. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_agent.py +0 -0
  177. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_agent_evaluators.py +0 -0
  178. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_agent_fallback_chain.py +0 -0
  179. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_agent_graph_store.py +0 -0
  180. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_agent_hooks.py +0 -0
  181. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_agent_pipeline.py +0 -0
  182. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_agent_retriever.py +0 -0
  183. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_build_retriever.py +0 -0
  184. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_cli_build_pipeline.py +0 -0
  185. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_cli_db.py +0 -0
  186. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_cli_debug.py +0 -0
  187. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_cli_docs.py +0 -0
  188. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_cli_eval.py +0 -0
  189. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_cli_health.py +0 -0
  190. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_cli_list_modules.py +0 -0
  191. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_config.py +0 -0
  192. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_env_bearer_auth.py +0 -0
  193. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_eval_consistency.py +0 -0
  194. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_eval_coverage.py +0 -0
  195. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_eval_format_compliance.py +0 -0
  196. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_eval_regression.py +0 -0
  197. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_fake_tool.py +0 -0
  198. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_findings.py +0 -0
  199. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_graph_store_properties.py +0 -0
  200. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_guardrails_builtins.py +0 -0
  201. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_guardrails_conformance.py +0 -0
  202. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_guardrails_engine.py +0 -0
  203. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_in_memory_graph_store.py +0 -0
  204. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_in_memory_store.py +0 -0
  205. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_in_memory_vector_store.py +0 -0
  206. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_manifest_apply.py +0 -0
  207. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_multi_agent_stream.py +0 -0
  208. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_pipeline_engine.py +0 -0
  209. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_plan.py +0 -0
  210. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_plan_execute_stream.py +0 -0
  211. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_recording.py +0 -0
  212. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_renderer_pipeline_findings.py +0 -0
  213. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_renderer_registry.py +0 -0
  214. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_renderers_builtin.py +0 -0
  215. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_replay.py +0 -0
  216. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_retrieval.py +0 -0
  217. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_retrieval_rerank.py +0 -0
  218. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_retriever_graphrag.py +0 -0
  219. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_retriever_hybrid.py +0 -0
  220. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_runtime.py +0 -0
  221. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_scaffold_state.py +0 -0
  222. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_shared_scaffold.py +0 -0
  223. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_strategies_base.py +0 -0
  224. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_strategies_budget_properties.py +0 -0
  225. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_strategies_dispatch_tool.py +0 -0
  226. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_strategies_multi_agent.py +0 -0
  227. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_strategies_plan_execute.py +0 -0
  228. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_strategies_tot.py +0 -0
  229. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_testing_factory.py +0 -0
  230. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_testing_fake_llm.py +0 -0
  231. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_testing_mock_llm.py +0 -0
  232. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_testing_recording.py +0 -0
  233. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_three_section_format.py +0 -0
  234. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_tool_decorator.py +0 -0
  235. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_tools_calculator.py +0 -0
  236. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_tools_file_read.py +0 -0
  237. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_tools_shell.py +0 -0
  238. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_tools_web_search.py +0 -0
  239. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_tot_stream.py +0 -0
  240. {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_vector_store_properties.py +0 -0
@@ -47,3 +47,13 @@ Thumbs.db
47
47
  # Project-local
48
48
  *.local
49
49
  .agentforge-state/.session-cache
50
+
51
+ # AI-assistant working state — local session tracking, not part of
52
+ # the published project. The process docs under .claude/ (standards,
53
+ # checklists, CLAUDE.md) are intentionally kept tracked; only the
54
+ # churny per-session state files are ignored.
55
+ .claude/state/
56
+
57
+ # Launch / go-to-market drafts — local-only marketing material,
58
+ # never published to the repo.
59
+ launch/
@@ -0,0 +1,158 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentforge-py
3
+ Version: 0.3.0
4
+ Summary: AgentForge — open-source plug-and-play framework for production AI agents
5
+ Project-URL: Homepage, https://github.com/Scaffoldic/agentforge-py
6
+ Project-URL: Repository, https://github.com/Scaffoldic/agentforge-py
7
+ Project-URL: Documentation, https://github.com/Scaffoldic/agentforge-py
8
+ Project-URL: Changelog, https://github.com/Scaffoldic/agentforge-py/blob/main/CHANGELOG.md
9
+ Project-URL: Issues, https://github.com/Scaffoldic/agentforge-py/issues
10
+ Author: The AgentForge Authors
11
+ License-Expression: Apache-2.0
12
+ License-File: LICENSE
13
+ Keywords: agent,agentic,ai,framework,llm,react,tools
14
+ Classifier: Development Status :: 2 - Pre-Alpha
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: Apache Software License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.13
23
+ Requires-Dist: agentforge-core~=0.3.0
24
+ Requires-Dist: copier>=9.4
25
+ Requires-Dist: pydantic>=2.10
26
+ Requires-Dist: pyyaml>=6.0
27
+ Requires-Dist: typer>=0.15
28
+ Provides-Extra: a2a
29
+ Requires-Dist: agentforge-a2a~=0.3.0; extra == 'a2a'
30
+ Provides-Extra: all
31
+ Requires-Dist: agentforge-a2a~=0.3.0; extra == 'all'
32
+ Requires-Dist: agentforge-anthropic[anthropic]~=0.3.0; extra == 'all'
33
+ Requires-Dist: agentforge-bedrock~=0.3.0; extra == 'all'
34
+ Requires-Dist: agentforge-chat-history-postgres~=0.3.0; extra == 'all'
35
+ Requires-Dist: agentforge-chat-history-redis~=0.3.0; extra == 'all'
36
+ Requires-Dist: agentforge-chat-http~=0.3.0; extra == 'all'
37
+ Requires-Dist: agentforge-chat-slack~=0.3.0; extra == 'all'
38
+ Requires-Dist: agentforge-chat~=0.3.0; extra == 'all'
39
+ Requires-Dist: agentforge-eval-geval~=0.3.0; extra == 'all'
40
+ Requires-Dist: agentforge-evidently[evidently]~=0.3.0; extra == 'all'
41
+ Requires-Dist: agentforge-guard-llamaguard~=0.3.0; extra == 'all'
42
+ Requires-Dist: agentforge-guard-llmguard~=0.3.0; extra == 'all'
43
+ Requires-Dist: agentforge-guard-nemo~=0.3.0; extra == 'all'
44
+ Requires-Dist: agentforge-guard-presidio~=0.3.0; extra == 'all'
45
+ Requires-Dist: agentforge-langfuse[langfuse]~=0.3.0; extra == 'all'
46
+ Requires-Dist: agentforge-litellm[litellm]~=0.3.0; extra == 'all'
47
+ Requires-Dist: agentforge-mcp[mcp]~=0.3.0; extra == 'all'
48
+ Requires-Dist: agentforge-memory-neo4j~=0.3.0; extra == 'all'
49
+ Requires-Dist: agentforge-memory-postgres~=0.3.0; extra == 'all'
50
+ Requires-Dist: agentforge-memory-sqlite~=0.3.0; extra == 'all'
51
+ Requires-Dist: agentforge-memory-surrealdb~=0.3.0; extra == 'all'
52
+ Requires-Dist: agentforge-ollama[ollama]~=0.3.0; extra == 'all'
53
+ Requires-Dist: agentforge-openai[openai]~=0.3.0; extra == 'all'
54
+ Requires-Dist: agentforge-otel~=0.3.0; extra == 'all'
55
+ Requires-Dist: agentforge-phoenix[phoenix]~=0.3.0; extra == 'all'
56
+ Requires-Dist: agentforge-reranker-cohere[cohere]~=0.3.0; extra == 'all'
57
+ Requires-Dist: agentforge-reranker-mixedbread[mixedbread]~=0.3.0; extra == 'all'
58
+ Requires-Dist: agentforge-reranker-sentence-transformers[sentence-transformers]~=0.3.0; extra == 'all'
59
+ Requires-Dist: agentforge-reranker-voyage[voyage]~=0.3.0; extra == 'all'
60
+ Requires-Dist: agentforge-statsd[statsd]~=0.3.0; extra == 'all'
61
+ Requires-Dist: agentforge-testing~=0.3.0; extra == 'all'
62
+ Requires-Dist: agentforge-voyage[voyage]~=0.3.0; extra == 'all'
63
+ Provides-Extra: anthropic
64
+ Requires-Dist: agentforge-anthropic[anthropic]~=0.3.0; extra == 'anthropic'
65
+ Provides-Extra: bedrock
66
+ Requires-Dist: agentforge-bedrock~=0.3.0; extra == 'bedrock'
67
+ Provides-Extra: chat
68
+ Requires-Dist: agentforge-chat~=0.3.0; extra == 'chat'
69
+ Provides-Extra: chat-history-postgres
70
+ Requires-Dist: agentforge-chat-history-postgres~=0.3.0; extra == 'chat-history-postgres'
71
+ Provides-Extra: chat-history-redis
72
+ Requires-Dist: agentforge-chat-history-redis~=0.3.0; extra == 'chat-history-redis'
73
+ Provides-Extra: chat-http
74
+ Requires-Dist: agentforge-chat-http~=0.3.0; extra == 'chat-http'
75
+ Provides-Extra: chat-slack
76
+ Requires-Dist: agentforge-chat-slack~=0.3.0; extra == 'chat-slack'
77
+ Provides-Extra: eval
78
+ Requires-Dist: agentforge-eval-geval~=0.3.0; extra == 'eval'
79
+ Provides-Extra: evidently
80
+ Requires-Dist: agentforge-evidently[evidently]~=0.3.0; extra == 'evidently'
81
+ Provides-Extra: guard-llamaguard
82
+ Requires-Dist: agentforge-guard-llamaguard~=0.3.0; extra == 'guard-llamaguard'
83
+ Provides-Extra: guard-llmguard
84
+ Requires-Dist: agentforge-guard-llmguard~=0.3.0; extra == 'guard-llmguard'
85
+ Provides-Extra: guard-nemo
86
+ Requires-Dist: agentforge-guard-nemo~=0.3.0; extra == 'guard-nemo'
87
+ Provides-Extra: guard-presidio
88
+ Requires-Dist: agentforge-guard-presidio~=0.3.0; extra == 'guard-presidio'
89
+ Provides-Extra: langfuse
90
+ Requires-Dist: agentforge-langfuse[langfuse]~=0.3.0; extra == 'langfuse'
91
+ Provides-Extra: litellm
92
+ Requires-Dist: agentforge-litellm[litellm]~=0.3.0; extra == 'litellm'
93
+ Provides-Extra: mcp
94
+ Requires-Dist: agentforge-mcp[mcp]~=0.3.0; extra == 'mcp'
95
+ Provides-Extra: memory-neo4j
96
+ Requires-Dist: agentforge-memory-neo4j~=0.3.0; extra == 'memory-neo4j'
97
+ Provides-Extra: memory-postgres
98
+ Requires-Dist: agentforge-memory-postgres~=0.3.0; extra == 'memory-postgres'
99
+ Provides-Extra: memory-sqlite
100
+ Requires-Dist: agentforge-memory-sqlite~=0.3.0; extra == 'memory-sqlite'
101
+ Provides-Extra: memory-surrealdb
102
+ Requires-Dist: agentforge-memory-surrealdb~=0.3.0; extra == 'memory-surrealdb'
103
+ Provides-Extra: ollama
104
+ Requires-Dist: agentforge-ollama[ollama]~=0.3.0; extra == 'ollama'
105
+ Provides-Extra: openai
106
+ Requires-Dist: agentforge-openai[openai]~=0.3.0; extra == 'openai'
107
+ Provides-Extra: otel
108
+ Requires-Dist: agentforge-otel~=0.3.0; extra == 'otel'
109
+ Provides-Extra: phoenix
110
+ Requires-Dist: agentforge-phoenix[phoenix]~=0.3.0; extra == 'phoenix'
111
+ Provides-Extra: reranker-cohere
112
+ Requires-Dist: agentforge-reranker-cohere[cohere]~=0.3.0; extra == 'reranker-cohere'
113
+ Provides-Extra: reranker-mixedbread
114
+ Requires-Dist: agentforge-reranker-mixedbread[mixedbread]~=0.3.0; extra == 'reranker-mixedbread'
115
+ Provides-Extra: reranker-sentence-transformers
116
+ Requires-Dist: agentforge-reranker-sentence-transformers[sentence-transformers]~=0.3.0; extra == 'reranker-sentence-transformers'
117
+ Provides-Extra: reranker-voyage
118
+ Requires-Dist: agentforge-reranker-voyage[voyage]~=0.3.0; extra == 'reranker-voyage'
119
+ Provides-Extra: statsd
120
+ Requires-Dist: agentforge-statsd[statsd]~=0.3.0; extra == 'statsd'
121
+ Provides-Extra: testing
122
+ Requires-Dist: agentforge-testing~=0.3.0; extra == 'testing'
123
+ Provides-Extra: voyage
124
+ Requires-Dist: agentforge-voyage[voyage]~=0.3.0; extra == 'voyage'
125
+ Description-Content-Type: text/markdown
126
+
127
+ # agentforge
128
+
129
+ The default runtime for the AgentForge framework — `Agent`, `ReActLoop`,
130
+ default tools, `SimpleFinding`, in-memory store, basic safety defaults,
131
+ `BudgetPolicy`. Most users install this package and add module extras
132
+ as needed.
133
+
134
+ ## Three-line agent (once feat-001 lands)
135
+
136
+ ```python
137
+ from agentforge import Agent
138
+
139
+ agent = Agent(model="anthropic:claude-sonnet-4.7")
140
+ result = await agent.run("Say hello in three words.")
141
+ ```
142
+
143
+ ## Install
144
+
145
+ ```bash
146
+ pip install agentforge-py # core runtime
147
+ pip install "agentforge-py[anthropic]" # + Anthropic provider
148
+ pip install "agentforge-py[anthropic,memory-postgres]" # + persistence
149
+ ```
150
+
151
+ ## Status
152
+
153
+ v0.0 — pre-alpha. Repo bootstrapped; feat-001 (Core contracts &
154
+ `Agent` orchestrator) is the next milestone.
155
+
156
+ ## License
157
+
158
+ Apache 2.0.
@@ -0,0 +1,189 @@
1
+ # agentforge — default runtime + prebuilt for the AgentForge framework.
2
+ #
3
+ # This package ships the sane defaults a developer expects on a fresh
4
+ # install: the `Agent` orchestrator, `ReActLoop` (stable reasoning
5
+ # strategy), the four built-in tools, the `SimpleFinding` variant +
6
+ # scorecard renderer, the in-memory MemoryStore, the basic safety
7
+ # defaults, and the BudgetPolicy.
8
+ #
9
+ # This package depends on `agentforge-core` (locked contracts) and
10
+ # nothing else from the AgentForge family. Optional extras pull in
11
+ # specific provider/persistence/observability modules.
12
+ #
13
+ # Per ADR-0003 (three-tier package model — this is Tier 2).
14
+
15
+ [project]
16
+ name = "agentforge-py"
17
+ version = "0.3.0"
18
+ description = "AgentForge — open-source plug-and-play framework for production AI agents"
19
+ readme = "README.md"
20
+ requires-python = ">=3.13"
21
+ license = "Apache-2.0"
22
+ license-files = ["LICENSE"]
23
+ authors = [
24
+ {name = "The AgentForge Authors"},
25
+ ]
26
+ keywords = ["ai", "agent", "llm", "framework", "agentic", "react", "tools"]
27
+ classifiers = [
28
+ "Development Status :: 2 - Pre-Alpha",
29
+ "Intended Audience :: Developers",
30
+ "License :: OSI Approved :: Apache Software License",
31
+ "Programming Language :: Python :: 3",
32
+ "Programming Language :: Python :: 3.13",
33
+ "Topic :: Software Development :: Libraries :: Python Modules",
34
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
35
+ "Typing :: Typed",
36
+ ]
37
+
38
+ dependencies = [
39
+ "agentforge-core ~= 0.3.0",
40
+ "pydantic>=2.10",
41
+ "pyyaml>=6.0",
42
+ "typer>=0.15",
43
+ # feat-011: Copier is the scaffolding + three-way-merge engine
44
+ # (ADR-0005). Used by `agentforge new` / `agentforge upgrade`.
45
+ "copier>=9.4",
46
+ ]
47
+
48
+ # Optional extras — names match the underlying provider/module package.
49
+ # Adding a module via `pip install "agentforge[<name>]"` pulls the
50
+ # corresponding package onto the path; entry-point discovery does the
51
+ # rest (per ADR-0004).
52
+ [project.optional-dependencies]
53
+ # Each extra installs one sister package at the matching coordinated
54
+ # release-train version. `pip install agentforge-py[anthropic]`
55
+ # resolves to `agentforge-py + agentforge-anthropic`, etc.
56
+ # Add a new entry here every time a new sister package ships.
57
+
58
+ # LLM providers. Where a sister package keeps its vendor SDK behind
59
+ # an optional `[<sdk>]` extra (the lazy-import pattern), the meta extra
60
+ # MUST chain that extra — otherwise `pip install "agentforge-py[x]"`
61
+ # installs the wrapper but not the SDK and the first call raises a
62
+ # ModuleError (bug-015). bedrock hard-deps its SDK (aioboto3/botocore),
63
+ # so it requests no extra — and must NOT request a phantom `[bedrock]`.
64
+ anthropic = ["agentforge-anthropic[anthropic] ~= 0.3.0"]
65
+ openai = ["agentforge-openai[openai] ~= 0.3.0"]
66
+ bedrock = ["agentforge-bedrock ~= 0.3.0"]
67
+ ollama = ["agentforge-ollama[ollama] ~= 0.3.0"]
68
+ litellm = ["agentforge-litellm[litellm] ~= 0.3.0"]
69
+
70
+ # Embeddings
71
+ voyage = ["agentforge-voyage[voyage] ~= 0.3.0"]
72
+
73
+ # Memory backends (each hard-deps its driver SDK — no extra to chain)
74
+ memory-sqlite = ["agentforge-memory-sqlite ~= 0.3.0"]
75
+ memory-postgres = ["agentforge-memory-postgres ~= 0.3.0"]
76
+ memory-neo4j = ["agentforge-memory-neo4j ~= 0.3.0"]
77
+ memory-surrealdb = ["agentforge-memory-surrealdb ~= 0.3.0"]
78
+
79
+ # Chat surface (chat hard-deps aiosqlite; history backends hard-dep their SDK)
80
+ chat = ["agentforge-chat ~= 0.3.0"]
81
+ chat-http = ["agentforge-chat-http ~= 0.3.0"]
82
+ chat-slack = ["agentforge-chat-slack ~= 0.3.0"]
83
+ chat-history-postgres = ["agentforge-chat-history-postgres ~= 0.3.0"]
84
+ chat-history-redis = ["agentforge-chat-history-redis ~= 0.3.0"]
85
+
86
+ # Rerankers
87
+ reranker-cohere = ["agentforge-reranker-cohere[cohere] ~= 0.3.0"]
88
+ reranker-voyage = ["agentforge-reranker-voyage[voyage] ~= 0.3.0"]
89
+ reranker-mixedbread = ["agentforge-reranker-mixedbread[mixedbread] ~= 0.3.0"]
90
+ reranker-sentence-transformers = ["agentforge-reranker-sentence-transformers[sentence-transformers] ~= 0.3.0"]
91
+
92
+ # Guardrails (each hard-deps its SDK — no extra to chain)
93
+ guard-llmguard = ["agentforge-guard-llmguard ~= 0.3.0"]
94
+ guard-presidio = ["agentforge-guard-presidio ~= 0.3.0"]
95
+ guard-nemo = ["agentforge-guard-nemo ~= 0.3.0"]
96
+ guard-llamaguard = ["agentforge-guard-llamaguard ~= 0.3.0"]
97
+
98
+ # Observability
99
+ langfuse = ["agentforge-langfuse[langfuse] ~= 0.3.0"]
100
+ phoenix = ["agentforge-phoenix[phoenix] ~= 0.3.0"]
101
+ otel = ["agentforge-otel ~= 0.3.0"]
102
+ statsd = ["agentforge-statsd[statsd] ~= 0.3.0"]
103
+ evidently = ["agentforge-evidently[evidently] ~= 0.3.0"]
104
+
105
+ # Protocols
106
+ mcp = ["agentforge-mcp[mcp] ~= 0.3.0"]
107
+ a2a = ["agentforge-a2a ~= 0.3.0"]
108
+
109
+ # Eval
110
+ eval = ["agentforge-eval-geval ~= 0.3.0"]
111
+
112
+ # Testing
113
+ testing = ["agentforge-testing ~= 0.3.0"]
114
+
115
+ # Everything (development / docs / smoke-test convenience — not
116
+ # recommended for production deploys; pick the actual integrations
117
+ # you use to keep the dependency tree small). Vendor-SDK extras are
118
+ # chained here too so `[all]` actually installs every SDK.
119
+ all = [
120
+ "agentforge-anthropic[anthropic] ~= 0.3.0",
121
+ "agentforge-openai[openai] ~= 0.3.0",
122
+ "agentforge-bedrock ~= 0.3.0",
123
+ "agentforge-ollama[ollama] ~= 0.3.0",
124
+ "agentforge-litellm[litellm] ~= 0.3.0",
125
+ "agentforge-voyage[voyage] ~= 0.3.0",
126
+ "agentforge-memory-sqlite ~= 0.3.0",
127
+ "agentforge-memory-postgres ~= 0.3.0",
128
+ "agentforge-memory-neo4j ~= 0.3.0",
129
+ "agentforge-memory-surrealdb ~= 0.3.0",
130
+ "agentforge-chat ~= 0.3.0",
131
+ "agentforge-chat-http ~= 0.3.0",
132
+ "agentforge-chat-slack ~= 0.3.0",
133
+ "agentforge-chat-history-postgres ~= 0.3.0",
134
+ "agentforge-chat-history-redis ~= 0.3.0",
135
+ "agentforge-reranker-cohere[cohere] ~= 0.3.0",
136
+ "agentforge-reranker-voyage[voyage] ~= 0.3.0",
137
+ "agentforge-reranker-mixedbread[mixedbread] ~= 0.3.0",
138
+ "agentforge-reranker-sentence-transformers[sentence-transformers] ~= 0.3.0",
139
+ "agentforge-guard-llmguard ~= 0.3.0",
140
+ "agentforge-guard-presidio ~= 0.3.0",
141
+ "agentforge-guard-nemo ~= 0.3.0",
142
+ "agentforge-guard-llamaguard ~= 0.3.0",
143
+ "agentforge-langfuse[langfuse] ~= 0.3.0",
144
+ "agentforge-phoenix[phoenix] ~= 0.3.0",
145
+ "agentforge-otel ~= 0.3.0",
146
+ "agentforge-statsd[statsd] ~= 0.3.0",
147
+ "agentforge-evidently[evidently] ~= 0.3.0",
148
+ "agentforge-mcp[mcp] ~= 0.3.0",
149
+ "agentforge-a2a ~= 0.3.0",
150
+ "agentforge-eval-geval ~= 0.3.0",
151
+ "agentforge-testing ~= 0.3.0",
152
+ ]
153
+
154
+ [project.scripts]
155
+ # feat-010 ships the read-only `list` command. Destructive commands
156
+ # (`add`, `swap`, `remove`) ship in a follow-up sub-feat alongside
157
+ # feat-012 (Configuration system).
158
+ agentforge = "agentforge.cli.main:main"
159
+
160
+ [project.urls]
161
+ Homepage = "https://github.com/Scaffoldic/agentforge-py"
162
+ Repository = "https://github.com/Scaffoldic/agentforge-py"
163
+ Documentation = "https://github.com/Scaffoldic/agentforge-py"
164
+ Changelog = "https://github.com/Scaffoldic/agentforge-py/blob/main/CHANGELOG.md"
165
+ Issues = "https://github.com/Scaffoldic/agentforge-py/issues"
166
+
167
+ [tool.uv.sources]
168
+ agentforge-core = { workspace = true }
169
+
170
+ [build-system]
171
+ requires = ["hatchling>=1.27"]
172
+ build-backend = "hatchling.build"
173
+
174
+ [tool.hatch.build.targets.wheel]
175
+ packages = ["src/agentforge"]
176
+ # feat-011: ship Copier templates inside the wheel. The
177
+ # `{{project_slug}}/` subdir is auto-included via the `packages`
178
+ # directive — hatchling walks all files under src/agentforge,
179
+ # including the Jinja2-named subdirs. Do NOT add a force-include
180
+ # for templates: it duplicates every entry and PyPI rejects the
181
+ # wheel with "Duplicate filename in local headers".
182
+
183
+ [tool.hatch.build.targets.sdist]
184
+ include = [
185
+ "src/agentforge",
186
+ "tests",
187
+ "README.md",
188
+ "LICENSE",
189
+ ]
@@ -20,7 +20,15 @@ Wraps a typed function as a concrete `Tool` subclass:
20
20
  The decorator inspects the wrapped function and constructs:
21
21
 
22
22
  - `name` from the function's `__name__` (or the
23
- `name=` override argument).
23
+ `name=` override argument). Keep it within
24
+ `[a-zA-Z0-9_-]` (1-64 chars): that's the
25
+ tool-name charset Bedrock, OpenAI, and
26
+ Anthropic all enforce, so a name outside it
27
+ is rejected at request-build time with
28
+ `ToolNameInvalidError` (bug-017). A plain
29
+ function name like `lookup_user` is already
30
+ legal; avoid dots / colons / spaces in
31
+ `name=` overrides.
24
32
  - `description` from the docstring's summary line + Args
25
33
  section, parsed Google-style. The first
26
34
  non-blank non-arg line is the summary;
@@ -22,7 +22,7 @@ from __future__ import annotations
22
22
 
23
23
  import logging
24
24
  import time
25
- from collections.abc import AsyncIterator, Awaitable, Callable
25
+ from collections.abc import AsyncIterator, Awaitable, Callable, Sequence
26
26
  from pathlib import Path
27
27
  from types import TracebackType
28
28
  from typing import Any
@@ -37,6 +37,7 @@ from agentforge_core.contracts.guardrails import (
37
37
  )
38
38
  from agentforge_core.contracts.llm import LLMClient
39
39
  from agentforge_core.contracts.memory import MemoryStore
40
+ from agentforge_core.contracts.protocol_bridge import ProtocolBridge
40
41
  from agentforge_core.contracts.strategy import ReasoningStrategy
41
42
  from agentforge_core.contracts.tool import Tool
42
43
  from agentforge_core.observability import get_tracer
@@ -119,6 +120,7 @@ class Agent:
119
120
  tool_gates: list[ToolCallGate] | None = None,
120
121
  guardrail_policy: GuardrailPolicy | None = None,
121
122
  pipeline: Pipeline | None = None,
123
+ protocol_bridges: Sequence[ProtocolBridge] | None = None,
122
124
  ) -> None:
123
125
  self._config: AgentForgeConfig = load_config(config_path)
124
126
 
@@ -198,6 +200,11 @@ class Agent:
198
200
  self._pipeline_tool = PipelineFindingsTool()
199
201
  self._tools.append(self._pipeline_tool)
200
202
 
203
+ # feat-013: protocol handlers (e.g. MCP bridges) already started
204
+ # by the config builder. Their tools are passed in via `tools=`;
205
+ # the Agent only owns tearing them down on `close()`.
206
+ self._protocol_bridges: list[ProtocolBridge] = list(protocol_bridges or [])
207
+
201
208
  self._closed = False
202
209
 
203
210
  if install_log_filter and self._config.logging.run_id_filter:
@@ -677,6 +684,8 @@ class Agent:
677
684
  await self._memory.close()
678
685
  if self._graph_store is not None:
679
686
  await self._graph_store.close()
687
+ for bridge in self._protocol_bridges:
688
+ await bridge.close()
680
689
  uninstall_run_id_filter()
681
690
  uninstall_json_formatter()
682
691
 
@@ -20,6 +20,8 @@ deterministic exit codes (per feat-017 §4 — config invalid → 2).
20
20
 
21
21
  from __future__ import annotations
22
22
 
23
+ import contextlib
24
+ import inspect
23
25
  from pathlib import Path
24
26
  from typing import TYPE_CHECKING, Any
25
27
 
@@ -30,6 +32,7 @@ from agentforge_core.contracts.evaluator import Evaluator
30
32
  from agentforge_core.contracts.graph_store import GraphStore
31
33
  from agentforge_core.contracts.llm import LLMClient
32
34
  from agentforge_core.contracts.memory import MemoryStore
35
+ from agentforge_core.contracts.protocol_bridge import ProtocolBridge
33
36
  from agentforge_core.contracts.reranker import Reranker
34
37
  from agentforge_core.contracts.vector_store import VectorStore
35
38
  from agentforge_core.production.exceptions import ModuleError
@@ -73,7 +76,7 @@ async def build_agent_from_config(
73
76
  Splits out from `load_and_build` for tests + reuse — tests build
74
77
  a `AgentForgeConfig` directly and skip the YAML parse.
75
78
  """
76
- memory = build_memory_from_config(config)
79
+ memory = await build_memory_from_config(config)
77
80
  if memory is not None:
78
81
  await _maybe_init_schema(memory)
79
82
  evaluators = build_evaluators_from_config(config)
@@ -82,26 +85,49 @@ async def build_agent_from_config(
82
85
  llm = _resolve_llm(config)
83
86
  strategy = config.agent.strategy if isinstance(config.agent.strategy, str) else None
84
87
 
85
- return Agent(
86
- model=llm,
87
- memory=memory if memory is not None else InMemoryStore(),
88
- evaluators=evaluators,
89
- strategy=strategy,
90
- retriever=retriever,
91
- system_prompt=config.agent.system_prompt,
92
- budget_usd=config.agent.budget.usd,
93
- max_iterations=config.agent.max_iterations,
94
- record_runs=memory if enable_recording and memory is not None else None,
95
- pipeline=pipeline,
96
- )
88
+ # feat-013 (bug-020): wire `modules.protocols` — resolve + start each
89
+ # handler (e.g. the MCP bridge), merge its tools with the native
90
+ # `agent.tools`, and hand the started bridges to the Agent so they're
91
+ # closed on `Agent.close()`. `build_protocols_from_config` has already
92
+ # awaited `start()` for every bridge it returns.
93
+ native_tools = build_tools_from_config(config)
94
+ mcp_tools, protocol_bridges = await build_protocols_from_config(config)
95
+ all_tools = [*native_tools, *mcp_tools]
96
+
97
+ try:
98
+ return Agent(
99
+ model=llm,
100
+ tools=all_tools or None,
101
+ memory=memory if memory is not None else InMemoryStore(),
102
+ evaluators=evaluators,
103
+ strategy=strategy,
104
+ retriever=retriever,
105
+ system_prompt=config.agent.system_prompt,
106
+ budget_usd=config.agent.budget.usd,
107
+ max_iterations=config.agent.max_iterations,
108
+ record_runs=memory if enable_recording and memory is not None else None,
109
+ pipeline=pipeline,
110
+ protocol_bridges=protocol_bridges,
111
+ )
112
+ except BaseException:
113
+ # Agent construction failed after bridges were started — don't
114
+ # leak the open transports / spawned subprocesses.
115
+ await _close_bridges(protocol_bridges)
116
+ raise
117
+
97
118
 
119
+ async def build_memory_from_config(config: AgentForgeConfig) -> MemoryStore | None:
120
+ """Resolve + instantiate `modules.memory`. Returns None when absent.
98
121
 
99
- def build_memory_from_config(config: AgentForgeConfig) -> MemoryStore | None:
100
- """Resolve + instantiate `modules.memory`. Returns None when absent."""
122
+ Async because the real memory backends (sqlite/postgres/neo4j/
123
+ surrealdb) open a connection at construction and expose an async
124
+ `from_config` factory (bug-022). Falls back to the sync
125
+ `_instantiate` path for stores that ship a plain/sync constructor.
126
+ """
101
127
  if config.modules.memory is None:
102
128
  return None
103
129
  cls = _resolve_class("memory", config.modules.memory.driver)
104
- instance = _instantiate(cls, config.modules.memory.config)
130
+ instance = await _ainstantiate_memory(cls, config.modules.memory.config)
105
131
  if not isinstance(instance, MemoryStore):
106
132
  msg = (
107
133
  f"Resolved memory driver {config.modules.memory.driver!r} "
@@ -259,6 +285,83 @@ def build_tools_from_config(config: AgentForgeConfig) -> list[Tool]:
259
285
  return tools
260
286
 
261
287
 
288
+ async def build_protocols_from_config(
289
+ config: AgentForgeConfig,
290
+ ) -> tuple[list[Tool], list[ProtocolBridge]]:
291
+ """Resolve + start every `modules.protocols` handler (feat-013).
292
+
293
+ For each entry: resolve its name under the ``protocols`` resolver
294
+ category, build the handler via its ``from_config(config)``
295
+ classmethod, ``await start()`` to open connections and discover
296
+ tools, then collect the merged tool list. The started bridges are
297
+ returned so the caller can ``close()`` them on agent teardown.
298
+
299
+ Returns an empty ``([], [])`` when no protocols are configured.
300
+
301
+ Raises:
302
+ ModuleError: a protocol isn't registered, lacks a
303
+ ``from_config`` classmethod, doesn't implement
304
+ `ProtocolBridge`, or requests server-side ``expose`` (not
305
+ wired into the runtime yet — see `_reject_unsupported_expose`).
306
+ """
307
+ from agentforge_core.contracts.tool import Tool as ToolBase # noqa: PLC0415
308
+
309
+ tools: list[ToolBase] = []
310
+ bridges: list[ProtocolBridge] = []
311
+ for entry in config.modules.protocols:
312
+ _reject_unsupported_expose(entry.name, entry.config)
313
+ cls = _resolve_class("protocols", entry.name)
314
+ from_config = getattr(cls, "from_config", None)
315
+ if not callable(from_config):
316
+ msg = (
317
+ f"Resolved protocol {entry.name!r} ({cls.__name__}) has no "
318
+ f"from_config(config) classmethod."
319
+ )
320
+ raise ModuleError(msg)
321
+ bridge = from_config(entry.config)
322
+ if not isinstance(bridge, ProtocolBridge):
323
+ msg = (
324
+ f"Resolved protocol {entry.name!r} ({cls.__name__}) does not "
325
+ f"implement ProtocolBridge (needs tools / start / close)."
326
+ )
327
+ raise ModuleError(msg)
328
+ try:
329
+ await bridge.start()
330
+ except BaseException:
331
+ # A later bridge failing must not leak earlier ones.
332
+ await _close_bridges(bridges)
333
+ raise
334
+ bridges.append(bridge)
335
+ tools.extend(bridge.tools)
336
+ return tools, bridges
337
+
338
+
339
+ def _reject_unsupported_expose(name: str, cfg: dict[str, Any]) -> None:
340
+ """Fail loud on server-side `expose`, which the runtime can't wire yet.
341
+
342
+ Auto-serving an MCP server from inside the agent process would hijack
343
+ the process's stdio. Consume-only is supported; expose runtime-wiring
344
+ is a follow-up (tracked alongside enh-001, MCP HTTP server transport).
345
+ """
346
+ expose = cfg.get("expose") or {}
347
+ if expose.get("enabled"):
348
+ msg = (
349
+ f"modules.protocols[{name!r}]: server-side `expose` is not wired "
350
+ "into the agent runtime yet (it would hijack the agent process's "
351
+ "stdio). Use consume-only config for now; expose runtime-wiring is "
352
+ "a follow-up (see enh-001)."
353
+ )
354
+ raise ModuleError(msg)
355
+
356
+
357
+ async def _close_bridges(bridges: list[ProtocolBridge]) -> None:
358
+ """Close every started bridge, swallowing teardown errors so one bad
359
+ close doesn't mask the original failure."""
360
+ for bridge in bridges:
361
+ with contextlib.suppress(Exception):
362
+ await bridge.close()
363
+
364
+
262
365
  def _resolve_llm(config: AgentForgeConfig) -> LLMClient | str | None:
263
366
  """Pick the LLM definition out of `config.agent.model` /
264
367
  `config.providers["default"]`.
@@ -266,8 +369,12 @@ def _resolve_llm(config: AgentForgeConfig) -> LLMClient | str | None:
266
369
  We hand a string back to `Agent.__init__` when the model is a
267
370
  plain `"<provider>:<model>"` string — `Agent` already knows how
268
371
  to resolve that. When `agent.model` is missing but
269
- `providers["default"]` is present, we synthesize the string from
270
- the named-provider record.
372
+ `providers["default"]` is present, the named-provider record is
373
+ used — and its `config:` block is **passed through to the provider
374
+ constructor** (enh-004): a plain `type:model` string can only carry
375
+ the model id, so provider settings (`region`, `aws_profile`,
376
+ `role_arn`, `timeout_seconds`, …) have to ride the `config` block.
377
+ Without this they were silently dropped.
271
378
  """
272
379
  raw = config.agent.model
273
380
  if isinstance(raw, str):
@@ -275,7 +382,25 @@ def _resolve_llm(config: AgentForgeConfig) -> LLMClient | str | None:
275
382
  default = config.providers.get("default")
276
383
  if default is None or default.model is None:
277
384
  return None
278
- return f"{default.type}:{default.model}"
385
+ if not default.config:
386
+ return f"{default.type}:{default.model}"
387
+ # Construct the provider directly with `model_id` + the `config`
388
+ # kwargs — the same `cls(model_id=...)` contract `Agent` uses to
389
+ # resolve a model string (every provider's __init__ accepts
390
+ # `model_id`), extended with the per-provider settings.
391
+ cls = _resolve_class("providers", default.type)
392
+ try:
393
+ instance = cls(model_id=default.model, **default.config)
394
+ except TypeError as exc:
395
+ msg = (
396
+ f"Provider {default.type!r} ({cls.__name__}) rejected "
397
+ f"providers.default.config keys {sorted(default.config)}: {exc}"
398
+ )
399
+ raise ModuleError(msg) from exc
400
+ if not isinstance(instance, LLMClient):
401
+ msg = f"Resolved provider {default.type!r} ({cls.__name__}) does not implement LLMClient."
402
+ raise ModuleError(msg)
403
+ return instance
279
404
 
280
405
 
281
406
  def _resolve_class(category: str, name: str) -> type:
@@ -306,6 +431,29 @@ def _instantiate(cls: type, cfg: dict[str, Any]) -> Any:
306
431
  return cls(**cfg)
307
432
 
308
433
 
434
+ async def _ainstantiate_memory(cls: type, cfg: dict[str, Any]) -> Any:
435
+ """Async-aware construction for memory stores (bug-022).
436
+
437
+ Memory backends construct asynchronously (they open a connection)
438
+ and expose an awaitable `from_config`. Prefer it; if the resolved
439
+ class only offers a sync constructor (e.g. a test double), fall
440
+ back to the shared sync `_instantiate`.
441
+
442
+ Mirrors `_instantiate`'s keyword-then-positional `from_config`
443
+ shape so externally-shipped stores using either signature load.
444
+ """
445
+ from_config = getattr(cls, "from_config", None)
446
+ if callable(from_config):
447
+ try:
448
+ result = from_config(**cfg)
449
+ except TypeError:
450
+ result = from_config(cfg)
451
+ if inspect.isawaitable(result):
452
+ return await result
453
+ return result
454
+ return cls(**cfg)
455
+
456
+
309
457
  async def _maybe_init_schema(memory: MemoryStore) -> None:
310
458
  init = getattr(memory, "init_schema", None)
311
459
  if callable(init):
@@ -317,6 +465,7 @@ __all__ = [
317
465
  "build_evaluators_from_config",
318
466
  "build_memory_from_config",
319
467
  "build_pipeline_from_config",
468
+ "build_protocols_from_config",
320
469
  "build_retriever_from_config",
321
470
  "build_tools_from_config",
322
471
  "load_and_build",