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.
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/.gitignore +10 -0
- agentforge_py-0.3.0/PKG-INFO +158 -0
- agentforge_py-0.3.0/pyproject.toml +189 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/_tools/decorator.py +9 -1
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/agent.py +10 -1
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/_build.py +168 -19
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/_shared_scaffold.py +3 -1
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/config_cmd.py +9 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/db_cmd.py +1 -1
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/debug_cmd.py +1 -1
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/health_cmd.py +3 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/module_cmd.py +52 -4
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/new_cmd.py +7 -2
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/run_cmd.py +28 -3
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/strategies/_base.py +22 -11
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/strategies/react.py +17 -2
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/AGENTS.md.tmpl +3 -2
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/02-add-a-tool.md +5 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/13-configure-multi-provider.md +39 -0
- agentforge_py-0.3.0/tests/conftest.py +25 -0
- agentforge_py-0.3.0/tests/integration/test_add_module_uv_live.py +101 -0
- agentforge_py-0.3.0/tests/integration/test_configured_runtime_e2e.py +107 -0
- agentforge_py-0.3.0/tests/unit/test_cli_build.py +495 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_cli_config.py +56 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_cli_run.py +46 -0
- agentforge_py-0.3.0/tests/unit/test_example_swap_smoke.py +35 -0
- agentforge_py-0.3.0/tests/unit/test_extras_chain.py +103 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_module_cmd.py +85 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_new_cmd.py +22 -1
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_react_stream.py +23 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_strategies_react.py +28 -0
- agentforge_py-0.2.3/PKG-INFO +0 -158
- agentforge_py-0.2.3/pyproject.toml +0 -187
- agentforge_py-0.2.3/tests/conftest.py +0 -3
- agentforge_py-0.2.3/tests/unit/test_cli_build.py +0 -227
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/LICENSE +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/README.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/__init__.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/_testing/__init__.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/_testing/fake_llm.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/_testing/fake_tool.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/_tools/__init__.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/_tools/calculator.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/_tools/file_read.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/_tools/shell.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/_tools/web_search.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/auth.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/__init__.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/_scaffold_state.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/docs_cmd.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/eval_cmd.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/list_modules.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/main.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/manifest_apply.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/cli/upgrade_cmd.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/config/__init__.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/eval/__init__.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/eval/consistency.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/eval/coverage.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/eval/format_compliance.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/eval/regression.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/findings.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/guardrails/__init__.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/guardrails/allowlist.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/guardrails/capability_check.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/guardrails/engine.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/guardrails/pii_redact_basic.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/guardrails/prompt_injection_basic.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/memory/__init__.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/memory/in_memory.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/memory/in_memory_graph.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/memory/in_memory_vector.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/pipeline/__init__.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/pipeline/engine.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/pipeline/errors.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/pipeline/tool.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/py.typed +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/recording.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/renderers/__init__.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/renderers/_defaults.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/renderers/markdown.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/renderers/patch_applier.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/renderers/registry.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/renderers/scorecard.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/renderers/span_table.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/replay.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/resolver_register.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/retrieval.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/runtime.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/strategies/__init__.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/strategies/_plan.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/strategies/multi_agent.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/strategies/plan_execute.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/strategies/tot.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/.cursorrules +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/.github/copilot-instructions.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/.gitkeep +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/CLAUDE.md +0 -0
- {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
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/03-add-a-pipeline-task.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/04-pick-reasoning-strategy.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/05-write-prompts.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/06-test-your-agent.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/07-debug-a-run.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/08-add-memory.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/09-add-mcp.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/10-add-evaluators.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/11-add-safety-guardrails.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/12-add-observability.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/14-deploy-your-agent.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/15-upgrade-your-agent.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/16-configuration-reference.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/17-add-reranker.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/18-add-hybrid-search.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/19-add-graphrag.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/20-apply-schema-migrations.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/21-use-streaming-guardrails.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/_shared/docs/runbooks/README.md.tmpl +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/code-reviewer/.env.example +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/code-reviewer/.gitignore +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/code-reviewer/README.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/code-reviewer/agentforge.yaml +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/code-reviewer/copier.yml +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/code-reviewer/pyproject.toml +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/code-reviewer/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/code-reviewer/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/docs-qa/.env.example +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/docs-qa/.gitignore +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/docs-qa/README.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/docs-qa/agentforge.yaml +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/docs-qa/copier.yml +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/docs-qa/pyproject.toml +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/docs-qa/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/docs-qa/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/minimal/.env.example +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/minimal/.gitignore +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/minimal/README.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/minimal/agentforge.yaml +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/minimal/copier.yml +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/minimal/pyproject.toml +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/minimal/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/minimal/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/patch-bot/.env.example +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/patch-bot/.gitignore +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/patch-bot/README.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/patch-bot/agentforge.yaml +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/patch-bot/copier.yml +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/patch-bot/pyproject.toml +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/patch-bot/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/patch-bot/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/research/.env.example +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/research/.gitignore +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/research/README.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/research/agentforge.yaml +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/research/copier.yml +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/research/pyproject.toml +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/research/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/research/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/triage/.env.example +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/triage/.gitignore +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/triage/README.md +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/triage/agentforge.yaml +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/triage/copier.yml +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/triage/pyproject.toml +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/triage/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/templates/triage/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/testing/__init__.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/testing/conformance.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/testing/factory.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/testing/fixtures.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/testing/llm.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/testing/recording.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/src/agentforge/tools/__init__.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/integration/test_web_search_live.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/.gitkeep +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_agent.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_agent_evaluators.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_agent_fallback_chain.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_agent_graph_store.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_agent_hooks.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_agent_pipeline.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_agent_retriever.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_build_retriever.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_cli_build_pipeline.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_cli_db.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_cli_debug.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_cli_docs.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_cli_eval.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_cli_health.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_cli_list_modules.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_config.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_env_bearer_auth.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_eval_consistency.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_eval_coverage.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_eval_format_compliance.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_eval_regression.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_fake_tool.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_findings.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_graph_store_properties.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_guardrails_builtins.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_guardrails_conformance.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_guardrails_engine.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_in_memory_graph_store.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_in_memory_store.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_in_memory_vector_store.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_manifest_apply.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_multi_agent_stream.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_pipeline_engine.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_plan.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_plan_execute_stream.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_recording.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_renderer_pipeline_findings.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_renderer_registry.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_renderers_builtin.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_replay.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_retrieval.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_retrieval_rerank.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_retriever_graphrag.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_retriever_hybrid.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_runtime.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_scaffold_state.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_shared_scaffold.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_strategies_base.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_strategies_budget_properties.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_strategies_dispatch_tool.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_strategies_multi_agent.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_strategies_plan_execute.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_strategies_tot.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_testing_factory.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_testing_fake_llm.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_testing_mock_llm.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_testing_recording.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_three_section_format.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_tool_decorator.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_tools_calculator.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_tools_file_read.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_tools_shell.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_tools_web_search.py +0 -0
- {agentforge_py-0.2.3 → agentforge_py-0.3.0}/tests/unit/test_tot_stream.py +0 -0
- {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
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
100
|
-
|
|
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 =
|
|
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,
|
|
270
|
-
the
|
|
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
|
-
|
|
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",
|