nighthawk-python 0.11.0__tar.gz → 0.13.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.
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/.claude/rules/docs.md +3 -3
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/.claude/rules/promptfoo.md +1 -1
- nighthawk_python-0.13.0/.devcontainer/devcontainer-lock.json +14 -0
- nighthawk_python-0.13.0/.devcontainer/devcontainer.json +16 -0
- nighthawk_python-0.13.0/.devcontainer/postCreateCommand.sh +16 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/.github/dependabot.yml +6 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/.github/workflows/docs.yml +1 -1
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/CHANGELOG.md +64 -1
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/CONTRIBUTING.md +15 -12
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/PKG-INFO +9 -9
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/README.md +3 -3
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/docs/api.md +31 -4
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/docs/coding-agent-backends.md +4 -3
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/docs/executors.md +3 -3
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/docs/for-coding-agents.md +6 -6
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/docs/index.md +4 -4
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/docs/natural-blocks.md +28 -3
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/docs/patterns.md +22 -10
- nighthawk_python-0.13.0/docs/philosophy.md +198 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/docs/pydantic-ai-providers.md +9 -5
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/docs/quickstart.md +1 -3
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/docs/roadmap.md +8 -0
- nighthawk_python-0.13.0/docs/runtime-configuration.md +355 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/docs/specification.md +68 -41
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/docs/verification.md +23 -14
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/promptfooconfig-agents.yaml +2 -2
- nighthawk_python-0.11.0/evals/promptfoo/promptfooconfig-nano-sanity.yaml → nighthawk_python-0.13.0/evals/promptfoo/promptfooconfig-luna-sanity.yaml +4 -4
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/promptfooconfig-prompt-ab.yaml +5 -5
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/promptfooconfig-suffix-ab.yaml +4 -4
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/promptfooconfig.yaml +4 -4
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/provider.py +16 -22
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/research-result.md +1 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/test_cases/loop_outcomes_ja.yaml +1 -1
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/pyproject.toml +8 -7
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/__init__.py +23 -9
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/backends/base.py +29 -3
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/backends/claude_code_cli.py +2 -3
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/backends/claude_code_sdk.py +2 -3
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/backends/codex.py +2 -3
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/backends/mcp_boundary.py +4 -4
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/backends/mcp_server.py +28 -16
- nighthawk_python-0.13.0/src/nighthawk/composition.py +59 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/configuration.py +17 -6
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/errors.py +10 -2
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/natural/decorator.py +50 -24
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/natural/transform.py +2 -4
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/oversight.py +49 -56
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/resilience/_budget.py +2 -2
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/runtime/runner.py +135 -94
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/runtime/scoping.py +181 -144
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/runtime/step_context.py +1 -1
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/runtime/step_executor.py +26 -18
- nighthawk_python-0.13.0/src/nighthawk/runtime/step_result.py +49 -0
- nighthawk_python-0.13.0/src/nighthawk/tools/declarations.py +110 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/backends/test_codex.py +2 -2
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/docs/test_docs_architecture.py +10 -1
- nighthawk_python-0.13.0/tests/execution/test_capabilities.py +113 -0
- nighthawk_python-0.13.0/tests/execution/test_managed_model.py +280 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/execution/test_runtime.py +41 -17
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/governance/test_governance.py +167 -13
- nighthawk_python-0.13.0/tests/governance/test_step_results.py +301 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/integration/test_carry_pattern.py +3 -3
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/integration/test_claude_code_cli_integration.py +7 -4
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/integration/test_claude_code_sdk_integration.py +13 -37
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/integration/test_codex_integration.py +18 -24
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/integration/test_llm_integration.py +71 -74
- nighthawk_python-0.13.0/tests/natural/test_decorator_globals.py +101 -0
- nighthawk_python-0.13.0/tests/natural/test_introspection.py +68 -0
- nighthawk_python-0.13.0/tests/public/test_composition.py +150 -0
- nighthawk_python-0.13.0/tests/public/test_model_configuration.py +68 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/public/test_public_api.py +54 -30
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/public/test_usage_meter.py +68 -8
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/resilience/test_budget.py +24 -20
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/resilience/test_circuit_breaker.py +1 -1
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/resilience/test_composition.py +3 -3
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/resilience/test_retry.py +1 -1
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/resilience/test_timeout.py +1 -1
- nighthawk_python-0.13.0/tests/tools/test_declarations.py +166 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/tools/test_tool_boundary.py +31 -31
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/uv.lock +263 -275
- nighthawk_python-0.11.0/.devcontainer/Dockerfile.devcontainer +0 -3
- nighthawk_python-0.11.0/.devcontainer/Dockerfile.litellm +0 -11
- nighthawk_python-0.11.0/.devcontainer/devcontainer.json +0 -24
- nighthawk_python-0.11.0/.devcontainer/docker-compose.yaml +0 -19
- nighthawk_python-0.11.0/.devcontainer/litellm-config.yaml +0 -37
- nighthawk_python-0.11.0/docs/philosophy.md +0 -178
- nighthawk_python-0.11.0/docs/runtime-configuration.md +0 -279
- nighthawk_python-0.11.0/src/nighthawk/tools/registry.py +0 -217
- nighthawk_python-0.11.0/tests/tools/test_registry.py +0 -149
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/.claude/rules/src.md +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/.claude/rules/tests.md +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/.claude/settings.json +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/.claude/unset_envs.sh +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/.github/workflows/ci.yml +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/.github/workflows/publish.yml +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/.gitignore +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/.python-version +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/AGENTS.md +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/CLAUDE.md +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/LICENSE +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/docs/AGENTS.md +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/docs/assets/nighthawk_logo-128x128.png +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/assertions/__init__.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/assertions/binding_value.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/assertions/outcome_kind.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/assertions/raise_message.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/evidence/2026-03-26-baseline-prompt-ab.md +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/evidence/2026-03-26-baseline-regression.md +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/evidence/2026-03-26-baseline-suffix-ab.md +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/evidence/2026-04-27-runtime-prompt-optimization.md +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/prompts/eval_coding_agent.txt +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/prompts/eval_default.txt +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/prompts/eval_legacy_default.txt +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/prompts/eval_mutation_aware.txt +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/prompts/eval_sequenced.txt +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/test_cases/binding_operations.yaml +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/test_cases/edge_cases.yaml +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/test_cases/loop_outcomes.yaml +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/test_cases/multi_step.yaml +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/test_cases/null_handling.yaml +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/test_cases/outcome_kinds.yaml +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/evals/promptfoo/test_cases/tool_selection.yaml +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/mkdocs.yml +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/pyrightconfig.json +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/AGENTS.md +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/backends/__init__.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/backends/_text_fallback.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/backends/claude_code_settings.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/backends/text_projection.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/backends/tool_bridge.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/identifier_path.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/json_renderer.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/natural/__init__.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/natural/blocks.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/resilience/__init__.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/resilience/_circuit_breaker.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/resilience/_fallback.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/resilience/_retry.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/resilience/_timeout.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/resilience/_vote.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/runtime/__init__.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/runtime/_user_content.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/runtime/async_bridge.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/runtime/prompt.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/runtime/step_contract.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/runtime/tool_calls.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/testing.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/tools/__init__.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/tools/_tool_return_content.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/tools/assignment.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/tools/contracts.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/tools/execution.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/tools/provided.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/src/nighthawk/ulid.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/AGENTS.md +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/__init__.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/backends/__init__.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/backends/test_claude_code_cli.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/backends/test_claude_code_sdk.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/conftest.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/docs/__init__.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/docs/test_coding_agent_examples.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/docs/test_prompt_examples.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/execution/__init__.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/execution/prompt_test_helpers.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/execution/stub_executor.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/execution/test_execution_outcome_prompt_fragment.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/execution/test_globals_prompt.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/execution/test_infer_binding_types.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/execution/test_natural_block_ordering.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/execution/test_natural_traceback.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/execution/test_variables_prompt.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/integration/__init__.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/integration/skip_helpers.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/natural/__init__.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/natural/test_blocks.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/public/__init__.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/public/test_readme_example.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/resilience/__init__.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/resilience/test_fallback.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/resilience/test_vote.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/test_renderer.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/test_testing.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/tools/__init__.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/tools/test_assignment_async.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/tools/test_contracts.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/tools/test_multimodal_helpers.py +0 -0
- {nighthawk_python-0.11.0 → nighthawk_python-0.13.0}/tests/tools/test_provided_async.py +0 -0
|
@@ -39,7 +39,7 @@ Public API documentation layering:
|
|
|
39
39
|
| `coding-agent-backends.md` | Backend users | Backend reference | Backend-specific settings, shared capabilities, skills, MCP tool exposure, working directory, troubleshooting. |
|
|
40
40
|
| `for-coding-agents.md` | Coding agents (LLMs) | Operational guide | Condensed, decision-oriented rules derived from human-oriented docs. Self-contained with absolute URLs. |
|
|
41
41
|
| `specification.md` | Implementors | Canonical spec | Syntax, state layers, tools, outcomes, frontmatter, runtime semantics, observability contract, and custom backend capability/protocol semantics. Numbered section headings. |
|
|
42
|
-
| `philosophy.md` | Evaluators | Design rationale | Execution model,
|
|
42
|
+
| `philosophy.md` | Evaluators | Design rationale | Execution model, design landscape, boundary-first consequences, trust and safety boundaries, tradeoffs, and runtime evaluation rationale. |
|
|
43
43
|
| `api.md` | Developers | API reference | Auto-generated from docstrings, including protocol and extension-hook symbols. |
|
|
44
44
|
| `roadmap.md` | Contributors | Future directions | Ideas only. Remove when implemented. |
|
|
45
45
|
| `docs/AGENTS.md` | Coding agents editing docs | Documentation governance | Canonical ownership, page roles, routing rules, and docs test invariants. Symlink to `.claude/rules/docs.md`. |
|
|
@@ -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
|
-
-
|
|
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.
|
|
@@ -171,7 +171,7 @@ Pages in the Getting started, Patterns & verification, and Configuration nav gro
|
|
|
171
171
|
|
|
172
172
|
**`philosophy.md`**
|
|
173
173
|
|
|
174
|
-
- Owns the cumulative argument: execution model,
|
|
174
|
+
- Owns the cumulative argument: execution model, design landscape, boundary-first consequences (resilience, scoped execution contexts, tool exposure, multi-agent coordination), trust and safety boundaries, tradeoffs, and runtime evaluation rationale.
|
|
175
175
|
- External references acceptable. Prefer stable URLs with enough inline context to survive link rot.
|
|
176
176
|
- No how-to code examples for patterns in `natural-blocks.md` or `patterns.md`. Exception: positioning examples may reuse function names from those pages.
|
|
177
177
|
|
|
@@ -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.
|
|
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
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"features": {
|
|
3
|
+
"ghcr.io/devcontainers/features/docker-in-docker:4.1.0": {
|
|
4
|
+
"version": "4.1.0",
|
|
5
|
+
"resolved": "ghcr.io/devcontainers/features/docker-in-docker@sha256:7d979c4a36d595eb4ab79909caa3f396daf3b6152dcf38e8328ea4eff42206c7",
|
|
6
|
+
"integrity": "sha256:7d979c4a36d595eb4ab79909caa3f396daf3b6152dcf38e8328ea4eff42206c7"
|
|
7
|
+
},
|
|
8
|
+
"ghcr.io/devcontainers/features/node:2.1.0": {
|
|
9
|
+
"version": "2.1.0",
|
|
10
|
+
"resolved": "ghcr.io/devcontainers/features/node@sha256:586c9a6f7dd40bd3ba2cd41e7f2f88dcc31fbe5d1442afcbf07ffbc66b686857",
|
|
11
|
+
"integrity": "sha256:586c9a6f7dd40bd3ba2cd41e7f2f88dcc31fbe5d1442afcbf07ffbc66b686857"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Python 3.13",
|
|
3
|
+
"image": "mcr.microsoft.com/devcontainers/python:3-3.13-bookworm",
|
|
4
|
+
"features": {
|
|
5
|
+
"ghcr.io/devcontainers/features/docker-in-docker:4.1.0": {},
|
|
6
|
+
"ghcr.io/devcontainers/features/node:2.1.0": {}
|
|
7
|
+
},
|
|
8
|
+
"postCreateCommand": "/bin/sh .devcontainer/postCreateCommand.sh",
|
|
9
|
+
"customizations": {
|
|
10
|
+
"vscode": {
|
|
11
|
+
"extensions": [
|
|
12
|
+
"charliermarsh.ruff"
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
set -eu
|
|
3
|
+
|
|
4
|
+
sudo apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
|
5
|
+
&& sudo apt-get -y install --no-install-recommends ripgrep fzf bubblewrap \
|
|
6
|
+
&& sudo apt-get clean \
|
|
7
|
+
&& sudo rm -rf /var/lib/apt/lists/*
|
|
8
|
+
|
|
9
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
10
|
+
|
|
11
|
+
uv sync
|
|
12
|
+
|
|
13
|
+
npm install -g pyright
|
|
14
|
+
|
|
15
|
+
curl -LsSf https://chatgpt.com/codex/install.sh | CODEX_NON_INTERACTIVE=1 sh
|
|
16
|
+
curl -LsSf https://claude.ai/install.sh | bash
|
|
@@ -7,6 +7,67 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.13.0]
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `nh.UNSET`, `nh.UnsetType`, `nh.Extend`, and `nh.Merge` express inheritance and per-field scope composition.
|
|
15
|
+
- Caller-constructed Pydantic AI Models in `StepExecutorConfiguration.model`, retaining identity and the managed execution contract. Clients are borrowed; hosts own authentication delivery and lifetime.
|
|
16
|
+
- Host-installed usage meters, scoped native tools and Pydantic AI capabilities, and public scope getters.
|
|
17
|
+
- Resolved `Pass`, `Return`, `Break`, `Continue`, and `Raise` outcomes through `nh.oversight`, with explicit `Rewrite(return_value=None)` support.
|
|
18
|
+
- `nh.get_transformed_function()` for compiled-body inspection through conventional wrappers.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- The default model is now `openai-responses:gpt-5.6-luna` (previously `openai-responses:gpt-5.4-nano`).
|
|
23
|
+
- Scope omission inherits; ordinary values replace and empty collections clear. Only oversight accepts `None`. Executor replacement precedes full configuration replacement.
|
|
24
|
+
- Run getters require a run; `get_step_context()` requires a step. Budget wrappers retain optional private meter discovery.
|
|
25
|
+
- Repeated identical tool declarations are idempotent. Conflicts use `NameConflictError` and `ToolNameConflictError`; invalid tools use `ToolDeclarationError`.
|
|
26
|
+
- `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.
|
|
27
|
+
- 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.
|
|
28
|
+
- Decorated functions share real module globals; `__wrapped__` and `inspect.unwrap` follow the original function.
|
|
29
|
+
- 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.
|
|
30
|
+
|
|
31
|
+
### Removed
|
|
32
|
+
|
|
33
|
+
- Global `scope(mode=...)`, the old `get_current_usage_meter` and `get_current_step_context` names, and `ToolRegistrationError`; no deprecated aliases remain.
|
|
34
|
+
- `@nighthawk.tool` and the process-global tool registry. Declare tools in scopes.
|
|
35
|
+
- `StepCommitProposal`, old proposed/rewritten fields, and parallel `StepCommit.step_outcome`/`return_value` fields.
|
|
36
|
+
|
|
37
|
+
### Compatibility
|
|
38
|
+
|
|
39
|
+
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.
|
|
40
|
+
|
|
41
|
+
### Migration notes for hosts
|
|
42
|
+
|
|
43
|
+
| Before | After |
|
|
44
|
+
|---|---|
|
|
45
|
+
| `scope(mode="inherit", tools=[fn])` | `scope(tools=nh.Extend([fn]))` |
|
|
46
|
+
| `scope(mode="replace", implicit_references={})` | `scope(implicit_references={})` |
|
|
47
|
+
| `scope(implicit_references=None)` to inherit | Omit the field or use `nh.UNSET`; use `nh.Merge(mapping)` to compose |
|
|
48
|
+
| `get_current_usage_meter()` / `get_current_step_context()` | `get_usage_meter()` / `get_step_context()`; missing context raises |
|
|
49
|
+
| `ToolRegistrationError` | `ToolDeclarationError`; catch `NameConflictError` across namespaces |
|
|
50
|
+
| Private meter context writes | `nh.run(executor, usage_meter=meter)` or `nh.scope(usage_meter=meter)` |
|
|
51
|
+
| `@nh.tool` at import time | `nh.scope(tools=[fn])` or an explicit Pydantic AI `Tool` |
|
|
52
|
+
| `StepCommit.return_value` | Check `isinstance(commit.outcome, nh.oversight.Return)`, then read `.value` |
|
|
53
|
+
| Expression-based `Rewrite(step_outcome=...)` | `Rewrite(outcome=nh.oversight.Return(value=...))` |
|
|
54
|
+
| Bindings rewrite that implicitly recalculates return | Supply both replacement bindings and `return_value` explicitly |
|
|
55
|
+
| `inspect.unwrap(function)` to find compiled code | `nh.get_transformed_function(function)` |
|
|
56
|
+
| Credential transport via environment for managed construction | Construct authenticated Provider/Model in memory and use `StepExecutorConfiguration(model=model)` |
|
|
57
|
+
| Dumping configuration containing a live Model | Explicitly exclude `model`; the partial dump cannot reconstruct it |
|
|
58
|
+
| Changing an external agent's configured model | Replace the executor with a managed executor or a host-configured external agent |
|
|
59
|
+
|
|
60
|
+
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.
|
|
61
|
+
|
|
62
|
+
## [0.12.0]
|
|
63
|
+
|
|
64
|
+
### Changed
|
|
65
|
+
- Clarified the boundary-first philosophy page.
|
|
66
|
+
- Clarified multimodal documentation and specification.
|
|
67
|
+
- Raised the minimum Pydantic AI version to 2.37.0 and migrated coding-agent backends to its native-tool and structured-instruction APIs.
|
|
68
|
+
- Raised the MCP minimum version to 2.1.1 and migrated the embedded tool server and content types to the MCP 2 API.
|
|
69
|
+
- Updated the Claude Agent SDK integration to 0.2.151.
|
|
70
|
+
|
|
10
71
|
## [0.11.0]
|
|
11
72
|
|
|
12
73
|
### Added
|
|
@@ -179,7 +240,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
179
240
|
- Step executor abstraction and provider integration foundation.
|
|
180
241
|
- Core documentation and project scaffolding.
|
|
181
242
|
|
|
182
|
-
[Unreleased]: https://github.com/kurusugawa-computer/nighthawk-python/compare/v0.
|
|
243
|
+
[Unreleased]: https://github.com/kurusugawa-computer/nighthawk-python/compare/v0.13.0...HEAD
|
|
244
|
+
[0.13.0]: https://github.com/kurusugawa-computer/nighthawk-python/compare/v0.12.0...v0.13.0
|
|
245
|
+
[0.12.0]: https://github.com/kurusugawa-computer/nighthawk-python/compare/v0.11.0...v0.12.0
|
|
183
246
|
[0.11.0]: https://github.com/kurusugawa-computer/nighthawk-python/compare/v0.10.0...v0.11.0
|
|
184
247
|
[0.10.0]: https://github.com/kurusugawa-computer/nighthawk-python/compare/v0.9.0...v0.10.0
|
|
185
248
|
[0.9.0]: https://github.com/kurusugawa-computer/nighthawk-python/compare/v0.8.0...v0.9.0
|
|
@@ -12,6 +12,14 @@
|
|
|
12
12
|
uv sync --all-extras --all-groups
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
`uv` manages the project virtual environment in `.venv`. Do not create or
|
|
16
|
+
activate a separate virtual environment; run project commands through `uv run`.
|
|
17
|
+
The `.venv` directory is generated and ignored by Git. It can be deleted to
|
|
18
|
+
rebuild the local environment, and the next `uv sync` or `uv run` recreates it.
|
|
19
|
+
|
|
20
|
+
Declare project dependencies in `pyproject.toml` through `uv add`, rather than
|
|
21
|
+
installing them directly into `.venv` with `uv pip install`.
|
|
22
|
+
|
|
15
23
|
If you see a `uv` warning about hardlinking (common in containers or cross-filesystem workspaces), suppress it with:
|
|
16
24
|
|
|
17
25
|
```bash
|
|
@@ -39,13 +47,8 @@ uv run pytest -q # quiet output
|
|
|
39
47
|
|
|
40
48
|
### Integration tests
|
|
41
49
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
uv pip install pydantic-ai-slim[openai]
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
Then run with your `.env` loaded:
|
|
50
|
+
The full setup command installs the OpenAI provider development dependency.
|
|
51
|
+
Run integration tests with your `.env` loaded:
|
|
49
52
|
|
|
50
53
|
```bash
|
|
51
54
|
set -a; source .env; set +a; uv run pytest -q
|
|
@@ -80,8 +83,8 @@ PFOO="cd evals/promptfoo && PROMPTFOO_PYTHON=\"$(uv python find)\" npx promptfoo
|
|
|
80
83
|
| Command | Purpose |
|
|
81
84
|
|---|---|
|
|
82
85
|
| `eval $PFOO eval` | Full regression (all backends, all tests) |
|
|
83
|
-
| `eval $PFOO eval -c promptfooconfig-prompt-ab.yaml` | Prompt A/B test (gpt-5.
|
|
84
|
-
| `eval $PFOO eval -c promptfooconfig-
|
|
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) |
|
|
85
88
|
| `eval $PFOO eval -c promptfooconfig-agents.yaml` | Coding agent backends (reduced test set) |
|
|
86
89
|
| `eval $PFOO eval -c promptfooconfig.yaml --filter-pattern "P-BIND-001"` | Single test |
|
|
87
90
|
| `eval $PFOO eval -c promptfooconfig.yaml --filter-providers "claude-code-cli"` | Single backend |
|
|
@@ -90,8 +93,8 @@ PFOO="cd evals/promptfoo && PROMPTFOO_PYTHON=\"$(uv python find)\" npx promptfoo
|
|
|
90
93
|
#### Config files (`evals/promptfoo/`)
|
|
91
94
|
|
|
92
95
|
- `promptfooconfig.yaml` — Regression: winner prompt combo across openai-responses, claude-code-cli, and codex backends. All test cases.
|
|
93
|
-
- `promptfooconfig-prompt-ab.yaml` — A/B testing: 4 prompt/tool variants on gpt-5.
|
|
94
|
-
- `promptfooconfig-
|
|
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.
|
|
95
98
|
- `promptfooconfig-agents.yaml` — Coding agent only: claude-code-cli and codex with reduced test set.
|
|
96
99
|
|
|
97
100
|
#### Directory layout
|
|
@@ -202,7 +205,7 @@ def run(
|
|
|
202
205
|
Example:
|
|
203
206
|
```python
|
|
204
207
|
executor = AgentStepExecutor.from_configuration(
|
|
205
|
-
configuration=StepExecutorConfiguration(model="openai-responses:gpt-5.
|
|
208
|
+
configuration=StepExecutorConfiguration(model="openai-responses:gpt-5.6-luna"),
|
|
206
209
|
)
|
|
207
210
|
with nighthawk.run(executor):
|
|
208
211
|
result = my_natural_function()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: nighthawk-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.13.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/
|
|
@@ -20,17 +20,17 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
20
20
|
Classifier: Typing :: Typed
|
|
21
21
|
Requires-Python: >=3.13
|
|
22
22
|
Requires-Dist: headson>=0.16.1
|
|
23
|
-
Requires-Dist: pydantic-ai-slim>=
|
|
23
|
+
Requires-Dist: pydantic-ai-slim>=2.37.0
|
|
24
24
|
Requires-Dist: pydantic>=2.13.3
|
|
25
25
|
Requires-Dist: pyyaml>=6.0.3
|
|
26
26
|
Requires-Dist: tenacity>=9.1.4
|
|
27
27
|
Requires-Dist: tiktoken>=0.12.0
|
|
28
28
|
Provides-Extra: claude-code-cli
|
|
29
|
-
Requires-Dist: mcp>=1.
|
|
29
|
+
Requires-Dist: mcp>=2.1.1; extra == 'claude-code-cli'
|
|
30
30
|
Provides-Extra: claude-code-sdk
|
|
31
|
-
Requires-Dist: claude-agent-sdk==0.
|
|
31
|
+
Requires-Dist: claude-agent-sdk==0.2.151; extra == 'claude-code-sdk'
|
|
32
32
|
Provides-Extra: codex
|
|
33
|
-
Requires-Dist: mcp>=1.
|
|
33
|
+
Requires-Dist: mcp>=2.1.1; extra == 'codex'
|
|
34
34
|
Description-Content-Type: text/markdown
|
|
35
35
|
|
|
36
36
|
[](https://pypi.org/project/nighthawk-python)
|
|
@@ -68,12 +68,12 @@ For other providers, see [Pydantic AI providers](https://kurusugawa-computer.git
|
|
|
68
68
|
```py
|
|
69
69
|
import nighthawk as nh
|
|
70
70
|
|
|
71
|
+
|
|
71
72
|
def python_average(numbers):
|
|
72
73
|
return sum(numbers) / len(numbers)
|
|
73
74
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
)
|
|
75
|
+
|
|
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
|
|
|
@@ -33,12 +33,12 @@ For other providers, see [Pydantic AI providers](https://kurusugawa-computer.git
|
|
|
33
33
|
```py
|
|
34
34
|
import nighthawk as nh
|
|
35
35
|
|
|
36
|
+
|
|
36
37
|
def python_average(numbers):
|
|
37
38
|
return sum(numbers) / len(numbers)
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
)
|
|
40
|
+
|
|
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,23 +8,31 @@
|
|
|
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
26
|
- ExecutionRef
|
|
22
|
-
-
|
|
23
|
-
-
|
|
27
|
+
- get_capabilities
|
|
28
|
+
- get_step_context
|
|
29
|
+
- get_usage_meter
|
|
24
30
|
- get_execution_ref
|
|
25
31
|
- get_implicit_references
|
|
32
|
+
- get_oversight
|
|
26
33
|
- get_step_executor
|
|
27
34
|
- get_system_prompt_suffix_fragments
|
|
35
|
+
- get_tools
|
|
28
36
|
- get_user_prompt_suffix_fragments
|
|
29
37
|
- resilience
|
|
30
38
|
- UsageMeter
|
|
@@ -93,7 +101,7 @@
|
|
|
93
101
|
members:
|
|
94
102
|
- StepContext
|
|
95
103
|
- ToolResultRenderingPolicy
|
|
96
|
-
-
|
|
104
|
+
- get_step_context
|
|
97
105
|
- step_context_scope
|
|
98
106
|
|
|
99
107
|
## Tool Contracts
|
|
@@ -128,3 +136,22 @@
|
|
|
128
136
|
## Testing
|
|
129
137
|
|
|
130
138
|
::: nighthawk.testing
|
|
139
|
+
|
|
140
|
+
::: nighthawk.oversight
|
|
141
|
+
options:
|
|
142
|
+
members:
|
|
143
|
+
- Pass
|
|
144
|
+
- Return
|
|
145
|
+
- Break
|
|
146
|
+
- Continue
|
|
147
|
+
- Raise
|
|
148
|
+
- StepResult
|
|
149
|
+
- StepCommit
|
|
150
|
+
- Rewrite
|
|
151
|
+
- Accept
|
|
152
|
+
- Reject
|
|
153
|
+
- ToolCall
|
|
154
|
+
- Oversight
|
|
155
|
+
- OversightRejectedError
|
|
156
|
+
- StepCommitDecision
|
|
157
|
+
- ToolCallDecision
|
|
@@ -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.
|
|
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
|
|
|
@@ -45,7 +45,7 @@ Coding agent backends do not receive native VLM-style user-prompt multimodal inp
|
|
|
45
45
|
- `BinaryContent` is staged to a local file and referenced in the prompt with `<image>` / `<file>` plus a local file path.
|
|
46
46
|
- URL-based content (`ImageUrl`, `AudioUrl`, `DocumentUrl`, `VideoUrl`) is referenced by URL in the projected prompt text.
|
|
47
47
|
- `UploadedFile` user-prompt content is rejected because these backends cannot resolve provider-owned file identifiers. Tool results still preserve the rest of the payload and replace only the `UploadedFile` item with explanatory fallback text.
|
|
48
|
-
- Tool results cross the backend boundary as MCP content. Image (`BinaryContent.is_image`) and audio (`BinaryContent.is_audio`) items travel natively as `ImageContent` / `AudioContent`; all other `BinaryContent` and `FileUrl` items project to `TextContent` so the MCP path stays symmetric with the text-projected prompt path. When mixed top-level text/multimodal tool-result sequences preserve their original order they satisfy the same `UserContent` rule used for prompt hoisting. The user prompt itself remains text-projected for these backends.
|
|
48
|
+
- Tool results cross the backend boundary as MCP content. Image (`BinaryContent.is_image`) and audio (`BinaryContent.is_audio`) items travel natively as `ImageContent` / `AudioContent`; all other `BinaryContent` and `FileUrl` items project to `TextContent` so the MCP path stays symmetric with the text-projected prompt path. Native MCP video carriage is intentionally unsupported for now because video-modal requirements are unstable; document carriage also remains text-projected unless a future backend advertises an explicit capability. When mixed top-level text/multimodal tool-result sequences preserve their original order they satisfy the same `UserContent` rule used for prompt hoisting. The user prompt itself remains text-projected for these backends.
|
|
49
49
|
- When a successful tool result splits to no text and no user content, the projected prompt stays header-only rather than inserting the preview JSON envelope.
|
|
50
50
|
|
|
51
51
|
This differs from provider-backed executors that can pass a `tuple[UserContent, ...]` to a multimodal-capable provider API directly.
|
|
@@ -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
|
|
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
|
|
@@ -281,6 +281,7 @@ Example Natural function that invokes the skill:
|
|
|
281
281
|
```py
|
|
282
282
|
import nighthawk as nh
|
|
283
283
|
|
|
284
|
+
|
|
284
285
|
@nh.natural_function
|
|
285
286
|
def summarize_feedback(feedback_items: list[str]) -> str:
|
|
286
287
|
def group_feedback_by_topic(feedback_items: list[str]) -> dict[str, list[str]]:
|
|
@@ -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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
- `
|
|
153
|
-
- `
|
|
154
|
-
- `
|
|
155
|
-
-
|
|
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
|
+
- Only `oversight` accepts `None` to clear 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
|
|
|
@@ -14,12 +14,12 @@ The same mechanism handles lightweight LLM judgments ("classify this sentiment")
|
|
|
14
14
|
```py
|
|
15
15
|
import nighthawk as nh
|
|
16
16
|
|
|
17
|
+
|
|
17
18
|
def python_average(numbers):
|
|
18
19
|
return sum(numbers) / len(numbers)
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
)
|
|
21
|
+
|
|
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
|
|
|
@@ -61,7 +61,7 @@ The LLM interprets the mixed-format input list via `<numbers>`, calls the Python
|
|
|
61
61
|
|
|
62
62
|
## Background and project
|
|
63
63
|
|
|
64
|
-
- **[Philosophy](philosophy.md)** -- Design rationale: execution model,
|
|
64
|
+
- **[Philosophy](philosophy.md)** -- Design rationale: execution model, design landscape, boundary-first consequences, trust and safety boundaries, tradeoffs, and runtime evaluation rationale.
|
|
65
65
|
- **[Roadmap](roadmap.md)** -- Future directions and open questions.
|
|
66
66
|
|
|
67
67
|
## Origins
|
|
@@ -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.
|
|
16
|
+
configuration=nh.StepExecutorConfiguration(model="openai-responses:gpt-5.6-luna"),
|
|
17
17
|
)
|
|
18
18
|
|
|
19
19
|
with nh.run(step_executor):
|
|
@@ -139,11 +139,13 @@ Write bindings can use Pydantic models for structured output with automatic vali
|
|
|
139
139
|
```py
|
|
140
140
|
from pydantic import BaseModel
|
|
141
141
|
|
|
142
|
+
|
|
142
143
|
class ReviewVerdict(BaseModel):
|
|
143
144
|
approved: bool
|
|
144
145
|
reason: str
|
|
145
146
|
risk_level: str
|
|
146
147
|
|
|
148
|
+
|
|
147
149
|
@nh.natural_function
|
|
148
150
|
def judge_review(review_data: str) -> ReviewVerdict:
|
|
149
151
|
verdict: ReviewVerdict
|
|
@@ -171,7 +173,21 @@ Transport depends on the executor:
|
|
|
171
173
|
- Provider-backed executors that accept Pydantic AI `UserContent` send the value natively to the VLM API.
|
|
172
174
|
- Coding-agent backends text-project the value (staged local files or URL references). See [Coding agent backends: multimodal inputs](coding-agent-backends.md#multimodal-inputs).
|
|
173
175
|
|
|
174
|
-
|
|
176
|
+
Nested multimodal values inside dicts, models, and objects are not recursively hoisted. Keep the prompt boundary explicit by lifting the media-bearing leaf into a helper variable before the Natural block:
|
|
177
|
+
|
|
178
|
+
```py
|
|
179
|
+
def summarize_report(report: Report) -> str:
|
|
180
|
+
report_scan = report.attachments.scan_image
|
|
181
|
+
summary = ""
|
|
182
|
+
"""natural
|
|
183
|
+
Read <report_scan> and summarize the visual evidence in <:summary>.
|
|
184
|
+
"""
|
|
185
|
+
return summary
|
|
186
|
+
```
|
|
187
|
+
|
|
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
|
+
|
|
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).
|
|
175
191
|
|
|
176
192
|
### f-string injection
|
|
177
193
|
|
|
@@ -180,6 +196,7 @@ Inline f-string blocks embed Python expressions directly into the Natural progra
|
|
|
180
196
|
```py
|
|
181
197
|
PROJECT_POLICY = ["safety-first", "concise-output", "cite-assumptions"]
|
|
182
198
|
|
|
199
|
+
|
|
183
200
|
@nh.natural_function
|
|
184
201
|
def choose_policy(post: str) -> str:
|
|
185
202
|
selected_policy = ""
|
|
@@ -219,10 +236,12 @@ Member accesses and function results work too:
|
|
|
219
236
|
```py
|
|
220
237
|
from pydantic import BaseModel
|
|
221
238
|
|
|
239
|
+
|
|
222
240
|
class Config(BaseModel):
|
|
223
241
|
max_length: int = 100
|
|
224
242
|
style: str = "formal"
|
|
225
243
|
|
|
244
|
+
|
|
226
245
|
@nh.natural_function
|
|
227
246
|
def generate(config: Config, topic: str) -> str:
|
|
228
247
|
output = ""
|
|
@@ -296,6 +315,7 @@ When a Natural block references a module-level name via `<name>`, it appears in
|
|
|
296
315
|
def python_average(numbers):
|
|
297
316
|
return sum(numbers) / len(numbers)
|
|
298
317
|
|
|
318
|
+
|
|
299
319
|
@nh.natural_function
|
|
300
320
|
def calculate_average(numbers):
|
|
301
321
|
"""natural
|
|
@@ -341,7 +361,7 @@ When you pass a module-level callable as a function parameter with a generic typ
|
|
|
341
361
|
|
|
342
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.
|
|
343
363
|
|
|
344
|
-
**Note:** Nighthawk also
|
|
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).
|
|
345
365
|
|
|
346
366
|
## Writing guidelines
|
|
347
367
|
|
|
@@ -375,11 +395,13 @@ For deterministic functions (no Natural blocks), the boundary is at the function
|
|
|
375
395
|
```py
|
|
376
396
|
from pydantic import BaseModel
|
|
377
397
|
|
|
398
|
+
|
|
378
399
|
class ScoreInput(BaseModel):
|
|
379
400
|
base: int
|
|
380
401
|
bonus: int
|
|
381
402
|
multiplier: float = 1.0
|
|
382
403
|
|
|
404
|
+
|
|
383
405
|
def compute_score(score_input: ScoreInput) -> int:
|
|
384
406
|
return int((score_input.base + score_input.bonus) * score_input.multiplier)
|
|
385
407
|
```
|
|
@@ -392,11 +414,13 @@ For judgment-heavy functions (containing Natural blocks), the boundary moves *in
|
|
|
392
414
|
from pydantic import BaseModel
|
|
393
415
|
from nighthawk import JsonableValue
|
|
394
416
|
|
|
417
|
+
|
|
395
418
|
class ReviewVerdict(BaseModel):
|
|
396
419
|
approved: bool
|
|
397
420
|
reason: str
|
|
398
421
|
risk_level: str
|
|
399
422
|
|
|
423
|
+
|
|
400
424
|
@nh.natural_function
|
|
401
425
|
def judge_review(review_data: str | JsonableValue) -> ReviewVerdict:
|
|
402
426
|
verdict: ReviewVerdict
|
|
@@ -470,6 +494,7 @@ def get_feedback_summary(topic: str, max_items: int = 10) -> str:
|
|
|
470
494
|
items = fetch_feedback(topic=topic, limit=max_items)
|
|
471
495
|
return format_summary(items)
|
|
472
496
|
|
|
497
|
+
|
|
473
498
|
# Natural block sees only what it needs
|
|
474
499
|
@nh.natural_function
|
|
475
500
|
def analyze_feedback(topic: str) -> str:
|