pyagentic-core 2.14.1.dev1__tar.gz → 2.15.1.dev1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. {pyagentic_core-2.14.1.dev1/pyagentic_core.egg-info → pyagentic_core-2.15.1.dev1}/PKG-INFO +1 -1
  2. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/agent-linking.md +16 -16
  3. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/api/creating-an-app.md +1 -1
  4. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/api/index.md +1 -1
  5. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/execution-modes.md +2 -2
  6. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/getting-started.md +6 -4
  7. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/inheritance.md +7 -7
  8. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/observability.md +2 -2
  9. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/phases.md +6 -6
  10. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/policies/built-in.md +1 -1
  11. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/policies/custom.md +3 -3
  12. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/policies/index.md +3 -3
  13. pyagentic_core-2.15.1.dev1/docs/prompts.md +140 -0
  14. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/reference/modules.md +18 -0
  15. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/responses.md +15 -0
  16. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/states.md +10 -10
  17. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/structured-output.md +1 -1
  18. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/tools.md +9 -9
  19. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/__init__.py +7 -1
  20. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/_base/_agent/_agent.py +11 -5
  21. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/_base/_agent/_agent_linking.py +2 -2
  22. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/_base/_agent/_agent_state.py +35 -3
  23. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/_base/_depends.py +1 -1
  24. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/_base/_exceptions.py +22 -3
  25. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/_base/_mcp.py +1 -1
  26. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/_base/_metaclasses.py +23 -9
  27. pyagentic_core-2.15.1.dev1/pyagentic/_base/_prompts.py +243 -0
  28. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/_base/_ref.py +1 -1
  29. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/_base/_spec.py +1 -1
  30. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/_base/_state.py +1 -1
  31. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/_base/_tool.py +1 -1
  32. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/models/response.py +9 -0
  33. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/policies/_policy.py +1 -1
  34. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/policies/messages.py +1 -1
  35. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1/pyagentic_core.egg-info}/PKG-INFO +1 -1
  36. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic_core.egg-info/SOURCES.txt +3 -0
  37. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic_core.egg-info/scm_file_list.json +3 -0
  38. pyagentic_core-2.15.1.dev1/pyagentic_core.egg-info/scm_version.json +8 -0
  39. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/_base/test_agent.py +5 -5
  40. pyagentic_core-2.15.1.dev1/tests/_base/test_prompts.py +289 -0
  41. pyagentic_core-2.14.1.dev1/pyagentic_core.egg-info/scm_version.json +0 -8
  42. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  43. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  44. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/.github/workflows/docs.yml +0 -0
  45. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/.github/workflows/release.yml +0 -0
  46. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/.github/workflows/testing.yml +0 -0
  47. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/.gitignore +0 -0
  48. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/CHANGELOG.md +0 -0
  49. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/LICENSE +0 -0
  50. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/README.md +0 -0
  51. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/api/deploying.md +0 -0
  52. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/api/jobs.md +0 -0
  53. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/api/running.md +0 -0
  54. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/diagrams/declaration.svg +0 -0
  55. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/diagrams/instantiation.svg +0 -0
  56. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/diagrams/runtime.svg +0 -0
  57. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/diagrams/source/README.md +0 -0
  58. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/diagrams/source/declaration.d2 +0 -0
  59. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/diagrams/source/instantiation.d2 +0 -0
  60. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/diagrams/source/runtime.d2 +0 -0
  61. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/images/langfuse.png +0 -0
  62. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/index.md +0 -0
  63. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/docs/reference/architecture.md +0 -0
  64. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/mkdocs.yml +0 -0
  65. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/_base/__init__.py +0 -0
  66. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/_base/_agent/__init__.py +0 -0
  67. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/_base/_info.py +0 -0
  68. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/_base/_validation.py +0 -0
  69. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/_utils/_typing.py +0 -0
  70. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/_utils/_warnings.py +0 -0
  71. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/_version_scheme.py +0 -0
  72. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/api/__init__.py +0 -0
  73. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/api/_app.py +0 -0
  74. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/api/_build.py +0 -0
  75. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/api/_config.py +0 -0
  76. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/api/_docker.py +0 -0
  77. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/api/_mcp_server.py +0 -0
  78. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/api/_models.py +0 -0
  79. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/api/_sessions.py +0 -0
  80. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/api/jobs/__init__.py +0 -0
  81. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/api/jobs/_models.py +0 -0
  82. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/api/jobs/_orchestrator.py +0 -0
  83. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/api/jobs/_routes.py +0 -0
  84. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/api/jobs/backends/__init__.py +0 -0
  85. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/api/jobs/backends/_base.py +0 -0
  86. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/api/jobs/backends/_in_process.py +0 -0
  87. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/api/jobs/store/__init__.py +0 -0
  88. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/api/jobs/store/_base.py +0 -0
  89. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/api/jobs/store/_sqlite.py +0 -0
  90. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/llm/__init__.py +0 -0
  91. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/llm/_anthropic.py +0 -0
  92. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/llm/_gemini.py +0 -0
  93. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/llm/_mock.py +0 -0
  94. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/llm/_openai.py +0 -0
  95. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/llm/_provider.py +0 -0
  96. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/logging.py +0 -0
  97. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/models/llm.py +0 -0
  98. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/models/tracing.py +0 -0
  99. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/policies/__init__.py +0 -0
  100. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/policies/_events.py +0 -0
  101. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/policies/_list.py +0 -0
  102. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/tracing/__init__.py +0 -0
  103. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/tracing/_basic.py +0 -0
  104. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/tracing/_langfuse.py +0 -0
  105. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/tracing/_tracer.py +0 -0
  106. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic/updates.py +0 -0
  107. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic_core.egg-info/dependency_links.txt +0 -0
  108. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic_core.egg-info/requires.txt +0 -0
  109. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyagentic_core.egg-info/top_level.txt +0 -0
  110. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/pyproject.toml +0 -0
  111. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/setup.cfg +0 -0
  112. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/setup.py +0 -0
  113. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/__init__.py +0 -0
  114. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/_base/__init__.py +0 -0
  115. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/_base/test_agent_forking.py +0 -0
  116. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/_base/test_agent_inheritance.py +0 -0
  117. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/_base/test_agent_linking.py +0 -0
  118. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/_base/test_agent_message_policies.py +0 -0
  119. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/_base/test_agent_provider.py +0 -0
  120. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/_base/test_params.py +0 -0
  121. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/_base/test_phases.py +0 -0
  122. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/_base/test_policy_list.py +0 -0
  123. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/_base/test_state.py +0 -0
  124. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/_base/test_tool.py +0 -0
  125. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/_base/test_validator.py +0 -0
  126. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/api/__init__.py +0 -0
  127. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/api/jobs/__init__.py +0 -0
  128. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/api/jobs/test_orchestrator.py +0 -0
  129. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/api/jobs/test_routes.py +0 -0
  130. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/api/jobs/test_store_sqlite.py +0 -0
  131. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/api/test_app.py +0 -0
  132. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/api/test_build_agent.py +0 -0
  133. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/api/test_config.py +0 -0
  134. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/api/test_construct_model.py +0 -0
  135. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/api/test_dependencies_integration.py +0 -0
  136. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/api/test_docker.py +0 -0
  137. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/api/test_mcp_server.py +0 -0
  138. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/api/test_metaclass_models.py +0 -0
  139. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/api/test_router.py +0 -0
  140. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/api/test_sessions.py +0 -0
  141. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/conftest.py +0 -0
  142. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/llm/__init__.py +0 -0
  143. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/llm/test_message_conversion.py +0 -0
  144. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/models/test_messages.py +0 -0
  145. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/models/test_responses.py +0 -0
  146. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/policies/__init__.py +0 -0
  147. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/policies/test_message_policies.py +0 -0
  148. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/tracing/__init__.py +0 -0
  149. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/tracing/test_basic_tracer.py +0 -0
  150. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/tracing/test_models.py +0 -0
  151. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/tests/tracing/test_tracer.py +0 -0
  152. {pyagentic_core-2.14.1.dev1 → pyagentic_core-2.15.1.dev1}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyagentic-core
3
- Version: 2.14.1.dev1
3
+ Version: 2.15.1.dev1
4
4
  Summary: Build LLM Agents in a Pythonic way
5
5
  Author-email: Ryan Mikulec <rmikulec.dev@gmail.com>
6
6
  License: MIT
@@ -16,14 +16,14 @@ The simplest way to link agents is by declaring them as typed attributes in your
16
16
  from pyagentic import BaseAgent, Link, tool
17
17
 
18
18
  class DatabaseAgent(BaseAgent):
19
- __system_message__ = "I query databases"
19
+ __instructions__ = "I query databases"
20
20
  __description__ = "Retrieves and analyzes data from databases"
21
21
 
22
22
  @tool("Execute SQL query")
23
23
  def query(self, sql: str) -> str: ...
24
24
 
25
25
  class ReportAgent(BaseAgent):
26
- __system_message__ = "I generate business reports"
26
+ __instructions__ = "I generate business reports"
27
27
 
28
28
  # Using Link[T] (recommended for advanced features)
29
29
  database: Link[DatabaseAgent]
@@ -45,15 +45,15 @@ Real-world applications often require coordination between multiple specialized
45
45
 
46
46
  ```python
47
47
  class EmailAgent(BaseAgent):
48
- __system_message__ = "I send emails"
48
+ __instructions__ = "I send emails"
49
49
  __description__ = "Sends and manages email communications"
50
50
 
51
51
  class CalendarAgent(BaseAgent):
52
- __system_message__ = "I manage calendars"
52
+ __instructions__ = "I manage calendars"
53
53
  __description__ = "Schedules meetings and manages calendar events"
54
54
 
55
55
  class AssistantAgent(BaseAgent):
56
- __system_message__ = "I help with daily tasks"
56
+ __instructions__ = "I help with daily tasks"
57
57
 
58
58
  email: EmailAgent
59
59
  calendar: CalendarAgent
@@ -75,14 +75,14 @@ Provide a default agent instance that will be used if none is provided during in
75
75
  from pyagentic import BaseAgent, Link, spec
76
76
 
77
77
  class AnalysisAgent(BaseAgent):
78
- __system_message__ = "I analyze data"
78
+ __instructions__ = "I analyze data"
79
79
  __description__ = "Performs data analysis"
80
80
 
81
81
  # Create a pre-configured analyzer
82
82
  default_analyzer = AnalysisAgent(model="gpt-4", api_key="sk-...")
83
83
 
84
84
  class ReportAgent(BaseAgent):
85
- __system_message__ = "I generate reports"
85
+ __instructions__ = "I generate reports"
86
86
 
87
87
  # Will use default_analyzer if no analyzer is provided
88
88
  analyzer: Link[AnalysisAgent] = spec.AgentLink(default=default_analyzer)
@@ -104,7 +104,7 @@ Use `default_factory` to create agent instances on-demand, similar to how `spec.
104
104
 
105
105
  ```python
106
106
  class SearchAgent(BaseAgent):
107
- __system_message__ = "I search databases"
107
+ __instructions__ = "I search databases"
108
108
  __description__ = "Database search specialist"
109
109
 
110
110
  def create_searcher():
@@ -116,7 +116,7 @@ def create_searcher():
116
116
  )
117
117
 
118
118
  class DataAgent(BaseAgent):
119
- __system_message__ = "I manage data operations"
119
+ __instructions__ = "I manage data operations"
120
120
 
121
121
  # Automatically creates a searcher if not provided
122
122
  searcher: Link[SearchAgent] = spec.AgentLink(default_factory=create_searcher)
@@ -139,11 +139,11 @@ Link agents conditionally based on runtime state, enabling dynamic agent composi
139
139
  from pyagentic import State
140
140
 
141
141
  class ExpertAgent(BaseAgent):
142
- __system_message__ = "I provide expert analysis"
142
+ __instructions__ = "I provide expert analysis"
143
143
  __description__ = "Expert consultant for complex problems"
144
144
 
145
145
  class SmartAgent(BaseAgent):
146
- __system_message__ = "I handle tasks with optional expert help"
146
+ __instructions__ = "I handle tasks with optional expert help"
147
147
 
148
148
  # State field to control expert availability
149
149
  needs_expert: State[bool] = spec.State(default=False)
@@ -203,7 +203,7 @@ calls — for example so the parent can read the linked agent's state through
203
203
  from pyagentic import BaseAgent, Link, spec
204
204
 
205
205
  class Orchestrator(BaseAgent):
206
- __system_message__ = "I coordinate a stateful researcher."
206
+ __instructions__ = "I coordinate a stateful researcher."
207
207
 
208
208
  # One persistent researcher; its state survives across calls and is
209
209
  # readable via ref.researcher.<field>.
@@ -226,13 +226,13 @@ Overriding the `__call__` method gives you complete control over how your linked
226
226
 
227
227
  ```python
228
228
  class AnalysisAgent(BaseAgent):
229
- __system_message__ = "I analyze data"
229
+ __instructions__ = "I analyze data"
230
230
  __description__ = "Performs statistical analysis on datasets"
231
231
 
232
232
  async def __call__(self, data: str, analysis_type: str = "basic") -> str: ...
233
233
 
234
234
  class ReportAgent(BaseAgent):
235
- __system_message__ = "I generate reports"
235
+ __instructions__ = "I generate reports"
236
236
  analyzer: AnalysisAgent
237
237
 
238
238
  # The LLM can now call the analyzer with specific parameters
@@ -254,7 +254,7 @@ class SearchParams(BaseModel):
254
254
  include_metadata: bool = Field(default=True, description="Whether to include metadata in results")
255
255
 
256
256
  class SearchAgent(BaseAgent):
257
- __system_message__ = "I search databases"
257
+ __instructions__ = "I search databases"
258
258
  __description__ = "Searches databases with advanced filtering"
259
259
 
260
260
  async def __call__(self, params: SearchParams) -> str:
@@ -263,7 +263,7 @@ class SearchAgent(BaseAgent):
263
263
  return f"Found {len(results)} results for '{params.query}'"
264
264
 
265
265
  class DataAgent(BaseAgent):
266
- __system_message__ = "I manage data operations"
266
+ __instructions__ = "I manage data operations"
267
267
  searcher: SearchAgent
268
268
 
269
269
  # The LLM can now call the searcher with structured parameters
@@ -69,7 +69,7 @@ agent class, exactly where you'd otherwise put `State[...]`:
69
69
  from pyagentic import BaseAgent, State, Depends
70
70
 
71
71
  class ResearchAgent(BaseAgent):
72
- __system_message__ = "You research topics."
72
+ __instructions__ = "You research topics."
73
73
 
74
74
  topic: State[Topic] # client-provided per session
75
75
  db: Depends[Database] # injected server-side, never sent by clients
@@ -26,7 +26,7 @@ from pyagentic.api import create_app
26
26
 
27
27
 
28
28
  class AssistantAgent(BaseAgent):
29
- __system_message__ = "You are a helpful assistant."
29
+ __instructions__ = "You are a helpful assistant."
30
30
 
31
31
  @tool("Add two numbers")
32
32
  def add(self, a: int, b: int) -> str:
@@ -35,7 +35,7 @@ The real power of `__call__` is that you can override it to accept typed paramet
35
35
  from typing import Optional
36
36
 
37
37
  class CoursePlannerAgent(BaseAgent):
38
- __system_message__ = "You design course curricula"
38
+ __instructions__ = "You design course curricula"
39
39
  __description__ = "Creates structured course plans based on learning goals"
40
40
  __response_format__ = CoursePlan
41
41
 
@@ -79,7 +79,7 @@ When you link an agent to another agent, PyAgentic extracts the parameters from
79
79
 
80
80
  ```python
81
81
  class AssistantAgent(BaseAgent):
82
- __system_message__ = "You help students with learning plans"
82
+ __instructions__ = "You help students with learning plans"
83
83
 
84
84
  # Link the course planner
85
85
  planner: CoursePlannerAgent
@@ -91,13 +91,15 @@ from pyagentic import BaseAgent
91
91
  class ResearchAgent(BaseAgent):
92
92
  """An AI assistant for managing and analyzing research papers."""
93
93
 
94
- __system_message__ = """
94
+ __instructions__ = """
95
95
  You are a research assistant that helps organize and analyze academic papers.
96
96
  You maintain a collection of research papers and can answer questions about them.
97
97
  You are knowledgeable, precise, and helpful in academic contexts.
98
98
  """
99
99
  ```
100
100
 
101
+ The `__instructions__` attribute defines the agent's system prompt — it can be a plain string like this, a Jinja template rendered with the agent's state, or a reference to a prompt managed outside your code (see [Prompt Management](prompts.md)).
102
+
101
103
  This creates a basic conversational agent, but it can't do much beyond chat. Let's add some memory and capabilities.
102
104
 
103
105
  ## Step 2: Adding State with State Fields
@@ -114,7 +116,7 @@ from arxiv import Result as Paper
114
116
  class ResearchAgent(BaseAgent):
115
117
  """An AI assistant for managing and analyzing research papers."""
116
118
 
117
- __system_message__ = """
119
+ __instructions__ = """
118
120
  You are a research assistant that helps organize and analyze academic papers.
119
121
  You have full access to the Arxiv
120
122
 
@@ -200,7 +202,7 @@ class ResearchState(BaseModel):
200
202
  return [paper.get_short_id() for paper in self.papers.get(self.current_topic, [])]
201
203
 
202
204
  class ResearchAgent(BaseAgent):
203
- # ... system message ...
205
+ # ... instructions ...
204
206
 
205
207
  state: State[ResearchState] = spec.State(default_factory=ResearchState)
206
208
 
@@ -266,7 +268,7 @@ class ResearchState(BaseModel):
266
268
  class ResearchAgent(BaseAgent):
267
269
  """An AI assistant for managing and analyzing research papers."""
268
270
 
269
- __system_message__ = """
271
+ __instructions__ = """
270
272
  You are a research assistant that helps organize and analyze academic papers.
271
273
  You have full access to the Arxiv
272
274
 
@@ -4,7 +4,7 @@ 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, and linked agents. However, each agent must define its own system message to maintain clear identity and purpose.
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, and linked agents. However, each agent must define its own instructions to maintain clear identity and purpose.
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
 
@@ -21,7 +21,7 @@ PyAgentic follows specific rules about what gets inherited and what must be rede
21
21
 
22
22
  #### What Must Be Redefined ❌
23
23
 
24
- - **System Messages** - Each agent must define its own `__system_message__` to maintain clear identity
24
+ - **Instructions** - Each agent must define its own `__instructions__` to maintain clear identity
25
25
  - **Input Templates** - `__input_template__` is not inherited, allowing agent-specific formatting
26
26
 
27
27
  This design ensures that while agents can share functionality, each maintains its own distinct purpose and behavior.
@@ -32,7 +32,7 @@ Extend agents using normal Python inheritance to build specialized capabilities
32
32
 
33
33
  ```python
34
34
  class BaseAssistantAgent(BaseAgent):
35
- __system_message__ = "I am a helpful AI assistant"
35
+ __instructions__ = "I am a helpful AI assistant"
36
36
 
37
37
  user_name: State[str] = spec.State(default="User")
38
38
  session_id: State[str] = spec.State(default="")
@@ -48,7 +48,7 @@ class BaseAssistantAgent(BaseAgent):
48
48
  def update_context(self, new_context: str) -> str: ...
49
49
 
50
50
  class CodeAssistantAgent(BaseAssistantAgent):
51
- __system_message__ = "I help with programming tasks and code review"
51
+ __instructions__ = "I help with programming tasks and code review"
52
52
 
53
53
  # Inherit user_name, session_id, conversation_context, and basic tools
54
54
  # Add coding-specific state
@@ -69,7 +69,7 @@ Inheritance also works with tool overriding to enhance parent functionality:
69
69
 
70
70
  ```python
71
71
  class AdvancedCodeAssistantAgent(CodeAssistantAgent):
72
- __system_message__ = "I provide advanced programming assistance with security analysis"
72
+ __instructions__ = "I provide advanced programming assistance with security analysis"
73
73
 
74
74
  # Override parent tool with enhanced functionality
75
75
  @tool("Format and validate code snippet")
@@ -110,7 +110,7 @@ Simply include extensions in your agent's inheritance list:
110
110
 
111
111
  ```python
112
112
  class ResearchAgent(BaseAgent, FileOperationsExtension, WebSearchExtension):
113
- __system_message__ = "I help with research by searching the web and managing files"
113
+ __instructions__ = "I help with research by searching the web and managing files"
114
114
 
115
115
  research_topic: State[str] = spec.State(default="")
116
116
 
@@ -134,7 +134,7 @@ class ConversationExtension(AgentExtension):
134
134
  def remember(self, info: str) -> str: ...
135
135
 
136
136
  class ChatbotAgent(BaseAgent, MemoryExtension, ConversationExtension):
137
- __system_message__ = "I am a conversational AI"
137
+ __instructions__ = "I am a conversational AI"
138
138
 
139
139
  # MRO: ChatbotAgent -> MemoryExtension -> ConversationExtension -> BaseAgent
140
140
  # The MemoryExtension.remember() method will be used
@@ -36,7 +36,7 @@ The BasicTracer is the simplest way to get started with tracing. It stores all t
36
36
  from pyagentic import BaseAgent
37
37
 
38
38
  class YourAgent(BaseAgent):
39
- __system_message__ = "Your agent description"
39
+ __instructions__ = "Your agent description"
40
40
  # ... your agent implementation ...
41
41
 
42
42
  # Create an agent - The BasicTracer is the default tracer of any declared agent
@@ -93,7 +93,7 @@ from pyagentic import BaseAgent
93
93
  from pyagentic.tracing import LangfuseTracer
94
94
 
95
95
  class YourAgent(BaseAgent):
96
- __system_message__ = "Your agent description"
96
+ __instructions__ = "Your agent description"
97
97
  # ... your agent implementation ...
98
98
 
99
99
  # Create an agent with the tracer
@@ -20,7 +20,7 @@ Define phases on your agent class using the `phases` class variable:
20
20
  from pyagentic import BaseAgent, tool, spec
21
21
 
22
22
  class ResearchAgent(BaseAgent):
23
- __system_message__ = """
23
+ __instructions__ = """
24
24
  You are a research agent.
25
25
  Current phase: {{ phase }}
26
26
  {% if phase == "planning" %}
@@ -120,19 +120,19 @@ Linked agents can be restricted to specific phases using the `phases` parameter
120
120
  from pyagentic import BaseAgent, tool, spec, Link
121
121
 
122
122
  class PlannerAgent(BaseAgent):
123
- __system_message__ = "I create detailed plans"
123
+ __instructions__ = "I create detailed plans"
124
124
  __description__ = "Planning specialist for strategy development"
125
125
 
126
126
  class ExecutorAgent(BaseAgent):
127
- __system_message__ = "I execute plans"
127
+ __instructions__ = "I execute plans"
128
128
  __description__ = "Execution specialist for implementing plans"
129
129
 
130
130
  class ReviewerAgent(BaseAgent):
131
- __system_message__ = "I review completed work"
131
+ __instructions__ = "I review completed work"
132
132
  __description__ = "Quality assurance and review specialist"
133
133
 
134
134
  class ProjectAgent(BaseAgent):
135
- __system_message__ = """
135
+ __instructions__ = """
136
136
  You manage projects through phases: {{ phase }}
137
137
  """
138
138
 
@@ -178,7 +178,7 @@ You can access the current phase in several ways:
178
178
  Use the `{{ phase }}` variable in your system message template:
179
179
 
180
180
  ```python
181
- __system_message__ = """
181
+ __instructions__ = """
182
182
  You are in the {{ phase }} phase.
183
183
  {% if phase == "planning" %}
184
184
  Create a detailed plan.
@@ -19,7 +19,7 @@ Attach them to an agent with the `__message_policies__` class attribute:
19
19
 
20
20
  ```python
21
21
  class ResearchAgent(BaseAgent):
22
- __system_message__ = "You research topics using tools."
22
+ __instructions__ = "You research topics using tools."
23
23
  __message_policies__ = [
24
24
  ToolOutputClipPolicy(max_chars=8000),
25
25
  ToolEvictionPolicy(keep_last_n=5),
@@ -55,7 +55,7 @@ class RangePolicy(Policy[int]):
55
55
 
56
56
 
57
57
  class GameAgent(BaseAgent):
58
- __system_message__ = "You run a text adventure."
58
+ __instructions__ = "You run a text adventure."
59
59
 
60
60
  score: State[int] = spec.State(
61
61
  default=0,
@@ -141,7 +141,7 @@ class NoEmptyStrings(Policy):
141
141
 
142
142
 
143
143
  class NotesAgent(BaseAgent):
144
- __system_message__ = "You keep notes."
144
+ __instructions__ = "You keep notes."
145
145
 
146
146
  notes: State[list] = spec.State(default_factory=list, policies=[NoEmptyStrings()])
147
147
 
@@ -333,7 +333,7 @@ LLM saw) versus `agent.state._messages` (what actually happened):
333
333
  @pytest.mark.asyncio
334
334
  async def test_budget_policy_in_agent():
335
335
  class _Agent(BaseAgent):
336
- __system_message__ = "test"
336
+ __instructions__ = "test"
337
337
  __message_policies__ = [AgentResultBudgetPolicy(max_chars=100)]
338
338
 
339
339
  agent = _Agent(model="_mock::test-model", api_key="k")
@@ -18,7 +18,7 @@ from pyagentic import BaseAgent, State, spec
18
18
  from pyagentic.policies import ToolEvictionPolicy, CompactionPolicy
19
19
 
20
20
  class SupportAgent(BaseAgent):
21
- __system_message__ = "You help customers with {{ product }}."
21
+ __instructions__ = "You help customers with {{ product }}."
22
22
 
23
23
  # Message policies: keep the LLM context bounded
24
24
  __message_policies__ = [
@@ -85,7 +85,7 @@ whether by your code, a tool body, or the autogenerated `get_*`/`set_*` tools.
85
85
 
86
86
  ```python
87
87
  class GameAgent(BaseAgent):
88
- __system_message__ = "You run a text adventure."
88
+ __instructions__ = "You run a text adventure."
89
89
 
90
90
  score: State[int] = spec.State(default=0, policies=[RangePolicy(0, 100)])
91
91
  ```
@@ -109,7 +109,7 @@ and results) and once more over the whole list right before each LLM call.
109
109
 
110
110
  ```python
111
111
  class ResearchAgent(BaseAgent):
112
- __system_message__ = "You research topics using tools."
112
+ __instructions__ = "You research topics using tools."
113
113
  __message_policies__ = [
114
114
  ToolOutputClipPolicy(max_chars=8000),
115
115
  ToolEvictionPolicy(keep_last_n=5),
@@ -0,0 +1,140 @@
1
+ # Prompt Management
2
+
3
+ Every agent declares its instructions — the system prompt the LLM receives — with the `__instructions__` class attribute. Instructions can be a plain string, but as agents mature, prompts tend to outgrow the code: they get edited more often than the logic around them, they need versioning, and non-developers may need to change them. PyAgentic's prompt engines let agents pull their instructions from a managed source instead of a hardcoded string.
4
+
5
+ ## Naming
6
+
7
+ Two terms, one for each side of the rendering step:
8
+
9
+ - **Instructions** — the raw template you declare: a string or a prompt-engine reference. Available at runtime as `agent.state.instructions`.
10
+ - **System message** — the rendered result actually sent to the LLM, with state interpolated into the template. Available as `agent.state.system_message`.
11
+
12
+ ```python
13
+ class ResearchAgent(BaseAgent):
14
+ __instructions__ = "You research {{ topic }}"
15
+
16
+ topic: State[str] = spec.State(default="transformers")
17
+
18
+ agent.state.instructions # "You research {{ topic }}"
19
+ agent.state.system_message # "You research transformers"
20
+ ```
21
+
22
+ !!! note "Deprecated: `__system_message__`"
23
+ Older versions used `__system_message__` for what is now `__instructions__`. The old name still works but emits a `DeprecationWarning` — new code should declare `__instructions__`.
24
+
25
+ ## Prompt Engines
26
+
27
+ A `PromptEngine` is a source of managed prompts. Engines load prompt text by key and return a `PromptSource` carrying the text plus metadata (where it came from, which version, when it was loaded). Instead of assigning a string, assign a reference:
28
+
29
+ ```python
30
+ from pyagentic import BaseAgent, LocalPromptEngine
31
+
32
+ prompts = LocalPromptEngine(".prompts")
33
+
34
+ class ResearchAgent(BaseAgent):
35
+ __instructions__ = prompts.ref("researcher")
36
+ ```
37
+
38
+ `ref(key)` returns a `PromptRef` — a deferred pointer that is resolved **when the agent is instantiated**, not when the class is defined:
39
+
40
+ - Every `ResearchAgent(...)` re-reads the prompt, so edits are picked up by new instances without restarting anything.
41
+ - The prompt is stable for the lifetime of an instance — it never changes mid-conversation.
42
+ - `agent.fork()` re-resolves too, so forked linked-agent calls also get the latest version.
43
+
44
+ To pin a specific version instead of tracking the latest:
45
+
46
+ ```python
47
+ __instructions__ = prompts.ref("researcher", version="v2")
48
+ ```
49
+
50
+ ## LocalPromptEngine
51
+
52
+ `LocalPromptEngine` serves prompts from files on the local file system. A **pattern** defines how your prompt storage is laid out under the root directory (default: `.prompts/` in the working directory). The pattern is a template with a required `{key}` placeholder and an optional `{version}` placeholder.
53
+
54
+ ### Flat layout (default)
55
+
56
+ The default pattern is `"{key}.md"` — one file per prompt, versioned by content hash:
57
+
58
+ ```
59
+ .prompts/
60
+ ├── researcher.md
61
+ └── summarizer.md
62
+ ```
63
+
64
+ ```python
65
+ prompts = LocalPromptEngine(".prompts")
66
+ prompts.load("researcher") # reads .prompts/researcher.md
67
+ ```
68
+
69
+ Any flat layout works by changing the pattern, e.g. `pattern="{key}.txt"` or `pattern="agents/{key}/prompt.md"`.
70
+
71
+ ### Versioned layout
72
+
73
+ When the pattern contains `{version}`, the file structure holds the versions and the engine derives versioning from it:
74
+
75
+ ```
76
+ .prompts/
77
+ └── researcher/
78
+ ├── v1.md
79
+ ├── v2.md
80
+ └── v10.md
81
+ ```
82
+
83
+ ```python
84
+ prompts = LocalPromptEngine(".prompts", pattern="{key}/{version}.md")
85
+
86
+ prompts.load("researcher") # latest → v10
87
+ prompts.load("researcher", version="v1") # pinned
88
+ ```
89
+
90
+ An unpinned load picks the latest version using natural sorting, so `v10` correctly orders after `v2`. Version names are up to you — `v1`, `2026-07-08`, `1.0.3` all work. Flat versioned layouts like `pattern="{key}_{version}.md"` work the same way.
91
+
92
+ A missing key (or pinned version) raises `PromptNotFound`. Requesting a `version` on a pattern without `{version}` raises `ValueError`.
93
+
94
+ ## Prompt provenance on responses
95
+
96
+ Every agent response records which prompt produced it in the `prompt` field, as a `PromptSource`:
97
+
98
+ ```python
99
+ response = await agent.run("hello")
100
+
101
+ response.prompt.text # the raw template that was loaded
102
+ response.prompt.source # ".prompts/researcher/v2.md"
103
+ response.prompt.source_type # "local"
104
+ response.prompt.version # "v2"
105
+ response.prompt.loaded_at # when it was resolved
106
+ ```
107
+
108
+ This works for plain-string instructions too: they produce an `inline` source named after the agent, with a content-hash version:
109
+
110
+ ```python
111
+ class PlainAgent(BaseAgent):
112
+ __instructions__ = "You are plain"
113
+
114
+ response.prompt.source_type # "inline"
115
+ response.prompt.source # "PlainAgent"
116
+ response.prompt.version # "3f2a9c1b04de" (content hash)
117
+ ```
118
+
119
+ Because the version is always populated — from the file structure or a content hash — you can group or diff runs by prompt version regardless of where the prompt lives. The same metadata is available on the agent as `agent.state.prompt_source`.
120
+
121
+ ## Writing a custom engine
122
+
123
+ Engines for other backends (a database, object storage, a prompt-management service) subclass `PromptEngine` and implement one method:
124
+
125
+ ```python
126
+ from pyagentic import PromptEngine, PromptSource
127
+
128
+ class MyServiceEngine(PromptEngine):
129
+ def load(self, key: str, version: str | None = None) -> PromptSource:
130
+ record = my_service.get_prompt(key, version=version or "latest")
131
+ return PromptSource(
132
+ text=record.text,
133
+ source=f"my-service/{key}",
134
+ source_type="my-service",
135
+ version=record.version,
136
+ loaded_at=record.fetched_at,
137
+ )
138
+ ```
139
+
140
+ `ref()`, instantiation-time resolution, and response provenance all come from the base class — a custom engine only decides how to fetch text and what to call a version.
@@ -48,3 +48,21 @@ Complete API documentation for PyAgentic's public interfaces.
48
48
  ### ref
49
49
 
50
50
  ::: pyagentic.ref
51
+
52
+ ## Prompt Management
53
+
54
+ ### PromptEngine
55
+
56
+ ::: pyagentic.PromptEngine
57
+
58
+ ### LocalPromptEngine
59
+
60
+ ::: pyagentic.LocalPromptEngine
61
+
62
+ ### PromptRef
63
+
64
+ ::: pyagentic.PromptRef
65
+
66
+ ### PromptSource
67
+
68
+ ::: pyagentic.PromptSource
@@ -9,6 +9,7 @@ Every agent response is a Pydantic model with a predictable structure:
9
9
  - `final_output: str` - The natural language response from the LLM
10
10
  - `tool_responses: List[ToolResponse]` - Details of any tools called (if agent has tools)
11
11
  - `agent_responses: List[AgentResponse]` - Responses from linked agents (if agent has linked agents)
12
+ - `prompt: PromptSource` - The prompt behind the agent's instructions, with source and version metadata
12
13
 
13
14
  The response model is predetermined when the agent class is defined. Each agent automatically gets its own response class that knows exactly what tools and linked agents it can use. This means you get full type safety and IDE autocompletion before you ever run the agent.
14
15
 
@@ -88,3 +89,17 @@ response.agent_responses[0].final_output # Database agent response
88
89
  ```
89
90
 
90
91
  This nested structure lets you trace exactly what each agent did and access the results of any sub-agent calls. The parent agent's response includes both its own tool calls and the complete responses from any linked agents it used.
92
+
93
+ ## Prompt Provenance
94
+
95
+ Every response records which prompt produced it in the `prompt` field. For instructions loaded from a [prompt engine](prompts.md), the version comes from the engine; plain-string instructions get an `inline` source named after the agent, versioned by content hash:
96
+
97
+ ```python
98
+ response = await agent.run("hello")
99
+
100
+ response.prompt.source # ".prompts/researcher/v2.md" or "ResearchAgent"
101
+ response.prompt.source_type # "local" or "inline"
102
+ response.prompt.version # "v2" or a content hash
103
+ ```
104
+
105
+ Since the version is always populated, you can group or diff runs by prompt version — useful when evaluating prompt changes across a set of conversations.