adapt-agent 0.3.2__tar.gz → 0.4.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.
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/CHANGELOG.md +233 -1
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/PKG-INFO +1 -1
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/__init__.py +1 -1
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/evaluation/__init__.py +9 -1
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/__init__.py +9 -1
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/introspection/claude_agent.py +95 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/introspection/crewai.py +62 -7
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/introspection/google_adk.py +13 -3
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/introspection/langgraph.py +10 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/introspection/microsoft_agent_framework.py +20 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/introspection/openai_agents.py +80 -7
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/introspection/pydantic_ai.py +8 -1
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/judge.py +44 -8
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/optimizers.py +333 -113
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/parameters.py +23 -3
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/providers.py +15 -1
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/runners.py +208 -9
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/target.py +123 -17
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent.egg-info/PKG-INFO +1 -1
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/docs/evals.md +38 -5
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/docs/optimization.md +116 -7
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/claude_agent/03_evaluate_and_optimize.py +8 -4
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/openai_agents/03_evaluate_and_optimize.py +6 -3
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimize_introspect_claude_agent.py +104 -1
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimize_introspect_crewai.py +93 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimize_introspect_google_adk.py +12 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimize_introspect_langgraph.py +15 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimize_introspect_microsoft_agent_framework.py +53 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimize_introspect_openai_agents.py +83 -1
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimize_introspect_pydantic_ai.py +21 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimize_judge.py +25 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimize_optimizers.py +274 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimize_parameters.py +28 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimize_providers.py +39 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimize_runners.py +220 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimize_target.py +249 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/CODE_OF_CONDUCT.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/CONTRIBUTING.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/LICENSE +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/MANIFEST.in +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/README.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/SECURITY.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/__main__.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/adapters/__init__.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/adapters/_governed.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/adapters/base.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/adapters/claude_agent/__init__.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/adapters/crewai/__init__.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/adapters/google_adk/__init__.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/adapters/langgraph/__init__.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/adapters/microsoft_agent_framework/__init__.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/adapters/openai_agents/__init__.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/adapters/pydantic_ai/__init__.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/adversarial/__init__.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/cli/__init__.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/cli/__main__.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/core/__init__.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/core/governance.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/core/memory.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/core/middleware.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/core/policy.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/core/trust.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/core/types.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/exceptions.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/integrations/__init__.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/integrations/_common.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/integrations/agent_framework.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/integrations/claude_agent.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/integrations/crewai.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/integrations/google_adk.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/integrations/langgraph.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/integrations/openai_agents.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/integrations/pydantic_ai.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/observability/__init__.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/config.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/dataset.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/evals.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/evaluation.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/extractors.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/introspection/__init__.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/judges.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/metrics.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/performance.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/proposers.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/retry.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/patches/__init__.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/py.typed +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/security/__init__.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/security/firewall.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/security/taint_tracker.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/skills/__init__.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/skills/adapt-agent/SKILL.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/skills/adapt-agent/references/evals.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/skills/adapt-agent/references/guardrails.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/skills/adapt-agent/references/optimization.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent.egg-info/SOURCES.txt +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent.egg-info/dependency_links.txt +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent.egg-info/entry_points.txt +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent.egg-info/requires.txt +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent.egg-info/top_level.txt +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/docs/adapters.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/docs/api.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/docs/cli.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/docs/frameworks/claude_agent.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/docs/frameworks/crewai.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/docs/frameworks/google_adk.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/docs/frameworks/index.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/docs/frameworks/langgraph.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/docs/frameworks/microsoft_agent_framework.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/docs/frameworks/openai_agents.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/docs/frameworks/pydantic_ai.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/docs/index.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/docs/integrations.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/docs/observability.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/docs/policy.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/docs/quickstart.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/docs/releasing.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/docs/security.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/docs/skill.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/01_firewall_and_policy.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/02_adversarial_defense.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/03_langgraph_guarded_agent.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/04_observability.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/05_multi_framework_adapters.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/06_optimize_with_golden_dataset.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/07_train_from_yaml.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/08_agent_evals.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/README.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/claude_agent/01_basic_guarded.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/claude_agent/02_policy_observability_trust.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/claude_agent/04_multi_agent_and_training.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/claude_agent/README.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/claude_agent/claude_agent.train.yaml +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/config.example.json +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/crewai/01_basic_guarded.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/crewai/02_policy_observability_trust.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/crewai/03_evaluate_and_optimize.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/crewai/04_multi_agent_and_training.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/crewai/README.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/crewai/crewai.train.yaml +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/google_adk/01_basic_guarded.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/google_adk/02_policy_observability_trust.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/google_adk/03_evaluate_and_optimize.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/google_adk/04_multi_agent_and_training.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/google_adk/README.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/google_adk/google_adk.train.yaml +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/langgraph/01_basic_guarded.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/langgraph/02_policy_observability_trust.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/langgraph/03_evaluate_and_optimize.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/langgraph/04_multi_agent_and_training.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/langgraph/README.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/langgraph/langgraph.train.yaml +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/microsoft_agent_framework/01_basic_guarded.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/microsoft_agent_framework/02_policy_observability_trust.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/microsoft_agent_framework/03_evaluate_and_optimize.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/microsoft_agent_framework/04_magentic_team_and_training.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/microsoft_agent_framework/README.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/microsoft_agent_framework/magentic.train.yaml +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/openai_agents/01_basic_guarded.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/openai_agents/02_policy_observability_trust.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/openai_agents/04_multi_agent_and_training.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/openai_agents/README.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/openai_agents/openai_agents.train.yaml +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/pydantic_ai/01_basic_guarded.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/pydantic_ai/02_policy_observability_trust.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/pydantic_ai/03_evaluate_and_optimize.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/pydantic_ai/04_multi_agent_and_training.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/pydantic_ai/README.md +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/pydantic_ai/pydantic_ai.train.yaml +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/examples/train.example.yaml +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/pyproject.toml +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/setup.cfg +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/__init__.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_action_refs.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_adapters.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_adversarial.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_adversarial_extra.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_async_governance.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_cli.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_cli_optimize.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_cli_skills.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_core.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_evaluation.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_exceptions.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_firewall_extra.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_governed_adapters.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_integrations.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_memory.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_middleware.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_observability.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_observability_extra.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimization.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimize_config.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimize_dataset.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimize_evals.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimize_evaluation.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimize_extractors.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimize_introspection.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimize_judges.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimize_metrics.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimize_proposers.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_optimize_retry.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_patches.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_policy.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_public_dataclass_compat.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_security.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_skills.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_structured_evals.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_taint_tracker.py +0 -0
- {adapt_agent-0.3.2 → adapt_agent-0.4.0}/tests/test_trust.py +0 -0
|
@@ -7,6 +7,205 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.4.0] - 2026-08-27
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`verbose=True` now reports where a long run actually is, not just what it
|
|
15
|
+
found.** Per-trial logging showed a candidate's score with no sense of
|
|
16
|
+
position or pace -- indistinguishable, over a run measured in hours, from a
|
|
17
|
+
hang. Every optimizer's trial log now includes the trial's position out of
|
|
18
|
+
the run's evaluation budget and the wall-clock time elapsed since the run
|
|
19
|
+
started (`trial 5/60 score=0.7100 ACCEPT (142.3s elapsed)`), and the
|
|
20
|
+
baseline-start line states the budget up front
|
|
21
|
+
(`baseline score=0.4100 (search budget: up to 60 evals)`).
|
|
22
|
+
`PipelineOptimizer` -- which overrides `optimize()` entirely and so never
|
|
23
|
+
ran the base class's verbose logging for itself, only ever forwarding
|
|
24
|
+
`verbose` into each stage -- now also logs its own stage transitions
|
|
25
|
+
(`stage 2/4 (coordinate_ascent) starting: 15/60 evals used so far (203.1s
|
|
26
|
+
elapsed)`) and a completion summary, so a multi-stage `make_default_optimizer`
|
|
27
|
+
pipeline no longer reads as one unexplained pause between each stage's own
|
|
28
|
+
output.
|
|
29
|
+
|
|
30
|
+
`OptimizationResult` gained `duration_seconds` (wall-clock time for the
|
|
31
|
+
whole `optimize` call), appended at the end of the dataclass per its
|
|
32
|
+
append-only convention, surfaced in `to_dict()`, `repr()`, and the
|
|
33
|
+
provenance header `to_config()` writes to a tuned-config file.
|
|
34
|
+
|
|
35
|
+
- **`OptimizableAgent` (and every `from_*` constructor, plus `wrap()`) gained
|
|
36
|
+
`exclude=` and `replace=`, so introspection catching up to a hand-bound
|
|
37
|
+
workaround no longer silently doubles a knob.** Parameters are opaque
|
|
38
|
+
getter/setter closures, so the library cannot detect that two of them target
|
|
39
|
+
the *same* underlying storage under *different* names — only that two names
|
|
40
|
+
collide, which already raised. The gap: a caller hand-binds a parameter to
|
|
41
|
+
work around introspection missing a knob (a real, documented, and until now
|
|
42
|
+
the *only* supported reason to declare extra parameters), a later release
|
|
43
|
+
teaches introspection to find that same knob under its own name, and the two
|
|
44
|
+
now coexist pointing at one piece of storage — doubling that part of the
|
|
45
|
+
search space and letting whichever knob an optimizer applies last silently
|
|
46
|
+
overwrite the other's candidate. Nothing raised, because the names never
|
|
47
|
+
matched.
|
|
48
|
+
|
|
49
|
+
`exclude={"agent.instructions", ...}` removes named introspected parameters
|
|
50
|
+
from the space before declared `parameters` are merged in — the fix for the
|
|
51
|
+
reported shape, where the hand-bound and introspected knobs have different
|
|
52
|
+
names. `replace=True` instead lets a declared parameter *under the same
|
|
53
|
+
name* as an introspected one win outright, for overriding how a knob with a
|
|
54
|
+
name you want to keep is read/written. The default collision behavior
|
|
55
|
+
(`ValueError`) is unchanged — an unintended same-name clash is still caught,
|
|
56
|
+
since `replace` is opt-in. New primitives underneath: `SearchSpace.remove(name)`
|
|
57
|
+
(drop a knob, never raises for a missing name) and `SearchSpace.add(parameter,
|
|
58
|
+
replace=True)`; `OptimizableAgent.add_parameter(parameter, replace=True)`
|
|
59
|
+
exposes the same override after construction.
|
|
60
|
+
|
|
61
|
+
### Fixed
|
|
62
|
+
|
|
63
|
+
- **A completion callable that could not accept `system=` made the judge
|
|
64
|
+
grade silently without its rubric.** Every judge call
|
|
65
|
+
(`score`/`critique`/`compare`/`improve_prompt`) sends the grading
|
|
66
|
+
rubric/instructions via `complete(prompt, system=...)`. A callable
|
|
67
|
+
conforming to the *documented* `CompletionFn` shape — a plain
|
|
68
|
+
`def f(prompt: str) -> str`, exactly the form shown in the quick-start
|
|
69
|
+
example — raises `TypeError` on that call, and both places that catch it
|
|
70
|
+
(`CallableProvider.complete`, and `LLMJudge._invoke` for a bare callable
|
|
71
|
+
passed directly) fell back to `complete(prompt)`, dropping the rubric with
|
|
72
|
+
no warning. The judge kept returning normal-looking scores, indistinguishable
|
|
73
|
+
from a working judge, while silently grading blind on every call — a search
|
|
74
|
+
can burn its entire budget on an oracle that was never actually applying the
|
|
75
|
+
rubric. Both fallback sites now emit a `logger.warning` naming the dropped
|
|
76
|
+
keyword and how to fix the callable's signature; behavior is otherwise
|
|
77
|
+
unchanged; nothing raises. `CompletionFn`'s type widened from
|
|
78
|
+
`Callable[[str], str]` to `Callable[..., str]` to stop documenting a
|
|
79
|
+
signature that silently loses information in practice.
|
|
80
|
+
|
|
81
|
+
- **Optimizers stop paying for configurations they have already measured.**
|
|
82
|
+
Every optimizer now carries an evaluation cache (`cache_evaluations=True`)
|
|
83
|
+
keyed on the *live parameter state* at evaluation time, living for exactly
|
|
84
|
+
one `optimize` call. `PipelineOptimizer` injects one shared cache into its
|
|
85
|
+
stages -- and this is where the money was: each stage begins by evaluating
|
|
86
|
+
its baseline over the full dataset, and each stage's baseline *is* the
|
|
87
|
+
previous stage's winner, already measured. The default four-stage
|
|
88
|
+
`make_default_optimizer` pipeline was spending five full-dataset baseline
|
|
89
|
+
passes per run, four of them redundant; they are now cache hits. Keying on
|
|
90
|
+
the live state (not the candidate diff) is what makes those hits happen,
|
|
91
|
+
since a stage baseline and the winning trial that produced it reach the
|
|
92
|
+
same state through different configs.
|
|
93
|
+
|
|
94
|
+
The cost machinery this loop already had is deliberately untouched:
|
|
95
|
+
incomplete reports (rows lost to transient provider failures) are never
|
|
96
|
+
cached, so the baseline's re-run-on-incomplete path always re-measures, and
|
|
97
|
+
a cache hit still performs the restore/apply so proposers observe identical
|
|
98
|
+
live state either way. Live objects in the state (tool lists holding
|
|
99
|
+
callables) key by identity -- distinct-but-equal objects miss rather than
|
|
100
|
+
falsely hit, which only costs a re-run. Trial histories are unchanged:
|
|
101
|
+
cached trials record the same scores in the same order, so results are
|
|
102
|
+
byte-identical for a deterministic agent. Pass `cache_evaluations=False`
|
|
103
|
+
(per optimizer or per stage -- a stage's opt-out is respected inside a
|
|
104
|
+
caching pipeline) to re-measure every configuration, e.g. to average out a
|
|
105
|
+
stochastic agent.
|
|
106
|
+
|
|
107
|
+
- **Every supported framework is now drivable through one entry point --
|
|
108
|
+
including the three whose agents cannot run themselves.** An OpenAI Agents
|
|
109
|
+
SDK `Agent` is a configuration object executed by `Runner.run_sync(agent,
|
|
110
|
+
input)`; a Claude Agent SDK setup is a `ClaudeAgentOptions` driven by
|
|
111
|
+
`query(prompt=..., options=...)`; a bare Google ADK agent runs inside a
|
|
112
|
+
session-holding `Runner`. `resolve_runner` knows none of that, so
|
|
113
|
+
`evaluate_agent(...)`, `framework_runner(...)` and
|
|
114
|
+
`OptimizableAgent.from_agent(...)` -- the documented "point it at your agent"
|
|
115
|
+
entry points -- raised `TypeError` for exactly these frameworks, and every
|
|
116
|
+
example hand-wrote the driving lambda the SDK documents anyway.
|
|
117
|
+
|
|
118
|
+
Two new runner builders close the gap, mirroring `adk_runner`:
|
|
119
|
+
|
|
120
|
+
- **`openai_agents_runner(agent, *, runner=None, run_kwargs=None,
|
|
121
|
+
output_extractor=...)`** drives the agent through the SDK's `Runner`
|
|
122
|
+
(imported lazily; inject anything with a compatible `run_sync` -- or an
|
|
123
|
+
async `run`, which is awaited -- for tests and custom runners), forwarding
|
|
124
|
+
`run_kwargs` (e.g. `max_turns`, a shared `context`) to every call.
|
|
125
|
+
- **`claude_agent_runner(options, *, query_fn=None, output_extractor=...)`**
|
|
126
|
+
drives `query`, draining the async message stream synchronously and
|
|
127
|
+
extracting the final `ResultMessage` text. The options object is closed
|
|
128
|
+
over, not copied -- so the runner always reads the *live* object the
|
|
129
|
+
introspected parameters mutate, which is exactly what optimization needs.
|
|
130
|
+
|
|
131
|
+
`framework_runner` now **delegates by detected framework** when an object
|
|
132
|
+
exposes no run method at all (OpenAI Agents -> `openai_agents_runner`,
|
|
133
|
+
Claude options -> `claude_agent_runner`, bare ADK agent -> `adk_runner`),
|
|
134
|
+
and `OptimizableAgent.from_agent` falls back to `framework_runner` when
|
|
135
|
+
`resolve_runner` finds nothing runnable. Directly-runnable frameworks are
|
|
136
|
+
untouched -- resolution is attempted first and wins, so existing behaviour
|
|
137
|
+
(including framework-native outputs) is byte-identical; the fallback only
|
|
138
|
+
replaces a `TypeError`, never a working runner. A missing SDK surfaces as an
|
|
139
|
+
`ImportError` naming the extra to install, which is strictly more useful
|
|
140
|
+
than the `TypeError` it replaces. Both builders are exported from
|
|
141
|
+
`adapt_agent.optimization` and `adapt_agent.evaluation`.
|
|
142
|
+
|
|
143
|
+
- **Framework introspection reaches the knobs that steer multi-agent behaviour,
|
|
144
|
+
not just the ones on the front agent.** Two whole categories of tunable text
|
|
145
|
+
were invisible to the optimizer:
|
|
146
|
+
|
|
147
|
+
- *OpenAI Agents SDK*: an agent's `handoff_description` -- the text a routing
|
|
148
|
+
agent reads when deciding whether to delegate to it -- is now a PROMPT
|
|
149
|
+
parameter, and a `Handoff` **wrapper** in a `handoffs` list now contributes
|
|
150
|
+
its `tool_description` (as `<agent>_handoff.tool_description`). A wrapper
|
|
151
|
+
holds its agent inside an `on_invoke_handoff` closure, so the sub-agent
|
|
152
|
+
itself is structurally unreachable -- but the description is what the
|
|
153
|
+
routing LLM actually reads, and it is the part worth tuning. Previously a
|
|
154
|
+
topology built with `handoff(...)` lost the wrapped branch entirely, and
|
|
155
|
+
nothing tuned routing text anywhere.
|
|
156
|
+
|
|
157
|
+
- *Claude Agent SDK*: the subagent definitions in `options.agents` are now
|
|
158
|
+
introspected -- each definition's `prompt` and `description` (both
|
|
159
|
+
prompts: one steers the specialist, the other steers delegation *to* it),
|
|
160
|
+
its `model`, and its `tools`/`skills` lists (with the same drop-one
|
|
161
|
+
ablation candidates every other tool list gets), namespaced under the
|
|
162
|
+
slugged subagent name. Both real `AgentDefinition` objects and the plain
|
|
163
|
+
mappings the SDK also accepts are handled, and a subagent whose name
|
|
164
|
+
collides with the root component is skipped rather than allowed to produce
|
|
165
|
+
duplicate parameter names. The `agents` field was already recognised (it
|
|
166
|
+
stopped vetoing detection in 0.3.x) but its contents were never bound, so
|
|
167
|
+
a multi-agent Claude setup exposed only the orchestrator's knobs.
|
|
168
|
+
|
|
169
|
+
- **Sampling knobs the frameworks expose but introspection didn't.** Each is
|
|
170
|
+
bound with the same duck-typing rules as its neighbours (only when present,
|
|
171
|
+
only when the value has the right shape): CrewAI LLM objects gain `top_p`;
|
|
172
|
+
Google ADK `generate_content_config` gains `top_k` (bounded (1, 40), valid
|
|
173
|
+
for every Gemini generation so a gridded candidate never becomes a runtime
|
|
174
|
+
rejection); Pydantic AI `model_settings` and Microsoft Agent Framework
|
|
175
|
+
agents/clients/`default_options` gain `frequency_penalty` and
|
|
176
|
+
`presence_penalty` (bounded (-2.0, 2.0)); LangGraph bound chat models gain
|
|
177
|
+
`top_p`.
|
|
178
|
+
|
|
179
|
+
- **CrewAI `allow_delegation` is a searchable ROUTING parameter** with
|
|
180
|
+
`[True, False]` candidates -- whether an agent may hand work to its
|
|
181
|
+
crew-mates is a real topology decision the optimizer can now measure instead
|
|
182
|
+
of inherit. Bound only when the live value is a genuine `bool`.
|
|
183
|
+
|
|
184
|
+
- **Microsoft Agent Framework: the model is found even when the client hides
|
|
185
|
+
it.** When none of the client's model attributes exist, the per-agent
|
|
186
|
+
`model_id` override in `default_options` now binds as the MODEL parameter
|
|
187
|
+
(the client still wins when both are present). Previously such an agent had
|
|
188
|
+
no model knob at all despite the identifier sitting in its options mapping.
|
|
189
|
+
|
|
190
|
+
- **Claude Agent SDK: `max_thinking_tokens`** binds as a HYPERPARAM (bounds
|
|
191
|
+
(1024, 32000) -- the floor is the API's minimum thinking budget) on SDK
|
|
192
|
+
versions that carry it as a flat option.
|
|
193
|
+
|
|
194
|
+
### Changed
|
|
195
|
+
|
|
196
|
+
- **OpenAI Agents SDK `model_settings.max_tokens` now carries bounds
|
|
197
|
+
(1, 32000)**, like every other framework's max-tokens knob. Boundless, its
|
|
198
|
+
search space collapsed to the current value -- `enumerate_candidates()`
|
|
199
|
+
returned one option and the numeric proposer skipped it -- so it appeared in
|
|
200
|
+
every report as a parameter the optimizer could never actually move.
|
|
201
|
+
|
|
202
|
+
- **CrewAI tasks with a `name` are namespaced under it** (slugged), falling
|
|
203
|
+
back to the positional `task_<index>` only when nameless. A name survives
|
|
204
|
+
reordering the task list; an index silently rebinds every exported tuned
|
|
205
|
+
config to a different task. A config exported before this release for a
|
|
206
|
+
*named* task addresses `task_<index>` and will no longer re-apply -- re-run
|
|
207
|
+
`to_config()` (unnamed tasks are unaffected).
|
|
208
|
+
|
|
10
209
|
## [0.3.2] - 2026-08-24
|
|
11
210
|
|
|
12
211
|
### Changed
|
|
@@ -67,6 +266,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
67
266
|
report its version and each has the same fix. A diagnostic that fails on a
|
|
68
267
|
damaged file tells you least exactly when you need it most.
|
|
69
268
|
|
|
269
|
+
### Fixed
|
|
270
|
+
|
|
271
|
+
- **The evaluation cache could serve a report across two different
|
|
272
|
+
evaluators.** The cache key covered only the dataset identity and live
|
|
273
|
+
parameter state, so a `PipelineOptimizer` assembled from stages carrying
|
|
274
|
+
*different* harnesses (different metrics, a different judge) could let one
|
|
275
|
+
stage reuse a report another stage's harness produced, ranking candidates
|
|
276
|
+
against the wrong scores. The harness identity is now part of the key;
|
|
277
|
+
stages sharing one harness instance (how `make_default_optimizer` builds
|
|
278
|
+
pipelines) still share hits.
|
|
279
|
+
- **A pipeline-level `cache_evaluations=False` didn't reach its stages.**
|
|
280
|
+
`PipelineOptimizer(..., cache_evaluations=False)` cleared the *shared*
|
|
281
|
+
cache, but a stage left at its own default (`True`) then built a private
|
|
282
|
+
per-stage cache anyway, so repeated configurations were still served from
|
|
283
|
+
cache instead of re-measured. The pipeline's opt-out now suppresses stage
|
|
284
|
+
caching for the run; a stage's own opt-out inside a caching pipeline is
|
|
285
|
+
still respected.
|
|
286
|
+
- **Two CrewAI tasks with the same (or identically-slugged) `name` collided.**
|
|
287
|
+
0.3.2's task-naming-by-`name` change (below) could make two tasks emit the
|
|
288
|
+
same component (`research_task.description` for both), and constructing the
|
|
289
|
+
`OptimizableAgent` raised `ValueError: Duplicate parameter name`. Colliding
|
|
290
|
+
names are now disambiguated with the task's positional index, so upgrading
|
|
291
|
+
to named-task components can no longer break agents whose tasks share a
|
|
292
|
+
name.
|
|
293
|
+
- **`PipelineOptimizer` assumed every stage carries a live `Optimizer`
|
|
294
|
+
state.** Cache injection read `stage._eval_cache` unconditionally, which
|
|
295
|
+
raised `AttributeError` for a minimal `Optimizer` subclass that
|
|
296
|
+
intentionally skips `Optimizer.__init__` (a pattern the cache's own read/
|
|
297
|
+
write helpers already tolerate via `getattr`). Stage attribute access is
|
|
298
|
+
now equally defensive.
|
|
299
|
+
|
|
70
300
|
|
|
71
301
|
## [0.3.1] - 2026-08-24
|
|
72
302
|
|
|
@@ -1861,7 +2091,9 @@ package that actually installs and is usable end to end.
|
|
|
1861
2091
|
optimization, adversarial defense, evaluation, observability, patches, and the
|
|
1862
2092
|
`adapt-agent` CLI (`info` command).
|
|
1863
2093
|
|
|
1864
|
-
[Unreleased]: https://github.com/CodeHalwell/ADAPT-Agent/compare/v0.
|
|
2094
|
+
[Unreleased]: https://github.com/CodeHalwell/ADAPT-Agent/compare/v0.4.0...HEAD
|
|
2095
|
+
[0.4.0]: https://github.com/CodeHalwell/ADAPT-Agent/compare/v0.3.2...v0.4.0
|
|
2096
|
+
[0.3.2]: https://github.com/CodeHalwell/ADAPT-Agent/releases/tag/v0.3.2
|
|
1865
2097
|
[0.3.1]: https://github.com/CodeHalwell/ADAPT-Agent/releases/tag/v0.3.1
|
|
1866
2098
|
[0.3.0]: https://github.com/CodeHalwell/ADAPT-Agent/releases/tag/v0.3.0
|
|
1867
2099
|
[0.2.0]: https://github.com/CodeHalwell/ADAPT-Agent/compare/v0.1.0...v0.2.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: adapt-agent
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: ADAPT-Agent: Adversarial Defense & Policy Training for LLM Agents - A comprehensive library for LLM agent optimization and security
|
|
5
5
|
Author-email: Daniel Halwell <danielhalwell@gmail.com>
|
|
6
6
|
Maintainer-email: Daniel Halwell <danielhalwell@gmail.com>
|
|
@@ -40,7 +40,13 @@ from adapt_agent.optimization.metrics import (
|
|
|
40
40
|
regex_match,
|
|
41
41
|
token_f1,
|
|
42
42
|
)
|
|
43
|
-
from adapt_agent.optimization.runners import
|
|
43
|
+
from adapt_agent.optimization.runners import (
|
|
44
|
+
adk_runner,
|
|
45
|
+
claude_agent_runner,
|
|
46
|
+
framework_runner,
|
|
47
|
+
langgraph_inputs,
|
|
48
|
+
openai_agents_runner,
|
|
49
|
+
)
|
|
44
50
|
|
|
45
51
|
logger = logging.getLogger(__name__)
|
|
46
52
|
|
|
@@ -209,4 +215,6 @@ __all__ = [
|
|
|
209
215
|
"framework_runner",
|
|
210
216
|
"langgraph_inputs",
|
|
211
217
|
"adk_runner",
|
|
218
|
+
"openai_agents_runner",
|
|
219
|
+
"claude_agent_runner",
|
|
212
220
|
]
|
|
@@ -115,7 +115,13 @@ from adapt_agent.optimization.retry import (
|
|
|
115
115
|
RetryPolicy,
|
|
116
116
|
is_transient_error,
|
|
117
117
|
)
|
|
118
|
-
from adapt_agent.optimization.runners import
|
|
118
|
+
from adapt_agent.optimization.runners import (
|
|
119
|
+
adk_runner,
|
|
120
|
+
claude_agent_runner,
|
|
121
|
+
framework_runner,
|
|
122
|
+
langgraph_inputs,
|
|
123
|
+
openai_agents_runner,
|
|
124
|
+
)
|
|
119
125
|
from adapt_agent.optimization.target import OptimizableAgent, wrap
|
|
120
126
|
|
|
121
127
|
__all__ = [
|
|
@@ -175,6 +181,8 @@ __all__ = [
|
|
|
175
181
|
"framework_runner",
|
|
176
182
|
"langgraph_inputs",
|
|
177
183
|
"adk_runner",
|
|
184
|
+
"openai_agents_runner",
|
|
185
|
+
"claude_agent_runner",
|
|
178
186
|
# target
|
|
179
187
|
"OptimizableAgent",
|
|
180
188
|
"wrap",
|
{adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/introspection/claude_agent.py
RENAMED
|
@@ -15,6 +15,14 @@ string we bind it directly; when it is a mapping carrying an ``"append"`` key we
|
|
|
15
15
|
bind that key so the appended instructions stay tunable while the preset itself
|
|
16
16
|
is preserved.
|
|
17
17
|
|
|
18
|
+
Subagents are covered too. ``options.agents`` maps a subagent name to a
|
|
19
|
+
definition -- an ``AgentDefinition`` dataclass or an equivalent plain mapping --
|
|
20
|
+
whose ``prompt`` and ``description`` are the prompts that steer the subagent and
|
|
21
|
+
the delegation to it, alongside its own ``model``, ``tools`` and ``skills``.
|
|
22
|
+
Each definition is introspected under its (slugged) subagent name, so a
|
|
23
|
+
multi-agent Claude setup exposes every specialist's knobs, not just the
|
|
24
|
+
orchestrator's.
|
|
25
|
+
|
|
18
26
|
Importing this module registers the introspector under the ``"claude_agent"``
|
|
19
27
|
key.
|
|
20
28
|
"""
|
|
@@ -69,6 +77,81 @@ def _predicate(obj: Any) -> bool:
|
|
|
69
77
|
return False
|
|
70
78
|
|
|
71
79
|
|
|
80
|
+
def _slug(text: Any) -> str | None:
|
|
81
|
+
"""Slugify a subagent name (lowercase, spaces -> underscores). ``None`` if empty."""
|
|
82
|
+
if not isinstance(text, str):
|
|
83
|
+
return None
|
|
84
|
+
slug = text.strip().lower().replace(" ", "_")
|
|
85
|
+
return slug or None
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _definition_params(definition: Any, component: str) -> list[Parameter]:
|
|
89
|
+
"""Bind one subagent definition's tunable fields.
|
|
90
|
+
|
|
91
|
+
A definition is an ``AgentDefinition`` dataclass in the real SDK, but the
|
|
92
|
+
SDK also accepts plain mappings, so both shapes are handled: attributes for
|
|
93
|
+
objects, keys for mappings. ``prompt`` and ``description`` are both PROMPT
|
|
94
|
+
knobs -- the prompt steers what the subagent does, the description steers
|
|
95
|
+
when the orchestrator delegates to it -- and ``tools``/``skills`` get the
|
|
96
|
+
same drop-one ablation candidates as every other tool list so subagent tool
|
|
97
|
+
selection is a real search space.
|
|
98
|
+
"""
|
|
99
|
+
is_mapping = isinstance(definition, dict)
|
|
100
|
+
|
|
101
|
+
def _value(field: str) -> Any:
|
|
102
|
+
return definition.get(field) if is_mapping else getattr(definition, field, None)
|
|
103
|
+
|
|
104
|
+
def _bind(
|
|
105
|
+
field: str, name: str, kind: ParameterKind, candidates: list[Any] | None = None
|
|
106
|
+
) -> Parameter | None:
|
|
107
|
+
if is_mapping:
|
|
108
|
+
return bind_item(
|
|
109
|
+
definition, field, name, kind, component=component, candidates=candidates
|
|
110
|
+
)
|
|
111
|
+
return bind_attr(definition, field, name, kind, component=component, candidates=candidates)
|
|
112
|
+
|
|
113
|
+
params: list[Parameter] = []
|
|
114
|
+
for field in ("prompt", "description"):
|
|
115
|
+
if isinstance(_value(field), str):
|
|
116
|
+
param = _bind(field, f"{component}.{field}", ParameterKind.PROMPT)
|
|
117
|
+
if param is not None:
|
|
118
|
+
params.append(param)
|
|
119
|
+
if isinstance(_value("model"), str):
|
|
120
|
+
param = _bind("model", f"{component}.model", ParameterKind.MODEL)
|
|
121
|
+
if param is not None:
|
|
122
|
+
params.append(param)
|
|
123
|
+
for field, kind in (("tools", ParameterKind.TOOL), ("skills", ParameterKind.SKILL)):
|
|
124
|
+
current = _value(field)
|
|
125
|
+
if isinstance(current, (list, tuple)):
|
|
126
|
+
param = _bind(
|
|
127
|
+
field, f"{component}.{field}", kind, tool_subset_candidates(current) or None
|
|
128
|
+
)
|
|
129
|
+
if param is not None:
|
|
130
|
+
params.append(param)
|
|
131
|
+
return params
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _introspect_subagents(obj: Any, params: list[Parameter]) -> None:
|
|
135
|
+
"""Introspect the subagent definitions in ``options.agents``.
|
|
136
|
+
|
|
137
|
+
Each definition is namespaced under its slugged dict key. Names already
|
|
138
|
+
emitted are skipped rather than duplicated -- a subagent literally named
|
|
139
|
+
``"agent"`` would otherwise collide with the root component's own knobs and
|
|
140
|
+
make ``SearchSpace.add`` raise downstream.
|
|
141
|
+
"""
|
|
142
|
+
definitions = getattr(obj, "agents", None)
|
|
143
|
+
if not isinstance(definitions, dict):
|
|
144
|
+
return
|
|
145
|
+
seen = {p.name for p in params}
|
|
146
|
+
for index, (key, definition) in enumerate(definitions.items()):
|
|
147
|
+
component = _slug(key) or f"subagent_{index}"
|
|
148
|
+
for param in _definition_params(definition, component):
|
|
149
|
+
if param.name in seen:
|
|
150
|
+
continue
|
|
151
|
+
seen.add(param.name)
|
|
152
|
+
params.append(param)
|
|
153
|
+
|
|
154
|
+
|
|
72
155
|
def _introspect_system_prompt(obj: Any, component: str) -> list[Parameter]:
|
|
73
156
|
"""Bind the ``system_prompt`` (string, or preset mapping with ``"append"``)."""
|
|
74
157
|
prompt = getattr(obj, "system_prompt", None)
|
|
@@ -137,6 +220,16 @@ def _introspect(obj: Any) -> list[Parameter]:
|
|
|
137
220
|
component=component,
|
|
138
221
|
bounds=(1, 100),
|
|
139
222
|
),
|
|
223
|
+
# The extended-thinking budget (present on SDK versions that carry
|
|
224
|
+
# it as a flat option). The floor matches the API's minimum budget.
|
|
225
|
+
bind_attr(
|
|
226
|
+
obj,
|
|
227
|
+
"max_thinking_tokens",
|
|
228
|
+
f"{component}.max_thinking_tokens",
|
|
229
|
+
ParameterKind.HYPERPARAM,
|
|
230
|
+
component=component,
|
|
231
|
+
bounds=(1024, 32000),
|
|
232
|
+
),
|
|
140
233
|
# ``permission_mode`` is a small discrete enum; giving it explicit
|
|
141
234
|
# candidates turns it from a dead knob into a searchable one.
|
|
142
235
|
bind_attr(
|
|
@@ -149,6 +242,8 @@ def _introspect(obj: Any) -> list[Parameter]:
|
|
|
149
242
|
),
|
|
150
243
|
]
|
|
151
244
|
params.extend(p for p in candidates if p is not None)
|
|
245
|
+
|
|
246
|
+
_introspect_subagents(obj, params)
|
|
152
247
|
except Exception:
|
|
153
248
|
return params
|
|
154
249
|
return params
|
|
@@ -8,9 +8,12 @@ importing ``crewai``: everything is discovered by duck-typing with ``getattr``.
|
|
|
8
8
|
|
|
9
9
|
For each agent we expose its ``role``/``goal``/``backstory`` prompts, its model
|
|
10
10
|
(a string identifier, or an introspected LLM object's
|
|
11
|
-
``model``/``temperature``/``max_tokens``), its ``tools`` allow-list,
|
|
12
|
-
``max_iter`` hyperparameter
|
|
13
|
-
``
|
|
11
|
+
``model``/``temperature``/``top_p``/``max_tokens``), its ``tools`` allow-list,
|
|
12
|
+
its ``max_iter`` hyperparameter, and its ``allow_delegation`` routing switch
|
|
13
|
+
(with ``[True, False]`` candidates, so the optimizer can search whether letting
|
|
14
|
+
the agent delegate helps or hurts). For each task we expose its ``description``
|
|
15
|
+
and ``expected_output`` prompts, named after the task's ``name`` when it has one
|
|
16
|
+
(falling back to the positional ``task_<index>``).
|
|
14
17
|
|
|
15
18
|
Importing this module registers the introspector under the ``"crewai"`` key.
|
|
16
19
|
"""
|
|
@@ -76,6 +79,14 @@ def _introspect_llm(llm: Any, component: str) -> list[Parameter]:
|
|
|
76
79
|
component=component,
|
|
77
80
|
bounds=(0.0, 2.0),
|
|
78
81
|
),
|
|
82
|
+
bind_attr(
|
|
83
|
+
llm,
|
|
84
|
+
"top_p",
|
|
85
|
+
f"{component}.top_p",
|
|
86
|
+
ParameterKind.HYPERPARAM,
|
|
87
|
+
component=component,
|
|
88
|
+
bounds=(0.0, 1.0),
|
|
89
|
+
),
|
|
79
90
|
bind_attr(
|
|
80
91
|
llm,
|
|
81
92
|
"max_tokens",
|
|
@@ -144,12 +155,55 @@ def _introspect_agent(agent: Any, index: int) -> list[Parameter]:
|
|
|
144
155
|
if max_iter is not None:
|
|
145
156
|
params.append(max_iter)
|
|
146
157
|
|
|
158
|
+
# ``allow_delegation`` decides whether this agent may hand work to its
|
|
159
|
+
# crew-mates -- a routing switch, and with explicit candidates a genuinely
|
|
160
|
+
# searchable one: the optimizer can measure whether delegation helps or
|
|
161
|
+
# just adds hops. Bound only when it is a real bool, so a Mock-ish or
|
|
162
|
+
# unset attribute never turns into a knob.
|
|
163
|
+
if isinstance(getattr(agent, "allow_delegation", None), bool):
|
|
164
|
+
delegation = bind_attr(
|
|
165
|
+
agent,
|
|
166
|
+
"allow_delegation",
|
|
167
|
+
f"{component}.allow_delegation",
|
|
168
|
+
ParameterKind.ROUTING,
|
|
169
|
+
component=component,
|
|
170
|
+
candidates=[True, False],
|
|
171
|
+
)
|
|
172
|
+
if delegation is not None:
|
|
173
|
+
params.append(delegation)
|
|
174
|
+
|
|
147
175
|
return params
|
|
148
176
|
|
|
149
177
|
|
|
150
|
-
def
|
|
151
|
-
"""
|
|
152
|
-
|
|
178
|
+
def _unique_component(component: str, index: int, used: set[str]) -> str:
|
|
179
|
+
"""Return ``component``, suffixed with the positional index while taken.
|
|
180
|
+
|
|
181
|
+
Two tasks may share a name (or names that slug identically), and a name
|
|
182
|
+
can even slug to another task's positional fallback. Identical components
|
|
183
|
+
would emit identical parameter names -- a duplicate ``SearchSpace`` entry
|
|
184
|
+
downstream -- where the positional components could never collide. The
|
|
185
|
+
index is unique per task, so one suffix round settles ordinary collisions;
|
|
186
|
+
the loop covers a name crafted to match the suffixed form as well.
|
|
187
|
+
"""
|
|
188
|
+
candidate = component
|
|
189
|
+
while candidate in used:
|
|
190
|
+
candidate = f"{candidate}_{index}"
|
|
191
|
+
used.add(candidate)
|
|
192
|
+
return candidate
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _introspect_task(task: Any, index: int, used: set[str]) -> list[Parameter]:
|
|
196
|
+
"""Introspect a single CrewAI ``Task``.
|
|
197
|
+
|
|
198
|
+
A task with a ``name`` is namespaced under it (slugged): the name survives
|
|
199
|
+
reordering the task list, where a positional ``task_<index>`` silently
|
|
200
|
+
rebinds every exported config to a different task. Nameless tasks keep the
|
|
201
|
+
positional fallback, and a component already claimed by an earlier task is
|
|
202
|
+
disambiguated with the positional index (see :func:`_unique_component`).
|
|
203
|
+
"""
|
|
204
|
+
component = _unique_component(
|
|
205
|
+
_slug(getattr(task, "name", None)) or f"task_{index}", index, used
|
|
206
|
+
)
|
|
153
207
|
candidates = [
|
|
154
208
|
bind_attr(
|
|
155
209
|
task,
|
|
@@ -176,9 +230,10 @@ def _introspect(obj: Any) -> list[Parameter]:
|
|
|
176
230
|
agents = getattr(obj, "agents", None) or []
|
|
177
231
|
for i, agent in enumerate(agents):
|
|
178
232
|
params.extend(_introspect_agent(agent, i))
|
|
233
|
+
used_task_components: set[str] = set()
|
|
179
234
|
tasks = getattr(obj, "tasks", None) or []
|
|
180
235
|
for i, task in enumerate(tasks):
|
|
181
|
-
params.extend(_introspect_task(task, i))
|
|
236
|
+
params.extend(_introspect_task(task, i, used_task_components))
|
|
182
237
|
except Exception:
|
|
183
238
|
return params
|
|
184
239
|
return params
|
{adapt_agent-0.3.2 → adapt_agent-0.4.0}/adapt_agent/optimization/introspection/google_adk.py
RENAMED
|
@@ -13,9 +13,9 @@ importing ``google.adk``: everything is discovered by duck-typing with
|
|
|
13
13
|
For each agent we expose its ``instruction`` and ``global_instruction`` prompts
|
|
14
14
|
(only when they are plain strings), its model (a string identifier, or an
|
|
15
15
|
introspected model object's ``model``/``model_name``), the
|
|
16
|
-
``temperature``/``top_p``/``max_output_tokens`` hyperparameters from
|
|
17
|
-
``generate_content_config``, its ``tools`` allow-list, and its
|
|
18
|
-
routing list. Nested ``sub_agents`` are introspected recursively and namespaced
|
|
16
|
+
``temperature``/``top_p``/``top_k``/``max_output_tokens`` hyperparameters from
|
|
17
|
+
its ``generate_content_config``, its ``tools`` allow-list, and its
|
|
18
|
+
``sub_agents`` routing list. Nested ``sub_agents`` are introspected recursively and namespaced
|
|
19
19
|
under their own component names; an ``id()`` visited set guards against cycles.
|
|
20
20
|
|
|
21
21
|
Importing this module registers the introspector under the ``"google_adk"`` key.
|
|
@@ -94,6 +94,16 @@ def _introspect_generate_config(config: Any, component: str) -> list[Parameter]:
|
|
|
94
94
|
component=component,
|
|
95
95
|
bounds=(0.0, 1.0),
|
|
96
96
|
),
|
|
97
|
+
# Kept within (1, 40): valid for every Gemini generation, so a gridded
|
|
98
|
+
# candidate never turns into a runtime rejection mid-search.
|
|
99
|
+
bind_attr(
|
|
100
|
+
config,
|
|
101
|
+
"top_k",
|
|
102
|
+
f"{component}.top_k",
|
|
103
|
+
ParameterKind.HYPERPARAM,
|
|
104
|
+
component=component,
|
|
105
|
+
bounds=(1, 40),
|
|
106
|
+
),
|
|
97
107
|
bind_attr(
|
|
98
108
|
config,
|
|
99
109
|
"max_output_tokens",
|
|
@@ -186,6 +186,16 @@ def _model_params(runnable: Any, component: str) -> list[Parameter]:
|
|
|
186
186
|
bounds=(0.0, 2.0),
|
|
187
187
|
)
|
|
188
188
|
)
|
|
189
|
+
params.append(
|
|
190
|
+
bind_attr(
|
|
191
|
+
model,
|
|
192
|
+
"top_p",
|
|
193
|
+
f"{component}.top_p",
|
|
194
|
+
ParameterKind.HYPERPARAM,
|
|
195
|
+
component=component,
|
|
196
|
+
bounds=(0.0, 1.0),
|
|
197
|
+
)
|
|
198
|
+
)
|
|
189
199
|
params.append(
|
|
190
200
|
bind_attr(
|
|
191
201
|
model,
|
|
@@ -118,6 +118,8 @@ _HYPERPARAMS: tuple[tuple[str, tuple[float, float]], ...] = (
|
|
|
118
118
|
("temperature", (0.0, 2.0)),
|
|
119
119
|
("top_p", (0.0, 1.0)),
|
|
120
120
|
("max_tokens", (1, 32000)),
|
|
121
|
+
("frequency_penalty", (-2.0, 2.0)),
|
|
122
|
+
("presence_penalty", (-2.0, 2.0)),
|
|
121
123
|
)
|
|
122
124
|
|
|
123
125
|
|
|
@@ -220,6 +222,7 @@ def _introspect(obj: Any) -> list[Parameter]:
|
|
|
220
222
|
params.append(instructions)
|
|
221
223
|
|
|
222
224
|
client = _client_of(obj)
|
|
225
|
+
found_model = False
|
|
223
226
|
if client is not None:
|
|
224
227
|
for attr in _MODEL_ATTRS:
|
|
225
228
|
model = bind_attr(
|
|
@@ -231,9 +234,26 @@ def _introspect(obj: Any) -> list[Parameter]:
|
|
|
231
234
|
)
|
|
232
235
|
if model is not None:
|
|
233
236
|
params.append(model)
|
|
237
|
+
found_model = True
|
|
234
238
|
break
|
|
235
239
|
params.extend(_introspect_hyperparams(client, component))
|
|
236
240
|
|
|
241
|
+
# A per-agent model override can live in ``default_options`` ("model_id"
|
|
242
|
+
# is a ChatOptions key) rather than on the client -- for a client that
|
|
243
|
+
# exposes no model attribute at all, this is the only place the model
|
|
244
|
+
# is tunable from.
|
|
245
|
+
if not found_model:
|
|
246
|
+
model = bind_mapping_key(
|
|
247
|
+
obj,
|
|
248
|
+
_OPTIONS_ATTR,
|
|
249
|
+
"model_id",
|
|
250
|
+
f"{component}.model",
|
|
251
|
+
ParameterKind.MODEL,
|
|
252
|
+
component=component,
|
|
253
|
+
)
|
|
254
|
+
if model is not None:
|
|
255
|
+
params.append(model)
|
|
256
|
+
|
|
237
257
|
# Sampling settings may live on the agent itself, or in its options
|
|
238
258
|
# mapping, rather than on the client. First source found wins per knob.
|
|
239
259
|
seen = {p.name for p in params}
|