nighthawk-python 0.1.0__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/.claude/rules/docs.md +2 -0
- nighthawk_python-0.3.0/.claude/settings.json +5 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/.github/workflows/ci.yml +3 -3
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/.github/workflows/docs.yml +1 -1
- nighthawk_python-0.3.0/CHANGELOG.md +47 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/CONTRIBUTING.md +17 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/PKG-INFO +5 -21
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/README.md +3 -19
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/docs/coding-agent-backends.md +2 -2
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/docs/design.md +142 -111
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/docs/for-coding-agents.md +3 -33
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/docs/index.md +2 -2
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/pyproject.toml +3 -2
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/runtime/runner.py +127 -82
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/runtime/scoping.py +33 -6
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/runtime/step_executor.py +11 -25
- nighthawk_python-0.3.0/tests/public/test_public_api.py +471 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/uv.lock +169 -45
- nighthawk_python-0.1.0/tests/public/test_public_api.py +0 -133
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/.claude/rules/coding.md +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/.claude/unset_envs.sh +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/.devcontainer/Dockerfile.devcontainer +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/.devcontainer/Dockerfile.litellm +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/.devcontainer/devcontainer.json +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/.devcontainer/docker-compose.yaml +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/.devcontainer/litellm-config.yaml +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/.github/dependabot.yml +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/.github/workflows/publish.yml +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/.gitignore +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/.python-version +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/AGENTS.md +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/CLAUDE.md +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/LICENSE +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/docs/api.md +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/docs/assets/nighthawk_logo-128x128.png +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/docs/providers.md +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/docs/quickstart.md +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/docs/roadmap.md +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/docs/tutorial.md +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/mkdocs.yml +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/pyrightconfig.json +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/__init__.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/backends/__init__.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/backends/base.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/backends/claude_code_cli.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/backends/claude_code_sdk.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/backends/codex.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/backends/mcp_boundary.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/backends/mcp_server.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/backends/tool_bridge.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/configuration.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/errors.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/identifier_path.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/json_renderer.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/natural/__init__.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/natural/blocks.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/natural/decorator.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/natural/transform.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/runtime/__init__.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/runtime/async_bridge.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/runtime/prompt.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/runtime/step_context.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/runtime/step_contract.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/runtime/tool_calls.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/tools/__init__.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/tools/assignment.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/tools/contracts.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/tools/execution.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/tools/provided.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/src/nighthawk/tools/registry.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/__init__.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/backends/__init__.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/backends/test_claude_code_cli.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/backends/test_claude_code_sdk.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/backends/test_codex.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/conftest.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/docs/__init__.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/docs/test_prompt_examples.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/execution/__init__.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/execution/prompt_test_helpers.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/execution/stub_executor.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/execution/test_execution_outcome_prompt_fragment.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/execution/test_globals_prompt.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/execution/test_natural_block_ordering.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/execution/test_natural_traceback.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/execution/test_runtime.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/execution/test_variables_prompt.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/integration/__init__.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/integration/skip_helpers.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/integration/test_carry_pattern.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/integration/test_claude_code_cli_integration.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/integration/test_claude_code_sdk_integration.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/integration/test_codex_integration.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/integration/test_llm_integration.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/natural/__init__.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/natural/test_blocks.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/public/__init__.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/public/test_readme_example.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/test_renderer.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/tools/__init__.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/tools/test_assignment_async.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/tools/test_contracts.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/tools/test_registry.py +0 -0
- {nighthawk_python-0.1.0 → nighthawk_python-0.3.0}/tests/tools/test_tool_boundary.py +0 -0
|
@@ -91,6 +91,8 @@ Each file has a distinct audience and scope. Content belongs in exactly one file
|
|
|
91
91
|
- This file should be self-contained: a coding agent reading only this file should be able to write correct Nighthawk code without consulting other docs.
|
|
92
92
|
- This file is consumed standalone (`@docs/for-coding-agents.md` in CLAUDE.md/AGENTS.md, GitHub raw URL, etc.). Do not assume sibling files exist at relative paths.
|
|
93
93
|
- All external references to other docs use absolute URLs based on `site_url` from `mkdocs.yml` (currently `https://kurusugawa-computer.github.io/nighthawk-python/`). If `site_url` changes, update the URLs in this file.
|
|
94
|
+
- `@nh.tool` is deprecated. Do not add examples, recommendations, or references to `@nh.tool` in this file. Binding functions are the only recommended callable exposure mechanism.
|
|
95
|
+
- Filter content for coding-agent relevance. Omit infrastructure-level concerns (scoped overrides parameter lists, exception hierarchy beyond `ExecutionError`, observability/tracing) that do not affect how an agent writes Natural blocks or binding functions. Mention existence and link to Tutorial or Design for details.
|
|
94
96
|
|
|
95
97
|
### api.md specifics
|
|
96
98
|
|
|
@@ -23,7 +23,7 @@ jobs:
|
|
|
23
23
|
with:
|
|
24
24
|
persist-credentials: false
|
|
25
25
|
|
|
26
|
-
- uses: astral-sh/setup-uv@
|
|
26
|
+
- uses: astral-sh/setup-uv@v7
|
|
27
27
|
with:
|
|
28
28
|
python-version: "3.13"
|
|
29
29
|
|
|
@@ -52,7 +52,7 @@ jobs:
|
|
|
52
52
|
with:
|
|
53
53
|
persist-credentials: false
|
|
54
54
|
|
|
55
|
-
- uses: astral-sh/setup-uv@
|
|
55
|
+
- uses: astral-sh/setup-uv@v7
|
|
56
56
|
with:
|
|
57
57
|
python-version: ${{ matrix.python-version }}
|
|
58
58
|
|
|
@@ -71,7 +71,7 @@ jobs:
|
|
|
71
71
|
with:
|
|
72
72
|
persist-credentials: false
|
|
73
73
|
|
|
74
|
-
- uses: astral-sh/setup-uv@
|
|
74
|
+
- uses: astral-sh/setup-uv@v7
|
|
75
75
|
|
|
76
76
|
- name: Build sdist and wheel
|
|
77
77
|
run: uv build
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.3.0] - 2026-03-18
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- `system_prompt_suffix_fragment_scope` and `user_prompt_suffix_fragment_scope` context managers for lightweight prompt fragment management without full scope overhead.
|
|
14
|
+
- OpenTelemetry tracer now reports `instrumenting_library_version`.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- Simplified OpenTelemetry span hierarchy: removed implicit `nighthawk.scope` spans and `nighthawk.step_executor` spans. `nighthawk.scope` spans are now emitted only for explicit `nh.scope()` calls.
|
|
18
|
+
- `nighthawk.run` span no longer includes `scope.id` attribute; only `run.id` is emitted.
|
|
19
|
+
- Trimmed `for-coding-agents.md` for coding-agent relevance: removed deprecated `@nh.tool` references, condensed exception hierarchy, scoped overrides, and added debugging context to `StepContextLimits`.
|
|
20
|
+
|
|
21
|
+
## [0.2.0] - 2026-03-16
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
- Added compact step trace support for Natural block execution attempts:
|
|
25
|
+
- `StepTrace`
|
|
26
|
+
- `StepTraceError`
|
|
27
|
+
- `nighthawk.get_step_traces()`
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
- Updated CI workflow setup (`setup-uv`) in project automation.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
- License badge reference in README.
|
|
34
|
+
- Documentation formatting inconsistencies.
|
|
35
|
+
|
|
36
|
+
## [0.1.0] - 2026-03-13
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
- Initial public release of `nighthawk-python`.
|
|
40
|
+
- Natural DSL execution runtime with run/scope execution context model.
|
|
41
|
+
- Step executor abstraction and provider integration foundation.
|
|
42
|
+
- Core documentation and project scaffolding.
|
|
43
|
+
|
|
44
|
+
[Unreleased]: https://github.com/kurusugawa-computer/nighthawk-python/compare/v0.3.0...HEAD
|
|
45
|
+
[0.3.0]: https://github.com/kurusugawa-computer/nighthawk-python/compare/v0.2.0...v0.3.0
|
|
46
|
+
[0.2.0]: https://github.com/kurusugawa-computer/nighthawk-python/compare/v0.1.0...v0.2.0
|
|
47
|
+
[0.1.0]: https://github.com/kurusugawa-computer/nighthawk-python/tree/v0.1.0
|
|
@@ -53,6 +53,23 @@ Then run with your `.env` loaded:
|
|
|
53
53
|
set -a; source .env; set +a; uv run pytest -q
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
+
### Trace inspection with otel-tui
|
|
57
|
+
|
|
58
|
+
Nighthawk emits OpenTelemetry traces for step execution. You can inspect them
|
|
59
|
+
locally using [otel-tui](https://github.com/ymtdzzz/otel-tui):
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
docker run --rm -it -p 4318:4318 --name otel-tui ymtdzzz/otel-tui:latest
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Then run integration tests with the collector endpoint:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 uv run pytest -q tests/integration/
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Traces appear in the otel-tui terminal UI in real time.
|
|
72
|
+
|
|
56
73
|
### Environment variables
|
|
57
74
|
|
|
58
75
|
- `OPENAI_API_KEY`: Required for OpenAI integration tests (also requires `pydantic-ai-slim[openai]`).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nighthawk-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: An experimental Python library that embeds Natural blocks inside Python functions and executes them using an LLM.
|
|
5
5
|
Project-URL: Repository, https://github.com/kurusugawa-computer/nighthawk-python
|
|
6
6
|
Project-URL: Documentation, https://kurusugawa-computer.github.io/nighthawk-python/
|
|
@@ -19,7 +19,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
19
19
|
Classifier: Typing :: Typed
|
|
20
20
|
Requires-Python: >=3.13
|
|
21
21
|
Requires-Dist: headson>=0.16.1
|
|
22
|
-
Requires-Dist: pydantic-ai-slim>=1.
|
|
22
|
+
Requires-Dist: pydantic-ai-slim>=1.68
|
|
23
23
|
Requires-Dist: pydantic>=2
|
|
24
24
|
Requires-Dist: pyyaml>=6
|
|
25
25
|
Requires-Dist: tiktoken>=0.12
|
|
@@ -33,7 +33,7 @@ Description-Content-Type: text/markdown
|
|
|
33
33
|
|
|
34
34
|
[](https://pypi.org/project/nighthawk-python)
|
|
35
35
|

|
|
36
|
-
[](https://github.com/kurusugawa-computer/nighthawk-python/blob/main/LICENSE)
|
|
37
37
|
[](https://github.com/kurusugawa-computer/nighthawk-python/issues)
|
|
38
38
|
|
|
39
39
|
# Nighthawk
|
|
@@ -86,25 +86,9 @@ python quickstart.py
|
|
|
86
86
|
|
|
87
87
|
For backends, credentials, model identifiers, and detailed guidance, see the [documentation site](https://kurusugawa-computer.github.io/nighthawk-python/).
|
|
88
88
|
|
|
89
|
-
## Development
|
|
89
|
+
## Development & Contributing
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
```bash
|
|
94
|
-
uv run pytest -q
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
Run an OTel collector UI (otel-tui) for observability:
|
|
98
|
-
|
|
99
|
-
```bash
|
|
100
|
-
docker run --rm -it -p 4318:4318 --name otel-tui ymtdzzz/otel-tui:latest
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
Then run integration tests with `OTEL_EXPORTER_OTLP_ENDPOINT` set:
|
|
104
|
-
|
|
105
|
-
```bash
|
|
106
|
-
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 uv run pytest -q tests/integration/test_llm_integration.py
|
|
107
|
-
```
|
|
91
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, development commands, and contribution guidelines.
|
|
108
92
|
|
|
109
93
|
## References
|
|
110
94
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[](https://pypi.org/project/nighthawk-python)
|
|
2
2
|

|
|
3
|
-
[](https://github.com/kurusugawa-computer/nighthawk-python/blob/main/LICENSE)
|
|
4
4
|
[](https://github.com/kurusugawa-computer/nighthawk-python/issues)
|
|
5
5
|
|
|
6
6
|
# Nighthawk
|
|
@@ -53,25 +53,9 @@ python quickstart.py
|
|
|
53
53
|
|
|
54
54
|
For backends, credentials, model identifiers, and detailed guidance, see the [documentation site](https://kurusugawa-computer.github.io/nighthawk-python/).
|
|
55
55
|
|
|
56
|
-
## Development
|
|
56
|
+
## Development & Contributing
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
```bash
|
|
61
|
-
uv run pytest -q
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
Run an OTel collector UI (otel-tui) for observability:
|
|
65
|
-
|
|
66
|
-
```bash
|
|
67
|
-
docker run --rm -it -p 4318:4318 --name otel-tui ymtdzzz/otel-tui:latest
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
Then run integration tests with `OTEL_EXPORTER_OTLP_ENDPOINT` set:
|
|
71
|
-
|
|
72
|
-
```bash
|
|
73
|
-
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 uv run pytest -q tests/integration/test_llm_integration.py
|
|
74
|
-
```
|
|
58
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, development commands, and contribution guidelines.
|
|
75
59
|
|
|
76
60
|
## References
|
|
77
61
|
|
|
@@ -196,8 +196,8 @@ The symlink approach above lets a single skill definition serve both backends.
|
|
|
196
196
|
|
|
197
197
|
Skill configuration differs between backends:
|
|
198
198
|
|
|
199
|
-
- **Claude Code** (SDK and CLI): supports SKILL.md frontmatter fields such as `context`, `agent`, `allowed-tools`, and `disable-model-invocation`. See the [Claude Code skills documentation](https://code.claude.com/docs/skills) for available options.
|
|
200
|
-
- **Codex**: uses a separate `agents/openai.yaml` file for invocation policy and tool dependencies. See the [Codex skills documentation](https://developers.openai.com/codex/
|
|
199
|
+
- **Claude Code** (SDK and CLI): supports SKILL.md frontmatter fields such as `context`, `agent`, `allowed-tools`, and `disable-model-invocation`. See the [Claude Code skills documentation](https://code.claude.com/docs/en/skills) for available options.
|
|
200
|
+
- **Codex**: uses a separate `agents/openai.yaml` file for invocation policy and tool dependencies. See the [Codex skills documentation](https://developers.openai.com/codex/skills/) for available options.
|
|
201
201
|
|
|
202
202
|
Example `SKILL.md`:
|
|
203
203
|
|
|
@@ -26,12 +26,12 @@ This file intentionally does not maintain a persistent divergence ledger.
|
|
|
26
26
|
|
|
27
27
|
- Provide a compact reimplementation of nightjarpy-like Natural blocks in Python.
|
|
28
28
|
- Support a hybrid style where Python controls flow, while the LLM executes a Natural DSL embedded as:
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
- Function docstring Natural blocks
|
|
30
|
+
- Inline Natural blocks (standalone string literal statements)
|
|
31
31
|
- Reduce the "LLM is a black box" problem by actively mapping LLM-relevant state into the Python interpreter:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
- expose a summary of step locals to the LLM
|
|
33
|
+
- allow the LLM to synchronize intermediate state into a step locals mapping during reasoning
|
|
34
|
+
- commit selected state back into Python locals at Natural block boundaries
|
|
35
35
|
- Provide a coherent execution model where all state is ordinary Python values in step locals, and persistence (if desired) is user-managed via ordinary bindings.
|
|
36
36
|
|
|
37
37
|
## 2. Non-goals
|
|
@@ -57,8 +57,8 @@ This file intentionally does not maintain a persistent divergence ledger.
|
|
|
57
57
|
- Step locals (`step_locals`): a locals mapping used as the execution environment for LLM expressions; updated during reasoning via tools.
|
|
58
58
|
- Step globals (`step_globals`): a limited globals mapping used as the execution environment for LLM expressions.
|
|
59
59
|
- StepContext: a mutable, per-step object (one Natural block execution) passed to tools and executors.
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
- Required fields include `step_id` (unique Id for the step).
|
|
61
|
+
- Model selection and prompt policy are owned by `StepExecutorConfiguration`; StepContext does not carry model configuration.
|
|
62
62
|
- Locals summary: a bounded text rendering of selected values from `step_locals`, included in the LLM prompt.
|
|
63
63
|
- Prompt suffix fragment: additional prompt text appended to the end of the effective system prompt or user prompt for the duration of a scoped override.
|
|
64
64
|
- Outcome: the single, unambiguous result of executing a Natural block.
|
|
@@ -71,54 +71,50 @@ This file intentionally does not maintain a persistent divergence ledger.
|
|
|
71
71
|
### 5.1. Decorator
|
|
72
72
|
|
|
73
73
|
- `nighthawk.natural_function`
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
- Decorator that compiles a function containing Natural blocks into an LLM-backed implementation.
|
|
75
|
+
- Compilation happens at decoration time, and Natural blocks are executed at function call time.
|
|
76
|
+
- Note: The decorator requires the function source to be available for inspection.
|
|
77
77
|
|
|
78
78
|
### 5.2. Configuration
|
|
79
79
|
|
|
80
80
|
- `StepExecutorConfiguration`
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
81
|
+
- `model`: Model identifier in `provider:model` format. Default: `openai-responses:gpt-5-nano` (see [Providers](providers.md)).
|
|
82
|
+
- Examples: `openai-responses:gpt-5-mini`, `openai-responses:gpt-5-nano`.
|
|
83
|
+
- Special cases:
|
|
84
|
+
- `claude-code-sdk:default`, `claude-code-cli:default`, and `codex:default` select the backend/provider default model (no explicit model selection is sent to the backend).
|
|
85
|
+
- `model_settings`: optional model/backend settings. Accepts a `dict[str, Any]` or a backend-specific `BaseModel` instance (auto-converted to dict). Forwarded to Pydantic AI Agent calls.
|
|
86
|
+
- `tokenizer_encoding`: tokenizer encoding identifier for approximate token budgeting. `None` means auto-resolve by model name, then fallback to `o200k_base`.
|
|
87
|
+
- `prompts`: prompt templates used for execution.
|
|
88
|
+
- `step_system_prompt_template`: system prompt template that defines the step execution protocol.
|
|
89
|
+
- `step_user_prompt_template`: full user prompt template including section delimiters.
|
|
90
|
+
- `context_limits`: limits for rendering dynamic context into the prompt.
|
|
91
|
+
- `json_renderer_style`: [headson](https://github.com/kantord/headson) rendering style used in prompt context and tool result envelopes. Available values: `"strict"` (valid JSON, no annotations), `"default"` (pseudo-JSON with omission markers like `…`), `"detailed"` (JS-like with inline comments such as `// N more`).
|
|
92
|
+
- `system_prompt_suffix_fragments`: optional baseline system prompt suffix fragments for this executor configuration.
|
|
93
|
+
- `user_prompt_suffix_fragments`: optional baseline user prompt suffix fragments for this executor configuration.
|
|
95
94
|
- `StepExecutorConfigurationPatch`
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
- Partial override object for scoped configuration updates.
|
|
96
|
+
- Supports patching model, model settings, templates, limits, renderer style, tokenizer encoding, and prompt suffix fragment tuples.
|
|
98
97
|
|
|
99
98
|
### 5.3. Supporting types
|
|
100
99
|
|
|
101
100
|
- `StepPromptTemplates`
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
101
|
+
- Prompt templates used for step execution.
|
|
102
|
+
- `step_system_prompt_template`: system prompt template.
|
|
103
|
+
- `step_user_prompt_template`: user prompt template.
|
|
106
104
|
- `StepContextLimits`
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
105
|
+
- Limits for rendering dynamic context into the LLM prompt.
|
|
106
|
+
- Fields: `locals_max_tokens`, `locals_max_items`, `globals_max_tokens`, `globals_max_items`, `value_max_tokens`, `tool_result_max_tokens`.
|
|
110
107
|
- `JsonableValue`
|
|
111
|
-
|
|
112
|
-
|
|
108
|
+
- Type alias for JSON-serializable Python values (`dict | list | str | int | float | bool | None`).
|
|
113
109
|
- `ExecutionContext`
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
110
|
+
- Frozen dataclass representing runtime execution identity.
|
|
111
|
+
- `run_id`: the Id of the outermost run (trace root).
|
|
112
|
+
- `scope_id`: the Id of the current scope.
|
|
117
113
|
|
|
118
114
|
### 5.4. Runtime accessors
|
|
119
115
|
|
|
120
116
|
- `nighthawk.get_current_step_context() -> StepContext`
|
|
121
|
-
|
|
117
|
+
- Get the `StepContext` for the currently executing Natural block. Raises if no step is active.
|
|
122
118
|
|
|
123
119
|
See [Section 10](#10-runtime-scoping) for additional runtime accessors (`get_step_executor`, `get_execution_context`).
|
|
124
120
|
|
|
@@ -194,7 +190,7 @@ Constraints:
|
|
|
194
190
|
|
|
195
191
|
- `name` is a simple identifier (no dotted paths).
|
|
196
192
|
- `<:name>` does not require prior declaration.
|
|
197
|
-
|
|
193
|
+
- Practical note: if subsequent Python code reads a variable that has not been assigned yet, Python will raise before any LLM behavior can help. Initialize variables in Python when needed.
|
|
198
194
|
|
|
199
195
|
Type note:
|
|
200
196
|
|
|
@@ -222,9 +218,9 @@ Nighthawk uses multiple state layers.
|
|
|
222
218
|
|
|
223
219
|
- `step_locals` is a mapping used as the locals environment for LLM expression evaluation.
|
|
224
220
|
- It is initialized at the start of each Natural block execution, in the following order:
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
221
|
+
1. If a parent step context exists on the step context stack, start from its `step_locals` values.
|
|
222
|
+
2. Overlay the caller frame's current `python_locals` (so current Python locals always win over inherited step-context state).
|
|
223
|
+
3. For each read binding (`<name>`), resolve the name using Python lexical rules (locals, enclosing cell scopes, name scopes, globals, builtins) and place the resolved value into `step_locals`.
|
|
228
224
|
- During execution, the LLM can update `step_locals` via tools (Section 8.3).
|
|
229
225
|
- At the end of execution, values for `<:name>` bindings are committed into Python locals.
|
|
230
226
|
|
|
@@ -259,9 +255,9 @@ Rendering format:
|
|
|
259
255
|
|
|
260
256
|
- Non-callable values: `name: type_name = json_value`, where `json_value` is the compact JSON rendering of the value (bounded by `context_limits.value_max_tokens`).
|
|
261
257
|
- Callable values: `name: (signature)`, where `(signature)` is the result of `inspect.signature`. Type annotations are included when available (e.g., `(base: int, bonus: int) -> int`).
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
258
|
+
- If the callable has a meaningful docstring, the first line is appended as `# intent: first_line`.
|
|
259
|
+
- If multiple callable entries share the same signature text, each is annotated with `# disambiguation: use name` to help the LLM distinguish them.
|
|
260
|
+
- If the signature cannot be resolved (e.g., `__signature__` raises), the entry renders as `name: <callable; signature-unavailable>`.
|
|
265
261
|
- `TypeAliasType` values (PEP 695): `name: type = underlying_type`.
|
|
266
262
|
|
|
267
263
|
Truncation:
|
|
@@ -319,10 +315,10 @@ User-defined tools:
|
|
|
319
315
|
Registration API:
|
|
320
316
|
|
|
321
317
|
- `@nighthawk.tool`: Decorator that registers a callable as a Nighthawk tool.
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
318
|
+
- `name`: Optional name override. Defaults to the function `__name__`.
|
|
319
|
+
- `overwrite`: If True, replaces any existing tool with the same name.
|
|
320
|
+
- `description`: Optional description override. Defaults to the function docstring.
|
|
321
|
+
- `metadata`: Arbitrary metadata dict attached to the tool definition.
|
|
326
322
|
- Tool names must be ASCII and match `^[A-Za-z_][A-Za-z0-9_]*$`.
|
|
327
323
|
- Tool registration targets the innermost active scope (call scope > tool scope > global).
|
|
328
324
|
- Name conflicts raise `ToolRegistrationError` unless `overwrite=True`.
|
|
@@ -361,14 +357,14 @@ Expressions are evaluated against `step_globals` + `step_locals`.
|
|
|
361
357
|
Inspect tool:
|
|
362
358
|
|
|
363
359
|
- `nh_eval(expression: str) -> object`
|
|
364
|
-
|
|
365
|
-
|
|
360
|
+
- Evaluate a Python expression and return the result. Use to inspect values and call functions.
|
|
361
|
+
- If the evaluated expression is awaitable, it is awaited before returning.
|
|
366
362
|
|
|
367
363
|
Mutation tool:
|
|
368
364
|
|
|
369
365
|
- `nh_exec(expression: str) -> object`
|
|
370
|
-
|
|
371
|
-
|
|
366
|
+
- Execute a Python expression for its side effect on mutable objects (e.g., `list.append()`, `dict.update()`, `set.add()`).
|
|
367
|
+
- Returns the expression result.
|
|
372
368
|
|
|
373
369
|
Implementation note: `nh_eval` and `nh_exec` share the same underlying implementation (Python `eval()`). The two-tool split exists as a semantic signal to the LLM (inspect intent vs mutate intent), not a runtime distinction.
|
|
374
370
|
|
|
@@ -390,16 +386,16 @@ Semantics of `nh_assign`:
|
|
|
390
386
|
- Evaluate `expression` as a Python expression using `step_globals` and `step_locals`.
|
|
391
387
|
- If the evaluated expression is awaitable, it is awaited before assignment.
|
|
392
388
|
- If `target_path` is a bare `name`:
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
389
|
+
- Assign into `step_locals[name]`.
|
|
390
|
+
- Validation:
|
|
391
|
+
- If extracted type information is available for the corresponding `<:name>` binding, validate/coerce to that type.
|
|
392
|
+
- Otherwise, assign without validation.
|
|
397
393
|
- If `target_path` is dotted (`name.field...`):
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
394
|
+
- Resolve the root object from `step_locals[name]`.
|
|
395
|
+
- Traverse attributes for each intermediate segment.
|
|
396
|
+
- Assign using attribute assignment on the final segment.
|
|
397
|
+
- Validation:
|
|
398
|
+
- Validate only when runtime type metadata is available; otherwise assign without validation.
|
|
403
399
|
|
|
404
400
|
Commit and mutation notes:
|
|
405
401
|
|
|
@@ -410,10 +406,10 @@ Commit and mutation notes:
|
|
|
410
406
|
Write tool return value:
|
|
411
407
|
|
|
412
408
|
- The tool returns a diagnostic object describing:
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
409
|
+
- whether it succeeded
|
|
410
|
+
- a bounded summary of the updated value (on success)
|
|
411
|
+
- validation details (when relevant)
|
|
412
|
+
- error details (on failure)
|
|
417
413
|
|
|
418
414
|
Tool result JSON format:
|
|
419
415
|
|
|
@@ -445,29 +441,26 @@ The outcome is a discriminated union keyed by the required field `kind`.
|
|
|
445
441
|
Outcome kinds:
|
|
446
442
|
|
|
447
443
|
- `pass`:
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
444
|
+
- Success with no control-flow change.
|
|
445
|
+
- Payload keys: `kind` only.
|
|
451
446
|
- `return`:
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
447
|
+
- Return from the surrounding Python function immediately.
|
|
448
|
+
- Payload keys: `kind`, and required `return_reference_path`.
|
|
449
|
+
- `return_reference_path` must be a dot-separated identifier path into step locals.
|
|
450
|
+
- The host resolves `return_reference_path` within step locals only, using attribute access only.
|
|
451
|
+
- If the surrounding function is async and the resolved value is awaitable, the host awaits it before validation.
|
|
452
|
+
- The host then validates/coerces the resolved Python value to the function's return type annotation.
|
|
453
|
+
- If the surrounding function is sync and the resolved value is awaitable, execution fails.
|
|
460
454
|
- `break` / `continue`:
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
455
|
+
- Loop control.
|
|
456
|
+
- Payload keys: `kind` only.
|
|
457
|
+
- These outcomes are valid only when the Natural block appears syntactically inside a Python `for` or `while` loop. If requested outside a loop, execution fails.
|
|
465
458
|
- `raise`:
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
459
|
+
- Failure.
|
|
460
|
+
- Payload keys: `kind`, `raise_message`, and optional `raise_error_type`.
|
|
461
|
+
- `raise_error_type` is optional. If provided, it MUST be one of the exception type names listed in the prompt.
|
|
462
|
+
- The host enforces this using the structured output JSON Schema: when `raise_error_type` is allowed for a block, its schema is an `enum` over the allowed exception type names.
|
|
463
|
+
- When `raise_error_type` is provided, the host raises that exception type with the provided `raise_message`.
|
|
471
464
|
|
|
472
465
|
The implementation chooses strict parsing. Any non-JSON final response is an error.
|
|
473
466
|
|
|
@@ -512,8 +505,8 @@ Allowed outcome type names in `deny` are a subset of the baseline outcome types:
|
|
|
512
505
|
Semantics:
|
|
513
506
|
|
|
514
507
|
- Syntactic context defines a hard cap on allowed outcomes:
|
|
515
|
-
|
|
516
|
-
|
|
508
|
+
- Outside a loop: `pass`, `return`, `raise`.
|
|
509
|
+
- Inside a loop: `pass`, `return`, `break`, `continue`, `raise`.
|
|
517
510
|
- Frontmatter deny declarations may only exclude outcome types; they must not expand the syntactic cap.
|
|
518
511
|
- If frontmatter denies an outcome type, and the model returns that outcome type, the host raises an `ExecutionError`.
|
|
519
512
|
|
|
@@ -548,23 +541,61 @@ Working directory selection for provider backends is configured via `ModelSettin
|
|
|
548
541
|
API:
|
|
549
542
|
|
|
550
543
|
- `nighthawk.run(step_executor: StepExecutor, *, run_id: str | None = None)`
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
544
|
+
- Replaces the current context step executor with the provided step executor.
|
|
545
|
+
- Generates a new `ExecutionContext` for the duration of the `with`.
|
|
546
|
+
- Uses provided `run_id` when given; otherwise generates a new `run_id` (trace root).
|
|
547
|
+
- Always generates a fresh `scope_id`.
|
|
548
|
+
- Can be used even when no step executor is currently set.
|
|
556
549
|
- `nighthawk.scope(*, step_executor_configuration: StepExecutorConfiguration | None = None, step_executor_configuration_patch: StepExecutorConfigurationPatch | None = None, step_executor: StepExecutor | None = None, system_prompt_suffix_fragment: str | None = None, user_prompt_suffix_fragment: str | None = None) -> Iterator[StepExecutor]`
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
550
|
+
- Enter a nested scope within the current run.
|
|
551
|
+
- Requires an existing step executor.
|
|
552
|
+
- Generates a new `scope_id` (keeps the current `run_id`).
|
|
553
|
+
- Only specified fields are overridden for the duration of the `with`.
|
|
554
|
+
- `system_prompt_suffix_fragment`: optional string appended to the system prompt for the duration of the scope.
|
|
555
|
+
- `user_prompt_suffix_fragment`: optional string appended to the user prompt for the duration of the scope.
|
|
556
|
+
- Yields the resolved `StepExecutor` for the scope.
|
|
564
557
|
- `nighthawk.get_step_executor() -> StepExecutor`
|
|
565
|
-
|
|
558
|
+
- Get the current step executor. Raises if unset.
|
|
566
559
|
- `nighthawk.get_execution_context() -> ExecutionContext`
|
|
567
|
-
|
|
560
|
+
- Get the current runtime execution identity. Raises if unset.
|
|
561
|
+
|
|
562
|
+
### 10.1. Observability contract (OpenTelemetry span/event)
|
|
563
|
+
|
|
564
|
+
Nighthawk uses OpenTelemetry spans as the sole runtime trace model.
|
|
565
|
+
|
|
566
|
+
Runtime spans:
|
|
567
|
+
|
|
568
|
+
- `nighthawk.run`
|
|
569
|
+
- `nighthawk.scope`
|
|
570
|
+
- `nighthawk.step`
|
|
571
|
+
- `nighthawk.step_executor`
|
|
572
|
+
|
|
573
|
+
Identity attributes:
|
|
574
|
+
|
|
575
|
+
- `run.id: str`
|
|
576
|
+
- `scope.id: str`
|
|
577
|
+
- `step.id: str` (exact format: `python_module:line`, on `nighthawk.step`)
|
|
578
|
+
|
|
579
|
+
Step events (emitted on `nighthawk.step`):
|
|
580
|
+
|
|
581
|
+
- `nighthawk.step.completed`
|
|
582
|
+
- attributes:
|
|
583
|
+
- `nighthawk.step.outcome_kind`
|
|
584
|
+
- `nighthawk.step.raised`
|
|
585
|
+
- attributes:
|
|
586
|
+
- `nighthawk.step.outcome_kind`
|
|
587
|
+
- `nighthawk.step.raise_message`
|
|
588
|
+
- `nighthawk.step.raise_error_type` (when provided)
|
|
589
|
+
- `nighthawk.step.failed`
|
|
590
|
+
- attributes:
|
|
591
|
+
- `nighthawk.step.error_kind`
|
|
592
|
+
- `nighthawk.step.error_message`
|
|
593
|
+
|
|
594
|
+
Semantics:
|
|
595
|
+
|
|
596
|
+
- `raise` outcome is treated as domain-level behavior, represented by `nighthawk.step.raised`.
|
|
597
|
+
- Nighthawk-side internal failures are represented by `nighthawk.step.failed`, and the span records exception + error status.
|
|
598
|
+
- There is no in-memory step trace API.
|
|
568
599
|
|
|
569
600
|
## 11. Interpolation (opt-in, f-strings only)
|
|
570
601
|
|
|
@@ -577,8 +608,8 @@ Natural blocks often need to embed computed values (for example, paths or JSON e
|
|
|
577
608
|
- Docstring Natural blocks are always literal. They are never interpolated.
|
|
578
609
|
- Interpolated Natural blocks are inline f-string Natural blocks (standalone f-string expression statements).
|
|
579
610
|
- Interpolation follows standard Python f-string semantics.
|
|
580
|
-
|
|
581
|
-
|
|
611
|
+
- Expression evaluation rules are those of Python.
|
|
612
|
+
- Brace escaping uses `{{` and `}}` in the f-string source to produce literal `{` and `}` in the rendered text.
|
|
582
613
|
|
|
583
614
|
Note:
|
|
584
615
|
|
|
@@ -608,17 +639,17 @@ Nighthawk defines a hierarchy of exceptions rooted at `NighthawkError`.
|
|
|
608
639
|
Exception hierarchy:
|
|
609
640
|
|
|
610
641
|
- `NighthawkError`: Base class for all Nighthawk exceptions.
|
|
611
|
-
|
|
642
|
+
- Raised when: runtime preconditions fail (e.g. no active run context, missing step executor).
|
|
612
643
|
- `NaturalParseError(NighthawkError)`: Natural block parsing or frontmatter parsing failed.
|
|
613
|
-
|
|
644
|
+
- Raised when: the sentinel is missing, bindings are invalid, frontmatter YAML is malformed, or AST extraction fails.
|
|
614
645
|
- `ExecutionError(NighthawkError)`: Natural block execution failed.
|
|
615
|
-
|
|
646
|
+
- Raised when: the LLM returns invalid JSON, an outcome kind is disallowed, return value validation fails, or `raise` outcome is triggered without a matching exception type.
|
|
616
647
|
- `ToolEvaluationError(NighthawkError)`: Expression evaluation inside a tool call failed.
|
|
617
|
-
|
|
648
|
+
- Raised when: `eval()` raises during `nh_eval`, `nh_exec`, or `nh_assign` expression evaluation.
|
|
618
649
|
- `ToolValidationError(NighthawkError)`: Type validation/coercion failed during `nh_assign`.
|
|
619
|
-
|
|
650
|
+
- Raised when: the assigned value does not match the expected binding type.
|
|
620
651
|
- `ToolRegistrationError(NighthawkError)`: Tool registration failed.
|
|
621
|
-
|
|
652
|
+
- Raised when: a tool name is invalid, or a name conflict occurs without `overwrite=True`.
|
|
622
653
|
|
|
623
654
|
All exceptions are surfaced as Python exceptions and can be caught with standard `try`/`except`.
|
|
624
655
|
|