nighthawk-python 0.12.0__tar.gz → 0.14.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 (192) hide show
  1. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/.claude/rules/docs.md +1 -1
  2. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/.claude/rules/promptfoo.md +1 -1
  3. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/.github/workflows/ci.yml +15 -6
  4. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/.github/workflows/docs.yml +8 -2
  5. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/.github/workflows/publish.yml +1 -1
  6. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/CHANGELOG.md +79 -1
  7. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/CONTRIBUTING.md +5 -5
  8. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/PKG-INFO +2 -2
  9. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/README.md +1 -1
  10. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/docs/api.md +79 -8
  11. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/docs/coding-agent-backends.md +2 -2
  12. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/docs/executors.md +3 -3
  13. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/docs/for-coding-agents.md +9 -9
  14. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/docs/index.md +1 -1
  15. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/docs/natural-blocks.md +3 -3
  16. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/docs/patterns.md +5 -5
  17. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/docs/philosophy.md +3 -1
  18. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/docs/pydantic-ai-providers.md +9 -5
  19. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/docs/quickstart.md +1 -1
  20. nighthawk_python-0.14.0/docs/runtime-configuration.md +390 -0
  21. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/docs/specification.md +132 -66
  22. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/docs/verification.md +5 -4
  23. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/promptfooconfig-agents.yaml +2 -2
  24. nighthawk_python-0.12.0/evals/promptfoo/promptfooconfig-nano-sanity.yaml → nighthawk_python-0.14.0/evals/promptfoo/promptfooconfig-luna-sanity.yaml +4 -4
  25. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/promptfooconfig-prompt-ab.yaml +5 -5
  26. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/promptfooconfig-suffix-ab.yaml +4 -4
  27. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/promptfooconfig.yaml +4 -4
  28. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/provider.py +16 -22
  29. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/test_cases/loop_outcomes_ja.yaml +1 -1
  30. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/pyproject.toml +1 -1
  31. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/__init__.py +31 -14
  32. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/backends/claude_code_cli.py +1 -1
  33. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/backends/claude_code_sdk.py +1 -1
  34. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/backends/codex.py +1 -1
  35. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/backends/mcp_boundary.py +2 -2
  36. nighthawk_python-0.14.0/src/nighthawk/composition.py +59 -0
  37. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/configuration.py +17 -6
  38. nighthawk_python-0.14.0/src/nighthawk/errors.py +47 -0
  39. nighthawk_python-0.14.0/src/nighthawk/lifecycle.py +129 -0
  40. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/natural/decorator.py +83 -66
  41. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/natural/transform.py +22 -9
  42. nighthawk_python-0.14.0/src/nighthawk/oversight.py +200 -0
  43. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/resilience/_budget.py +2 -2
  44. nighthawk_python-0.14.0/src/nighthawk/runtime/execution_reference.py +13 -0
  45. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/runtime/prompt.py +6 -6
  46. nighthawk_python-0.14.0/src/nighthawk/runtime/runner.py +860 -0
  47. nighthawk_python-0.14.0/src/nighthawk/runtime/scoping.py +527 -0
  48. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/runtime/step_context.py +3 -2
  49. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/runtime/step_executor.py +25 -17
  50. nighthawk_python-0.14.0/src/nighthawk/runtime/step_result.py +49 -0
  51. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/testing.py +4 -0
  52. nighthawk_python-0.14.0/src/nighthawk/tools/declarations.py +110 -0
  53. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/tools/execution.py +6 -11
  54. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/backends/test_codex.py +16 -4
  55. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/docs/test_docs_architecture.py +32 -0
  56. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/docs/test_prompt_examples.py +2 -1
  57. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/execution/prompt_test_helpers.py +1 -1
  58. nighthawk_python-0.14.0/tests/execution/test_capabilities.py +113 -0
  59. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/execution/test_globals_prompt.py +1 -1
  60. nighthawk_python-0.14.0/tests/execution/test_managed_model.py +285 -0
  61. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/execution/test_natural_block_ordering.py +12 -11
  62. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/execution/test_natural_traceback.py +3 -3
  63. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/execution/test_runtime.py +29 -33
  64. nighthawk_python-0.14.0/tests/governance/test_governance.py +352 -0
  65. nighthawk_python-0.14.0/tests/governance/test_return_expression_policy.py +172 -0
  66. nighthawk_python-0.14.0/tests/governance/test_step_completion.py +630 -0
  67. nighthawk_python-0.14.0/tests/governance/test_step_ledger.py +462 -0
  68. nighthawk_python-0.14.0/tests/governance/test_step_results.py +301 -0
  69. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/integration/test_carry_pattern.py +3 -3
  70. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/integration/test_claude_code_cli_integration.py +7 -4
  71. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/integration/test_claude_code_sdk_integration.py +13 -37
  72. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/integration/test_codex_integration.py +18 -24
  73. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/integration/test_llm_integration.py +71 -74
  74. nighthawk_python-0.14.0/tests/natural/test_decorator_globals.py +101 -0
  75. nighthawk_python-0.14.0/tests/natural/test_introspection.py +68 -0
  76. nighthawk_python-0.14.0/tests/public/test_composition.py +150 -0
  77. nighthawk_python-0.14.0/tests/public/test_model_configuration.py +68 -0
  78. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/public/test_public_api.py +66 -41
  79. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/public/test_usage_meter.py +68 -8
  80. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/resilience/test_budget.py +23 -19
  81. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/resilience/test_composition.py +3 -3
  82. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/tools/test_assignment_async.py +7 -6
  83. nighthawk_python-0.14.0/tests/tools/test_declarations.py +166 -0
  84. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/tools/test_provided_async.py +2 -1
  85. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/tools/test_tool_boundary.py +26 -26
  86. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/uv.lock +1 -1
  87. nighthawk_python-0.12.0/docs/runtime-configuration.md +0 -279
  88. nighthawk_python-0.12.0/src/nighthawk/errors.py +0 -25
  89. nighthawk_python-0.12.0/src/nighthawk/oversight.py +0 -180
  90. nighthawk_python-0.12.0/src/nighthawk/runtime/runner.py +0 -721
  91. nighthawk_python-0.12.0/src/nighthawk/runtime/scoping.py +0 -476
  92. nighthawk_python-0.12.0/src/nighthawk/tools/registry.py +0 -217
  93. nighthawk_python-0.12.0/tests/governance/test_governance.py +0 -198
  94. nighthawk_python-0.12.0/tests/tools/test_registry.py +0 -149
  95. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/.claude/rules/src.md +0 -0
  96. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/.claude/rules/tests.md +0 -0
  97. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/.claude/settings.json +0 -0
  98. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/.claude/unset_envs.sh +0 -0
  99. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/.devcontainer/devcontainer-lock.json +0 -0
  100. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/.devcontainer/devcontainer.json +0 -0
  101. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/.devcontainer/postCreateCommand.sh +0 -0
  102. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/.github/dependabot.yml +0 -0
  103. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/.gitignore +0 -0
  104. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/.python-version +0 -0
  105. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/AGENTS.md +0 -0
  106. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/CLAUDE.md +0 -0
  107. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/LICENSE +0 -0
  108. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/docs/AGENTS.md +0 -0
  109. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/docs/assets/nighthawk_logo-128x128.png +0 -0
  110. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/docs/roadmap.md +0 -0
  111. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/assertions/__init__.py +0 -0
  112. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/assertions/binding_value.py +0 -0
  113. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/assertions/outcome_kind.py +0 -0
  114. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/assertions/raise_message.py +0 -0
  115. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/evidence/2026-03-26-baseline-prompt-ab.md +0 -0
  116. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/evidence/2026-03-26-baseline-regression.md +0 -0
  117. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/evidence/2026-03-26-baseline-suffix-ab.md +0 -0
  118. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/evidence/2026-04-27-runtime-prompt-optimization.md +0 -0
  119. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/prompts/eval_coding_agent.txt +0 -0
  120. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/prompts/eval_default.txt +0 -0
  121. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/prompts/eval_legacy_default.txt +0 -0
  122. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/prompts/eval_mutation_aware.txt +0 -0
  123. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/prompts/eval_sequenced.txt +0 -0
  124. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/research-result.md +0 -0
  125. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/test_cases/binding_operations.yaml +0 -0
  126. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/test_cases/edge_cases.yaml +0 -0
  127. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/test_cases/loop_outcomes.yaml +0 -0
  128. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/test_cases/multi_step.yaml +0 -0
  129. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/test_cases/null_handling.yaml +0 -0
  130. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/test_cases/outcome_kinds.yaml +0 -0
  131. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/evals/promptfoo/test_cases/tool_selection.yaml +0 -0
  132. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/mkdocs.yml +0 -0
  133. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/pyrightconfig.json +0 -0
  134. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/AGENTS.md +0 -0
  135. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/backends/__init__.py +0 -0
  136. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/backends/_text_fallback.py +0 -0
  137. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/backends/base.py +0 -0
  138. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/backends/claude_code_settings.py +0 -0
  139. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/backends/mcp_server.py +0 -0
  140. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/backends/text_projection.py +0 -0
  141. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/backends/tool_bridge.py +0 -0
  142. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/identifier_path.py +0 -0
  143. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/json_renderer.py +0 -0
  144. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/natural/__init__.py +0 -0
  145. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/natural/blocks.py +0 -0
  146. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/resilience/__init__.py +0 -0
  147. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/resilience/_circuit_breaker.py +0 -0
  148. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/resilience/_fallback.py +0 -0
  149. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/resilience/_retry.py +0 -0
  150. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/resilience/_timeout.py +0 -0
  151. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/resilience/_vote.py +0 -0
  152. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/runtime/__init__.py +0 -0
  153. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/runtime/_user_content.py +0 -0
  154. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/runtime/async_bridge.py +0 -0
  155. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/runtime/step_contract.py +0 -0
  156. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/runtime/tool_calls.py +0 -0
  157. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/tools/__init__.py +0 -0
  158. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/tools/_tool_return_content.py +0 -0
  159. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/tools/assignment.py +0 -0
  160. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/tools/contracts.py +0 -0
  161. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/tools/provided.py +0 -0
  162. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/src/nighthawk/ulid.py +0 -0
  163. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/AGENTS.md +0 -0
  164. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/__init__.py +0 -0
  165. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/backends/__init__.py +0 -0
  166. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/backends/test_claude_code_cli.py +0 -0
  167. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/backends/test_claude_code_sdk.py +0 -0
  168. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/conftest.py +0 -0
  169. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/docs/__init__.py +0 -0
  170. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/docs/test_coding_agent_examples.py +0 -0
  171. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/execution/__init__.py +0 -0
  172. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/execution/stub_executor.py +0 -0
  173. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/execution/test_execution_outcome_prompt_fragment.py +0 -0
  174. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/execution/test_infer_binding_types.py +0 -0
  175. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/execution/test_variables_prompt.py +0 -0
  176. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/integration/__init__.py +0 -0
  177. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/integration/skip_helpers.py +0 -0
  178. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/natural/__init__.py +0 -0
  179. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/natural/test_blocks.py +0 -0
  180. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/public/__init__.py +0 -0
  181. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/public/test_readme_example.py +0 -0
  182. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/resilience/__init__.py +0 -0
  183. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/resilience/test_circuit_breaker.py +0 -0
  184. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/resilience/test_fallback.py +0 -0
  185. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/resilience/test_retry.py +0 -0
  186. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/resilience/test_timeout.py +0 -0
  187. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/resilience/test_vote.py +0 -0
  188. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/test_renderer.py +0 -0
  189. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/test_testing.py +0 -0
  190. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/tools/__init__.py +0 -0
  191. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/tools/test_contracts.py +0 -0
  192. {nighthawk_python-0.12.0 → nighthawk_python-0.14.0}/tests/tools/test_multimodal_helpers.py +0 -0
@@ -77,7 +77,7 @@ List only topics that commonly drift across multiple files or are easy to mispla
77
77
  - Terminology: "task" = structural unit (contract), "judgment" = cognitive act. Use "one task per block".
78
78
  - Code examples: self-contained and understandable without surrounding prose.
79
79
  - Built-in tools (`nh_eval`, `nh_assign`): implementation details. Only `specification.md` may expose them.
80
- - `@nh.tool`: `specification.md` documents as spec, `natural-blocks.md` may mention it with a "prefer binding functions" note, all others must not reference it.
80
+ - Native tools (`nh.scope(tools=...)`): `specification.md` documents as spec, `runtime-configuration.md` documents usage and the role split with `implicit_references`, `natural-blocks.md` may mention it with a "prefer binding functions" note, all others must not reference it.
81
81
  - Package name: always `nighthawk-python` in `pip install` commands.
82
82
  - When renaming a document or changing its role, update all inbound references, routing rules here, relevant `tests/docs`, and navigation metadata if applicable.
83
83
  - When a governance file under `docs/` is not meant for publication, its MkDocs handling must be explicit.
@@ -21,7 +21,7 @@ paths:
21
21
  4. Once validated, port the change to the corresponding production code (see mapping below).
22
22
  5. Run `uv run pytest -q` to confirm no regressions.
23
23
 
24
- **`--filter-providers` caveat**: The flag takes a regex pattern, not an exact label. A pattern like `"gpt-5.4-mini"` matches every provider whose label contains that substring (e.g. both `openai-responses` and `codex` labels). Use an anchored or label-specific pattern (e.g. `"^gpt-5.4-mini"`, `"codex:"`) to target a single provider.
24
+ **`--filter-providers` caveat**: The flag takes a regex pattern, not an exact label. A pattern like `"gpt-5.6-luna"` matches every provider whose label contains that substring (e.g. both `openai-responses` and `codex` labels). Use an anchored or label-specific pattern (e.g. `"^gpt-5.6-luna"`, `"codex:"`) to target a single provider.
25
25
 
26
26
  ## Prompt variant cleanup (deletion timing and criteria)
27
27
 
@@ -19,13 +19,17 @@ jobs:
19
19
  name: Lint and type check
20
20
  runs-on: ubuntu-latest
21
21
  steps:
22
- - uses: actions/checkout@v6
22
+ - uses: actions/checkout@v7
23
23
  with:
24
24
  persist-credentials: false
25
25
 
26
- - uses: astral-sh/setup-uv@v7
26
+ # setup-uv publishes no floating major tag since v8, so pin an exact release.
27
+ - uses: astral-sh/setup-uv@v10.0.1
27
28
  with:
28
29
  python-version: "3.13"
30
+ # Same dependency set and cache key as "test (3.13)". Only that job
31
+ # saves the entry; concurrent writers race to reserve the same key.
32
+ save-cache: false
29
33
 
30
34
  - name: Install dependencies
31
35
  run: uv sync --all-extras --all-groups
@@ -48,11 +52,12 @@ jobs:
48
52
  python-version: ["3.13", "3.14"]
49
53
  continue-on-error: ${{ matrix.python-version != '3.13' }}
50
54
  steps:
51
- - uses: actions/checkout@v6
55
+ - uses: actions/checkout@v7
52
56
  with:
53
57
  persist-credentials: false
54
58
 
55
- - uses: astral-sh/setup-uv@v7
59
+ # Sole writer of the per-Python-version dependency cache.
60
+ - uses: astral-sh/setup-uv@v10.0.1
56
61
  with:
57
62
  python-version: ${{ matrix.python-version }}
58
63
 
@@ -67,11 +72,15 @@ jobs:
67
72
  needs: [lint, test]
68
73
  runs-on: ubuntu-latest
69
74
  steps:
70
- - uses: actions/checkout@v6
75
+ - uses: actions/checkout@v7
71
76
  with:
72
77
  persist-credentials: false
73
78
 
74
- - uses: astral-sh/setup-uv@v7
79
+ # "uv build" only resolves the build backend, so a cache entry would add
80
+ # no measurable benefit while colliding with the docs workflow key.
81
+ - uses: astral-sh/setup-uv@v10.0.1
82
+ with:
83
+ enable-cache: false
75
84
 
76
85
  - name: Build sdist and wheel
77
86
  run: uv build
@@ -24,9 +24,15 @@ jobs:
24
24
  build:
25
25
  runs-on: ubuntu-latest
26
26
  steps:
27
- - uses: actions/checkout@v6
27
+ - uses: actions/checkout@v7
28
28
 
29
- - uses: astral-sh/setup-uv@v7
29
+ # setup-uv publishes no floating major tag since v8, so pin an exact release.
30
+ - uses: astral-sh/setup-uv@v10.0.1
31
+ with:
32
+ python-version: "3.13"
33
+ # The docs group is a subset of the cache "test (3.13)" saves under
34
+ # this key, so restore it here but never overwrite it.
35
+ save-cache: false
30
36
 
31
37
  - name: Install dependencies
32
38
  run: uv sync --group docs
@@ -24,7 +24,7 @@ jobs:
24
24
  id-token: write
25
25
  steps:
26
26
  - name: Download distribution artifacts
27
- uses: actions/download-artifact@v6
27
+ uses: actions/download-artifact@v7
28
28
  with:
29
29
  name: python-package-distributions
30
30
  path: dist/
@@ -7,6 +7,82 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.14.0]
11
+
12
+ ### Added
13
+
14
+ - Scoped `nh.lifecycle.StepLifecycle` delivers typed completion, DSL raise, failure, or interruption records after generated caller assignments. Hosts can record one terminal event and translate failures with explicit exception chaining.
15
+ - `Oversight.inspect_return_expression` approves expressions before core evaluation, await, and return validation.
16
+ - `StepDeliveryError` supports host storage adapters without claiming persistence succeeded.
17
+
18
+ ### Changed
19
+
20
+ - `ExecutionReference` and `get_execution_reference` replace the abbreviated identity API. `step_execution_id` identifies each invocation; `source_location` identifies its source. StepContext, inspection, testing observations, terminal records, and spans share this identity.
21
+ - Runtime internal exceptions, including preparation and await failures, now propagate through `ExecutionError.step_failed` with the original exception as cause. Rejection is a classified failure. DSL exceptions remain distinct.
22
+ - Completion tracing follows actual caller assignments. Cancellation retains priority if terminal delivery fails. Delivery errors never retry execution or undo effects.
23
+ - Natural functions preserve original closure cells for nonlocal assignments and source locations for generated execution.
24
+
25
+ ### Fixed
26
+
27
+ - Lifecycle handlers can rethrow an already-recorded host exception or interruption without replacing its original cause with a self-reference.
28
+ - Host integration guidance distinguishes one delivery attempt from ledger deduplication and explains the validation, await, and rewrite limits of name-only return approval.
29
+
30
+ ### Removed
31
+
32
+ - `ExecutionRef`, `get_execution_ref`, and `step_id`, without compatibility aliases. Span attributes use `step.execution.id` and `step.source_location`.
33
+
34
+ ## [0.13.0]
35
+
36
+ ### Added
37
+
38
+ - `nh.UNSET`, `nh.UnsetType`, `nh.Extend`, and `nh.Merge` express inheritance and per-field scope composition.
39
+ - Caller-constructed Pydantic AI Models in `StepExecutorConfiguration.model`, retaining identity and the managed execution contract. Clients are borrowed; hosts own authentication delivery and lifetime.
40
+ - Host-installed usage meters, scoped native tools and Pydantic AI capabilities, and public scope getters.
41
+ - Resolved `Pass`, `Return`, `Break`, `Continue`, and `Raise` outcomes through `nh.oversight`, with explicit `Rewrite(return_value=None)` support.
42
+ - `nh.get_transformed_function()` for compiled-body inspection through conventional wrappers.
43
+
44
+ ### Changed
45
+
46
+ - The default model is now `openai-responses:gpt-5.6-luna` (previously `openai-responses:gpt-5.4-nano`).
47
+ - Scope omission inherits; ordinary values replace and empty collections clear. Only oversight accepts `None`. Executor replacement precedes full configuration replacement.
48
+ - Run getters require a run; `get_step_context()` requires a step. Budget wrappers retain optional private meter discovery.
49
+ - Repeated identical tool declarations are idempotent. Conflicts use `NameConflictError` and `ToolNameConflictError`; invalid tools use `ToolDeclarationError`.
50
+ - `StepCommit.outcome` contains resolved Python values in variants. Inspection mappings preserve contained types and identity through shallow read-only views. Trusted hooks must not mutate references.
51
+ - One validated candidate is inspected, then supplied rewrites are validated before final assignment. Bindings-only rewrites preserve the resolved return; return expressions are never replayed. Rejection cannot roll back preceding host side effects.
52
+ - Decorated functions share real module globals; `__wrapped__` and `inspect.unwrap` follow the original function.
53
+ - Live Model configuration serialization requires explicit model-field exclusion, including nested records. External agents reject Model injection and configured model switches rather than silently changing a label.
54
+
55
+ ### Removed
56
+
57
+ - Global `scope(mode=...)`, the old `get_current_usage_meter` and `get_current_step_context` names, and `ToolRegistrationError`; no deprecated aliases remain.
58
+ - `@nighthawk.tool` and the process-global tool registry. Declare tools in scopes.
59
+ - `StepCommitProposal`, old proposed/rewritten fields, and parallel `StepCommit.step_outcome`/`return_value` fields.
60
+
61
+ ### Compatibility
62
+
63
+ The supported public API is `nighthawk.__all__` plus the modules listed in `docs/api.md`. Private names may change without notice. Minor releases in the 0.x series may contain the breaking changes listed here.
64
+
65
+ ### Migration notes for hosts
66
+
67
+ | Before | After |
68
+ |---|---|
69
+ | `scope(mode="inherit", tools=[fn])` | `scope(tools=nh.Extend([fn]))` |
70
+ | `scope(mode="replace", implicit_references={})` | `scope(implicit_references={})` |
71
+ | `scope(implicit_references=None)` to inherit | Omit the field or use `nh.UNSET`; use `nh.Merge(mapping)` to compose |
72
+ | `get_current_usage_meter()` / `get_current_step_context()` | `get_usage_meter()` / `get_step_context()`; missing context raises |
73
+ | `ToolRegistrationError` | `ToolDeclarationError`; catch `NameConflictError` across namespaces |
74
+ | Private meter context writes | `nh.run(executor, usage_meter=meter)` or `nh.scope(usage_meter=meter)` |
75
+ | `@nh.tool` at import time | `nh.scope(tools=[fn])` or an explicit Pydantic AI `Tool` |
76
+ | `StepCommit.return_value` | Check `isinstance(commit.outcome, nh.oversight.Return)`, then read `.value` |
77
+ | Expression-based `Rewrite(step_outcome=...)` | `Rewrite(outcome=nh.oversight.Return(value=...))` |
78
+ | Bindings rewrite that implicitly recalculates return | Supply both replacement bindings and `return_value` explicitly |
79
+ | `inspect.unwrap(function)` to find compiled code | `nh.get_transformed_function(function)` |
80
+ | Credential transport via environment for managed construction | Construct authenticated Provider/Model in memory and use `StepExecutorConfiguration(model=model)` |
81
+ | Dumping configuration containing a live Model | Explicitly exclude `model`; the partial dump cannot reconstruct it |
82
+ | Changing an external agent's configured model | Replace the executor with a managed executor or a host-configured external agent |
83
+
84
+ Invalid initial results fail before oversight; use resilience retries to recover. `from_configuration(configuration=...)` retains its signature. String model settings remain serializable, and environment-configured provider strings remain supported.
85
+
10
86
  ## [0.12.0]
11
87
 
12
88
  ### Changed
@@ -188,7 +264,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
188
264
  - Step executor abstraction and provider integration foundation.
189
265
  - Core documentation and project scaffolding.
190
266
 
191
- [Unreleased]: https://github.com/kurusugawa-computer/nighthawk-python/compare/v0.12.0...HEAD
267
+ [Unreleased]: https://github.com/kurusugawa-computer/nighthawk-python/compare/v0.14.0...HEAD
268
+ [0.14.0]: https://github.com/kurusugawa-computer/nighthawk-python/compare/v0.13.0...v0.14.0
269
+ [0.13.0]: https://github.com/kurusugawa-computer/nighthawk-python/compare/v0.12.0...v0.13.0
192
270
  [0.12.0]: https://github.com/kurusugawa-computer/nighthawk-python/compare/v0.11.0...v0.12.0
193
271
  [0.11.0]: https://github.com/kurusugawa-computer/nighthawk-python/compare/v0.10.0...v0.11.0
194
272
  [0.10.0]: https://github.com/kurusugawa-computer/nighthawk-python/compare/v0.9.0...v0.10.0
@@ -83,8 +83,8 @@ PFOO="cd evals/promptfoo && PROMPTFOO_PYTHON=\"$(uv python find)\" npx promptfoo
83
83
  | Command | Purpose |
84
84
  |---|---|
85
85
  | `eval $PFOO eval` | Full regression (all backends, all tests) |
86
- | `eval $PFOO eval -c promptfooconfig-prompt-ab.yaml` | Prompt A/B test (gpt-5.4-mini only) |
87
- | `eval $PFOO eval -c promptfooconfig-nano-sanity.yaml --no-cache` | Default-model sanity check (gpt-5.4-nano only) |
86
+ | `eval $PFOO eval -c promptfooconfig-prompt-ab.yaml` | Prompt A/B test (gpt-5.6-luna only) |
87
+ | `eval $PFOO eval -c promptfooconfig-luna-sanity.yaml --no-cache` | Default-model sanity check (gpt-5.6-luna only) |
88
88
  | `eval $PFOO eval -c promptfooconfig-agents.yaml` | Coding agent backends (reduced test set) |
89
89
  | `eval $PFOO eval -c promptfooconfig.yaml --filter-pattern "P-BIND-001"` | Single test |
90
90
  | `eval $PFOO eval -c promptfooconfig.yaml --filter-providers "claude-code-cli"` | Single backend |
@@ -93,8 +93,8 @@ PFOO="cd evals/promptfoo && PROMPTFOO_PYTHON=\"$(uv python find)\" npx promptfoo
93
93
  #### Config files (`evals/promptfoo/`)
94
94
 
95
95
  - `promptfooconfig.yaml` — Regression: winner prompt combo across openai-responses, claude-code-cli, and codex backends. All test cases.
96
- - `promptfooconfig-prompt-ab.yaml` — A/B testing: 4 prompt/tool variants on gpt-5.4-mini. All test cases.
97
- - `promptfooconfig-nano-sanity.yaml` — Default-model sanity check on openai-responses:gpt-5.4-nano. All test cases.
96
+ - `promptfooconfig-prompt-ab.yaml` — A/B testing: 4 prompt/tool variants on gpt-5.6-luna. All test cases.
97
+ - `promptfooconfig-luna-sanity.yaml` — Default-model sanity check on openai-responses:gpt-5.6-luna. All test cases.
98
98
  - `promptfooconfig-agents.yaml` — Coding agent only: claude-code-cli and codex with reduced test set.
99
99
 
100
100
  #### Directory layout
@@ -205,7 +205,7 @@ def run(
205
205
  Example:
206
206
  ```python
207
207
  executor = AgentStepExecutor.from_configuration(
208
- configuration=StepExecutorConfiguration(model="openai-responses:gpt-5.4-mini"),
208
+ configuration=StepExecutorConfiguration(model="openai-responses:gpt-5.6-luna"),
209
209
  )
210
210
  with nighthawk.run(executor):
211
211
  result = my_natural_function()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: nighthawk-python
3
- Version: 0.12.0
3
+ Version: 0.14.0
4
4
  Summary: A Python library where Python controls flow and LLMs or coding agents reason within constrained Natural blocks.
5
5
  Project-URL: Repository, https://github.com/kurusugawa-computer/nighthawk-python
6
6
  Project-URL: Documentation, https://kurusugawa-computer.github.io/nighthawk-python/
@@ -73,7 +73,7 @@ def python_average(numbers):
73
73
  return sum(numbers) / len(numbers)
74
74
 
75
75
 
76
- step_executor = nh.AgentStepExecutor.from_configuration(configuration=nh.StepExecutorConfiguration(model="openai-responses:gpt-5.4-nano"))
76
+ step_executor = nh.AgentStepExecutor.from_configuration(configuration=nh.StepExecutorConfiguration(model="openai-responses:gpt-5.6-luna"))
77
77
 
78
78
  with nh.run(step_executor):
79
79
 
@@ -38,7 +38,7 @@ def python_average(numbers):
38
38
  return sum(numbers) / len(numbers)
39
39
 
40
40
 
41
- step_executor = nh.AgentStepExecutor.from_configuration(configuration=nh.StepExecutorConfiguration(model="openai-responses:gpt-5.4-nano"))
41
+ step_executor = nh.AgentStepExecutor.from_configuration(configuration=nh.StepExecutorConfiguration(model="openai-responses:gpt-5.6-luna"))
42
42
 
43
43
  with nh.run(step_executor):
44
44
 
@@ -8,27 +8,37 @@
8
8
  ::: nighthawk
9
9
  options:
10
10
  members:
11
+ - UNSET
12
+ - UnsetType
13
+ - Extend
14
+ - Merge
15
+ - get_transformed_function
11
16
  - natural_function
12
- - tool
13
17
  - run
14
18
  - scope
15
19
  - AgentStepExecutor
20
+ - StepExecutor
16
21
  - StepExecutorConfiguration
17
22
  - StepPromptTemplates
18
23
  - StepContextLimits
19
24
  - JsonableValue
20
25
  - to_jsonable_value
21
- - ExecutionRef
22
- - get_current_step_context
23
- - get_current_usage_meter
24
- - get_execution_ref
26
+ - ExecutionReference
27
+ - get_capabilities
28
+ - get_step_context
29
+ - get_usage_meter
30
+ - get_execution_reference
25
31
  - get_implicit_references
32
+ - get_oversight
33
+ - get_lifecycle
26
34
  - get_step_executor
27
35
  - get_system_prompt_suffix_fragments
36
+ - get_tools
28
37
  - get_user_prompt_suffix_fragments
29
38
  - resilience
30
39
  - UsageMeter
31
40
  - oversight
41
+ - lifecycle
32
42
 
33
43
  ## Errors
34
44
 
@@ -93,18 +103,45 @@
93
103
  members:
94
104
  - StepContext
95
105
  - ToolResultRenderingPolicy
96
- - get_current_step_context
106
+ - get_step_context
97
107
  - step_context_scope
98
108
 
109
+ ## Step Contracts
110
+
111
+ Import these types from `nighthawk.runtime.step_contract` when implementing a custom
112
+ `StepExecutor` or constructing a `nighthawk.testing.StepResponse`.
113
+ `StepKind` describes the allowed outcome kinds, and `StepOutcome` is the union of
114
+ the five outcome models, discriminated by their `kind` field.
115
+
116
+ These models describe executor results before the runner resolves them for
117
+ oversight. In particular, `ReturnStepOutcome.return_expression` holds a Python
118
+ expression that the runner evaluates, whereas `nighthawk.oversight.Return.value`
119
+ holds the evaluated value. Oversight hooks use `nighthawk.oversight.StepResult`.
120
+
121
+ ::: nighthawk.runtime.step_contract
122
+ options:
123
+ members:
124
+ - StepKind
125
+ - StepOutcome
126
+ - PassStepOutcome
127
+ - ReturnStepOutcome
128
+ - BreakStepOutcome
129
+ - ContinueStepOutcome
130
+ - RaiseStepOutcome
131
+
99
132
  ## Tool Contracts
100
133
 
101
134
  ::: nighthawk.tools.contracts
102
135
  options:
103
136
  members:
104
- - ToolResult
137
+ - ToolOutcome
105
138
  - ToolBoundaryError
106
- - Error
139
+ - ToolError
107
140
  - ErrorKind
141
+
142
+ ::: nighthawk.tools.execution
143
+ options:
144
+ members:
108
145
  - ToolResultWrapperToolset
109
146
 
110
147
  ## Resilience
@@ -128,3 +165,37 @@
128
165
  ## Testing
129
166
 
130
167
  ::: nighthawk.testing
168
+
169
+ ::: nighthawk.oversight
170
+ options:
171
+ members:
172
+ - Pass
173
+ - Return
174
+ - Break
175
+ - Continue
176
+ - Raise
177
+ - StepResult
178
+ - StepCommit
179
+ - ReturnExpression
180
+ - Rewrite
181
+ - Accept
182
+ - Reject
183
+ - ToolCall
184
+ - Oversight
185
+ - OversightRejectedError
186
+ - StepCommitDecision
187
+ - ToolCallDecision
188
+
189
+ ## Lifecycle
190
+
191
+ ::: nighthawk.lifecycle
192
+ options:
193
+ members:
194
+ - StepLifecycle
195
+ - StepFinished
196
+ - StepCompleted
197
+ - StepRaised
198
+ - StepFailed
199
+ - StepInterrupted
200
+ - FailureStage
201
+ - StepDeliveryError
@@ -25,7 +25,7 @@ Codex:
25
25
  configuration = nh.StepExecutorConfiguration(model="codex:default")
26
26
  ```
27
27
 
28
- The segment after `:` selects the model. Use `default` to let the backend choose its default model, or specify a model alias recognized by the backend CLI (e.g., `claude-code-sdk:sonnet`, `codex:gpt-5.4-mini`). Available aliases depend on the backend CLI version.
28
+ The segment after `:` selects the model. Use `default` to let the backend choose its default model, or specify a model alias recognized by the backend CLI (e.g., `claude-code-sdk:sonnet`, `codex:gpt-5.6-luna`). Available aliases depend on the backend CLI version.
29
29
 
30
30
  Backend-specific settings are configured via the `model_settings` field of `StepExecutorConfiguration`. Each backend provides a settings class (`ClaudeCodeSdkModelSettings`, `ClaudeCodeCliModelSettings`, `CodexModelSettings`) that can be passed directly — `StepExecutorConfiguration` auto-converts `BaseModel` instances to dicts internally.
31
31
 
@@ -63,7 +63,7 @@ If a backend CLI process fails (e.g., crashes, times out, or returns an invalid
63
63
 
64
64
  ### Allowed tool names
65
65
 
66
- Use `allowed_tool_names` to restrict which Nighthawk tools are exposed to the backend via MCP. When `None` (default), all registered tools are exposed.
66
+ Use `allowed_tool_names` to restrict which Nighthawk tools are exposed to the backend via MCP. When `None` (default), all tools visible in the current scope are exposed.
67
67
 
68
68
  ```py
69
69
  from nighthawk.backends.claude_code_sdk import ClaudeCodeSdkModelSettings
@@ -33,11 +33,11 @@ See [Philosophy](philosophy.md) for the full design rationale, including the des
33
33
  ```py
34
34
  import nighthawk as nh
35
35
 
36
- configuration = nh.StepExecutorConfiguration(model="openai-responses:gpt-5.4-nano")
36
+ configuration = nh.StepExecutorConfiguration(model="openai-responses:gpt-5.6-luna")
37
37
  step_executor = nh.AgentStepExecutor.from_configuration(configuration=configuration)
38
38
  ```
39
39
 
40
- The `model` field accepts a `provider:model` format identifier. The default model is `openai-responses:gpt-5.4-nano`.
40
+ The `model` field accepts a `provider:model` format identifier. The default model is `openai-responses:gpt-5.6-luna`.
41
41
 
42
42
  All Natural functions must be called inside a `with nh.run(step_executor):` context:
43
43
 
@@ -57,7 +57,7 @@ For most cases, wrap a Pydantic AI `Agent` using `AgentStepExecutor`:
57
57
  ```py
58
58
  from pydantic_ai import Agent
59
59
 
60
- agent = Agent(model="openai-responses:gpt-5.4-nano", ...)
60
+ agent = Agent(model="openai-responses:gpt-5.6-luna", ...)
61
61
  executor = nh.AgentStepExecutor.from_agent(agent=agent)
62
62
  ```
63
63
 
@@ -79,7 +79,7 @@ def summarize(text: str) -> str:
79
79
 
80
80
  executor = nh.AgentStepExecutor.from_configuration(
81
81
  configuration=nh.StepExecutorConfiguration(
82
- model="openai-responses:gpt-5.4-mini",
82
+ model="openai-responses:gpt-5.6-luna",
83
83
  ),
84
84
  )
85
85
 
@@ -99,7 +99,7 @@ import nighthawk as nh
99
99
 
100
100
  fast_executor = nh.AgentStepExecutor.from_configuration(
101
101
  configuration=nh.StepExecutorConfiguration(
102
- model="openai-responses:gpt-5.4-mini",
102
+ model="openai-responses:gpt-5.6-luna",
103
103
  ),
104
104
  )
105
105
 
@@ -149,10 +149,10 @@ with nh.run(fast_executor):
149
149
 
150
150
  - `implicit_references` inject helper functions as block capabilities.
151
151
  - `nh.scope()` must run inside `nh.run()`; it keeps `run_id` and creates a new `scope_id`.
152
- - `mode` affects only `system_prompt_suffix_fragments`, `user_prompt_suffix_fragments`, and `implicit_references`.
153
- - `inherit`: suffix lists append; `implicit_references` merge with conflict check (same key + different object => `NighthawkError`).
154
- - `replace`: explicit list/mapping fully replace; `[]`/`{}` clear; `None` keeps inherited value.
155
- - `step_executor` / `step_executor_configuration` are resolved independently of `mode`.
152
+ - Omission or `nh.UNSET` inherits; ordinary values replace and `[]`/`{}` clear collections.
153
+ - Use `nh.Extend([...])` to append suffix fragments and `nh.Merge({...})` to merge implicit references by identity.
154
+ - `oversight` and `lifecycle` accept `None` to clear their hooks; other scope fields reject it.
155
+ - Executor replacement precedes full configuration replacement. Managed Model instances retain identity; external agents own their model selection.
156
156
 
157
157
  ## 4. The standard contract shape
158
158
 
@@ -321,9 +321,9 @@ Error-handling rule:
321
321
 
322
322
  Async rule:
323
323
 
324
- - Async natural functions can use async binding functions.
325
- - If a sync natural function triggers an async binding function and gets an awaitable, Nighthawk raises `ExecutionError`.
326
- - Fix that by making the natural function `async`.
324
+ - Both sync and async Natural functions can call async binding functions through tools; tool expressions await their results.
325
+ - Only an async Natural function may have a final return expression that produces an awaitable. A sync Natural function rejects that final result with `ExecutionError`.
326
+ - Make the Natural function `async` when it needs an awaitable final return expression, not merely because it uses an async binding function.
327
327
 
328
328
  Resilience rule:
329
329
 
@@ -19,7 +19,7 @@ def python_average(numbers):
19
19
  return sum(numbers) / len(numbers)
20
20
 
21
21
 
22
- step_executor = nh.AgentStepExecutor.from_configuration(configuration=nh.StepExecutorConfiguration(model="openai-responses:gpt-5.4-nano"))
22
+ step_executor = nh.AgentStepExecutor.from_configuration(configuration=nh.StepExecutorConfiguration(model="openai-responses:gpt-5.6-luna"))
23
23
 
24
24
  with nh.run(step_executor):
25
25
 
@@ -13,7 +13,7 @@ All examples assume the [Quickstart](quickstart.md) setup:
13
13
  import nighthawk as nh
14
14
 
15
15
  step_executor = nh.AgentStepExecutor.from_configuration(
16
- configuration=nh.StepExecutorConfiguration(model="openai-responses:gpt-5.4-nano"),
16
+ configuration=nh.StepExecutorConfiguration(model="openai-responses:gpt-5.6-luna"),
17
17
  )
18
18
 
19
19
  with nh.run(step_executor):
@@ -187,7 +187,7 @@ def summarize_report(report: Report) -> str:
187
187
 
188
188
  This keeps the media selection visible in ordinary Python, avoids accidental traversal of large object graphs, and lets normal LOCALS budgeting decide whether the helper variable is rendered.
189
189
 
190
- For the normative rendering and transport rules, including dotted-reference hoisting and nested multimodal behavior, see [Specification Section 8.2](specification.md#82-locals-summary).
190
+ For the normative rendering and transport rules, including dotted-reference hoisting and nested multimodal behavior, see [Specification Section 8.2](specification.md#822-locals-summary).
191
191
 
192
192
  ### f-string injection
193
193
 
@@ -361,7 +361,7 @@ When you pass a module-level callable as a function parameter with a generic typ
361
361
 
362
362
  The principle extends beyond callables. Any module-level name that is stable across invocations -- constants, classes, utility functions -- should stay in GLOBALS via `<name>` read bindings rather than being pulled into LOCALS via parameters or local assignments. Reserve function parameters for data that genuinely varies per call.
363
363
 
364
- **Note:** Nighthawk also provides `@nh.tool`, which registers functions via the model's native tool-calling interface. This path is reserved for cases that require `RunContext[StepContext]` access. Binding functions are preferred for all other uses because they incur no per-definition token overhead beyond a signature line in the prompt context. See [Specification Section 8.3](specification.md#83-tools-available-to-the-llm) for the `@nh.tool` specification.
364
+ **Note:** Nighthawk also accepts native tools through `nh.scope(tools=[...])`, which exposes functions via the model's native tool-calling interface for the duration of the scope. This path is reserved for cases that need native tool calling, such as strict argument schemas or Pydantic AI tool features. Binding functions are preferred for all other uses because they incur no per-definition token overhead beyond a signature line in the prompt context. See [Runtime configuration](runtime-configuration.md#scoped-tools) and [Specification Section 8.3](specification.md#83-tools-available-to-the-llm).
365
365
 
366
366
  ## Writing guidelines
367
367
 
@@ -153,7 +153,7 @@ except InputError as e:
153
153
 
154
154
  All Nighthawk exceptions inherit from `NighthawkError`. The most common exception in application code is `ExecutionError`, raised when a Natural block produces an invalid outcome, a disallowed outcome type, or a validation failure.
155
155
 
156
- For the full exception hierarchy (`NaturalParseError`, `ToolEvaluationError`, `ToolValidationError`, `ToolRegistrationError`), see [Specification Section 13](specification.md#13-error-handling).
156
+ For the full exception hierarchy (`NaturalParseError`, `ToolEvaluationError`, `ToolValidationError`, `ToolDeclarationError`), see [Specification Section 13](specification.md#13-error-handling).
157
157
 
158
158
  ## Async Natural functions
159
159
 
@@ -224,12 +224,12 @@ Each concurrent Natural block executes independently -- there is no shared messa
224
224
 
225
225
  Async natural functions can call sync binding functions, and sync natural functions can reference async binding functions. Nighthawk detects awaitable return values and handles them automatically:
226
226
 
227
- - In async natural functions: awaitable results from `nh_eval` and `nh_assign` expressions are awaited before returning to the LLM.
228
- - In sync natural functions: if the resolved return value is awaitable, execution fails (the caller must be async to await).
227
+ - Tool expressions await async binding function results in both sync and async Natural functions before returning them to the LLM.
228
+ - A final return expression may produce an awaitable only in an async Natural function. A sync Natural function rejects an awaitable final return value.
229
229
 
230
- This means you can mix sync and async binding functions freely in async natural functions without special handling.
230
+ You can therefore use async binding functions through tools without changing a synchronous Natural function into an async function.
231
231
 
232
- **Failure mode:** if a sync natural function references an async binding function and the LLM calls it, the expression produces an awaitable that cannot be awaited in a sync context. Nighthawk raises an `ExecutionError`. To fix, make the natural function `async`.
232
+ **Failure mode:** if a sync Natural function selects a return expression such as `fetch_result()` and that expression produces an awaitable, Nighthawk raises `ExecutionError`. Make the Natural function `async` to permit an awaitable final return expression. This restriction does not apply when the model calls `fetch_result()` through a tool and writes its resolved result to a binding. See [async execution semantics](specification.md#85-async-execution-model).
233
233
 
234
234
  ## Cross-block composition
235
235
 
@@ -118,11 +118,13 @@ Nighthawk keeps resilience in Python. The `nighthawk.resilience` primitives are
118
118
 
119
119
  The host controls exactly which calls are retried, how many attempts are allowed, which exceptions trigger fallback, what gets logged, and what happens on exhaustion. This applies to lightweight provider-backed judgments and to autonomous coding-agent executions. See [Patterns](patterns.md#resilience-patterns) for examples.
120
120
 
121
+ Hosts inspect one validated candidate per step. Acceptance preserves its values; explicit replacements are validated before final assignment. The read-only inspection mappings retain references to application values, so trusted hooks use rewrites rather than in-place mutations. Return expressions run once, and rejection cannot undo their side effects.
122
+
121
123
  ### Scoped execution contexts
122
124
 
123
125
  `run()` establishes the execution boundary by linking a step executor to the current context through an explicit Python `with` statement. `scope()` narrows configuration within an existing run: model override, prompt suffix, executor replacement, implicit references, or oversight.
124
126
 
125
- Nesting follows Python lexical structure. The host program's control flow, not a framework runtime, determines which configuration is active at any point. Runtime behavior lives in Python structures rather than in prose-only instructions or static configuration. See [Runtime configuration](runtime-configuration.md) for details.
127
+ Configuration follows the active execution context and propagates through calls and async tasks using Python context variables. The host program's control flow, not a framework runtime, determines which configuration is active at any point. Runtime behavior lives in Python structures rather than in prose-only instructions or static configuration. See [Runtime configuration](runtime-configuration.md) for details.
126
128
 
127
129
  ### Tool exposure efficiency
128
130
 
@@ -7,10 +7,10 @@ Nighthawk delegates Natural block execution to an LLM. The model is selected thr
7
7
  ```py
8
8
  import nighthawk as nh
9
9
 
10
- configuration = nh.StepExecutorConfiguration(model="openai-responses:gpt-5.4-nano")
10
+ configuration = nh.StepExecutorConfiguration(model="openai-responses:gpt-5.6-luna")
11
11
  ```
12
12
 
13
- The default model is `openai-responses:gpt-5.4-nano`. Recommended model for quality: `openai-responses:gpt-5.4`.
13
+ The default model is `openai-responses:gpt-5.6-luna`. Recommended model for quality: `openai-responses:gpt-5.6-terra`.
14
14
 
15
15
  ## Pydantic AI providers
16
16
 
@@ -20,7 +20,7 @@ Examples:
20
20
 
21
21
  OpenAI:
22
22
  ```py
23
- configuration = nh.StepExecutorConfiguration(model="openai-responses:gpt-5.4-nano")
23
+ configuration = nh.StepExecutorConfiguration(model="openai-responses:gpt-5.6-luna")
24
24
  ```
25
25
 
26
26
  Anthropic (direct API):
@@ -83,7 +83,7 @@ Pydantic AI providers accept standard Pydantic AI model settings via the `model_
83
83
 
84
84
  ```py
85
85
  configuration = nh.StepExecutorConfiguration(
86
- model="openai-responses:gpt-5.4-nano",
86
+ model="openai-responses:gpt-5.6-luna",
87
87
  model_settings={"temperature": 0.5},
88
88
  )
89
89
  ```
@@ -96,8 +96,12 @@ Install the required provider package. For example: `pip install pydantic-ai-sli
96
96
 
97
97
  **`ValueError: Invalid model identifier`**
98
98
 
99
- The model identifier must be in `provider:model` format (e.g., `openai-responses:gpt-5.4-mini`). Check for typos or a missing provider prefix. See the [Pydantic AI documentation](https://ai.pydantic.dev/models/overview/) for valid provider prefixes.
99
+ The model identifier must be in `provider:model` format (e.g., `openai-responses:gpt-5.6-luna`). Check for typos or a missing provider prefix. See the [Pydantic AI documentation](https://ai.pydantic.dev/models/overview/) for valid provider prefixes.
100
100
 
101
101
  **Provider authentication errors**
102
102
 
103
103
  Each Pydantic AI provider requires its own credentials (e.g., `OPENAI_API_KEY` for OpenAI). Nighthawk does not manage provider credentials -- see the [Pydantic AI documentation](https://ai.pydantic.dev/models/overview/) for provider-specific credential setup.
104
+
105
+ ## In-memory authentication
106
+
107
+ Pydantic AI Providers accept caller-owned authentication clients or keys through Python constructors. Construct an authenticated Model and pass it through `StepExecutorConfiguration.model`; see [Caller-authenticated models](runtime-configuration.md#caller-authenticated-models) for the handoff and [the configuration contract](specification.md#52-configuration) for ownership and serialization. The Docker host supplies its own credential input channel. This option does not remove environment-configured provider strings.
@@ -21,7 +21,7 @@ Save as `quickstart.py`:
21
21
  ```py
22
22
  import nighthawk as nh
23
23
 
24
- step_executor = nh.AgentStepExecutor.from_configuration(configuration=nh.StepExecutorConfiguration(model="openai-responses:gpt-5.4-nano"))
24
+ step_executor = nh.AgentStepExecutor.from_configuration(configuration=nh.StepExecutorConfiguration(model="openai-responses:gpt-5.6-luna"))
25
25
 
26
26
  with nh.run(step_executor):
27
27