agentforge-py 0.2.3__tar.gz → 0.2.4__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 (235) hide show
  1. agentforge_py-0.2.4/PKG-INFO +158 -0
  2. agentforge_py-0.2.4/pyproject.toml +189 -0
  3. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/_tools/decorator.py +9 -1
  4. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/agent.py +10 -1
  5. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/cli/_build.py +109 -12
  6. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/cli/_shared_scaffold.py +3 -1
  7. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/cli/new_cmd.py +7 -2
  8. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/strategies/_base.py +22 -11
  9. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/strategies/react.py +17 -2
  10. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/docs/runbooks/02-add-a-tool.md +5 -0
  11. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_cli_build.py +139 -1
  12. agentforge_py-0.2.4/tests/unit/test_extras_chain.py +103 -0
  13. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_new_cmd.py +21 -0
  14. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_react_stream.py +23 -0
  15. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_strategies_react.py +28 -0
  16. agentforge_py-0.2.3/PKG-INFO +0 -158
  17. agentforge_py-0.2.3/pyproject.toml +0 -187
  18. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/.gitignore +0 -0
  19. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/LICENSE +0 -0
  20. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/README.md +0 -0
  21. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/__init__.py +0 -0
  22. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/_testing/__init__.py +0 -0
  23. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/_testing/fake_llm.py +0 -0
  24. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/_testing/fake_tool.py +0 -0
  25. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/_tools/__init__.py +0 -0
  26. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/_tools/calculator.py +0 -0
  27. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/_tools/file_read.py +0 -0
  28. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/_tools/shell.py +0 -0
  29. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/_tools/web_search.py +0 -0
  30. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/auth.py +0 -0
  31. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/cli/__init__.py +0 -0
  32. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/cli/_scaffold_state.py +0 -0
  33. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/cli/config_cmd.py +0 -0
  34. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/cli/db_cmd.py +0 -0
  35. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/cli/debug_cmd.py +0 -0
  36. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/cli/docs_cmd.py +0 -0
  37. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/cli/eval_cmd.py +0 -0
  38. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/cli/health_cmd.py +0 -0
  39. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/cli/list_modules.py +0 -0
  40. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/cli/main.py +0 -0
  41. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/cli/manifest_apply.py +0 -0
  42. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/cli/module_cmd.py +0 -0
  43. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/cli/run_cmd.py +0 -0
  44. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/cli/upgrade_cmd.py +0 -0
  45. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/config/__init__.py +0 -0
  46. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/eval/__init__.py +0 -0
  47. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/eval/consistency.py +0 -0
  48. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/eval/coverage.py +0 -0
  49. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/eval/format_compliance.py +0 -0
  50. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/eval/regression.py +0 -0
  51. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/findings.py +0 -0
  52. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/guardrails/__init__.py +0 -0
  53. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/guardrails/allowlist.py +0 -0
  54. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/guardrails/capability_check.py +0 -0
  55. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/guardrails/engine.py +0 -0
  56. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/guardrails/pii_redact_basic.py +0 -0
  57. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/guardrails/prompt_injection_basic.py +0 -0
  58. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/memory/__init__.py +0 -0
  59. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/memory/in_memory.py +0 -0
  60. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/memory/in_memory_graph.py +0 -0
  61. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/memory/in_memory_vector.py +0 -0
  62. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/pipeline/__init__.py +0 -0
  63. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/pipeline/engine.py +0 -0
  64. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/pipeline/errors.py +0 -0
  65. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/pipeline/tool.py +0 -0
  66. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/py.typed +0 -0
  67. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/recording.py +0 -0
  68. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/renderers/__init__.py +0 -0
  69. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/renderers/_defaults.py +0 -0
  70. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/renderers/markdown.py +0 -0
  71. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/renderers/patch_applier.py +0 -0
  72. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/renderers/registry.py +0 -0
  73. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/renderers/scorecard.py +0 -0
  74. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/renderers/span_table.py +0 -0
  75. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/replay.py +0 -0
  76. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/resolver_register.py +0 -0
  77. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/retrieval.py +0 -0
  78. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/runtime.py +0 -0
  79. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/strategies/__init__.py +0 -0
  80. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/strategies/_plan.py +0 -0
  81. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/strategies/multi_agent.py +0 -0
  82. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/strategies/plan_execute.py +0 -0
  83. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/strategies/tot.py +0 -0
  84. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/.cursorrules +0 -0
  85. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/.github/copilot-instructions.md +0 -0
  86. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/.gitkeep +0 -0
  87. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/AGENTS.md.tmpl +0 -0
  88. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/CLAUDE.md +0 -0
  89. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/docs/runbooks/01-set-up-new-agent.md.tmpl +0 -0
  90. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/docs/runbooks/03-add-a-pipeline-task.md +0 -0
  91. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/docs/runbooks/04-pick-reasoning-strategy.md +0 -0
  92. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/docs/runbooks/05-write-prompts.md +0 -0
  93. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/docs/runbooks/06-test-your-agent.md +0 -0
  94. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/docs/runbooks/07-debug-a-run.md +0 -0
  95. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/docs/runbooks/08-add-memory.md +0 -0
  96. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/docs/runbooks/09-add-mcp.md +0 -0
  97. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/docs/runbooks/10-add-evaluators.md +0 -0
  98. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/docs/runbooks/11-add-safety-guardrails.md +0 -0
  99. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/docs/runbooks/12-add-observability.md +0 -0
  100. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/docs/runbooks/13-configure-multi-provider.md +0 -0
  101. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/docs/runbooks/14-deploy-your-agent.md +0 -0
  102. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/docs/runbooks/15-upgrade-your-agent.md +0 -0
  103. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/docs/runbooks/16-configuration-reference.md +0 -0
  104. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/docs/runbooks/17-add-reranker.md +0 -0
  105. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/docs/runbooks/18-add-hybrid-search.md +0 -0
  106. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/docs/runbooks/19-add-graphrag.md +0 -0
  107. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/docs/runbooks/20-apply-schema-migrations.md +0 -0
  108. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/docs/runbooks/21-use-streaming-guardrails.md +0 -0
  109. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/_shared/docs/runbooks/README.md.tmpl +0 -0
  110. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/code-reviewer/.env.example +0 -0
  111. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/code-reviewer/.gitignore +0 -0
  112. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/code-reviewer/README.md +0 -0
  113. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/code-reviewer/agentforge.yaml +0 -0
  114. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/code-reviewer/copier.yml +0 -0
  115. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/code-reviewer/pyproject.toml +0 -0
  116. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/code-reviewer/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
  117. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/code-reviewer/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
  118. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/docs-qa/.env.example +0 -0
  119. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/docs-qa/.gitignore +0 -0
  120. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/docs-qa/README.md +0 -0
  121. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/docs-qa/agentforge.yaml +0 -0
  122. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/docs-qa/copier.yml +0 -0
  123. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/docs-qa/pyproject.toml +0 -0
  124. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/docs-qa/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
  125. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/docs-qa/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
  126. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/minimal/.env.example +0 -0
  127. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/minimal/.gitignore +0 -0
  128. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/minimal/README.md +0 -0
  129. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/minimal/agentforge.yaml +0 -0
  130. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/minimal/copier.yml +0 -0
  131. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/minimal/pyproject.toml +0 -0
  132. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/minimal/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
  133. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/minimal/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
  134. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/patch-bot/.env.example +0 -0
  135. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/patch-bot/.gitignore +0 -0
  136. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/patch-bot/README.md +0 -0
  137. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/patch-bot/agentforge.yaml +0 -0
  138. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/patch-bot/copier.yml +0 -0
  139. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/patch-bot/pyproject.toml +0 -0
  140. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/patch-bot/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
  141. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/patch-bot/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
  142. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/research/.env.example +0 -0
  143. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/research/.gitignore +0 -0
  144. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/research/README.md +0 -0
  145. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/research/agentforge.yaml +0 -0
  146. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/research/copier.yml +0 -0
  147. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/research/pyproject.toml +0 -0
  148. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/research/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
  149. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/research/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
  150. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/triage/.env.example +0 -0
  151. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/triage/.gitignore +0 -0
  152. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/triage/README.md +0 -0
  153. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/triage/agentforge.yaml +0 -0
  154. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/triage/copier.yml +0 -0
  155. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/triage/pyproject.toml +0 -0
  156. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/triage/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
  157. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/templates/triage/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
  158. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/testing/__init__.py +0 -0
  159. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/testing/conformance.py +0 -0
  160. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/testing/factory.py +0 -0
  161. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/testing/fixtures.py +0 -0
  162. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/testing/llm.py +0 -0
  163. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/testing/recording.py +0 -0
  164. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/src/agentforge/tools/__init__.py +0 -0
  165. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/conftest.py +0 -0
  166. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/integration/test_web_search_live.py +0 -0
  167. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/.gitkeep +0 -0
  168. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_agent.py +0 -0
  169. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_agent_evaluators.py +0 -0
  170. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_agent_fallback_chain.py +0 -0
  171. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_agent_graph_store.py +0 -0
  172. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_agent_hooks.py +0 -0
  173. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_agent_pipeline.py +0 -0
  174. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_agent_retriever.py +0 -0
  175. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_build_retriever.py +0 -0
  176. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_cli_build_pipeline.py +0 -0
  177. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_cli_config.py +0 -0
  178. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_cli_db.py +0 -0
  179. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_cli_debug.py +0 -0
  180. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_cli_docs.py +0 -0
  181. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_cli_eval.py +0 -0
  182. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_cli_health.py +0 -0
  183. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_cli_list_modules.py +0 -0
  184. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_cli_run.py +0 -0
  185. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_config.py +0 -0
  186. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_env_bearer_auth.py +0 -0
  187. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_eval_consistency.py +0 -0
  188. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_eval_coverage.py +0 -0
  189. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_eval_format_compliance.py +0 -0
  190. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_eval_regression.py +0 -0
  191. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_fake_tool.py +0 -0
  192. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_findings.py +0 -0
  193. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_graph_store_properties.py +0 -0
  194. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_guardrails_builtins.py +0 -0
  195. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_guardrails_conformance.py +0 -0
  196. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_guardrails_engine.py +0 -0
  197. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_in_memory_graph_store.py +0 -0
  198. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_in_memory_store.py +0 -0
  199. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_in_memory_vector_store.py +0 -0
  200. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_manifest_apply.py +0 -0
  201. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_module_cmd.py +0 -0
  202. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_multi_agent_stream.py +0 -0
  203. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_pipeline_engine.py +0 -0
  204. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_plan.py +0 -0
  205. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_plan_execute_stream.py +0 -0
  206. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_recording.py +0 -0
  207. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_renderer_pipeline_findings.py +0 -0
  208. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_renderer_registry.py +0 -0
  209. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_renderers_builtin.py +0 -0
  210. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_replay.py +0 -0
  211. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_retrieval.py +0 -0
  212. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_retrieval_rerank.py +0 -0
  213. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_retriever_graphrag.py +0 -0
  214. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_retriever_hybrid.py +0 -0
  215. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_runtime.py +0 -0
  216. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_scaffold_state.py +0 -0
  217. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_shared_scaffold.py +0 -0
  218. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_strategies_base.py +0 -0
  219. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_strategies_budget_properties.py +0 -0
  220. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_strategies_dispatch_tool.py +0 -0
  221. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_strategies_multi_agent.py +0 -0
  222. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_strategies_plan_execute.py +0 -0
  223. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_strategies_tot.py +0 -0
  224. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_testing_factory.py +0 -0
  225. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_testing_fake_llm.py +0 -0
  226. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_testing_mock_llm.py +0 -0
  227. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_testing_recording.py +0 -0
  228. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_three_section_format.py +0 -0
  229. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_tool_decorator.py +0 -0
  230. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_tools_calculator.py +0 -0
  231. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_tools_file_read.py +0 -0
  232. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_tools_shell.py +0 -0
  233. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_tools_web_search.py +0 -0
  234. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_tot_stream.py +0 -0
  235. {agentforge_py-0.2.3 → agentforge_py-0.2.4}/tests/unit/test_vector_store_properties.py +0 -0
@@ -0,0 +1,158 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentforge-py
3
+ Version: 0.2.4
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.2.4
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.2.4; extra == 'a2a'
30
+ Provides-Extra: all
31
+ Requires-Dist: agentforge-a2a~=0.2.4; extra == 'all'
32
+ Requires-Dist: agentforge-anthropic[anthropic]~=0.2.4; extra == 'all'
33
+ Requires-Dist: agentforge-bedrock~=0.2.4; extra == 'all'
34
+ Requires-Dist: agentforge-chat-history-postgres~=0.2.4; extra == 'all'
35
+ Requires-Dist: agentforge-chat-history-redis~=0.2.4; extra == 'all'
36
+ Requires-Dist: agentforge-chat-http~=0.2.4; extra == 'all'
37
+ Requires-Dist: agentforge-chat-slack~=0.2.4; extra == 'all'
38
+ Requires-Dist: agentforge-chat~=0.2.4; extra == 'all'
39
+ Requires-Dist: agentforge-eval-geval~=0.2.4; extra == 'all'
40
+ Requires-Dist: agentforge-evidently[evidently]~=0.2.4; extra == 'all'
41
+ Requires-Dist: agentforge-guard-llamaguard~=0.2.4; extra == 'all'
42
+ Requires-Dist: agentforge-guard-llmguard~=0.2.4; extra == 'all'
43
+ Requires-Dist: agentforge-guard-nemo~=0.2.4; extra == 'all'
44
+ Requires-Dist: agentforge-guard-presidio~=0.2.4; extra == 'all'
45
+ Requires-Dist: agentforge-langfuse[langfuse]~=0.2.4; extra == 'all'
46
+ Requires-Dist: agentforge-litellm[litellm]~=0.2.4; extra == 'all'
47
+ Requires-Dist: agentforge-mcp[mcp]~=0.2.4; extra == 'all'
48
+ Requires-Dist: agentforge-memory-neo4j~=0.2.4; extra == 'all'
49
+ Requires-Dist: agentforge-memory-postgres~=0.2.4; extra == 'all'
50
+ Requires-Dist: agentforge-memory-sqlite~=0.2.4; extra == 'all'
51
+ Requires-Dist: agentforge-memory-surrealdb~=0.2.4; extra == 'all'
52
+ Requires-Dist: agentforge-ollama[ollama]~=0.2.4; extra == 'all'
53
+ Requires-Dist: agentforge-openai[openai]~=0.2.4; extra == 'all'
54
+ Requires-Dist: agentforge-otel~=0.2.4; extra == 'all'
55
+ Requires-Dist: agentforge-phoenix[phoenix]~=0.2.4; extra == 'all'
56
+ Requires-Dist: agentforge-reranker-cohere[cohere]~=0.2.4; extra == 'all'
57
+ Requires-Dist: agentforge-reranker-mixedbread[mixedbread]~=0.2.4; extra == 'all'
58
+ Requires-Dist: agentforge-reranker-sentence-transformers[sentence-transformers]~=0.2.4; extra == 'all'
59
+ Requires-Dist: agentforge-reranker-voyage[voyage]~=0.2.4; extra == 'all'
60
+ Requires-Dist: agentforge-statsd[statsd]~=0.2.4; extra == 'all'
61
+ Requires-Dist: agentforge-testing~=0.2.4; extra == 'all'
62
+ Requires-Dist: agentforge-voyage[voyage]~=0.2.4; extra == 'all'
63
+ Provides-Extra: anthropic
64
+ Requires-Dist: agentforge-anthropic[anthropic]~=0.2.4; extra == 'anthropic'
65
+ Provides-Extra: bedrock
66
+ Requires-Dist: agentforge-bedrock~=0.2.4; extra == 'bedrock'
67
+ Provides-Extra: chat
68
+ Requires-Dist: agentforge-chat~=0.2.4; extra == 'chat'
69
+ Provides-Extra: chat-history-postgres
70
+ Requires-Dist: agentforge-chat-history-postgres~=0.2.4; extra == 'chat-history-postgres'
71
+ Provides-Extra: chat-history-redis
72
+ Requires-Dist: agentforge-chat-history-redis~=0.2.4; extra == 'chat-history-redis'
73
+ Provides-Extra: chat-http
74
+ Requires-Dist: agentforge-chat-http~=0.2.4; extra == 'chat-http'
75
+ Provides-Extra: chat-slack
76
+ Requires-Dist: agentforge-chat-slack~=0.2.4; extra == 'chat-slack'
77
+ Provides-Extra: eval
78
+ Requires-Dist: agentforge-eval-geval~=0.2.4; extra == 'eval'
79
+ Provides-Extra: evidently
80
+ Requires-Dist: agentforge-evidently[evidently]~=0.2.4; extra == 'evidently'
81
+ Provides-Extra: guard-llamaguard
82
+ Requires-Dist: agentforge-guard-llamaguard~=0.2.4; extra == 'guard-llamaguard'
83
+ Provides-Extra: guard-llmguard
84
+ Requires-Dist: agentforge-guard-llmguard~=0.2.4; extra == 'guard-llmguard'
85
+ Provides-Extra: guard-nemo
86
+ Requires-Dist: agentforge-guard-nemo~=0.2.4; extra == 'guard-nemo'
87
+ Provides-Extra: guard-presidio
88
+ Requires-Dist: agentforge-guard-presidio~=0.2.4; extra == 'guard-presidio'
89
+ Provides-Extra: langfuse
90
+ Requires-Dist: agentforge-langfuse[langfuse]~=0.2.4; extra == 'langfuse'
91
+ Provides-Extra: litellm
92
+ Requires-Dist: agentforge-litellm[litellm]~=0.2.4; extra == 'litellm'
93
+ Provides-Extra: mcp
94
+ Requires-Dist: agentforge-mcp[mcp]~=0.2.4; extra == 'mcp'
95
+ Provides-Extra: memory-neo4j
96
+ Requires-Dist: agentforge-memory-neo4j~=0.2.4; extra == 'memory-neo4j'
97
+ Provides-Extra: memory-postgres
98
+ Requires-Dist: agentforge-memory-postgres~=0.2.4; extra == 'memory-postgres'
99
+ Provides-Extra: memory-sqlite
100
+ Requires-Dist: agentforge-memory-sqlite~=0.2.4; extra == 'memory-sqlite'
101
+ Provides-Extra: memory-surrealdb
102
+ Requires-Dist: agentforge-memory-surrealdb~=0.2.4; extra == 'memory-surrealdb'
103
+ Provides-Extra: ollama
104
+ Requires-Dist: agentforge-ollama[ollama]~=0.2.4; extra == 'ollama'
105
+ Provides-Extra: openai
106
+ Requires-Dist: agentforge-openai[openai]~=0.2.4; extra == 'openai'
107
+ Provides-Extra: otel
108
+ Requires-Dist: agentforge-otel~=0.2.4; extra == 'otel'
109
+ Provides-Extra: phoenix
110
+ Requires-Dist: agentforge-phoenix[phoenix]~=0.2.4; extra == 'phoenix'
111
+ Provides-Extra: reranker-cohere
112
+ Requires-Dist: agentforge-reranker-cohere[cohere]~=0.2.4; extra == 'reranker-cohere'
113
+ Provides-Extra: reranker-mixedbread
114
+ Requires-Dist: agentforge-reranker-mixedbread[mixedbread]~=0.2.4; extra == 'reranker-mixedbread'
115
+ Provides-Extra: reranker-sentence-transformers
116
+ Requires-Dist: agentforge-reranker-sentence-transformers[sentence-transformers]~=0.2.4; extra == 'reranker-sentence-transformers'
117
+ Provides-Extra: reranker-voyage
118
+ Requires-Dist: agentforge-reranker-voyage[voyage]~=0.2.4; extra == 'reranker-voyage'
119
+ Provides-Extra: statsd
120
+ Requires-Dist: agentforge-statsd[statsd]~=0.2.4; extra == 'statsd'
121
+ Provides-Extra: testing
122
+ Requires-Dist: agentforge-testing~=0.2.4; extra == 'testing'
123
+ Provides-Extra: voyage
124
+ Requires-Dist: agentforge-voyage[voyage]~=0.2.4; 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.2.4"
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.2.4",
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.2.4"]
65
+ openai = ["agentforge-openai[openai] ~= 0.2.4"]
66
+ bedrock = ["agentforge-bedrock ~= 0.2.4"]
67
+ ollama = ["agentforge-ollama[ollama] ~= 0.2.4"]
68
+ litellm = ["agentforge-litellm[litellm] ~= 0.2.4"]
69
+
70
+ # Embeddings
71
+ voyage = ["agentforge-voyage[voyage] ~= 0.2.4"]
72
+
73
+ # Memory backends (each hard-deps its driver SDK — no extra to chain)
74
+ memory-sqlite = ["agentforge-memory-sqlite ~= 0.2.4"]
75
+ memory-postgres = ["agentforge-memory-postgres ~= 0.2.4"]
76
+ memory-neo4j = ["agentforge-memory-neo4j ~= 0.2.4"]
77
+ memory-surrealdb = ["agentforge-memory-surrealdb ~= 0.2.4"]
78
+
79
+ # Chat surface (chat hard-deps aiosqlite; history backends hard-dep their SDK)
80
+ chat = ["agentforge-chat ~= 0.2.4"]
81
+ chat-http = ["agentforge-chat-http ~= 0.2.4"]
82
+ chat-slack = ["agentforge-chat-slack ~= 0.2.4"]
83
+ chat-history-postgres = ["agentforge-chat-history-postgres ~= 0.2.4"]
84
+ chat-history-redis = ["agentforge-chat-history-redis ~= 0.2.4"]
85
+
86
+ # Rerankers
87
+ reranker-cohere = ["agentforge-reranker-cohere[cohere] ~= 0.2.4"]
88
+ reranker-voyage = ["agentforge-reranker-voyage[voyage] ~= 0.2.4"]
89
+ reranker-mixedbread = ["agentforge-reranker-mixedbread[mixedbread] ~= 0.2.4"]
90
+ reranker-sentence-transformers = ["agentforge-reranker-sentence-transformers[sentence-transformers] ~= 0.2.4"]
91
+
92
+ # Guardrails (each hard-deps its SDK — no extra to chain)
93
+ guard-llmguard = ["agentforge-guard-llmguard ~= 0.2.4"]
94
+ guard-presidio = ["agentforge-guard-presidio ~= 0.2.4"]
95
+ guard-nemo = ["agentforge-guard-nemo ~= 0.2.4"]
96
+ guard-llamaguard = ["agentforge-guard-llamaguard ~= 0.2.4"]
97
+
98
+ # Observability
99
+ langfuse = ["agentforge-langfuse[langfuse] ~= 0.2.4"]
100
+ phoenix = ["agentforge-phoenix[phoenix] ~= 0.2.4"]
101
+ otel = ["agentforge-otel ~= 0.2.4"]
102
+ statsd = ["agentforge-statsd[statsd] ~= 0.2.4"]
103
+ evidently = ["agentforge-evidently[evidently] ~= 0.2.4"]
104
+
105
+ # Protocols
106
+ mcp = ["agentforge-mcp[mcp] ~= 0.2.4"]
107
+ a2a = ["agentforge-a2a ~= 0.2.4"]
108
+
109
+ # Eval
110
+ eval = ["agentforge-eval-geval ~= 0.2.4"]
111
+
112
+ # Testing
113
+ testing = ["agentforge-testing ~= 0.2.4"]
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.2.4",
121
+ "agentforge-openai[openai] ~= 0.2.4",
122
+ "agentforge-bedrock ~= 0.2.4",
123
+ "agentforge-ollama[ollama] ~= 0.2.4",
124
+ "agentforge-litellm[litellm] ~= 0.2.4",
125
+ "agentforge-voyage[voyage] ~= 0.2.4",
126
+ "agentforge-memory-sqlite ~= 0.2.4",
127
+ "agentforge-memory-postgres ~= 0.2.4",
128
+ "agentforge-memory-neo4j ~= 0.2.4",
129
+ "agentforge-memory-surrealdb ~= 0.2.4",
130
+ "agentforge-chat ~= 0.2.4",
131
+ "agentforge-chat-http ~= 0.2.4",
132
+ "agentforge-chat-slack ~= 0.2.4",
133
+ "agentforge-chat-history-postgres ~= 0.2.4",
134
+ "agentforge-chat-history-redis ~= 0.2.4",
135
+ "agentforge-reranker-cohere[cohere] ~= 0.2.4",
136
+ "agentforge-reranker-voyage[voyage] ~= 0.2.4",
137
+ "agentforge-reranker-mixedbread[mixedbread] ~= 0.2.4",
138
+ "agentforge-reranker-sentence-transformers[sentence-transformers] ~= 0.2.4",
139
+ "agentforge-guard-llmguard ~= 0.2.4",
140
+ "agentforge-guard-presidio ~= 0.2.4",
141
+ "agentforge-guard-nemo ~= 0.2.4",
142
+ "agentforge-guard-llamaguard ~= 0.2.4",
143
+ "agentforge-langfuse[langfuse] ~= 0.2.4",
144
+ "agentforge-phoenix[phoenix] ~= 0.2.4",
145
+ "agentforge-otel ~= 0.2.4",
146
+ "agentforge-statsd[statsd] ~= 0.2.4",
147
+ "agentforge-evidently[evidently] ~= 0.2.4",
148
+ "agentforge-mcp[mcp] ~= 0.2.4",
149
+ "agentforge-a2a ~= 0.2.4",
150
+ "agentforge-eval-geval ~= 0.2.4",
151
+ "agentforge-testing ~= 0.2.4",
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,7 @@ deterministic exit codes (per feat-017 §4 — config invalid → 2).
20
20
 
21
21
  from __future__ import annotations
22
22
 
23
+ import contextlib
23
24
  from pathlib import Path
24
25
  from typing import TYPE_CHECKING, Any
25
26
 
@@ -30,6 +31,7 @@ from agentforge_core.contracts.evaluator import Evaluator
30
31
  from agentforge_core.contracts.graph_store import GraphStore
31
32
  from agentforge_core.contracts.llm import LLMClient
32
33
  from agentforge_core.contracts.memory import MemoryStore
34
+ from agentforge_core.contracts.protocol_bridge import ProtocolBridge
33
35
  from agentforge_core.contracts.reranker import Reranker
34
36
  from agentforge_core.contracts.vector_store import VectorStore
35
37
  from agentforge_core.production.exceptions import ModuleError
@@ -82,18 +84,35 @@ async def build_agent_from_config(
82
84
  llm = _resolve_llm(config)
83
85
  strategy = config.agent.strategy if isinstance(config.agent.strategy, str) else None
84
86
 
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
- )
87
+ # feat-013 (bug-020): wire `modules.protocols` — resolve + start each
88
+ # handler (e.g. the MCP bridge), merge its tools with the native
89
+ # `agent.tools`, and hand the started bridges to the Agent so they're
90
+ # closed on `Agent.close()`. `build_protocols_from_config` has already
91
+ # awaited `start()` for every bridge it returns.
92
+ native_tools = build_tools_from_config(config)
93
+ mcp_tools, protocol_bridges = await build_protocols_from_config(config)
94
+ all_tools = [*native_tools, *mcp_tools]
95
+
96
+ try:
97
+ return Agent(
98
+ model=llm,
99
+ tools=all_tools or None,
100
+ memory=memory if memory is not None else InMemoryStore(),
101
+ evaluators=evaluators,
102
+ strategy=strategy,
103
+ retriever=retriever,
104
+ system_prompt=config.agent.system_prompt,
105
+ budget_usd=config.agent.budget.usd,
106
+ max_iterations=config.agent.max_iterations,
107
+ record_runs=memory if enable_recording and memory is not None else None,
108
+ pipeline=pipeline,
109
+ protocol_bridges=protocol_bridges,
110
+ )
111
+ except BaseException:
112
+ # Agent construction failed after bridges were started — don't
113
+ # leak the open transports / spawned subprocesses.
114
+ await _close_bridges(protocol_bridges)
115
+ raise
97
116
 
98
117
 
99
118
  def build_memory_from_config(config: AgentForgeConfig) -> MemoryStore | None:
@@ -259,6 +278,83 @@ def build_tools_from_config(config: AgentForgeConfig) -> list[Tool]:
259
278
  return tools
260
279
 
261
280
 
281
+ async def build_protocols_from_config(
282
+ config: AgentForgeConfig,
283
+ ) -> tuple[list[Tool], list[ProtocolBridge]]:
284
+ """Resolve + start every `modules.protocols` handler (feat-013).
285
+
286
+ For each entry: resolve its name under the ``protocols`` resolver
287
+ category, build the handler via its ``from_config(config)``
288
+ classmethod, ``await start()`` to open connections and discover
289
+ tools, then collect the merged tool list. The started bridges are
290
+ returned so the caller can ``close()`` them on agent teardown.
291
+
292
+ Returns an empty ``([], [])`` when no protocols are configured.
293
+
294
+ Raises:
295
+ ModuleError: a protocol isn't registered, lacks a
296
+ ``from_config`` classmethod, doesn't implement
297
+ `ProtocolBridge`, or requests server-side ``expose`` (not
298
+ wired into the runtime yet — see `_reject_unsupported_expose`).
299
+ """
300
+ from agentforge_core.contracts.tool import Tool as ToolBase # noqa: PLC0415
301
+
302
+ tools: list[ToolBase] = []
303
+ bridges: list[ProtocolBridge] = []
304
+ for entry in config.modules.protocols:
305
+ _reject_unsupported_expose(entry.name, entry.config)
306
+ cls = _resolve_class("protocols", entry.name)
307
+ from_config = getattr(cls, "from_config", None)
308
+ if not callable(from_config):
309
+ msg = (
310
+ f"Resolved protocol {entry.name!r} ({cls.__name__}) has no "
311
+ f"from_config(config) classmethod."
312
+ )
313
+ raise ModuleError(msg)
314
+ bridge = from_config(entry.config)
315
+ if not isinstance(bridge, ProtocolBridge):
316
+ msg = (
317
+ f"Resolved protocol {entry.name!r} ({cls.__name__}) does not "
318
+ f"implement ProtocolBridge (needs tools / start / close)."
319
+ )
320
+ raise ModuleError(msg)
321
+ try:
322
+ await bridge.start()
323
+ except BaseException:
324
+ # A later bridge failing must not leak earlier ones.
325
+ await _close_bridges(bridges)
326
+ raise
327
+ bridges.append(bridge)
328
+ tools.extend(bridge.tools)
329
+ return tools, bridges
330
+
331
+
332
+ def _reject_unsupported_expose(name: str, cfg: dict[str, Any]) -> None:
333
+ """Fail loud on server-side `expose`, which the runtime can't wire yet.
334
+
335
+ Auto-serving an MCP server from inside the agent process would hijack
336
+ the process's stdio. Consume-only is supported; expose runtime-wiring
337
+ is a follow-up (tracked alongside enh-001, MCP HTTP server transport).
338
+ """
339
+ expose = cfg.get("expose") or {}
340
+ if expose.get("enabled"):
341
+ msg = (
342
+ f"modules.protocols[{name!r}]: server-side `expose` is not wired "
343
+ "into the agent runtime yet (it would hijack the agent process's "
344
+ "stdio). Use consume-only config for now; expose runtime-wiring is "
345
+ "a follow-up (see enh-001)."
346
+ )
347
+ raise ModuleError(msg)
348
+
349
+
350
+ async def _close_bridges(bridges: list[ProtocolBridge]) -> None:
351
+ """Close every started bridge, swallowing teardown errors so one bad
352
+ close doesn't mask the original failure."""
353
+ for bridge in bridges:
354
+ with contextlib.suppress(Exception):
355
+ await bridge.close()
356
+
357
+
262
358
  def _resolve_llm(config: AgentForgeConfig) -> LLMClient | str | None:
263
359
  """Pick the LLM definition out of `config.agent.model` /
264
360
  `config.providers["default"]`.
@@ -317,6 +413,7 @@ __all__ = [
317
413
  "build_evaluators_from_config",
318
414
  "build_memory_from_config",
319
415
  "build_pipeline_from_config",
416
+ "build_protocols_from_config",
320
417
  "build_retriever_from_config",
321
418
  "build_tools_from_config",
322
419
  "load_and_build",
@@ -150,7 +150,9 @@ def _framework_version() -> str:
150
150
  from importlib.metadata import PackageNotFoundError, version # noqa: PLC0415
151
151
 
152
152
  try:
153
- return version("agentforge")
153
+ # Distribution name is `agentforge-py`, not the import name
154
+ # `agentforge` (bug-008). Do NOT change this back to "agentforge".
155
+ return version("agentforge-py")
154
156
  except PackageNotFoundError: # pragma: no cover
155
157
  return "0.0.0+unknown"
156
158
 
@@ -166,12 +166,17 @@ def _write_answers_file(
166
166
 
167
167
 
168
168
  def _template_version() -> str:
169
- """Resolve the installed `agentforge` version — used as the
169
+ """Resolve the installed framework version — used as the
170
170
  template's `source_version` in the lock file."""
171
171
  from importlib.metadata import PackageNotFoundError, version # noqa: PLC0415
172
172
 
173
173
  try:
174
- return version("agentforge")
174
+ # The PyPI *distribution* name is `agentforge-py` (the import name
175
+ # `agentforge` is a squatted PyPI project). `version()` keys off the
176
+ # distribution name, so `version("agentforge")` raised on every
177
+ # install and fell through to the sentinel (bug-008). Do NOT change
178
+ # this back to "agentforge".
179
+ return version("agentforge-py")
175
180
  except PackageNotFoundError: # pragma: no cover
176
181
  return "0.0.0+unknown"
177
182
 
@@ -54,18 +54,29 @@ log = logging.getLogger(__name__)
54
54
  def _events_for_new_steps(steps: list[Step], before: int) -> list[StreamingEvent]:
55
55
  """Build ``step`` `StreamingEvent`s for every step appended since
56
56
  the ``before`` index. Keeps the streaming-side rendering of state
57
- deltas separate from the strategy's recording semantics."""
58
- return [
59
- StreamingEvent(
60
- kind="step",
61
- content=step.content,
62
- metadata={
63
- "iteration": step.iteration,
64
- "kind": step.kind,
65
- },
57
+ deltas separate from the strategy's recording semantics.
58
+
59
+ ``tool_call`` is mirrored into metadata as a serialised dict when
60
+ present, so streaming consumers (e.g. `ChatSession._stream_per_token`,
61
+ bug-010) can persist tool turns alongside the final assistant turn
62
+ without needing access to the underlying `AgentState`.
63
+ """
64
+ out: list[StreamingEvent] = []
65
+ for step in steps[before:]:
66
+ metadata: dict[str, Any] = {
67
+ "iteration": step.iteration,
68
+ "kind": step.kind,
69
+ }
70
+ if step.tool_call is not None:
71
+ metadata["tool_call"] = step.tool_call.model_dump()
72
+ out.append(
73
+ StreamingEvent(
74
+ kind="step",
75
+ content=step.content,
76
+ metadata=metadata,
77
+ )
66
78
  )
67
- for step in steps[before:]
68
- ]
79
+ return out
69
80
 
70
81
 
71
82
  def get_runtime(state: AgentState) -> RuntimeContext:
@@ -83,7 +83,16 @@ class ReActLoop(StrategyBase):
83
83
  break
84
84
 
85
85
  # Record the assistant's turn for the next iteration's context.
86
- messages.append(Message(role="assistant", content=response.content))
86
+ # `tool_calls` must round-trip so provider clients can emit
87
+ # native tool-use blocks matching the subsequent tool result
88
+ # (bug-009 — Bedrock Converse rejects orphaned toolResult).
89
+ messages.append(
90
+ Message(
91
+ role="assistant",
92
+ content=response.content,
93
+ tool_calls=response.tool_calls,
94
+ )
95
+ )
87
96
 
88
97
  # Dispatch every tool call the LLM emitted.
89
98
  for tool_call in response.tool_calls:
@@ -174,7 +183,13 @@ class ReActLoop(StrategyBase):
174
183
  if not response.tool_calls:
175
184
  break
176
185
 
177
- messages.append(Message(role="assistant", content=response.content))
186
+ messages.append(
187
+ Message(
188
+ role="assistant",
189
+ content=response.content,
190
+ tool_calls=response.tool_calls,
191
+ )
192
+ )
178
193
 
179
194
  for tool_call in response.tool_calls:
180
195
  self._record_step(