agentframe-py 0.1.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. agentframe_py-0.3.0/.github/workflows/base-image.yml +62 -0
  2. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/AGENTS.md +167 -35
  3. agentframe_py-0.3.0/CHANGELOG.md +506 -0
  4. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/PKG-INFO +198 -77
  5. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/README.md +189 -76
  6. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/docs/README.md +11 -3
  7. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/docs/api/README.md +18 -14
  8. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/docs/api/agents.md +14 -9
  9. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/docs/api/authorization.md +369 -19
  10. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/docs/api/configuration.md +10 -7
  11. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/docs/api/decorators.md +1 -1
  12. agentframe_py-0.3.0/docs/api/discovery.md +1110 -0
  13. agentframe_py-0.3.0/docs/api/evaluation.md +964 -0
  14. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/docs/api/hosting.md +212 -34
  15. agentframe_py-0.3.0/docs/api/orchestration.md +1059 -0
  16. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/docs/api/runtime.md +84 -7
  17. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/docs/design/base-classes.md +3 -5
  18. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/docs/design/discovery.md +188 -109
  19. agentframe_py-0.3.0/docs/design/evaluation.md +530 -0
  20. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/docs/design/mcp-skills.md +1 -1
  21. agentframe_py-0.3.0/docs/design/orchestration.md +662 -0
  22. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/docs/design/prompt-safeguarding.md +13 -2
  23. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/docs/design/tracing.md +31 -0
  24. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/docs/guides/agent-examples.md +76 -21
  25. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/docs/guides/annotations.md +1 -1
  26. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/docs/guides/authorization.md +173 -5
  27. agentframe_py-0.3.0/docs/guides/development.md +225 -0
  28. agentframe_py-0.3.0/docs/guides/evaluation.md +365 -0
  29. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/docs/guides/limits.md +93 -6
  30. agentframe_py-0.3.0/docs/guides/orchestration.md +295 -0
  31. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/docs/guides/releasing.md +6 -5
  32. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/docs/roadmap.md +155 -30
  33. agentframe_py-0.3.0/examples/evaluation.py +90 -0
  34. agentframe_py-0.3.0/examples/multi_agent/__init__.py +1 -0
  35. agentframe_py-0.3.0/examples/multi_agent/agentframe.yaml +13 -0
  36. agentframe_py-0.3.0/examples/multi_agent/planner.py +286 -0
  37. agentframe_py-0.3.0/examples/multi_agent/planner_evaluation.py +175 -0
  38. agentframe_py-0.3.0/examples/multi_agent/research.py +108 -0
  39. agentframe_py-0.3.0/examples/multi_agent/writer.py +56 -0
  40. agentframe_py-0.3.0/examples/plan_approval.py +143 -0
  41. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/examples/smoke.py +152 -3
  42. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/pyproject.toml +12 -2
  43. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/__init__.py +58 -3
  44. agentframe_py-0.3.0/src/agentframe/__main__.py +5 -0
  45. agentframe_py-0.3.0/src/agentframe/authoring/context.py +458 -0
  46. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/authoring/definitions.py +20 -7
  47. agentframe_py-0.3.0/src/agentframe/cli.py +587 -0
  48. agentframe_py-0.3.0/src/agentframe/compose.py +230 -0
  49. agentframe_py-0.3.0/src/agentframe/dev.py +180 -0
  50. agentframe_py-0.3.0/src/agentframe/dev_server.py +302 -0
  51. agentframe_py-0.3.0/src/agentframe/discovery/__init__.py +1 -0
  52. agentframe_py-0.3.0/src/agentframe/discovery/cards.py +189 -0
  53. agentframe_py-0.3.0/src/agentframe/discovery/directory.py +467 -0
  54. agentframe_py-0.3.0/src/agentframe/discovery/foundry.py +232 -0
  55. agentframe_py-0.3.0/src/agentframe/discovery/identity.py +344 -0
  56. agentframe_py-0.3.0/src/agentframe/discovery/registry.py +291 -0
  57. agentframe_py-0.3.0/src/agentframe/discovery/remote.py +950 -0
  58. agentframe_py-0.3.0/src/agentframe/discovery/transport.py +82 -0
  59. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/errors.py +58 -0
  60. agentframe_py-0.3.0/src/agentframe/evaluation/__init__.py +41 -0
  61. agentframe_py-0.3.0/src/agentframe/evaluation/budget.py +62 -0
  62. agentframe_py-0.3.0/src/agentframe/evaluation/cases.py +179 -0
  63. agentframe_py-0.3.0/src/agentframe/evaluation/harness.py +379 -0
  64. agentframe_py-0.3.0/src/agentframe/evaluation/judge.py +257 -0
  65. agentframe_py-0.3.0/src/agentframe/evaluation/report.py +765 -0
  66. agentframe_py-0.3.0/src/agentframe/evaluation/scoring.py +190 -0
  67. agentframe_py-0.3.0/src/agentframe/evaluation/targets.py +450 -0
  68. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/hosting/a2a_executor.py +175 -47
  69. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/hosting/app.py +150 -28
  70. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/hosting/card.py +9 -6
  71. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/hosting/host.py +48 -8
  72. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/hosting/lifecycle.py +10 -5
  73. agentframe_py-0.3.0/src/agentframe/hosting/skill_call.py +222 -0
  74. agentframe_py-0.3.0/src/agentframe/hosting/task_store.py +61 -0
  75. agentframe_py-0.3.0/src/agentframe/orchestration/__init__.py +1 -0
  76. agentframe_py-0.3.0/src/agentframe/orchestration/card_text.py +113 -0
  77. agentframe_py-0.3.0/src/agentframe/orchestration/catalog.py +671 -0
  78. agentframe_py-0.3.0/src/agentframe/orchestration/execution.py +506 -0
  79. agentframe_py-0.3.0/src/agentframe/orchestration/plan.py +462 -0
  80. agentframe_py-0.3.0/src/agentframe/orchestration/planning.py +242 -0
  81. agentframe_py-0.3.0/src/agentframe/orchestration/remote_tools.py +275 -0
  82. agentframe_py-0.3.0/src/agentframe/project.py +127 -0
  83. agentframe_py-0.3.0/src/agentframe/runtime/correlation.py +147 -0
  84. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/runtime/generation.py +82 -24
  85. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/runtime/limits.py +7 -0
  86. agentframe_py-0.3.0/src/agentframe/runtime/remotes.py +198 -0
  87. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/runtime/runtime.py +137 -8
  88. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/runtime/tools.py +16 -6
  89. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/security/authentication.py +7 -1
  90. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/security/authorization.py +2 -1
  91. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/security/entra.py +109 -7
  92. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/security/execution_policy.py +71 -4
  93. agentframe_py-0.3.0/tests/integration/test_agentframe_dev.py +219 -0
  94. agentframe_py-0.3.0/tests/integration/test_compose_containers.py +131 -0
  95. agentframe_py-0.3.0/tests/integration/test_directory_localhost.py +56 -0
  96. agentframe_py-0.3.0/tests/integration/test_evaluation_a2a.py +292 -0
  97. agentframe_py-0.3.0/tests/integration/test_evaluation_interop.py +120 -0
  98. agentframe_py-0.3.0/tests/integration/test_evaluation_release.py +147 -0
  99. agentframe_py-0.3.0/tests/integration/test_foundry_agents.py +194 -0
  100. agentframe_py-0.3.0/tests/integration/test_multi_agent_interop.py +308 -0
  101. agentframe_py-0.3.0/tests/integration/test_multi_agent_release.py +240 -0
  102. agentframe_py-0.3.0/tests/integration/test_on_behalf_of.py +390 -0
  103. agentframe_py-0.3.0/tests/integration/test_orchestration_release.py +493 -0
  104. agentframe_py-0.3.0/tests/integration/test_plan_approval.py +196 -0
  105. agentframe_py-0.3.0/tests/integration/test_providers.py +902 -0
  106. agentframe_py-0.3.0/tests/integration/test_remote_agents.py +327 -0
  107. agentframe_py-0.3.0/tests/integration/test_remote_budgets.py +399 -0
  108. agentframe_py-0.3.0/tests/integration/test_remote_context.py +362 -0
  109. agentframe_py-0.3.0/tests/integration/test_remote_correlation.py +419 -0
  110. agentframe_py-0.3.0/tests/integration/test_remote_identity.py +190 -0
  111. agentframe_py-0.3.0/tests/integration/test_remote_tools_hosted.py +373 -0
  112. agentframe_py-0.3.0/tests/integration/test_run_plan_hosted.py +1057 -0
  113. agentframe_py-0.3.0/tests/integration/test_skill_catalog_hosted.py +122 -0
  114. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/support/a2a_client.py +23 -13
  115. agentframe_py-0.3.0/tests/support/a2a_peer.py +131 -0
  116. agentframe_py-0.3.0/tests/support/agent_processes.py +130 -0
  117. agentframe_py-0.3.0/tests/support/dev_targets.py +69 -0
  118. agentframe_py-0.3.0/tests/support/eval_targets.py +56 -0
  119. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/support/fake_entra.py +74 -1
  120. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/support/local_server.py +5 -2
  121. agentframe_py-0.3.0/tests/support/peer_process.py +16 -0
  122. agentframe_py-0.3.0/tests/support/release_targets.py +333 -0
  123. agentframe_py-0.3.0/tests/unit/discovery/test_directory.py +548 -0
  124. agentframe_py-0.3.0/tests/unit/discovery/test_directory_find.py +220 -0
  125. agentframe_py-0.3.0/tests/unit/discovery/test_foundry_registry.py +414 -0
  126. agentframe_py-0.3.0/tests/unit/discovery/test_outbound_identity.py +148 -0
  127. agentframe_py-0.3.0/tests/unit/discovery/test_registry.py +294 -0
  128. agentframe_py-0.3.0/tests/unit/discovery/test_remote.py +1135 -0
  129. agentframe_py-0.3.0/tests/unit/evaluation/test_a2a_target.py +73 -0
  130. agentframe_py-0.3.0/tests/unit/evaluation/test_cases.py +137 -0
  131. agentframe_py-0.3.0/tests/unit/evaluation/test_controls.py +423 -0
  132. agentframe_py-0.3.0/tests/unit/evaluation/test_evaluation.py +443 -0
  133. agentframe_py-0.3.0/tests/unit/evaluation/test_judge.py +365 -0
  134. agentframe_py-0.3.0/tests/unit/evaluation/test_report.py +574 -0
  135. agentframe_py-0.3.0/tests/unit/evaluation/test_scorers.py +205 -0
  136. agentframe_py-0.3.0/tests/unit/golden/Dockerfile +9 -0
  137. agentframe_py-0.3.0/tests/unit/golden/compose.yaml +68 -0
  138. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/hosting/test_admission.py +2 -1
  139. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/hosting/test_app.py +29 -1
  140. agentframe_py-0.3.0/tests/unit/hosting/test_caller_context.py +458 -0
  141. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/hosting/test_card.py +8 -1
  142. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/hosting/test_shutdown.py +32 -0
  143. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/hosting/test_task_operations.py +1 -0
  144. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/models/test_foundry.py +33 -0
  145. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/models/test_ollama.py +32 -0
  146. agentframe_py-0.3.0/tests/unit/orchestration/test_default_remote.py +331 -0
  147. agentframe_py-0.3.0/tests/unit/orchestration/test_plan.py +459 -0
  148. agentframe_py-0.3.0/tests/unit/orchestration/test_planning.py +448 -0
  149. agentframe_py-0.3.0/tests/unit/orchestration/test_remote_tools.py +512 -0
  150. agentframe_py-0.3.0/tests/unit/orchestration/test_skill_catalog.py +612 -0
  151. agentframe_py-0.3.0/tests/unit/runtime/test_correlation.py +106 -0
  152. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/runtime/test_options.py +2 -0
  153. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/security/test_entra.py +61 -0
  154. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/security/test_execution_policy.py +59 -0
  155. agentframe_py-0.3.0/tests/unit/test_compose.py +188 -0
  156. agentframe_py-0.3.0/tests/unit/test_dev.py +135 -0
  157. agentframe_py-0.3.0/tests/unit/test_eval_cli.py +150 -0
  158. agentframe_py-0.3.0/tests/unit/test_package.py +36 -0
  159. agentframe_py-0.3.0/tests/unit/test_project.py +62 -0
  160. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/uv.lock +63 -1
  161. agentframe_py-0.1.0/CHANGELOG.md +0 -48
  162. agentframe_py-0.1.0/docs/api/discovery.md +0 -760
  163. agentframe_py-0.1.0/docs/guides/development.md +0 -117
  164. agentframe_py-0.1.0/src/agentframe/authoring/context.py +0 -123
  165. agentframe_py-0.1.0/src/agentframe/cli.py +0 -293
  166. agentframe_py-0.1.0/tests/integration/test_providers.py +0 -481
  167. agentframe_py-0.1.0/tests/unit/test_package.py +0 -19
  168. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/.github/actions/check-wheel/action.yml +0 -0
  169. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/.github/workflows/ci.yml +0 -0
  170. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/.github/workflows/foundry.yml +0 -0
  171. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/.github/workflows/release.yml +0 -0
  172. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/.gitignore +0 -0
  173. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/.pre-commit-config.yaml +0 -0
  174. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/.python-version +0 -0
  175. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/LICENSE +0 -0
  176. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/docs/api/models.md +0 -0
  177. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/docs/api/streaming.md +0 -0
  178. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/docs/design/streaming.md +0 -0
  179. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/examples/__init__.py +0 -0
  180. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/examples/assistant.py +0 -0
  181. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/examples/echo.py +0 -0
  182. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/examples/orders.py +0 -0
  183. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/examples/routed_assistant.py +0 -0
  184. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/authoring/__init__.py +0 -0
  185. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/authoring/agent.py +0 -0
  186. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/authoring/decorators.py +0 -0
  187. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/authoring/services.py +0 -0
  188. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/hosting/__init__.py +0 -0
  189. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/hosting/admission.py +0 -0
  190. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/hosting/dedup.py +0 -0
  191. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/hosting/draining_server.py +0 -0
  192. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/hosting/model_router.py +0 -0
  193. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/hosting/request_size.py +0 -0
  194. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/hosting/routing.py +0 -0
  195. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/models/__init__.py +0 -0
  196. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/models/base.py +0 -0
  197. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/models/foundry.py +0 -0
  198. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/models/ollama.py +0 -0
  199. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/models/strict_schema.py +0 -0
  200. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/py.typed +0 -0
  201. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/runtime/__init__.py +0 -0
  202. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/runtime/options.py +0 -0
  203. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/runtime/usage.py +0 -0
  204. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/security/__init__.py +0 -0
  205. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/security/principal.py +0 -0
  206. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/src/agentframe/testing.py +0 -0
  207. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/conftest.py +0 -0
  208. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/integration/test_entra_interoperability.py +0 -0
  209. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/integration/test_example.py +0 -0
  210. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/integration/test_graceful_shutdown.py +0 -0
  211. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/integration/test_hardening.py +0 -0
  212. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/integration/test_interoperability.py +0 -0
  213. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/integration/test_routing_example.py +0 -0
  214. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/integration/test_smoke.py +0 -0
  215. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/integration/test_structured_example.py +0 -0
  216. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/integration/test_success_criterion.py +0 -0
  217. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/integration/test_tools_example.py +0 -0
  218. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/support/cli_targets.py +0 -0
  219. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/authoring/test_decorators.py +0 -0
  220. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/authoring/test_services.py +0 -0
  221. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/authoring/test_tool_registration.py +0 -0
  222. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/authoring/test_tools.py +0 -0
  223. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/hosting/test_a2a_binding.py +0 -0
  224. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/hosting/test_a2a_executor.py +0 -0
  225. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/hosting/test_dedup.py +0 -0
  226. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/hosting/test_limits_ceiling.py +0 -0
  227. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/hosting/test_model_router.py +0 -0
  228. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/hosting/test_routing.py +0 -0
  229. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/hosting/test_size_limits.py +0 -0
  230. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/models/test_models.py +0 -0
  231. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/models/test_strict_schema.py +0 -0
  232. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/runtime/test_generation.py +0 -0
  233. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/runtime/test_limits.py +0 -0
  234. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/runtime/test_retries.py +0 -0
  235. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/runtime/test_runtime.py +0 -0
  236. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/runtime/test_structured_output.py +0 -0
  237. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/runtime/test_tool_loop.py +0 -0
  238. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/runtime/test_tool_replay.py +0 -0
  239. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/runtime/test_validation.py +0 -0
  240. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/security/test_authentication.py +0 -0
  241. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/security/test_authorization.py +0 -0
  242. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/security/test_tool_authorization.py +0 -0
  243. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/test_cli.py +0 -0
  244. {agentframe_py-0.1.0 → agentframe_py-0.3.0}/tests/unit/test_testing.py +0 -0
@@ -0,0 +1,62 @@
1
+ # Weekly check that the python:3.13-slim digest pinned by `agentframe compose`
2
+ # (src/agentframe/compose.py, tests/unit/golden/Dockerfile and
3
+ # docs/guides/development.md) is still the tag's current digest. When it is
4
+ # not, it opens one issue and fails, so a maintainer refreshes the pin
5
+ # deliberately; it never writes to the repository.
6
+ name: Base image digest
7
+
8
+ on:
9
+ schedule:
10
+ - cron: "0 6 * * 1"
11
+ workflow_dispatch:
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ jobs:
17
+ check:
18
+ runs-on: ubuntu-latest
19
+ permissions:
20
+ contents: read
21
+ issues: write
22
+ env:
23
+ IMAGE: python
24
+ TAG: 3.13-slim
25
+ ISSUE_TITLE: Refresh the pinned python:3.13-slim digest
26
+ steps:
27
+ - uses: actions/checkout@v7
28
+ - name: Compare the pinned and current digests
29
+ env:
30
+ GH_TOKEN: ${{ github.token }}
31
+ run: |
32
+ set -euo pipefail
33
+ pinned=$(sed -n 's/^FROM .*@//p' tests/unit/golden/Dockerfile)
34
+ token=$(curl -fsS "https://auth.docker.io/token?service=registry.docker.io&scope=repository:library/${IMAGE}:pull" | jq -r .token)
35
+ current=$(curl -fsSI \
36
+ -H "Authorization: Bearer ${token}" \
37
+ -H "Accept: application/vnd.oci.image.index.v1+json" \
38
+ -H "Accept: application/vnd.docker.distribution.manifest.list.v2+json" \
39
+ "https://registry-1.docker.io/v2/library/${IMAGE}/manifests/${TAG}" \
40
+ | tr -d '\r' | sed -n 's/^docker-content-digest: //Ip')
41
+ if [[ ! "${current}" =~ ^sha256:[0-9a-f]{64}$ ]]; then
42
+ echo "::error::Could not read the current ${IMAGE}:${TAG} digest."
43
+ exit 1
44
+ fi
45
+ echo "Pinned: ${pinned}"
46
+ echo "Current: ${current}"
47
+ if [[ "${pinned}" == "${current}" ]]; then
48
+ exit 0
49
+ fi
50
+ open=$(gh issue list --state open --search "\"${ISSUE_TITLE}\" in:title" --json number --jq length)
51
+ if [[ "${open}" == "0" ]]; then
52
+ gh issue create --title "${ISSUE_TITLE}" --body "$(cat <<EOF
53
+ \`${IMAGE}:${TAG}\` now resolves to \`${current}\`; \`agentframe compose\` pins \`${pinned}\`.
54
+
55
+ After testing the new image, update the digest in \`src/agentframe/compose.py\` (\`BASE_IMAGE\`), \`tests/unit/golden/Dockerfile\` and \`docs/guides/development.md\`. See the Containers section of the development guide.
56
+
57
+ Opened by the [Base image digest workflow](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}).
58
+ EOF
59
+ )"
60
+ fi
61
+ echo "::error::${IMAGE}:${TAG} moved to ${current}; refresh the pinned digest."
62
+ exit 1
@@ -12,13 +12,17 @@ release (M8+), not an optional add-on or a hosting platform.
12
12
 
13
13
  This repository contains the M0 development tooling, M1 model-free
14
14
  authoring/local `Runtime`, M2 native A2A hosting, M3 Ollama/Foundry text
15
- generation, M4 typed structured outputs, M5 bounded tool calling and M6 built-in
16
- opt-in model routing alongside design documentation. There
17
- is no published package or stable API, and later-milestone features are not
18
- implemented. Keep design API examples beyond the implemented surface labeled
19
- as unimplemented; explicitly approved names/defaults
20
- are decisions, not still-unresolved recommendations. Do not scaffold implementation or
21
- add dependencies merely to make design snippets executable.
15
+ generation, M4 typed structured outputs, M5 bounded tool calling, M6 built-in
16
+ opt-in model routing and M7 hardening alongside design documentation. Version
17
+ 0.1.0, the first usable single-agent release, and version 0.2.0, the M8+
18
+ multi-agent release (#83-#97), are published on PyPI as `agentframe-py`
19
+ (import `agentframe`). Pre-1.0 there is no stable API. M9 evaluation (#164, #152-#163)
20
+ and M10 model-planned orchestration (#177, #166-#176) are complete and form
21
+ version 0.3.0; later features (MCP, telemetry, streaming) are not implemented. Keep design API examples beyond
22
+ the implemented surface labeled as unimplemented; explicitly approved
23
+ names/defaults are decisions, not still-unresolved recommendations. Do not
24
+ scaffold implementation or add dependencies merely to make design snippets
25
+ executable.
22
26
 
23
27
  ## Code quality and readability
24
28
 
@@ -85,23 +89,27 @@ Folders stay one level deep. Put new code in the group that owns the concept:
85
89
  | Path | Contents |
86
90
  | --- | --- |
87
91
  | `src/agentframe/__init__.py` | Public API re-exports; every public name is importable from `agentframe`. |
88
- | `src/agentframe/` (root) | `errors.py`, `testing.py` (`ScriptedModel`), `cli.py` (`agentframe run`). |
92
+ | `src/agentframe/` (root) | `errors.py`, `testing.py` (`ScriptedModel`), `cli.py` (`agentframe run` / `dev` / `compose` / `eval`), `project.py` (`agentframe.yaml`), `dev.py` (`dev_settings()`), `dev_server.py` (`agentframe dev` supervisor), `compose.py` (`agentframe compose` generator). |
89
93
  | `src/agentframe/authoring/` | `Agent`, `@agent` / `@skill`, definitions, `RunContext`, `Inject` / `Services`. |
90
94
  | `src/agentframe/runtime/` | `Runtime`, generation, `RunLimits`, `RunOptions`, `Usage`. |
91
95
  | `src/agentframe/models/` | `base.py` model protocol and settings; provider adapters `ollama.py`, `foundry.py`; `strict_schema.py` (OpenAI strict JSON-schema converter). |
92
96
  | `src/agentframe/hosting/` | `AgentApp`, `HostConfig`, Agent Card, A2A executor, routing. |
93
97
  | `src/agentframe/security/` | `Principal`, authentication, authorization. |
98
+ | `src/agentframe/orchestration/` | `RemoteSkill`, `SkillCatalog`, bounding of untrusted card text, `RemoteTool` (remote entries as model tools, with per-entry permissions and tool checks), `Plan` / `PlanStep` with static checks and reference substitution (`plan.py`), the `ctx.plan` planning call (`planning.py`) and the plan executor behind `ctx.run_plan` (`execution.py`, `PlanResult`, `StepResult`) (M10). |
99
+ | `src/agentframe/discovery/` | `AgentRegistry`, `AgentReference`, `AgentQuery`, file and environment registries (M8+). |
100
+ | `src/agentframe/evaluation/` | Evaluation harness (M9): `cases.py` (`Case`, `load_cases`), `targets.py` (`Target`, `TargetResult`, `LocalSkill`, `A2ATarget`), `scoring.py` (`Score`, scorer calls, built-ins `equals`, `contains`, `valid`), `judge.py` (`Judge`, the rubric scorer's model-backed run and its budget holds), `report.py` (`CaseResult`, `EvalReport`, versioned JSON, `require`), `budget.py` (`TokenBudget`, evaluation-wide token holds), `harness.py` (`Evaluation`). Imported as `agentframe.evaluation`, not re-exported from `agentframe`, so its `__init__.py` re-exports its own public names. |
94
101
  | `tests/unit/<group>/` | Unit tests mirroring the source groups; root-module tests in `tests/unit/`. |
95
102
  | `tests/integration/` | Interoperability, real providers, success criterion, README example. |
96
- | `tests/support/` | Shared helpers, on pytest's `pythonpath` (`from local_server import ...`). |
97
- | `examples/` | Runnable examples, each with `create_app()`; `smoke.py` checks them all against the installed wheel in CI. |
103
+ | `tests/support/` | Shared helpers, on pytest's `pythonpath` (`from local_server import ...`); `agent_processes.py` starts agents (`agentframe run`) and the plain A2A peer (`peer_process.py`) as separate processes for release tests. |
104
+ | `examples/` | Runnable examples, each with `create_app()` (`evaluation.py` has `create_evaluation()` instead; `multi_agent/planner_evaluation.py` has `create_planner_evaluation(model, runtime)`); `smoke.py` checks them all against the installed wheel in CI. `multi_agent/` holds the research, writer and planner agents (hand-written `plan`, model-planned `propose` / `planned`, M10). |
98
105
  | `docs/roadmap.md` | Product boundaries, decisions and milestones. |
99
106
  | `docs/guides/` | How to use AgentFrame and how its behavior works. |
100
107
  | `docs/design/` | Rationale and proposed designs. |
101
108
  | `docs/api/` | Public surface reference. |
102
109
 
103
110
  Keep subpackage `__init__.py` files to a short docstring; add public exports to
104
- the top-level `__init__.py` only. Import internal modules by full path, for
111
+ the top-level `__init__.py` only (except `agentframe.evaluation`, which
112
+ `import agentframe` must not load). Import internal modules by full path, for
105
113
  example `from agentframe.runtime.limits import RunLimits`. Keep test basenames
106
114
  unique, since test folders are not packages.
107
115
 
@@ -114,7 +122,20 @@ clear error for an unknown model/deployment, a hosted structured call through
114
122
  the official A2A client, a validated typed `output=` result and the example's
115
123
  `summarize` skill returning a typed data part over A2A, a one-tool round trip
116
124
  run locally and through `examples/orders.py` over A2A (skipped if the model
117
- lacks tool support), a Foundry one-tool round trip that replays encrypted
125
+ lacks tool support), a model calling a localhost agent's skill as a remote
126
+ tool (M10 #167, checking only that the entry was called; skipped without tool
127
+ support), a rubric `Judge` grading one model-free case in an `Evaluation`
128
+ by majority of `votes=3` (M9 #160, #161), `examples/evaluation.py`'s answers
129
+ graded by a rubric judge (M9 #163; xfails for Ollama when the small judge
130
+ fails correct answers), a model planning one unambiguous
131
+ two-step goal over two localhost agents' cards with `ctx.plan` (M10 #170,
132
+ checking only the entries and the dependency; `llama3.2:3b` often writes
133
+ an invalid or different plan, an Ollama xfail), the `examples/multi_agent` planner planning and running its
134
+ post with the real model and the planner evaluation with `report.require`
135
+ (M10 #176, `-k real_planner`; specialists use stand-in models; for Ollama only
136
+ model-quality outcomes xfail: an invalid or empty plan, a plan the example's
137
+ checks refuse, or more than half the evaluation's plans erroring that way;
138
+ any other failure fails), a Foundry one-tool round trip that replays encrypted
118
139
  reasoning items and one unambiguous free-text request routed by
119
140
  `examples/routed_assistant.py` over A2A (checking only the selected skill and
120
141
  that its argument is present, since routing is nondeterministic). They are marked
@@ -145,6 +166,20 @@ AGENTFRAME_TEST_FOUNDRY=1 AGENTFRAME_FOUNDRY_ENDPOINT=<base-url> \
145
166
 
146
167
  An enabled provider with a missing required variable fails rather than skips.
147
168
 
169
+ `tests/integration/test_foundry_agents.py` has opt-in `foundry` tests for
170
+ `FoundryAgentRegistry` (#86): it lists a real project with one A2A-enabled
171
+ agent and fetches that agent's card, read-only. It runs only with
172
+ `AGENTFRAME_TEST_FOUNDRY_AGENTS=1`, `AGENTFRAME_FOUNDRY_PROJECT_ENDPOINT`
173
+ (`https://<account>.services.ai.azure.com/api/projects/<project>`) and
174
+ `AGENTFRAME_FOUNDRY_A2A_AGENT` (the agent's name), after `az login`. Setup and
175
+ roles are in `docs/api/discovery.md#foundryagentregistry`. The same agent is the
176
+ real non-AgentFrame server for #94: one test `ask`s it once, another checks
177
+ `call` is refused before sending. In CI, `test_multi_agent_interop.py` proves
178
+ both directions against a plain SDK peer (`tests/support/a2a_peer.py`). For
179
+ #159 the same file evaluates the agent with one `A2ATarget` `ask` case and
180
+ checks a `skill=` case is refused before sending; `test_evaluation_interop.py`
181
+ does the same against the plain SDK peer in CI.
182
+
148
183
  `tests/integration/test_entra_interoperability.py` has one opt-in `entra` test
149
184
  using a real token from `az account get-access-token`, enabled with
150
185
  `AGENTFRAME_TEST_ENTRA=1`, `AGENTFRAME_ENTRA_TENANT_ID` and
@@ -248,6 +283,20 @@ downgrade to prompts. Implemented wire format (M2 #5): activate the card's
248
283
  skill-call URI via `A2A-Extensions` (echoed in the response), skill ID in message
249
284
  metadata `agentframe.skill`, exactly one JSON-object data part; malformed ->
250
285
  JSON-RPC InvalidParams, no task. Not a standard A2A `skill` field.
286
+ Implemented (#89): the same URI carries caller context; an activated message
287
+ without `agentframe.skill` is free text. Cards list `params.context`
288
+ (`deadline_ms`, `hops`, `max_total_tokens` since #90); senders send only
289
+ listed fields (0.1.0 lists none).
290
+ Receiver timeout = min(own, `agentframe.deadline_ms`); `RunContext.hops`;
291
+ `RunLimits.max_remote_hops=5`: caller fails before sending, deeper request
292
+ REJECTED with base `LimitExceededError` message; depth is cooperative.
293
+ Implemented (#91): context fields `root_invocation_id`/`parent_invocation_id`
294
+ (lowercase UUID strings; invalid -> ignored, new root, never echoed or an
295
+ error). Hosted runs log `Run started`/`Run completed` (INFO) with `extra`
296
+ `agent`, `invocation_id`, `root_invocation_id`, `parent_invocation_id`; no
297
+ log format set; root not exposed on `RunContext`. Valid W3C `traceparent`
298
+ (version 00) plus valid `tracestate` forwarded unchanged as headers to every
299
+ peer, invalid dropped; no spans or trace IDs created. Never authentication.
251
300
  Free-text/extension-unaware callers use custom or opt-in model routing plus
252
301
  validated extraction. Ambiguity/missing arguments asks back through
253
302
  `TASK_STATE_INPUT_REQUIRED`, never guesses; the caller answers in the same task,
@@ -400,9 +449,11 @@ call specialists over A2A, not a workflow/graph engine.
400
449
  `AgentRegistry` is a small read-only abstract base with proposed async
401
450
  `get(agent_id) -> AgentReference` and `list(query: AgentQuery) ->
402
451
  list[AgentReference]`; pagination is unresolved. Environment/file adapters read
403
- explicit sources. `FileAgentRegistry("agents.yaml")` reads a YAML name+URL list
404
- (detailed keys/schema open); `EnvironmentAgentRegistry("AGENTFRAME_AGENTS")`
405
- uses an explicit variable (payload encoding open).
452
+ explicit sources. Implemented (#83): `AgentReference(name, card_url)` (the Agent
453
+ Card URL), `AgentQuery(names=...)`; `FileAgentRegistry("agents.yaml")` reads a
454
+ YAML `name`/`url` list on each call (1 MiB, `safe_load`, PyYAML core dep);
455
+ `EnvironmentAgentRegistry("AGENTFRAME_AGENTS")` reads comma-separated
456
+ `name=url` pairs. Config problems and unknown names raise `DefinitionError`.
406
457
  `FoundryAgentRegistry` uses the chosen Foundry project agents API through
407
458
  `azure-ai-projects` 2.x (2.10.0 observed), project endpoint
408
459
  `https://{account}.services.ai.azure.com/api/projects/{project}`. Incoming A2A
@@ -416,15 +467,28 @@ Foundry A2A connections are a possible additional reference source, not decided.
416
467
  Model deployments are not agent endpoints; no AgentFrame-to-Foundry deployment
417
468
  or tested registry integration is claimed.
418
469
 
419
- Separate `AgentCardResolver` and library-managed `AgentDirectory` own native SDK
420
- card fetch/validation/cache/refresh and owned-resource lifecycle, not
421
- per-backend user HTTP loops. No import/construction I/O or implicit polling;
422
- background refresh is opt-in. Cache TTL defaults to 300 seconds; automatically
423
- refresh on stale access, failing unless `allow_stale=True` explicitly.
470
+ Implemented (#84): `AgentDirectory(sources=[...], card_ttl_seconds=300,
471
+ allow_stale=False, allow_http_hosts=(), http_client=None,
472
+ max_reply_bytes=8 MiB)` (#150: `Remote` replies streamed, over it -> safe
473
+ `RemoteAgentError`) owns SDK card
474
+ fetch/validation/cache/refresh via an internal fetcher (no public
475
+ `AgentCardResolver`/`CardCacheConfig`). Sources read on every `get`; cards
476
+ cached per card URL, refetched when stale; failed refresh raises unless
477
+ `allow_stale=True` (`DiscoveredAgent.stale`, warning). https only except
478
+ loopback/`allow_http_hosts`, no redirects, 10 s, 1 MiB, interface URL same
479
+ origin as the registry `card_url`; no caller credentials. Remote failures
480
+ raise `RemoteAgentError`; duplicate names across sources `DefinitionError`.
481
+ No construction I/O or background tasks; closes only its own client.
424
482
  Compose `AgentDirectory(sources=[...])`, inject via `AgentApp(directory=...)`,
425
- and validate configured `Remote["name"]` bindings at startup.
483
+ and validate configured `Remote[Literal["name"]]` bindings at startup.
426
484
  `directory.find(skill="find_sources")` / `find(tags=["research"])` returns
427
485
  matching native cards from bounded validated enrichment, not assumed reference fields.
486
+ Implemented (#85): `find(*, skill=None, tags=())`, at least one filter; skill
487
+ ID and all-of tags must match on the same card skill; every source listed,
488
+ cards resolved through the cache, at most 8 fetches at a time; any source/card
489
+ failure raises (honouring `allow_stale`); source order; no pagination (small
490
+ curated sources). Found cards are not callable; orchestrators call configured
491
+ remotes, dynamic invocation is deferred.
428
492
  Inject directories as application dependencies;
429
493
  caller-owned resources stay caller-owned unless explicitly transferred. No
430
494
  registration writes, deploy/start/stop/delete, leases/federation, or A2A task
@@ -440,11 +504,47 @@ references/cards/source files; enforce application-selected outbound auth and
440
504
  destination/redirect policy, bounded reads/deadlines/cancellation and safe
441
505
  telemetry. Discovery does not delegate or auto-expose skills as tools. A separate
442
506
  `RemoteAgentClient` may remain underlying/explicit client with construction open.
443
- Author skills use `Remote["name"]` (excluded from external schemas),
507
+ Author skills use `Remote[Literal["name"]]` (excluded from external schemas),
444
508
  `call("skill", ..., output=list[Source], max_total_tokens=...)` for structured
445
509
  A2A, or `ask(text)` for any compatible peer. Both wait within caller deadline;
446
510
  remote input-required raises `ClarificationNeededError` with question, no
447
- automatic back-and-forth. See `docs/design/discovery.md` and `docs/api/discovery.md`.
511
+ automatic back-and-forth. Implemented (#87): `class Remote[N: str]` read from the
512
+ `Literal` (alias `type Research = Remote[Literal["research-agent"]]`; string form
513
+ fails mypy), `Runtime(directory=)`/`AgentApp(directory=)` (app-owned; no
514
+ directory -> construction `DefinitionError`), `Runtime.validate_remotes` at
515
+ startup, bound per run inside its deadline. `ask` sends via the SDK
516
+ `JsonRpcTransport` with the directory client to `interface_url` only,
517
+ `return_immediately` then `GetTask` polling (0.25 s -> 1 s), per-request
518
+ `A2A-Version`/timeout headers; deadline or cancellation sends best-effort
519
+ `CancelTask`.
520
+ Implemented (#88): `call(skill, /, *, output=None, **arguments)` checks the
521
+ card declares the skill-call extension and skill (else `RemoteAgentError`, no
522
+ send, no `ask` fallback), sends the M2 wire format with per-request
523
+ `A2A-Extensions`, reuses `ask`'s wait/cancel, decodes text or `{"value": ...}`
524
+ and validates `output` (`OutputValidationError`, no remote data).
525
+ Implemented (#90): `ask`/`call` take `max_total_tokens=` (default: all the run
526
+ has left), held atomically in the run's `RunAccounting` before sending and sent
527
+ as `agentframe.max_total_tokens` only to peers listing it in `params.context`
528
+ (older receivers reject unknown keys). Receiver uses min(own, incoming). The
529
+ task's usage snapshot `total_tokens` replaces the hold, even if higher;
530
+ non-advertising peers hold nothing and make usage unknown (`None`). Over the
531
+ remaining budget -> `TokenLimitExceededError` before sending (default-ceiling
532
+ message says to pass `max_total_tokens` per call for fan-out).
533
+ Implemented (#92): `remotes={name: Service(credential=...)}` on
534
+ `Runtime`/`AgentApp` (same rule as `services=`); `OutboundCredential` protocol
535
+ `async headers()` + `satisfies(scheme)`, built-ins `APIKeyCredential(key,
536
+ header="X-API-Key")`, `EntraAppCredential(credential, scope=...)`. Headers per
537
+ request (send, polls, cancel) to `interface_url` only; no redirects. Startup:
538
+ card security must be met by the entry, else `DefinitionError`; open cards need
539
+ none. Implemented (#93): `OnBehalfOf(scope=...)` entries; credential on
540
+ inbound `EntraIDAuth(client_id=audience, client_credential=secret|cert bytes|
541
+ assertion func)`; delegated tokens (`scp`, not `idtyp=app`) kept privately as
542
+ `VerifiedCaller.user_assertion`; one azure `OnBehalfOfCredential` per run.
543
+ Non-Entra host/no credential -> startup `DefinitionError`; no user (app-only,
544
+ local run) -> `PermissionDeniedError`; failed exchange -> `AuthenticationError`;
545
+ never a `Service` fallback. Opt-in `entra` OBO test uses two registrations.
546
+ `ClarificationNeededError(question, task_id, context_id)` fails a hosted
547
+ orchestrator task. See `docs/design/discovery.md` and `docs/api/discovery.md`.
448
548
 
449
549
  Plan cross-hop verified identity/delegation without authority amplification,
450
550
  permissions, deadlines, remaining token allowance and trace/correlation;
@@ -460,18 +560,41 @@ reservations. Default max 5 remote hops, excess fails. These controls use the
460
560
  same A2A extension; detailed config/wire/usage trust remains open, not base
461
561
  protocol fields or hard billing guarantees.
462
562
  No orchestration helpers in the first multi-agent release: plain await,
463
- asyncio.TaskGroup and directory.find. Later optional `Remote[ResearchAgent]`
563
+ asyncio.TaskGroup and directory.find. M10 (0.3.0) adds opt-in remote skills as model
564
+ tools and checked plans (`docs/guides/orchestration.md`); plain await stays
565
+ the default. Later optional `Remote[ResearchAgent]`
464
566
  typed proxy always uses structured selection, never prompt routing. Prove two or more
465
567
  independently deployed AgentFrame agents, an orchestrator discovering/calling a
466
568
  specialist with propagated context, and non-AgentFrame A2A client/server interop.
467
569
  Development support starts with running N agents locally, then container
468
570
  packaging; Foundry/Kubernetes templates are later. M2 `agentframe run module:create_app`
469
571
  serves the app's own configured `AgentApp` (`--dev module:Class` is localhost-only
470
- anonymous; Uvicorn is the `server` extra). M8+ `agentframe dev` reads agentframe.yaml (names/modules/ports),
471
- starts localhost agents, writes local registry, configures dev API keys and
472
- combines logs tagged by agent/invocation. One container per agent; Dockerfile
473
- template and generated docker-compose example. Exact schema/generation/key
474
- lifecycle remains open; no actual config files before implementation.
572
+ anonymous; Uvicorn is the `server` extra). Implemented (#95): `agentframe dev`
573
+ reads agentframe.yaml (`agents: {name: {app: module:create_app, port}}`,
574
+ `project.py`), starts each as `python -m agentframe run` on 127.0.0.1 in file
575
+ order after the previous `/ready`, writes `.agentframe/agents.yaml` (name/url
576
+ only, self-gitignored), generates one random key per agent per session (an
577
+ agent calls others with its own key, verified as its name), passes keys only
578
+ via child env (`AGENTFRAME_DEV`, `AGENTFRAME_PUBLIC_URL`,
579
+ `AGENTFRAME_DEV_REGISTRY`, `AGENTFRAME_DEV_API_KEYS`,
580
+ `AGENTFRAME_DEV_REMOTE_KEYS`), never disk/logs; optional
581
+ `AGENTFRAME_DEV_CLIENT_KEY` is caller `developer`. Factories call
582
+ `dev_settings()` (refuses without `AGENTFRAME_DEV=1`; directory has its own
583
+ http client; reads `AGENTFRAME_ALLOW_HTTP_HOSTS`). Output prefixed
584
+ `[agent-name]`, agents log INFO; failures stop all and exit 1; Ctrl+C sends
585
+ one SIGTERM (children in own session), kills after 35 s; a client key with
586
+ `,`/`=` is refused. Implemented (#96): `agentframe compose [--config]
587
+ [--force]` (`compose.py`) writes development `compose.yaml` (one service per
588
+ agent, `agentframe run APP --host 0.0.0.0 --port P`, `127.0.0.1:P:P`, `/ready`
589
+ healthcheck, depends on earlier agents healthy; env = dev contract with
590
+ `AGENTFRAME_PUBLIC_URL=http://name:P`, `AGENTFRAME_AGENTS` (read by
591
+ `dev_settings()` as an `EnvironmentAgentRegistry`), `AGENTFRAME_DEV=1`,
592
+ `AGENTFRAME_ALLOW_HTTP_HOSTS`=service names; keys only
593
+ `${NAME_API_KEY:?...}`/`${AGENTFRAME_DEV_CLIENT_KEY:?...}` from user `.env`)
594
+ and, only if missing, a `Dockerfile` (digest-pinned `python:3.13-slim`,
595
+ `dist/*.whl`, `USER 10001:10001`); `--force` overwrites only `compose.yaml`.
596
+ Golden files in `tests/unit/golden/`; opt-in `docker` test
597
+ (`AGENTFRAME_TEST_DOCKER=1`, skipped without a running Docker).
475
598
  No hosting platform is implied. See `docs/guides/development.md`.
476
599
 
477
600
  ### Initial release boundaries
@@ -504,11 +627,19 @@ A2A failures use safe failed/rejected states as appropriate; no raw provider
504
627
  exception, stack trace or secret goes to callers. Log diagnostics with redaction:
505
628
  failed runs log ID, class and safe message; skill/tool/router tracebacks stay in
506
629
  operator logs with the ID, so authors keep secrets out of exception messages.
507
- `tests/integration/test_hardening.py` is the M7 end-to-end acceptance suite.
630
+ `tests/integration/test_hardening.py` is the M7 end-to-end acceptance suite;
631
+ `tests/integration/test_multi_agent_release.py` is M8+'s, running
632
+ `examples/multi_agent` as separate `agentframe run` processes;
633
+ `tests/integration/test_orchestration_release.py` is M10's (#176), running its
634
+ research, writer and planner agents, the plain SDK peer and a registry-wide
635
+ coordinator (`tests/support/release_targets.py`) as separate processes with a
636
+ scripted planning model, plus the planner evaluation.
508
637
  Network host examples must include clearly labeled application-supplied
509
638
  development authentication/authorization placeholders where appropriate;
510
639
  loopback/omission is not access policy or a production-safe default.
511
- M8+ adds `ClarificationNeededError` under `AgentFrameError`; local client
640
+ M8+ adds `RemoteAgentError` (#84; failures caused by another agent, optional
641
+ `task_id`/`task_state`) and `ClarificationNeededError` under
642
+ `AgentFrameError`; local client
512
643
  input-required question is not a failed remote task or durable resumption.
513
644
 
514
645
  Use explicit model selection, finite execution limits, validated inputs/outputs,
@@ -570,11 +701,12 @@ remain open; tracing/accounting/enforcement work independently. See
570
701
 
571
702
  Read `README.md` and `docs/README.md` first. Keep `docs/roadmap.md`, the
572
703
  guides (`docs/guides/annotations.md`, `agent-examples.md`, `limits.md`,
573
- `authorization.md`, `development.md`) and the design docs
704
+ `authorization.md`, `development.md`, `evaluation.md`, `orchestration.md`) and the design docs
574
705
  (`docs/design/base-classes.md`, `tracing.md`, `mcp-skills.md`,
575
- `prompt-safeguarding.md`, `discovery.md`, `streaming.md`) consistent, including
576
- discovery/streaming API pages and navigation. Preserve the distinction between
577
- confirmed product direction and illustrative API details.
706
+ `prompt-safeguarding.md`, `discovery.md`, `streaming.md`, `evaluation.md`,
707
+ `orchestration.md`) consistent, including discovery/streaming API pages and
708
+ navigation. Preserve the distinction between confirmed product direction and
709
+ illustrative API details.
578
710
 
579
711
  Maintain `docs/api/README.md` and its linked surface reference pages alongside
580
712
  those design documents. Give every proposed decorator, class, and known public