Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,20 @@ printf "%s" "$TASK" | nanoPyCodeAgent
The task is carried out in the current directory. `--max-turns N` caps how
many model replies one run may spend (50 by default).

Add `--trajectory PATH` to save that headless Agent Run as one complete
[ATIF-v1.7](https://www.harborframework.com/docs/agents/trajectory-format)
JSON document without changing stdout:

```bash
nanoPyCodeAgent -p "read README.md and summarize it" \
--trajectory ./trajectory.json
```

The option creates the requested file with owner-only permissions (`0600`)
after the run reaches a terminal state. It refuses to overwrite an existing
path. Trajectories may contain the task, model replies, tool arguments, and
tool results, so treat them as sensitive data.

A run like this exits `0` whenever the agent actually ran — including when it
gave up or ran out of turns with the task unfinished, which is for whatever
checks the result to judge. A non-zero exit means the run could not happen at
Expand Down
13 changes: 13 additions & 0 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,19 @@ printf "%s" "$TASK" | nanoPyCodeAgent
任务在当前目录下执行。`--max-turns N` 限制一次运行最多花费多少轮模型回复(默认
50 轮)。

增加 `--trajectory PATH` 可以把这次 headless Agent Run 保存为一份完整的
[ATIF-v1.7](https://www.harborframework.com/docs/agents/trajectory-format) JSON
文档,同时不改变 stdout:

```bash
nanoPyCodeAgent -p "read README.md and summarize it" \
--trajectory ./trajectory.json
```

run 到达终态后,该选项才会以仅当前用户可读写的权限(`0600`)创建目标文件;如果
目标已存在则拒绝覆盖。trajectory 可能包含任务、模型回复、工具参数和工具结果,
应按敏感数据处理。

只要 agent 真的跑起来了,退出码就是 `0`——包括它放弃了、或者轮数用尽而任务没做
完,那该由检查结果的一方去判定。非零退出码表示这次运行根本没能进行:`1` 是缺少
凭据或 API 持续失败,`2` 是命令行用错了。
Expand Down
4 changes: 4 additions & 0 deletions benchmarks/harbor/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ packages = ["src/harbor_adapter"]

[dependency-groups]
dev = [
"nanopycodeagent",
"pytest>=9.1.1",
]

[tool.uv.sources]
nanopycodeagent = { path = "../..", editable = true }

[tool.pytest.ini_options]
testpaths = ["tests"]
7 changes: 7 additions & 0 deletions benchmarks/harbor/tests/fixtures/atif-journal-v1.jsonl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{"schema_version":1,"run_id":"run-harbor-atif","seq":1,"recorded_at":"2026-08-26T10:00:00.001Z","type":"run.started","payload":{"mode":"headless","model":"test-model","max_turns":10,"producer":{"name":"nanoPyCodeAgent","version":"0.8.0"},"source_timestamp":"2026-08-26T10:00:00.000Z"}}
{"schema_version":1,"run_id":"run-harbor-atif","seq":2,"recorded_at":"2026-08-26T10:00:00.002Z","type":"user.message","payload":{"message_id":"user-1","content":"read README.md","source_timestamp":"2026-08-26T10:00:00.010Z"}}
{"schema_version":1,"run_id":"run-harbor-atif","seq":3,"recorded_at":"2026-08-26T10:00:00.003Z","type":"model.started","payload":{"model_call_id":"model-1","model":"test-model","source_timestamp":"2026-08-26T10:00:00.020Z"}}
{"schema_version":1,"run_id":"run-harbor-atif","seq":4,"recorded_at":"2026-08-26T10:00:00.004Z","type":"model.completed","payload":{"model_call_id":"model-1","message_id":"msg-1","content":[{"type":"text","text":"checking"},{"type":"tool_call","tool_call_id":"call-1","tool_name":"read","input":{"path":"README.md"}}],"tool_calls":[{"type":"tool_call","tool_call_id":"call-1","tool_name":"read","input":{"path":"README.md"}}],"model":"test-model","stop_reason":"tool_use","usage":{"input_tokens":10,"output_tokens":2,"cache_read_input_tokens":3,"cache_creation_input_tokens":1},"provider_response_id":"msg-1","generation_id":null,"duration_ms":15,"source_timestamp":"2026-08-26T10:00:00.030Z"}}
{"schema_version":1,"run_id":"run-harbor-atif","seq":5,"recorded_at":"2026-08-26T10:00:00.005Z","type":"tool.started","payload":{"model_call_id":"model-1","tool_call_id":"call-1","tool_name":"read","input":{"path":"README.md"},"source_timestamp":"2026-08-26T10:00:00.040Z"}}
{"schema_version":1,"run_id":"run-harbor-atif","seq":6,"recorded_at":"2026-08-26T10:00:00.006Z","type":"tool.completed","payload":{"model_call_id":"model-1","tool_call_id":"call-1","tool_name":"read","result":"contents","is_error":false,"duration_ms":4,"source_timestamp":"2026-08-26T10:00:00.050Z"}}
{"schema_version":1,"run_id":"run-harbor-atif","seq":7,"recorded_at":"2026-08-26T10:00:00.007Z","type":"run.completed","payload":{"outcome":"completed","duration_ms":60,"source_timestamp":"2026-08-26T10:00:00.060Z"}}
15 changes: 15 additions & 0 deletions benchmarks/harbor/tests/test_atif_compatibility.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""Compatibility checks against Harbor's pinned ATIF-v1.7 validator."""

from pathlib import Path

from harbor.utils.trajectory_validator import TrajectoryValidator
from nanopycodeagent.atif import project_atif
from nanopycodeagent.event_journal import EventJournal


def test_projector_output_passes_harbor_atif_validator():
journal_path = Path(__file__).parent / "fixtures" / "atif-journal-v1.jsonl"
trajectory = project_atif(EventJournal.replay(journal_path))
validator = TrajectoryValidator()

assert validator.validate(trajectory), validator.get_errors()
97 changes: 96 additions & 1 deletion benchmarks/harbor/uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions docs/changelogs/0.8.x.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ All notable changes in the **0.8.x** release series are documented here.
response metadata, and explicit truncation metadata. Journals are stored as
sensitive user-only files while the existing text stdout remains unchanged
as an event projection.
- An opt-in `--trajectory PATH` interface for headless runs. It projects the
internal Event Journal into one complete ATIF-v1.7 JSON document with
user/model steps, tool observations, token metrics, and terminal state,
while preserving text stdout and refusing to overwrite an existing file.

### Fixed
- Declare `httpx` as a direct runtime dependency so clean and containerized
Expand Down
Loading
Loading