Skip to content
Merged
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
16 changes: 14 additions & 2 deletions README-cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,20 @@ uv run yada --task-file issue.md --workspace /workspace --yes
Yada 会打印每轮 DeepSeek 调用和工具执行,最后报告任务是否通过验证门槛。默认
Trace 保存在目标仓库的 `.yada/runs/` 目录下。

仓库测试可以执行任意代码。Yada 提供 Guardrail,但不是完整的操作系统沙箱;
处理陌生项目时请使用一次性 VM 或容器。
陌生项目可能包含并执行任意代码。Yada 虽然提供了 Guardrail,但并不是完整的
操作系统沙箱,运行这类项目仍可能危及系统安全。处理陌生项目时,请使用一次性
VM 或容器。

## 检查每一个步骤

将任意 JSONL Trace 转换成完全离线、自包含的可视化页面,无需服务器、CDN 或
额外运行时依赖:

```bash
uv run yada-trace TRACE.jsonl --html
```

[![Yada 离线 Trace Viewer](docs/assets/yada-trace-viewer.jpg)](docs/assets/yada-trace-viewer.jpg)

## 更多文档

Expand Down
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,21 @@ Yada prints each DeepSeek turn and tool execution, then reports whether the task
passed its verification gate. Traces are written under the target repository's
`.yada/runs/` directory by default.

Repository tests can execute arbitrary code. Yada provides guardrails, not a
complete OS sandbox; use a disposable VM or container for unfamiliar projects.
Unfamiliar projects may contain and execute arbitrary code. Yada provides
guardrails, but it is not a complete operating-system sandbox, so running such
projects can still put your system at risk. Use a disposable VM or container
when working with unfamiliar projects.

## Inspect every step

Turn any JSONL trace into a self-contained offline viewer—no server, CDN, or
additional runtime dependency required:

```bash
uv run yada-trace TRACE.jsonl --html
```

[![Yada offline trace viewer](docs/assets/yada-trace-viewer.jpg)](docs/assets/yada-trace-viewer.jpg)

## Learn more

Expand Down
Binary file added docs/assets/yada-trace-viewer.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 13 additions & 1 deletion docs/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,14 +301,15 @@ errors or non-verdict outcomes such as skipped grading.
## `yada-trace`

```text
yada-trace TRACE.jsonl [--step N | --verbose | --events]
yada-trace TRACE.jsonl [--step N | --verbose | --events | --html [PATH]]
```

| Option | Meaning |
| --- | --- |
| `--step N` | Expand one complete request → response → tools step. |
| `--verbose` | Expand payloads inside every grouped step. |
| `--events` | Show the flat event timeline with physical JSONL line numbers. |
| `--html [PATH]` | Write one self-contained offline HTML viewer. Without `PATH`, write it beside the trace and open it. |

The default view groups records by agent step and shows physical JSONL line
references for the model request/response and each tool call/result pair:
Expand All @@ -317,8 +318,19 @@ references for the model request/response and each tool call/result pair:
uv run yada-trace TRACE.jsonl
uv run yada-trace TRACE.jsonl --step 8
uv run yada-trace TRACE.jsonl --events
uv run yada-trace TRACE.jsonl --html
uv run yada-trace TRACE.jsonl --html trace.html
```

Without an output path, `--html` writes `TRACE.html` beside `TRACE.jsonl` and
opens it in the default browser. Pass a path to export the viewer without opening
it. The HTML viewer groups the same validated records by step and adds local step
filtering, failure/file-change filters, collapsed large payloads, and the final
diff. It contains inline CSS and JavaScript only: opening the file
does not start a server or request external resources. The generated file can
contain prompts, reasoning, source, patches, and command output from the source
trace, so handle it with the same care as the JSONL.

`yada-trace` returns `0` after rendering and `2` for an unreadable or invalid
trace. See the [debugging guide](dev/debugging.md) for event semantics, trace
levels, `jq` recipes, and reproduction workflows.
Expand Down
17 changes: 17 additions & 0 deletions docs/dev/debugging.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,23 @@ investigation:
uv run yada-trace TRACE.jsonl --events
```

For longer runs, generate a portable semantic view and open it directly in a
browser:

```bash
uv run yada-trace TRACE.jsonl --html
```

This writes `TRACE.html` beside the JSONL and opens it in the default browser.
Pass an explicit path after `--html` to export without opening it. The single
HTML file works offline and groups requests, reasoning, responses,
plans, tool calls/results, failures, and the final diff by step. Step filtering
runs locally in the browser. Large prompts, patches, and command output
are collapsed by default. The viewer preserves redaction from the JSONL and
cannot recover omitted or redacted fields.

[![Yada offline trace viewer](../assets/yada-trace-viewer.jpg)](../assets/yada-trace-viewer.jpg)

Then inspect exact records using the line references:

```bash
Expand Down
3 changes: 3 additions & 0 deletions src/yada/traces/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Trace persistence and human-readable run diagnostics."""

from yada.traces.html import render_trace_html, write_trace_html
from yada.traces.jsonl import TRACE_LEVELS, TRACE_SCHEMA_VERSION, TraceWriter
from yada.traces.report import (
LocatedTraceEvent,
Expand Down Expand Up @@ -27,5 +28,7 @@
"read_located_trace",
"read_trace",
"reconstruct_model_request",
"render_trace_html",
"render_trace_report",
"write_trace_html",
]
46 changes: 45 additions & 1 deletion src/yada/traces/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@

import argparse
import sys
import webbrowser
from pathlib import Path

from yada.traces.html import write_trace_html
from yada.traces.report import TraceFormatError, render_trace_report

_AUTO_HTML = object()


def build_parser() -> argparse.ArgumentParser:
"""Create the parser for the lightweight ``yada-trace`` command."""
Expand All @@ -32,6 +36,17 @@ def build_parser() -> argparse.ArgumentParser:
action="store_true",
help="Show the legacy flat event timeline with physical line numbers.",
)
parser.add_argument(
"--html",
nargs="?",
const=_AUTO_HTML,
type=Path,
metavar="PATH",
help=(
"Write a self-contained offline HTML viewer; omit PATH to write "
"beside TRACE and open it."
),
)
return parser


Expand All @@ -40,8 +55,30 @@ def run_cli(argv: list[str] | None = None) -> int:

args = build_parser().parse_args(argv)
try:
trace_path = args.trace.expanduser().resolve()
if args.html is not None:
if args.step is not None or args.verbose or args.events:
raise TraceFormatError(
"--html cannot be combined with --step, --verbose, or --events"
)
auto_open = args.html is _AUTO_HTML
output_path = (
trace_path.with_suffix(".html")
if auto_open
else args.html.expanduser().resolve()
)
write_trace_html(trace_path, output_path)
if auto_open and _open_html(output_path):
print(f"Wrote and opened offline trace viewer: {output_path}")
else:
print(f"Wrote offline trace viewer: {output_path}")
if auto_open:
print(
"Could not open it automatically; open the file in a browser."
)
return 0
report = render_trace_report(
args.trace.expanduser().resolve(),
trace_path,
step=args.step,
verbose=args.verbose,
events=args.events,
Expand All @@ -63,6 +100,13 @@ def _positive_step(value: str) -> int:
return step


def _open_html(path: Path) -> bool:
try:
return webbrowser.open(path.as_uri(), new=2)
except (OSError, webbrowser.Error):
return False


def main() -> None:
"""Console-script entry point."""

Expand Down
Loading