agentforge-py 0.2.4__tar.gz → 0.3.1__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.4 → agentforge_py-0.3.1}/.gitignore +10 -0
- agentforge_py-0.3.1/PKG-INFO +158 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/pyproject.toml +66 -66
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/__init__.py +9 -1
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/cli/_build.py +59 -7
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/cli/config_cmd.py +9 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/cli/db_cmd.py +1 -1
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/cli/debug_cmd.py +1 -1
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/cli/health_cmd.py +3 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/cli/main.py +1 -1
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/cli/module_cmd.py +52 -4
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/cli/run_cmd.py +28 -3
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/AGENTS.md.tmpl +3 -2
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/docs/runbooks/13-configure-multi-provider.md +39 -0
- agentforge_py-0.3.1/tests/conftest.py +25 -0
- agentforge_py-0.3.1/tests/integration/test_add_module_uv_live.py +101 -0
- agentforge_py-0.3.1/tests/integration/test_configured_runtime_e2e.py +107 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_cli_build.py +136 -6
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_cli_config.py +56 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_cli_run.py +46 -0
- agentforge_py-0.3.1/tests/unit/test_cli_version.py +39 -0
- agentforge_py-0.3.1/tests/unit/test_example_swap_smoke.py +35 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_module_cmd.py +85 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_new_cmd.py +1 -1
- agentforge_py-0.2.4/PKG-INFO +0 -158
- agentforge_py-0.2.4/tests/conftest.py +0 -3
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/LICENSE +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/README.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/_testing/__init__.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/_testing/fake_llm.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/_testing/fake_tool.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/_tools/__init__.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/_tools/calculator.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/_tools/decorator.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/_tools/file_read.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/_tools/shell.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/_tools/web_search.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/agent.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/auth.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/cli/__init__.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/cli/_scaffold_state.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/cli/_shared_scaffold.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/cli/docs_cmd.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/cli/eval_cmd.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/cli/list_modules.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/cli/manifest_apply.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/cli/new_cmd.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/cli/upgrade_cmd.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/config/__init__.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/eval/__init__.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/eval/consistency.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/eval/coverage.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/eval/format_compliance.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/eval/regression.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/findings.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/guardrails/__init__.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/guardrails/allowlist.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/guardrails/capability_check.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/guardrails/engine.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/guardrails/pii_redact_basic.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/guardrails/prompt_injection_basic.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/memory/__init__.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/memory/in_memory.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/memory/in_memory_graph.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/memory/in_memory_vector.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/pipeline/__init__.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/pipeline/engine.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/pipeline/errors.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/pipeline/tool.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/py.typed +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/recording.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/renderers/__init__.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/renderers/_defaults.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/renderers/markdown.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/renderers/patch_applier.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/renderers/registry.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/renderers/scorecard.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/renderers/span_table.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/replay.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/resolver_register.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/retrieval.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/runtime.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/strategies/__init__.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/strategies/_base.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/strategies/_plan.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/strategies/multi_agent.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/strategies/plan_execute.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/strategies/react.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/strategies/tot.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/.cursorrules +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/.github/copilot-instructions.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/.gitkeep +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/CLAUDE.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/docs/runbooks/01-set-up-new-agent.md.tmpl +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/docs/runbooks/02-add-a-tool.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/docs/runbooks/03-add-a-pipeline-task.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/docs/runbooks/04-pick-reasoning-strategy.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/docs/runbooks/05-write-prompts.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/docs/runbooks/06-test-your-agent.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/docs/runbooks/07-debug-a-run.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/docs/runbooks/08-add-memory.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/docs/runbooks/09-add-mcp.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/docs/runbooks/10-add-evaluators.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/docs/runbooks/11-add-safety-guardrails.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/docs/runbooks/12-add-observability.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/docs/runbooks/14-deploy-your-agent.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/docs/runbooks/15-upgrade-your-agent.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/docs/runbooks/16-configuration-reference.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/docs/runbooks/17-add-reranker.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/docs/runbooks/18-add-hybrid-search.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/docs/runbooks/19-add-graphrag.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/docs/runbooks/20-apply-schema-migrations.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/docs/runbooks/21-use-streaming-guardrails.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/_shared/docs/runbooks/README.md.tmpl +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/code-reviewer/.env.example +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/code-reviewer/.gitignore +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/code-reviewer/README.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/code-reviewer/agentforge.yaml +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/code-reviewer/copier.yml +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/code-reviewer/pyproject.toml +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/code-reviewer/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/code-reviewer/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/docs-qa/.env.example +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/docs-qa/.gitignore +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/docs-qa/README.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/docs-qa/agentforge.yaml +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/docs-qa/copier.yml +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/docs-qa/pyproject.toml +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/docs-qa/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/docs-qa/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/minimal/.env.example +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/minimal/.gitignore +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/minimal/README.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/minimal/agentforge.yaml +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/minimal/copier.yml +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/minimal/pyproject.toml +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/minimal/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/minimal/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/patch-bot/.env.example +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/patch-bot/.gitignore +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/patch-bot/README.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/patch-bot/agentforge.yaml +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/patch-bot/copier.yml +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/patch-bot/pyproject.toml +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/patch-bot/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/patch-bot/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/research/.env.example +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/research/.gitignore +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/research/README.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/research/agentforge.yaml +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/research/copier.yml +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/research/pyproject.toml +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/research/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/research/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/triage/.env.example +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/triage/.gitignore +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/triage/README.md +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/triage/agentforge.yaml +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/triage/copier.yml +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/triage/pyproject.toml +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/triage/src/{{project_slug.replace('-', '_')}}/__init__.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/templates/triage/src/{{project_slug.replace('-', '_')}}/main.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/testing/__init__.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/testing/conformance.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/testing/factory.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/testing/fixtures.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/testing/llm.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/testing/recording.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/src/agentforge/tools/__init__.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/integration/test_web_search_live.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/.gitkeep +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_agent.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_agent_evaluators.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_agent_fallback_chain.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_agent_graph_store.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_agent_hooks.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_agent_pipeline.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_agent_retriever.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_build_retriever.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_cli_build_pipeline.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_cli_db.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_cli_debug.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_cli_docs.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_cli_eval.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_cli_health.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_cli_list_modules.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_config.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_env_bearer_auth.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_eval_consistency.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_eval_coverage.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_eval_format_compliance.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_eval_regression.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_extras_chain.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_fake_tool.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_findings.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_graph_store_properties.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_guardrails_builtins.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_guardrails_conformance.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_guardrails_engine.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_in_memory_graph_store.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_in_memory_store.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_in_memory_vector_store.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_manifest_apply.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_multi_agent_stream.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_pipeline_engine.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_plan.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_plan_execute_stream.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_react_stream.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_recording.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_renderer_pipeline_findings.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_renderer_registry.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_renderers_builtin.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_replay.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_retrieval.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_retrieval_rerank.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_retriever_graphrag.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_retriever_hybrid.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_runtime.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_scaffold_state.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_shared_scaffold.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_strategies_base.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_strategies_budget_properties.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_strategies_dispatch_tool.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_strategies_multi_agent.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_strategies_plan_execute.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_strategies_react.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_strategies_tot.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_testing_factory.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_testing_fake_llm.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_testing_mock_llm.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_testing_recording.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_three_section_format.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_tool_decorator.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_tools_calculator.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_tools_file_read.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_tools_shell.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_tools_web_search.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/tests/unit/test_tot_stream.py +0 -0
- {agentforge_py-0.2.4 → agentforge_py-0.3.1}/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.1
|
|
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.1
|
|
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.1; extra == 'a2a'
|
|
30
|
+
Provides-Extra: all
|
|
31
|
+
Requires-Dist: agentforge-a2a~=0.3.1; extra == 'all'
|
|
32
|
+
Requires-Dist: agentforge-anthropic[anthropic]~=0.3.1; extra == 'all'
|
|
33
|
+
Requires-Dist: agentforge-bedrock~=0.3.1; extra == 'all'
|
|
34
|
+
Requires-Dist: agentforge-chat-history-postgres~=0.3.1; extra == 'all'
|
|
35
|
+
Requires-Dist: agentforge-chat-history-redis~=0.3.1; extra == 'all'
|
|
36
|
+
Requires-Dist: agentforge-chat-http~=0.3.1; extra == 'all'
|
|
37
|
+
Requires-Dist: agentforge-chat-slack~=0.3.1; extra == 'all'
|
|
38
|
+
Requires-Dist: agentforge-chat~=0.3.1; extra == 'all'
|
|
39
|
+
Requires-Dist: agentforge-eval-geval~=0.3.1; extra == 'all'
|
|
40
|
+
Requires-Dist: agentforge-evidently[evidently]~=0.3.1; extra == 'all'
|
|
41
|
+
Requires-Dist: agentforge-guard-llamaguard~=0.3.1; extra == 'all'
|
|
42
|
+
Requires-Dist: agentforge-guard-llmguard~=0.3.1; extra == 'all'
|
|
43
|
+
Requires-Dist: agentforge-guard-nemo~=0.3.1; extra == 'all'
|
|
44
|
+
Requires-Dist: agentforge-guard-presidio~=0.3.1; extra == 'all'
|
|
45
|
+
Requires-Dist: agentforge-langfuse[langfuse]~=0.3.1; extra == 'all'
|
|
46
|
+
Requires-Dist: agentforge-litellm[litellm]~=0.3.1; extra == 'all'
|
|
47
|
+
Requires-Dist: agentforge-mcp[mcp]~=0.3.1; extra == 'all'
|
|
48
|
+
Requires-Dist: agentforge-memory-neo4j~=0.3.1; extra == 'all'
|
|
49
|
+
Requires-Dist: agentforge-memory-postgres~=0.3.1; extra == 'all'
|
|
50
|
+
Requires-Dist: agentforge-memory-sqlite~=0.3.1; extra == 'all'
|
|
51
|
+
Requires-Dist: agentforge-memory-surrealdb~=0.3.1; extra == 'all'
|
|
52
|
+
Requires-Dist: agentforge-ollama[ollama]~=0.3.1; extra == 'all'
|
|
53
|
+
Requires-Dist: agentforge-openai[openai]~=0.3.1; extra == 'all'
|
|
54
|
+
Requires-Dist: agentforge-otel~=0.3.1; extra == 'all'
|
|
55
|
+
Requires-Dist: agentforge-phoenix[phoenix]~=0.3.1; extra == 'all'
|
|
56
|
+
Requires-Dist: agentforge-reranker-cohere[cohere]~=0.3.1; extra == 'all'
|
|
57
|
+
Requires-Dist: agentforge-reranker-mixedbread[mixedbread]~=0.3.1; extra == 'all'
|
|
58
|
+
Requires-Dist: agentforge-reranker-sentence-transformers[sentence-transformers]~=0.3.1; extra == 'all'
|
|
59
|
+
Requires-Dist: agentforge-reranker-voyage[voyage]~=0.3.1; extra == 'all'
|
|
60
|
+
Requires-Dist: agentforge-statsd[statsd]~=0.3.1; extra == 'all'
|
|
61
|
+
Requires-Dist: agentforge-testing~=0.3.1; extra == 'all'
|
|
62
|
+
Requires-Dist: agentforge-voyage[voyage]~=0.3.1; extra == 'all'
|
|
63
|
+
Provides-Extra: anthropic
|
|
64
|
+
Requires-Dist: agentforge-anthropic[anthropic]~=0.3.1; extra == 'anthropic'
|
|
65
|
+
Provides-Extra: bedrock
|
|
66
|
+
Requires-Dist: agentforge-bedrock~=0.3.1; extra == 'bedrock'
|
|
67
|
+
Provides-Extra: chat
|
|
68
|
+
Requires-Dist: agentforge-chat~=0.3.1; extra == 'chat'
|
|
69
|
+
Provides-Extra: chat-history-postgres
|
|
70
|
+
Requires-Dist: agentforge-chat-history-postgres~=0.3.1; extra == 'chat-history-postgres'
|
|
71
|
+
Provides-Extra: chat-history-redis
|
|
72
|
+
Requires-Dist: agentforge-chat-history-redis~=0.3.1; extra == 'chat-history-redis'
|
|
73
|
+
Provides-Extra: chat-http
|
|
74
|
+
Requires-Dist: agentforge-chat-http~=0.3.1; extra == 'chat-http'
|
|
75
|
+
Provides-Extra: chat-slack
|
|
76
|
+
Requires-Dist: agentforge-chat-slack~=0.3.1; extra == 'chat-slack'
|
|
77
|
+
Provides-Extra: eval
|
|
78
|
+
Requires-Dist: agentforge-eval-geval~=0.3.1; extra == 'eval'
|
|
79
|
+
Provides-Extra: evidently
|
|
80
|
+
Requires-Dist: agentforge-evidently[evidently]~=0.3.1; extra == 'evidently'
|
|
81
|
+
Provides-Extra: guard-llamaguard
|
|
82
|
+
Requires-Dist: agentforge-guard-llamaguard~=0.3.1; extra == 'guard-llamaguard'
|
|
83
|
+
Provides-Extra: guard-llmguard
|
|
84
|
+
Requires-Dist: agentforge-guard-llmguard~=0.3.1; extra == 'guard-llmguard'
|
|
85
|
+
Provides-Extra: guard-nemo
|
|
86
|
+
Requires-Dist: agentforge-guard-nemo~=0.3.1; extra == 'guard-nemo'
|
|
87
|
+
Provides-Extra: guard-presidio
|
|
88
|
+
Requires-Dist: agentforge-guard-presidio~=0.3.1; extra == 'guard-presidio'
|
|
89
|
+
Provides-Extra: langfuse
|
|
90
|
+
Requires-Dist: agentforge-langfuse[langfuse]~=0.3.1; extra == 'langfuse'
|
|
91
|
+
Provides-Extra: litellm
|
|
92
|
+
Requires-Dist: agentforge-litellm[litellm]~=0.3.1; extra == 'litellm'
|
|
93
|
+
Provides-Extra: mcp
|
|
94
|
+
Requires-Dist: agentforge-mcp[mcp]~=0.3.1; extra == 'mcp'
|
|
95
|
+
Provides-Extra: memory-neo4j
|
|
96
|
+
Requires-Dist: agentforge-memory-neo4j~=0.3.1; extra == 'memory-neo4j'
|
|
97
|
+
Provides-Extra: memory-postgres
|
|
98
|
+
Requires-Dist: agentforge-memory-postgres~=0.3.1; extra == 'memory-postgres'
|
|
99
|
+
Provides-Extra: memory-sqlite
|
|
100
|
+
Requires-Dist: agentforge-memory-sqlite~=0.3.1; extra == 'memory-sqlite'
|
|
101
|
+
Provides-Extra: memory-surrealdb
|
|
102
|
+
Requires-Dist: agentforge-memory-surrealdb~=0.3.1; extra == 'memory-surrealdb'
|
|
103
|
+
Provides-Extra: ollama
|
|
104
|
+
Requires-Dist: agentforge-ollama[ollama]~=0.3.1; extra == 'ollama'
|
|
105
|
+
Provides-Extra: openai
|
|
106
|
+
Requires-Dist: agentforge-openai[openai]~=0.3.1; extra == 'openai'
|
|
107
|
+
Provides-Extra: otel
|
|
108
|
+
Requires-Dist: agentforge-otel~=0.3.1; extra == 'otel'
|
|
109
|
+
Provides-Extra: phoenix
|
|
110
|
+
Requires-Dist: agentforge-phoenix[phoenix]~=0.3.1; extra == 'phoenix'
|
|
111
|
+
Provides-Extra: reranker-cohere
|
|
112
|
+
Requires-Dist: agentforge-reranker-cohere[cohere]~=0.3.1; extra == 'reranker-cohere'
|
|
113
|
+
Provides-Extra: reranker-mixedbread
|
|
114
|
+
Requires-Dist: agentforge-reranker-mixedbread[mixedbread]~=0.3.1; extra == 'reranker-mixedbread'
|
|
115
|
+
Provides-Extra: reranker-sentence-transformers
|
|
116
|
+
Requires-Dist: agentforge-reranker-sentence-transformers[sentence-transformers]~=0.3.1; extra == 'reranker-sentence-transformers'
|
|
117
|
+
Provides-Extra: reranker-voyage
|
|
118
|
+
Requires-Dist: agentforge-reranker-voyage[voyage]~=0.3.1; extra == 'reranker-voyage'
|
|
119
|
+
Provides-Extra: statsd
|
|
120
|
+
Requires-Dist: agentforge-statsd[statsd]~=0.3.1; extra == 'statsd'
|
|
121
|
+
Provides-Extra: testing
|
|
122
|
+
Requires-Dist: agentforge-testing~=0.3.1; extra == 'testing'
|
|
123
|
+
Provides-Extra: voyage
|
|
124
|
+
Requires-Dist: agentforge-voyage[voyage]~=0.3.1; 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.
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
[project]
|
|
16
16
|
name = "agentforge-py"
|
|
17
|
-
version = "0.
|
|
17
|
+
version = "0.3.1"
|
|
18
18
|
description = "AgentForge — open-source plug-and-play framework for production AI agents"
|
|
19
19
|
readme = "README.md"
|
|
20
20
|
requires-python = ">=3.13"
|
|
@@ -36,7 +36,7 @@ classifiers = [
|
|
|
36
36
|
]
|
|
37
37
|
|
|
38
38
|
dependencies = [
|
|
39
|
-
"agentforge-core ~= 0.
|
|
39
|
+
"agentforge-core ~= 0.3.1",
|
|
40
40
|
"pydantic>=2.10",
|
|
41
41
|
"pyyaml>=6.0",
|
|
42
42
|
"typer>=0.15",
|
|
@@ -61,94 +61,94 @@ dependencies = [
|
|
|
61
61
|
# installs the wrapper but not the SDK and the first call raises a
|
|
62
62
|
# ModuleError (bug-015). bedrock hard-deps its SDK (aioboto3/botocore),
|
|
63
63
|
# so it requests no extra — and must NOT request a phantom `[bedrock]`.
|
|
64
|
-
anthropic = ["agentforge-anthropic[anthropic] ~= 0.
|
|
65
|
-
openai = ["agentforge-openai[openai] ~= 0.
|
|
66
|
-
bedrock = ["agentforge-bedrock ~= 0.
|
|
67
|
-
ollama = ["agentforge-ollama[ollama] ~= 0.
|
|
68
|
-
litellm = ["agentforge-litellm[litellm] ~= 0.
|
|
64
|
+
anthropic = ["agentforge-anthropic[anthropic] ~= 0.3.1"]
|
|
65
|
+
openai = ["agentforge-openai[openai] ~= 0.3.1"]
|
|
66
|
+
bedrock = ["agentforge-bedrock ~= 0.3.1"]
|
|
67
|
+
ollama = ["agentforge-ollama[ollama] ~= 0.3.1"]
|
|
68
|
+
litellm = ["agentforge-litellm[litellm] ~= 0.3.1"]
|
|
69
69
|
|
|
70
70
|
# Embeddings
|
|
71
|
-
voyage = ["agentforge-voyage[voyage] ~= 0.
|
|
71
|
+
voyage = ["agentforge-voyage[voyage] ~= 0.3.1"]
|
|
72
72
|
|
|
73
73
|
# Memory backends (each hard-deps its driver SDK — no extra to chain)
|
|
74
|
-
memory-sqlite = ["agentforge-memory-sqlite ~= 0.
|
|
75
|
-
memory-postgres = ["agentforge-memory-postgres ~= 0.
|
|
76
|
-
memory-neo4j = ["agentforge-memory-neo4j ~= 0.
|
|
77
|
-
memory-surrealdb = ["agentforge-memory-surrealdb ~= 0.
|
|
74
|
+
memory-sqlite = ["agentforge-memory-sqlite ~= 0.3.1"]
|
|
75
|
+
memory-postgres = ["agentforge-memory-postgres ~= 0.3.1"]
|
|
76
|
+
memory-neo4j = ["agentforge-memory-neo4j ~= 0.3.1"]
|
|
77
|
+
memory-surrealdb = ["agentforge-memory-surrealdb ~= 0.3.1"]
|
|
78
78
|
|
|
79
79
|
# Chat surface (chat hard-deps aiosqlite; history backends hard-dep their SDK)
|
|
80
|
-
chat = ["agentforge-chat ~= 0.
|
|
81
|
-
chat-http = ["agentforge-chat-http ~= 0.
|
|
82
|
-
chat-slack = ["agentforge-chat-slack ~= 0.
|
|
83
|
-
chat-history-postgres = ["agentforge-chat-history-postgres ~= 0.
|
|
84
|
-
chat-history-redis = ["agentforge-chat-history-redis ~= 0.
|
|
80
|
+
chat = ["agentforge-chat ~= 0.3.1"]
|
|
81
|
+
chat-http = ["agentforge-chat-http ~= 0.3.1"]
|
|
82
|
+
chat-slack = ["agentforge-chat-slack ~= 0.3.1"]
|
|
83
|
+
chat-history-postgres = ["agentforge-chat-history-postgres ~= 0.3.1"]
|
|
84
|
+
chat-history-redis = ["agentforge-chat-history-redis ~= 0.3.1"]
|
|
85
85
|
|
|
86
86
|
# Rerankers
|
|
87
|
-
reranker-cohere = ["agentforge-reranker-cohere[cohere] ~= 0.
|
|
88
|
-
reranker-voyage = ["agentforge-reranker-voyage[voyage] ~= 0.
|
|
89
|
-
reranker-mixedbread = ["agentforge-reranker-mixedbread[mixedbread] ~= 0.
|
|
90
|
-
reranker-sentence-transformers = ["agentforge-reranker-sentence-transformers[sentence-transformers] ~= 0.
|
|
87
|
+
reranker-cohere = ["agentforge-reranker-cohere[cohere] ~= 0.3.1"]
|
|
88
|
+
reranker-voyage = ["agentforge-reranker-voyage[voyage] ~= 0.3.1"]
|
|
89
|
+
reranker-mixedbread = ["agentforge-reranker-mixedbread[mixedbread] ~= 0.3.1"]
|
|
90
|
+
reranker-sentence-transformers = ["agentforge-reranker-sentence-transformers[sentence-transformers] ~= 0.3.1"]
|
|
91
91
|
|
|
92
92
|
# Guardrails (each hard-deps its SDK — no extra to chain)
|
|
93
|
-
guard-llmguard = ["agentforge-guard-llmguard ~= 0.
|
|
94
|
-
guard-presidio = ["agentforge-guard-presidio ~= 0.
|
|
95
|
-
guard-nemo = ["agentforge-guard-nemo ~= 0.
|
|
96
|
-
guard-llamaguard = ["agentforge-guard-llamaguard ~= 0.
|
|
93
|
+
guard-llmguard = ["agentforge-guard-llmguard ~= 0.3.1"]
|
|
94
|
+
guard-presidio = ["agentforge-guard-presidio ~= 0.3.1"]
|
|
95
|
+
guard-nemo = ["agentforge-guard-nemo ~= 0.3.1"]
|
|
96
|
+
guard-llamaguard = ["agentforge-guard-llamaguard ~= 0.3.1"]
|
|
97
97
|
|
|
98
98
|
# Observability
|
|
99
|
-
langfuse = ["agentforge-langfuse[langfuse] ~= 0.
|
|
100
|
-
phoenix = ["agentforge-phoenix[phoenix] ~= 0.
|
|
101
|
-
otel = ["agentforge-otel ~= 0.
|
|
102
|
-
statsd = ["agentforge-statsd[statsd] ~= 0.
|
|
103
|
-
evidently = ["agentforge-evidently[evidently] ~= 0.
|
|
99
|
+
langfuse = ["agentforge-langfuse[langfuse] ~= 0.3.1"]
|
|
100
|
+
phoenix = ["agentforge-phoenix[phoenix] ~= 0.3.1"]
|
|
101
|
+
otel = ["agentforge-otel ~= 0.3.1"]
|
|
102
|
+
statsd = ["agentforge-statsd[statsd] ~= 0.3.1"]
|
|
103
|
+
evidently = ["agentforge-evidently[evidently] ~= 0.3.1"]
|
|
104
104
|
|
|
105
105
|
# Protocols
|
|
106
|
-
mcp = ["agentforge-mcp[mcp] ~= 0.
|
|
107
|
-
a2a = ["agentforge-a2a ~= 0.
|
|
106
|
+
mcp = ["agentforge-mcp[mcp] ~= 0.3.1"]
|
|
107
|
+
a2a = ["agentforge-a2a ~= 0.3.1"]
|
|
108
108
|
|
|
109
109
|
# Eval
|
|
110
|
-
eval = ["agentforge-eval-geval ~= 0.
|
|
110
|
+
eval = ["agentforge-eval-geval ~= 0.3.1"]
|
|
111
111
|
|
|
112
112
|
# Testing
|
|
113
|
-
testing = ["agentforge-testing ~= 0.
|
|
113
|
+
testing = ["agentforge-testing ~= 0.3.1"]
|
|
114
114
|
|
|
115
115
|
# Everything (development / docs / smoke-test convenience — not
|
|
116
116
|
# recommended for production deploys; pick the actual integrations
|
|
117
117
|
# you use to keep the dependency tree small). Vendor-SDK extras are
|
|
118
118
|
# chained here too so `[all]` actually installs every SDK.
|
|
119
119
|
all = [
|
|
120
|
-
"agentforge-anthropic[anthropic] ~= 0.
|
|
121
|
-
"agentforge-openai[openai] ~= 0.
|
|
122
|
-
"agentforge-bedrock ~= 0.
|
|
123
|
-
"agentforge-ollama[ollama] ~= 0.
|
|
124
|
-
"agentforge-litellm[litellm] ~= 0.
|
|
125
|
-
"agentforge-voyage[voyage] ~= 0.
|
|
126
|
-
"agentforge-memory-sqlite ~= 0.
|
|
127
|
-
"agentforge-memory-postgres ~= 0.
|
|
128
|
-
"agentforge-memory-neo4j ~= 0.
|
|
129
|
-
"agentforge-memory-surrealdb ~= 0.
|
|
130
|
-
"agentforge-chat ~= 0.
|
|
131
|
-
"agentforge-chat-http ~= 0.
|
|
132
|
-
"agentforge-chat-slack ~= 0.
|
|
133
|
-
"agentforge-chat-history-postgres ~= 0.
|
|
134
|
-
"agentforge-chat-history-redis ~= 0.
|
|
135
|
-
"agentforge-reranker-cohere[cohere] ~= 0.
|
|
136
|
-
"agentforge-reranker-voyage[voyage] ~= 0.
|
|
137
|
-
"agentforge-reranker-mixedbread[mixedbread] ~= 0.
|
|
138
|
-
"agentforge-reranker-sentence-transformers[sentence-transformers] ~= 0.
|
|
139
|
-
"agentforge-guard-llmguard ~= 0.
|
|
140
|
-
"agentforge-guard-presidio ~= 0.
|
|
141
|
-
"agentforge-guard-nemo ~= 0.
|
|
142
|
-
"agentforge-guard-llamaguard ~= 0.
|
|
143
|
-
"agentforge-langfuse[langfuse] ~= 0.
|
|
144
|
-
"agentforge-phoenix[phoenix] ~= 0.
|
|
145
|
-
"agentforge-otel ~= 0.
|
|
146
|
-
"agentforge-statsd[statsd] ~= 0.
|
|
147
|
-
"agentforge-evidently[evidently] ~= 0.
|
|
148
|
-
"agentforge-mcp[mcp] ~= 0.
|
|
149
|
-
"agentforge-a2a ~= 0.
|
|
150
|
-
"agentforge-eval-geval ~= 0.
|
|
151
|
-
"agentforge-testing ~= 0.
|
|
120
|
+
"agentforge-anthropic[anthropic] ~= 0.3.1",
|
|
121
|
+
"agentforge-openai[openai] ~= 0.3.1",
|
|
122
|
+
"agentforge-bedrock ~= 0.3.1",
|
|
123
|
+
"agentforge-ollama[ollama] ~= 0.3.1",
|
|
124
|
+
"agentforge-litellm[litellm] ~= 0.3.1",
|
|
125
|
+
"agentforge-voyage[voyage] ~= 0.3.1",
|
|
126
|
+
"agentforge-memory-sqlite ~= 0.3.1",
|
|
127
|
+
"agentforge-memory-postgres ~= 0.3.1",
|
|
128
|
+
"agentforge-memory-neo4j ~= 0.3.1",
|
|
129
|
+
"agentforge-memory-surrealdb ~= 0.3.1",
|
|
130
|
+
"agentforge-chat ~= 0.3.1",
|
|
131
|
+
"agentforge-chat-http ~= 0.3.1",
|
|
132
|
+
"agentforge-chat-slack ~= 0.3.1",
|
|
133
|
+
"agentforge-chat-history-postgres ~= 0.3.1",
|
|
134
|
+
"agentforge-chat-history-redis ~= 0.3.1",
|
|
135
|
+
"agentforge-reranker-cohere[cohere] ~= 0.3.1",
|
|
136
|
+
"agentforge-reranker-voyage[voyage] ~= 0.3.1",
|
|
137
|
+
"agentforge-reranker-mixedbread[mixedbread] ~= 0.3.1",
|
|
138
|
+
"agentforge-reranker-sentence-transformers[sentence-transformers] ~= 0.3.1",
|
|
139
|
+
"agentforge-guard-llmguard ~= 0.3.1",
|
|
140
|
+
"agentforge-guard-presidio ~= 0.3.1",
|
|
141
|
+
"agentforge-guard-nemo ~= 0.3.1",
|
|
142
|
+
"agentforge-guard-llamaguard ~= 0.3.1",
|
|
143
|
+
"agentforge-langfuse[langfuse] ~= 0.3.1",
|
|
144
|
+
"agentforge-phoenix[phoenix] ~= 0.3.1",
|
|
145
|
+
"agentforge-otel ~= 0.3.1",
|
|
146
|
+
"agentforge-statsd[statsd] ~= 0.3.1",
|
|
147
|
+
"agentforge-evidently[evidently] ~= 0.3.1",
|
|
148
|
+
"agentforge-mcp[mcp] ~= 0.3.1",
|
|
149
|
+
"agentforge-a2a ~= 0.3.1",
|
|
150
|
+
"agentforge-eval-geval ~= 0.3.1",
|
|
151
|
+
"agentforge-testing ~= 0.3.1",
|
|
152
152
|
]
|
|
153
153
|
|
|
154
154
|
[project.scripts]
|
|
@@ -19,6 +19,11 @@ the per-feature specs under `docs/features/`.
|
|
|
19
19
|
|
|
20
20
|
from __future__ import annotations
|
|
21
21
|
|
|
22
|
+
# Version is sourced from the installed distribution metadata so it can
|
|
23
|
+
# never drift from pyproject.toml (bug-024).
|
|
24
|
+
from importlib.metadata import PackageNotFoundError as _PkgNotFound
|
|
25
|
+
from importlib.metadata import version as _dist_version
|
|
26
|
+
|
|
22
27
|
from agentforge_core import FallbackChain
|
|
23
28
|
|
|
24
29
|
# feat-018: importing `agentforge.guardrails` here triggers the
|
|
@@ -69,7 +74,10 @@ from agentforge.strategies import (
|
|
|
69
74
|
get_runtime,
|
|
70
75
|
)
|
|
71
76
|
|
|
72
|
-
|
|
77
|
+
try:
|
|
78
|
+
__version__ = _dist_version("agentforge-py")
|
|
79
|
+
except _PkgNotFound: # pragma: no cover - source tree without installed metadata
|
|
80
|
+
__version__ = "0.0.0+unknown"
|
|
73
81
|
|
|
74
82
|
__all__ = [
|
|
75
83
|
"RUNTIME_KEY",
|
|
@@ -21,6 +21,7 @@ deterministic exit codes (per feat-017 §4 — config invalid → 2).
|
|
|
21
21
|
from __future__ import annotations
|
|
22
22
|
|
|
23
23
|
import contextlib
|
|
24
|
+
import inspect
|
|
24
25
|
from pathlib import Path
|
|
25
26
|
from typing import TYPE_CHECKING, Any
|
|
26
27
|
|
|
@@ -75,7 +76,7 @@ async def build_agent_from_config(
|
|
|
75
76
|
Splits out from `load_and_build` for tests + reuse — tests build
|
|
76
77
|
a `AgentForgeConfig` directly and skip the YAML parse.
|
|
77
78
|
"""
|
|
78
|
-
memory = build_memory_from_config(config)
|
|
79
|
+
memory = await build_memory_from_config(config)
|
|
79
80
|
if memory is not None:
|
|
80
81
|
await _maybe_init_schema(memory)
|
|
81
82
|
evaluators = build_evaluators_from_config(config)
|
|
@@ -115,12 +116,18 @@ async def build_agent_from_config(
|
|
|
115
116
|
raise
|
|
116
117
|
|
|
117
118
|
|
|
118
|
-
def build_memory_from_config(config: AgentForgeConfig) -> MemoryStore | None:
|
|
119
|
-
"""Resolve + instantiate `modules.memory`. Returns None when absent.
|
|
119
|
+
async def build_memory_from_config(config: AgentForgeConfig) -> MemoryStore | None:
|
|
120
|
+
"""Resolve + instantiate `modules.memory`. Returns None when absent.
|
|
121
|
+
|
|
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
|
+
"""
|
|
120
127
|
if config.modules.memory is None:
|
|
121
128
|
return None
|
|
122
129
|
cls = _resolve_class("memory", config.modules.memory.driver)
|
|
123
|
-
instance =
|
|
130
|
+
instance = await _ainstantiate_memory(cls, config.modules.memory.config)
|
|
124
131
|
if not isinstance(instance, MemoryStore):
|
|
125
132
|
msg = (
|
|
126
133
|
f"Resolved memory driver {config.modules.memory.driver!r} "
|
|
@@ -362,8 +369,12 @@ def _resolve_llm(config: AgentForgeConfig) -> LLMClient | str | None:
|
|
|
362
369
|
We hand a string back to `Agent.__init__` when the model is a
|
|
363
370
|
plain `"<provider>:<model>"` string — `Agent` already knows how
|
|
364
371
|
to resolve that. When `agent.model` is missing but
|
|
365
|
-
`providers["default"]` is present,
|
|
366
|
-
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.
|
|
367
378
|
"""
|
|
368
379
|
raw = config.agent.model
|
|
369
380
|
if isinstance(raw, str):
|
|
@@ -371,7 +382,25 @@ def _resolve_llm(config: AgentForgeConfig) -> LLMClient | str | None:
|
|
|
371
382
|
default = config.providers.get("default")
|
|
372
383
|
if default is None or default.model is None:
|
|
373
384
|
return None
|
|
374
|
-
|
|
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
|
|
375
404
|
|
|
376
405
|
|
|
377
406
|
def _resolve_class(category: str, name: str) -> type:
|
|
@@ -402,6 +431,29 @@ def _instantiate(cls: type, cfg: dict[str, Any]) -> Any:
|
|
|
402
431
|
return cls(**cfg)
|
|
403
432
|
|
|
404
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
|
+
|
|
405
457
|
async def _maybe_init_schema(memory: MemoryStore) -> None:
|
|
406
458
|
init = getattr(memory, "init_schema", None)
|
|
407
459
|
if callable(init):
|
|
@@ -26,6 +26,7 @@ import yaml
|
|
|
26
26
|
from agentforge_core.config import (
|
|
27
27
|
AgentForgeConfig,
|
|
28
28
|
load_config,
|
|
29
|
+
validate_app_config,
|
|
29
30
|
validate_module_configs,
|
|
30
31
|
)
|
|
31
32
|
from agentforge_core.production.exceptions import ModuleError
|
|
@@ -128,6 +129,14 @@ def _run_validate(args: argparse.Namespace) -> int:
|
|
|
128
129
|
except ModuleError as exc:
|
|
129
130
|
sys.stderr.write(f"module config validation failed: {exc}\n")
|
|
130
131
|
return 1
|
|
132
|
+
# Registered `app.<section>` schemas are always validated strictly
|
|
133
|
+
# (feat-026 Phase 2). Unregistered / not-installed sections are
|
|
134
|
+
# free-form, so `--strict-modules` governs only module resolution.
|
|
135
|
+
try:
|
|
136
|
+
validate_app_config(cfg)
|
|
137
|
+
except ModuleError as exc:
|
|
138
|
+
sys.stderr.write(f"app config validation failed: {exc}\n")
|
|
139
|
+
return 1
|
|
131
140
|
sys.stdout.write("OK\n")
|
|
132
141
|
return 0
|
|
133
142
|
|
|
@@ -83,7 +83,7 @@ async def _dispatch(args: argparse.Namespace) -> int:
|
|
|
83
83
|
from agentforge_core.config.loader import load_config # noqa: PLC0415
|
|
84
84
|
|
|
85
85
|
config = load_config(args.path, env=args.env, overrides=list(args.override) or None)
|
|
86
|
-
memory = build_memory_from_config(config)
|
|
86
|
+
memory = await build_memory_from_config(config)
|
|
87
87
|
if memory is None:
|
|
88
88
|
sys.stderr.write("agentforge db: modules.memory must be configured.\n")
|
|
89
89
|
return 1
|
|
@@ -49,7 +49,7 @@ async def _dispatch(args: argparse.Namespace) -> int:
|
|
|
49
49
|
from agentforge_core.config.loader import load_config # noqa: PLC0415
|
|
50
50
|
|
|
51
51
|
config = load_config(args.path, env=args.env, overrides=list(args.override) or None)
|
|
52
|
-
memory = build_memory_from_config(config)
|
|
52
|
+
memory = await build_memory_from_config(config)
|
|
53
53
|
if memory is None:
|
|
54
54
|
sys.stderr.write("agentforge debug: modules.memory must be configured.\n")
|
|
55
55
|
return 1
|
|
@@ -16,6 +16,7 @@ from __future__ import annotations
|
|
|
16
16
|
|
|
17
17
|
import argparse
|
|
18
18
|
import asyncio
|
|
19
|
+
import inspect
|
|
19
20
|
import json
|
|
20
21
|
import sys
|
|
21
22
|
from pathlib import Path
|
|
@@ -113,6 +114,8 @@ async def _check_backends(config: AgentForgeConfig) -> list[dict[str, Any]]:
|
|
|
113
114
|
async def _probe(label: str, factory: Any) -> dict[str, Any]:
|
|
114
115
|
try:
|
|
115
116
|
instance = factory()
|
|
117
|
+
if inspect.isawaitable(instance):
|
|
118
|
+
instance = await instance
|
|
116
119
|
if instance is None:
|
|
117
120
|
return {"name": label, "kind": "backend", "ok": True, "detail": "none configured"}
|
|
118
121
|
init = getattr(instance, "init_schema", None)
|
|
@@ -72,7 +72,7 @@ def main(argv: Sequence[str] | None = None) -> int:
|
|
|
72
72
|
def _resolve_version() -> str:
|
|
73
73
|
"""Return the installed `agentforge` distribution's version."""
|
|
74
74
|
try:
|
|
75
|
-
return version("agentforge")
|
|
75
|
+
return version("agentforge-py")
|
|
76
76
|
except PackageNotFoundError: # pragma: no cover - unusual at runtime
|
|
77
77
|
return "0.0.0+unknown"
|
|
78
78
|
|
|
@@ -5,13 +5,24 @@ PR #16. They edit `agentforge.yaml`, apply per-module manifest
|
|
|
5
5
|
files, and shell out to `pip install` / `pip uninstall`.
|
|
6
6
|
|
|
7
7
|
The pip subprocess is injected via the `pip_run` callable so tests
|
|
8
|
-
can mock it without actually installing packages. Production uses
|
|
9
|
-
|
|
8
|
+
can mock it without actually installing packages. Production uses an
|
|
9
|
+
environment-aware default runner (`_default_pip_runner`) that picks
|
|
10
|
+
the right installer for the active environment:
|
|
11
|
+
|
|
12
|
+
1. **uv-managed project** (a `uv.lock` exists in the cwd or any
|
|
13
|
+
parent): use `uv add` / `uv remove` so the dependency is persisted
|
|
14
|
+
to `pyproject.toml` + `uv.lock` and survives a later `uv sync`.
|
|
15
|
+
2. **classic venv** (the `pip` module is importable): use
|
|
16
|
+
`python -m pip` so traditional pip-managed environments keep
|
|
17
|
+
working.
|
|
18
|
+
3. **uv venv that isn't a project** (no `uv.lock`, no `pip` module):
|
|
19
|
+
fall back to `uv pip --python <interpreter>`.
|
|
10
20
|
"""
|
|
11
21
|
|
|
12
22
|
from __future__ import annotations
|
|
13
23
|
|
|
14
24
|
import argparse
|
|
25
|
+
import importlib.util
|
|
15
26
|
import subprocess # nosec B404
|
|
16
27
|
import sys
|
|
17
28
|
from collections.abc import Callable, Sequence
|
|
@@ -239,9 +250,46 @@ def _print_next_steps(manifest: Manifest) -> None:
|
|
|
239
250
|
sys.stdout.write(f" - {step}\n")
|
|
240
251
|
|
|
241
252
|
|
|
253
|
+
def _find_uv_lock(start: Path) -> bool:
|
|
254
|
+
"""Return True if a `uv.lock` exists in `start` or any parent.
|
|
255
|
+
|
|
256
|
+
Walks from `start` up to the filesystem root. The presence of a
|
|
257
|
+
`uv.lock` is uv's signal that the current directory belongs to a
|
|
258
|
+
uv-managed project, where `uv add` / `uv remove` (which edit
|
|
259
|
+
`pyproject.toml` + `uv.lock`) are the correct install verbs.
|
|
260
|
+
"""
|
|
261
|
+
return any((directory / "uv.lock").exists() for directory in (start, *start.parents))
|
|
262
|
+
|
|
263
|
+
|
|
242
264
|
def _default_pip_runner(args: Sequence[str]) -> int:
|
|
243
|
-
"""
|
|
244
|
-
|
|
265
|
+
"""Install/uninstall a distribution using the right tool for the
|
|
266
|
+
active environment.
|
|
267
|
+
|
|
268
|
+
The runner receives pip-style args — `["install", <dist>]` or
|
|
269
|
+
`["uninstall", "-y", <dist>]` — and selects one of three commands:
|
|
270
|
+
|
|
271
|
+
1. **uv-managed project** (a `uv.lock` is found in the cwd or any
|
|
272
|
+
parent): translate to `uv add <dist>` / `uv remove <dist>`.
|
|
273
|
+
These edit `pyproject.toml` + `uv.lock`, so the dependency is
|
|
274
|
+
persisted and survives a later `uv sync` (plain `uv pip install`
|
|
275
|
+
does not — `uv sync` would uninstall it).
|
|
276
|
+
2. **classic venv** (the `pip` module is importable): use
|
|
277
|
+
`python -m pip <args>` so traditional pip-managed environments
|
|
278
|
+
keep working.
|
|
279
|
+
3. **uv venv that isn't a project** (no `uv.lock`, no `pip`
|
|
280
|
+
module): fall back to `uv pip --python <sys.executable> <args>`,
|
|
281
|
+
which installs into the active interpreter without needing a
|
|
282
|
+
`pip` module.
|
|
283
|
+
"""
|
|
284
|
+
if _find_uv_lock(Path.cwd()):
|
|
285
|
+
verb = args[0]
|
|
286
|
+
distribution = args[-1]
|
|
287
|
+
uv_verb = "add" if verb == "install" else "remove"
|
|
288
|
+
cmd = ["uv", uv_verb, distribution]
|
|
289
|
+
elif importlib.util.find_spec("pip") is not None:
|
|
290
|
+
cmd = [sys.executable, "-m", "pip", *args]
|
|
291
|
+
else:
|
|
292
|
+
cmd = ["uv", "pip", "--python", sys.executable, *args]
|
|
245
293
|
# No untrusted input — args is built from CLI arg `distribution`
|
|
246
294
|
# which is just a distribution name string. shell=False (default).
|
|
247
295
|
return subprocess.run(cmd, check=False).returncode # noqa: S603 # nosec B603
|