pyagentic-core 2.15.1.dev1__tar.gz → 2.16.0a1__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.
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/PKG-INFO +1 -1
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/inheritance.md +28 -8
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/mkdocs.yml +1 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/_base/_agent/_agent.py +10 -5
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/_base/_agent/_agent_state.py +26 -6
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/_base/_exceptions.py +3 -2
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/_base/_metaclasses.py +30 -5
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic_core.egg-info/PKG-INFO +1 -1
- pyagentic_core-2.16.0a1/pyagentic_core.egg-info/scm_version.json +8 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/_base/test_agent_inheritance.py +131 -1
- pyagentic_core-2.15.1.dev1/pyagentic_core.egg-info/scm_version.json +0 -8
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/.github/workflows/docs.yml +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/.github/workflows/release.yml +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/.github/workflows/testing.yml +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/.gitignore +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/CHANGELOG.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/LICENSE +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/README.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/agent-linking.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/api/creating-an-app.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/api/deploying.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/api/index.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/api/jobs.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/api/running.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/diagrams/declaration.svg +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/diagrams/instantiation.svg +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/diagrams/runtime.svg +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/diagrams/source/README.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/diagrams/source/declaration.d2 +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/diagrams/source/instantiation.d2 +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/diagrams/source/runtime.d2 +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/execution-modes.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/getting-started.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/images/langfuse.png +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/index.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/observability.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/phases.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/policies/built-in.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/policies/custom.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/policies/index.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/prompts.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/reference/architecture.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/reference/modules.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/responses.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/states.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/structured-output.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/tools.md +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/__init__.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/_base/__init__.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/_base/_agent/__init__.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/_base/_agent/_agent_linking.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/_base/_depends.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/_base/_info.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/_base/_mcp.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/_base/_prompts.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/_base/_ref.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/_base/_spec.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/_base/_state.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/_base/_tool.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/_base/_validation.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/_utils/_typing.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/_utils/_warnings.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/_version_scheme.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/api/__init__.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/api/_app.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/api/_build.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/api/_config.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/api/_docker.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/api/_mcp_server.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/api/_models.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/api/_sessions.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/api/jobs/__init__.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/api/jobs/_models.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/api/jobs/_orchestrator.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/api/jobs/_routes.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/api/jobs/backends/__init__.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/api/jobs/backends/_base.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/api/jobs/backends/_in_process.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/api/jobs/store/__init__.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/api/jobs/store/_base.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/api/jobs/store/_sqlite.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/llm/__init__.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/llm/_anthropic.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/llm/_gemini.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/llm/_mock.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/llm/_openai.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/llm/_provider.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/logging.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/models/llm.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/models/response.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/models/tracing.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/policies/__init__.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/policies/_events.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/policies/_list.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/policies/_policy.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/policies/messages.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/tracing/__init__.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/tracing/_basic.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/tracing/_langfuse.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/tracing/_tracer.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/updates.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic_core.egg-info/SOURCES.txt +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic_core.egg-info/dependency_links.txt +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic_core.egg-info/requires.txt +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic_core.egg-info/scm_file_list.json +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic_core.egg-info/top_level.txt +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyproject.toml +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/setup.cfg +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/setup.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/__init__.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/_base/__init__.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/_base/test_agent.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/_base/test_agent_forking.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/_base/test_agent_linking.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/_base/test_agent_message_policies.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/_base/test_agent_provider.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/_base/test_params.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/_base/test_phases.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/_base/test_policy_list.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/_base/test_prompts.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/_base/test_state.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/_base/test_tool.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/_base/test_validator.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/api/__init__.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/api/jobs/__init__.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/api/jobs/test_orchestrator.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/api/jobs/test_routes.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/api/jobs/test_store_sqlite.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/api/test_app.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/api/test_build_agent.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/api/test_config.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/api/test_construct_model.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/api/test_dependencies_integration.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/api/test_docker.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/api/test_mcp_server.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/api/test_metaclass_models.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/api/test_router.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/api/test_sessions.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/conftest.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/llm/__init__.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/llm/test_message_conversion.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/models/test_messages.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/models/test_responses.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/policies/__init__.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/policies/test_message_policies.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/tracing/__init__.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/tracing/test_basic_tracer.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/tracing/test_models.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/tracing/test_tracer.py +0 -0
- {pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/uv.lock +0 -0
|
@@ -4,27 +4,47 @@ PyAgentic supports standard Python inheritance, allowing you to build agent hier
|
|
|
4
4
|
|
|
5
5
|
## How Inheritance Works
|
|
6
6
|
|
|
7
|
-
Agent inheritance follows Python's standard rules with some PyAgentic-specific behaviors. When you inherit from an agent, you get all its tools, context items,
|
|
7
|
+
Agent inheritance follows Python's standard rules with some PyAgentic-specific behaviors. When you inherit from an agent, you get all its tools, context items, linked agents, and instructions.
|
|
8
8
|
|
|
9
9
|
PyAgentic builds the complete agent schema at class definition time, combining inherited elements with new ones to create a fully-typed, predictable agent interface.
|
|
10
10
|
|
|
11
11
|
### Inheritance Rules
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
#### What Gets Inherited ✅
|
|
13
|
+
Everything inherits by default:
|
|
16
14
|
|
|
17
15
|
- **Tools** - All `@tool` methods are inherited and can be overridden
|
|
18
16
|
- **State Fields** - `State` fields inherit with their defaults and types
|
|
19
17
|
- **Linked Agents** - Agent references are inherited, child classes can add more
|
|
20
18
|
- **Properties** - Dynamic properties are inherited and overridable
|
|
19
|
+
- **Instructions** - `__instructions__` is inherited from the nearest ancestor when not declared; somewhere in the hierarchy it must be declared
|
|
20
|
+
|
|
21
|
+
When a child declares its own `__instructions__`, it fully replaces the parent's — unless it opts back in with `{{ super }}` (see below).
|
|
22
|
+
|
|
23
|
+
### Inheriting and Extending Instructions
|
|
24
|
+
|
|
25
|
+
A child that doesn't declare `__instructions__` simply uses its parent's:
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
class SupportAgent(BaseAgent):
|
|
29
|
+
__instructions__ = "You help customers troubleshoot {{ product }} issues."
|
|
21
30
|
|
|
22
|
-
|
|
31
|
+
product: State[str] = spec.State(default="our product")
|
|
23
32
|
|
|
24
|
-
|
|
25
|
-
|
|
33
|
+
class BillingSupportAgent(SupportAgent):
|
|
34
|
+
# No __instructions__ — inherits SupportAgent's
|
|
35
|
+
...
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
A child that overrides can embed the parent's fully rendered instructions with `{{ super }}`, mirroring Jinja's template inheritance:
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
class BillingSupportAgent(SupportAgent):
|
|
42
|
+
__instructions__ = """{{ super }}
|
|
43
|
+
|
|
44
|
+
You specialize in billing: refunds, invoices, and subscription changes."""
|
|
45
|
+
```
|
|
26
46
|
|
|
27
|
-
|
|
47
|
+
`{{ super }}` is the parent's instructions rendered with the *same* state, so templates like `{{ product }}` in the parent interpolate as usual. Chains fold through multiple levels — a grandchild's `{{ super }}` includes the parent's `{{ super }}` expansion, and so on. If there is no parent to inherit from, `{{ super }}` renders as an empty string.
|
|
28
48
|
|
|
29
49
|
## Basic Inheritance
|
|
30
50
|
|
|
@@ -128,10 +128,12 @@ class BaseAgent(metaclass=AgentMeta):
|
|
|
128
128
|
|
|
129
129
|
Agent definition requires the use of special decorators and class attributes:
|
|
130
130
|
- @tool: Declares a method as a tool callable by the LLM
|
|
131
|
-
- __instructions__:
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
131
|
+
- __instructions__: Class attribute defining the agent's instructions, either as
|
|
132
|
+
a string or a PromptRef from a PromptEngine. Rendered with state into the
|
|
133
|
+
system message sent to the LLM. Inherited from the nearest ancestor when
|
|
134
|
+
not declared; an overriding declaration can embed the parent's rendered
|
|
135
|
+
instructions with `{{ super }}`. Required somewhere in the hierarchy.
|
|
136
|
+
(__system_message__ is the deprecated spelling.)
|
|
135
137
|
- __description__: Optional description used when agent is linked to another agent
|
|
136
138
|
- __input_template__: Optional template for formatting user input
|
|
137
139
|
- __response_format__: Optional Pydantic model for structured output
|
|
@@ -179,8 +181,11 @@ class BaseAgent(metaclass=AgentMeta):
|
|
|
179
181
|
__dependencies__: ClassVar[dict[str, type]] # Depends[T] field -> dependency type
|
|
180
182
|
|
|
181
183
|
# User-set Class Attributes (defined in subclass)
|
|
182
|
-
__instructions__: ClassVar[Union[str, PromptRef]] #
|
|
184
|
+
__instructions__: ClassVar[Union[str, PromptRef]] # The agent's instructions (inheritable)
|
|
183
185
|
__system_message__: ClassVar[str] # Deprecated: old spelling of __instructions__
|
|
186
|
+
# Overridden ancestor instructions, oldest first (set by metaclass); rendered
|
|
187
|
+
# into __instructions__ as `{{ super }}`
|
|
188
|
+
__parent_instructions__: ClassVar[tuple[Union[str, PromptRef], ...]] = ()
|
|
184
189
|
__description__: ClassVar[str] # Optional: description for linked agents
|
|
185
190
|
__input_template__: ClassVar[str] = None # Optional: template for user input
|
|
186
191
|
__response_format__: ClassVar[Type[BaseModel]] = None # Optional: structured output format
|
{pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/_base/_agent/_agent_state.py
RENAMED
|
@@ -36,6 +36,10 @@ class _AgentState(BaseModel):
|
|
|
36
36
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
37
37
|
|
|
38
38
|
instructions: str | PromptRef
|
|
39
|
+
# Instructions of overridden ancestors, oldest first; rendered into the
|
|
40
|
+
# template as `{{ super }}`. Excluded from dumps so it never leaks into
|
|
41
|
+
# template context or serialized state.
|
|
42
|
+
parent_instructions: tuple = Field(default=(), exclude=True)
|
|
39
43
|
input_template: Optional[str] = "{{ user_message }}"
|
|
40
44
|
|
|
41
45
|
_machine: Machine = PrivateAttr(default=None)
|
|
@@ -44,6 +48,7 @@ class _AgentState(BaseModel):
|
|
|
44
48
|
_last_usage: Optional[UsageInfo] = PrivateAttr(default=None)
|
|
45
49
|
_prompt_source: Optional[PromptSource] = PrivateAttr(default=None)
|
|
46
50
|
_instructions_template: Template = PrivateAttr(default_factory=lambda: Template(source=""))
|
|
51
|
+
_parent_templates: list[Template] = PrivateAttr(default_factory=list)
|
|
47
52
|
_input_template: Template = PrivateAttr(
|
|
48
53
|
default_factory=lambda: Template(source="{{ user_message }}")
|
|
49
54
|
)
|
|
@@ -91,6 +96,14 @@ class _AgentState(BaseModel):
|
|
|
91
96
|
)
|
|
92
97
|
|
|
93
98
|
self._instructions_template = Template(source=self.instructions)
|
|
99
|
+
|
|
100
|
+
# Templates for overridden ancestor instructions (oldest first); each may
|
|
101
|
+
# itself be a PromptRef, resolved here just like the main instructions
|
|
102
|
+
self._parent_templates = [
|
|
103
|
+
Template(source=parent.resolve().text if isinstance(parent, PromptRef) else parent)
|
|
104
|
+
for parent in self.parent_instructions
|
|
105
|
+
]
|
|
106
|
+
|
|
94
107
|
if self.input_template:
|
|
95
108
|
self._input_template = Template(source=self.input_template)
|
|
96
109
|
|
|
@@ -417,16 +430,23 @@ class _AgentState(BaseModel):
|
|
|
417
430
|
"""
|
|
418
431
|
Returns the current formatted system message with state fields interpolated.
|
|
419
432
|
|
|
433
|
+
When the agent overrides an ancestor's instructions, the ancestor chain is
|
|
434
|
+
rendered first (with the same state context) and exposed to each template
|
|
435
|
+
as `{{ super }}`, mirroring template inheritance in Jinja.
|
|
436
|
+
|
|
420
437
|
Returns:
|
|
421
438
|
str: The rendered system message with state values
|
|
422
439
|
"""
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
# now format your instruction template
|
|
440
|
+
context = self.model_dump()
|
|
426
441
|
if self.phase:
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
442
|
+
context["phase"] = self.phase
|
|
443
|
+
|
|
444
|
+
# Fold the ancestor chain oldest-to-newest so each template's `{{ super }}`
|
|
445
|
+
# is its own parent's fully rendered instructions
|
|
446
|
+
rendered = ""
|
|
447
|
+
for template in (*self._parent_templates, self._instructions_template):
|
|
448
|
+
rendered = template.render(**{**context, "super": rendered})
|
|
449
|
+
return rendered
|
|
430
450
|
|
|
431
451
|
@property
|
|
432
452
|
def messages(self) -> list[Message]:
|
|
@@ -18,12 +18,13 @@ class InvalidToolDefinition(Exception):
|
|
|
18
18
|
class InstructionsNotDeclared(Exception):
|
|
19
19
|
"""
|
|
20
20
|
Exception raised when an Agent subclass is created without declaring __instructions__
|
|
21
|
-
(or the deprecated __system_message__).
|
|
21
|
+
(or the deprecated __system_message__) and no ancestor declares one to inherit.
|
|
22
22
|
"""
|
|
23
23
|
|
|
24
24
|
def __init__(self):
|
|
25
25
|
super().__init__(
|
|
26
|
-
"Instructions not declared on agent. Agent must be declared with
|
|
26
|
+
"Instructions not declared on agent. Agent must be declared with "
|
|
27
|
+
"`__instructions__` or inherit one from a parent agent"
|
|
27
28
|
)
|
|
28
29
|
|
|
29
30
|
|
|
@@ -611,6 +611,7 @@ class AgentMeta(type):
|
|
|
611
611
|
# Create the state object with instructions and state fields
|
|
612
612
|
self.state = self.__state_class__(
|
|
613
613
|
instructions=self.__instructions__,
|
|
614
|
+
parent_instructions=self.__parent_instructions__,
|
|
614
615
|
input_template=self.__input_template__,
|
|
615
616
|
**compiled,
|
|
616
617
|
)
|
|
@@ -665,7 +666,10 @@ class AgentMeta(type):
|
|
|
665
666
|
|
|
666
667
|
Inheritance is respected in MRO order. Tools, state attributes, and linked agents
|
|
667
668
|
can all be inherited from other agents or mixins.
|
|
668
|
-
__instructions__
|
|
669
|
+
__instructions__ is inherited from the nearest ancestor when not declared. When a
|
|
670
|
+
subclass declares its own __instructions__, the ancestor chain is recorded on
|
|
671
|
+
__parent_instructions__ so the template can embed the parent's rendered
|
|
672
|
+
instructions via `{{ super }}`.
|
|
669
673
|
|
|
670
674
|
Args:
|
|
671
675
|
name (str): Name of the new class
|
|
@@ -700,10 +704,11 @@ class AgentMeta(type):
|
|
|
700
704
|
mcs.__BaseAgent__ = cls
|
|
701
705
|
return cls
|
|
702
706
|
cls.__abstract_base__ = False
|
|
703
|
-
#
|
|
704
|
-
#
|
|
707
|
+
# Resolve instructions; __system_message__ is the deprecated spelling
|
|
708
|
+
# and normalizes onto __instructions__
|
|
709
|
+
declared = None
|
|
705
710
|
if "__instructions__" in namespace:
|
|
706
|
-
|
|
711
|
+
declared = namespace["__instructions__"]
|
|
707
712
|
elif "__system_message__" in namespace:
|
|
708
713
|
warnings.warn(
|
|
709
714
|
f"`__system_message__` on {name} is deprecated; "
|
|
@@ -711,7 +716,27 @@ class AgentMeta(type):
|
|
|
711
716
|
DeprecationWarning,
|
|
712
717
|
stacklevel=2,
|
|
713
718
|
)
|
|
714
|
-
|
|
719
|
+
declared = namespace["__system_message__"]
|
|
720
|
+
|
|
721
|
+
inherited_instructions = inherited_namespace.get(
|
|
722
|
+
"__instructions__", inherited_namespace.get("__system_message__")
|
|
723
|
+
)
|
|
724
|
+
if declared is not None:
|
|
725
|
+
cls.__instructions__ = declared
|
|
726
|
+
# When overriding an ancestor's instructions, record the ancestor
|
|
727
|
+
# chain (oldest first) so the template can embed the parent's
|
|
728
|
+
# rendered instructions via `{{ super }}`
|
|
729
|
+
if inherited_instructions is not None:
|
|
730
|
+
cls.__parent_instructions__ = (
|
|
731
|
+
*inherited_namespace.get("__parent_instructions__", ()),
|
|
732
|
+
inherited_instructions,
|
|
733
|
+
)
|
|
734
|
+
else:
|
|
735
|
+
cls.__parent_instructions__ = ()
|
|
736
|
+
elif inherited_instructions is not None:
|
|
737
|
+
# Instructions are inherited from the nearest ancestor;
|
|
738
|
+
# __parent_instructions__ resolves to the declaring ancestor's chain
|
|
739
|
+
cls.__instructions__ = inherited_instructions
|
|
715
740
|
else:
|
|
716
741
|
raise InstructionsNotDeclared()
|
|
717
742
|
# Keep the deprecated attribute readable for backwards compatibility
|
{pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/_base/test_agent_inheritance.py
RENAMED
|
@@ -2,7 +2,9 @@ import pytest
|
|
|
2
2
|
from pydantic import BaseModel
|
|
3
3
|
|
|
4
4
|
from pyagentic import BaseAgent, AgentExtension, tool, spec, State
|
|
5
|
-
from pyagentic._base._exceptions import SystemMessageNotDeclared
|
|
5
|
+
from pyagentic._base._exceptions import InstructionsNotDeclared, SystemMessageNotDeclared
|
|
6
|
+
|
|
7
|
+
_PROVIDER_KWARGS = {"model": "openai::validation", "api_key": "validation"}
|
|
6
8
|
|
|
7
9
|
|
|
8
10
|
class TestBasicInheritance:
|
|
@@ -128,6 +130,134 @@ class TestAgentExtension:
|
|
|
128
130
|
assert "cache" in MyAgent.__tool_defs__
|
|
129
131
|
|
|
130
132
|
|
|
133
|
+
class TestInstructionInheritance:
|
|
134
|
+
"""Test that __instructions__ are inherited and composable via {{ super }}."""
|
|
135
|
+
|
|
136
|
+
def test_child_inherits_parent_instructions(self):
|
|
137
|
+
"""Test that a child without __instructions__ uses the parent's."""
|
|
138
|
+
|
|
139
|
+
class ParentAgent(BaseAgent):
|
|
140
|
+
__instructions__ = "I am a parent agent"
|
|
141
|
+
|
|
142
|
+
class ChildAgent(ParentAgent):
|
|
143
|
+
pass
|
|
144
|
+
|
|
145
|
+
assert ChildAgent.__instructions__ == "I am a parent agent"
|
|
146
|
+
child = ChildAgent(**_PROVIDER_KWARGS)
|
|
147
|
+
assert child.state.system_message == "I am a parent agent"
|
|
148
|
+
|
|
149
|
+
def test_no_instructions_anywhere_raises(self):
|
|
150
|
+
"""Test that an agent hierarchy with no instructions at all still raises."""
|
|
151
|
+
|
|
152
|
+
with pytest.raises(InstructionsNotDeclared):
|
|
153
|
+
|
|
154
|
+
class NoInstructionsAgent(BaseAgent):
|
|
155
|
+
pass
|
|
156
|
+
|
|
157
|
+
def test_override_injects_parent_via_super(self):
|
|
158
|
+
"""Test that an overriding child can embed the parent's instructions."""
|
|
159
|
+
|
|
160
|
+
class ParentAgent(BaseAgent):
|
|
161
|
+
__instructions__ = "I am a parent agent."
|
|
162
|
+
|
|
163
|
+
class ChildAgent(ParentAgent):
|
|
164
|
+
__instructions__ = "{{ super }} I also review code."
|
|
165
|
+
|
|
166
|
+
child = ChildAgent(**_PROVIDER_KWARGS)
|
|
167
|
+
assert child.state.system_message == "I am a parent agent. I also review code."
|
|
168
|
+
|
|
169
|
+
def test_override_without_super_replaces(self):
|
|
170
|
+
"""Test that overriding without {{ super }} fully replaces the parent's."""
|
|
171
|
+
|
|
172
|
+
class ParentAgent(BaseAgent):
|
|
173
|
+
__instructions__ = "I am a parent agent."
|
|
174
|
+
|
|
175
|
+
class ChildAgent(ParentAgent):
|
|
176
|
+
__instructions__ = "I am my own agent."
|
|
177
|
+
|
|
178
|
+
child = ChildAgent(**_PROVIDER_KWARGS)
|
|
179
|
+
assert child.state.system_message == "I am my own agent."
|
|
180
|
+
|
|
181
|
+
def test_super_renders_parent_with_state(self):
|
|
182
|
+
"""Test that state fields interpolate inside the injected parent template."""
|
|
183
|
+
|
|
184
|
+
class ParentAgent(BaseAgent):
|
|
185
|
+
__instructions__ = "I help the {{ team }} team."
|
|
186
|
+
|
|
187
|
+
team: State[str] = spec.State(default="core")
|
|
188
|
+
|
|
189
|
+
class ChildAgent(ParentAgent):
|
|
190
|
+
__instructions__ = "{{ super }} I specialize in {{ language }}."
|
|
191
|
+
|
|
192
|
+
language: State[str] = spec.State(default="python")
|
|
193
|
+
|
|
194
|
+
child = ChildAgent(team="data", **_PROVIDER_KWARGS)
|
|
195
|
+
assert child.state.system_message == "I help the data team. I specialize in python."
|
|
196
|
+
|
|
197
|
+
def test_super_chains_through_grandparent(self):
|
|
198
|
+
"""Test that {{ super }} folds through multiple overriding levels."""
|
|
199
|
+
|
|
200
|
+
class GrandparentAgent(BaseAgent):
|
|
201
|
+
__instructions__ = "Level 1."
|
|
202
|
+
|
|
203
|
+
class ParentAgent(GrandparentAgent):
|
|
204
|
+
__instructions__ = "{{ super }} Level 2."
|
|
205
|
+
|
|
206
|
+
class ChildAgent(ParentAgent):
|
|
207
|
+
__instructions__ = "{{ super }} Level 3."
|
|
208
|
+
|
|
209
|
+
child = ChildAgent(**_PROVIDER_KWARGS)
|
|
210
|
+
assert child.state.system_message == "Level 1. Level 2. Level 3."
|
|
211
|
+
|
|
212
|
+
def test_super_chain_skips_non_declaring_level(self):
|
|
213
|
+
"""Test that a non-declaring middle class passes its parent's chain through."""
|
|
214
|
+
|
|
215
|
+
class GrandparentAgent(BaseAgent):
|
|
216
|
+
__instructions__ = "Level 1."
|
|
217
|
+
|
|
218
|
+
class ParentAgent(GrandparentAgent):
|
|
219
|
+
pass
|
|
220
|
+
|
|
221
|
+
class ChildAgent(ParentAgent):
|
|
222
|
+
__instructions__ = "{{ super }} Level 3."
|
|
223
|
+
|
|
224
|
+
child = ChildAgent(**_PROVIDER_KWARGS)
|
|
225
|
+
assert child.state.system_message == "Level 1. Level 3."
|
|
226
|
+
|
|
227
|
+
def test_super_empty_without_parent(self):
|
|
228
|
+
"""Test that {{ super }} renders empty when there is nothing to inherit."""
|
|
229
|
+
|
|
230
|
+
class RootAgent(BaseAgent):
|
|
231
|
+
__instructions__ = "{{ super }}Root."
|
|
232
|
+
|
|
233
|
+
agent = RootAgent(**_PROVIDER_KWARGS)
|
|
234
|
+
assert agent.state.system_message == "Root."
|
|
235
|
+
|
|
236
|
+
def test_fork_preserves_inherited_instructions(self):
|
|
237
|
+
"""Test that forked agents render the same composed system message."""
|
|
238
|
+
|
|
239
|
+
class ParentAgent(BaseAgent):
|
|
240
|
+
__instructions__ = "I am a parent agent."
|
|
241
|
+
|
|
242
|
+
class ChildAgent(ParentAgent):
|
|
243
|
+
__instructions__ = "{{ super }} I also review code."
|
|
244
|
+
|
|
245
|
+
child = ChildAgent(**_PROVIDER_KWARGS)
|
|
246
|
+
fork = child.fork()
|
|
247
|
+
assert fork.state.system_message == child.state.system_message
|
|
248
|
+
|
|
249
|
+
def test_deprecated_system_message_inherits(self):
|
|
250
|
+
"""Test that the deprecated __system_message__ spelling still inherits."""
|
|
251
|
+
|
|
252
|
+
class ParentAgent(BaseAgent):
|
|
253
|
+
__system_message__ = "I am a parent agent"
|
|
254
|
+
|
|
255
|
+
class ChildAgent(ParentAgent):
|
|
256
|
+
pass
|
|
257
|
+
|
|
258
|
+
assert ChildAgent.__instructions__ == "I am a parent agent"
|
|
259
|
+
|
|
260
|
+
|
|
131
261
|
class TestComplexInheritance:
|
|
132
262
|
"""Test complex inheritance scenarios."""
|
|
133
263
|
|
|
File without changes
|
{pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/.github/ISSUE_TEMPLATE/feature_request.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/docs/diagrams/source/instantiation.d2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/_base/_agent/_agent_linking.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/api/jobs/backends/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic/api/jobs/backends/_in_process.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic_core.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
{pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic_core.egg-info/scm_file_list.json
RENAMED
|
File without changes
|
{pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/pyagentic_core.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/_base/test_agent_message_policies.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/api/test_dependencies_integration.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyagentic_core-2.15.1.dev1 → pyagentic_core-2.16.0a1}/tests/policies/test_message_policies.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|