ablation-workbench 0.2.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.
- ablation_workbench-0.2.0/.gitignore +12 -0
- ablation_workbench-0.2.0/CHANGELOG.md +86 -0
- ablation_workbench-0.2.0/CONTRIBUTING.md +23 -0
- ablation_workbench-0.2.0/LICENSE +21 -0
- ablation_workbench-0.2.0/PKG-INFO +217 -0
- ablation_workbench-0.2.0/README.md +197 -0
- ablation_workbench-0.2.0/README.zh-CN.md +82 -0
- ablation_workbench-0.2.0/docs/implementation-contract.md +70 -0
- ablation_workbench-0.2.0/docs/release-review.md +64 -0
- ablation_workbench-0.2.0/hatch_build.py +9 -0
- ablation_workbench-0.2.0/package-lock.json +600 -0
- ablation_workbench-0.2.0/package.json +19 -0
- ablation_workbench-0.2.0/pyproject.toml +61 -0
- ablation_workbench-0.2.0/scripts/build-ui.cjs +21 -0
- ablation_workbench-0.2.0/scripts/vendor-voyage.cjs +15 -0
- ablation_workbench-0.2.0/skills/ablation/SKILL.md +46 -0
- ablation_workbench-0.2.0/skills/ablation/references/zh.md +46 -0
- ablation_workbench-0.2.0/src/ablation_workbench/__init__.py +3 -0
- ablation_workbench-0.2.0/src/ablation_workbench/__main__.py +3 -0
- ablation_workbench-0.2.0/src/ablation_workbench/cli.py +270 -0
- ablation_workbench-0.2.0/src/ablation_workbench/demo.py +26 -0
- ablation_workbench-0.2.0/src/ablation_workbench/engine.py +716 -0
- ablation_workbench-0.2.0/src/ablation_workbench/installation.py +59 -0
- ablation_workbench-0.2.0/src/ablation_workbench/models.py +144 -0
- ablation_workbench-0.2.0/src/ablation_workbench/observation.py +170 -0
- ablation_workbench-0.2.0/src/ablation_workbench/replay.py +243 -0
- ablation_workbench-0.2.0/src/ablation_workbench/runner.py +379 -0
- ablation_workbench-0.2.0/src/ablation_workbench/server.py +309 -0
- ablation_workbench-0.2.0/src/ablation_workbench/sources.py +360 -0
- ablation_workbench-0.2.0/src/ablation_workbench/storage.py +128 -0
- ablation_workbench-0.2.0/src/ablation_workbench/updates.py +198 -0
- ablation_workbench-0.2.0/src/ablation_workbench/web/app.js +769 -0
- ablation_workbench-0.2.0/src/ablation_workbench/web/bifrost-LICENSE.txt +201 -0
- ablation_workbench-0.2.0/src/ablation_workbench/web/bifrost-NOTICE.txt +21 -0
- ablation_workbench-0.2.0/src/ablation_workbench/web/favicon.svg +9 -0
- ablation_workbench-0.2.0/src/ablation_workbench/web/index.html +68 -0
- ablation_workbench-0.2.0/src/ablation_workbench/web/messages.css +1 -0
- ablation_workbench-0.2.0/src/ablation_workbench/web/messages.js +59 -0
- ablation_workbench-0.2.0/src/ablation_workbench/web/styles.css +252 -0
- ablation_workbench-0.2.0/src/ablation_workbench/web/theme.js +2 -0
- ablation_workbench-0.2.0/src/ablation_workbench/web/voyage-toolbar.js +50 -0
- ablation_workbench-0.2.0/src/ablation_workbench/web/voyage.css +2284 -0
- ablation_workbench-0.2.0/tests/browser_smoke.cjs +414 -0
- ablation_workbench-0.2.0/tests/messages.test.cjs +71 -0
- ablation_workbench-0.2.0/tests/test_cli.py +126 -0
- ablation_workbench-0.2.0/tests/test_engine.py +568 -0
- ablation_workbench-0.2.0/tests/test_installation.py +127 -0
- ablation_workbench-0.2.0/tests/test_observation.py +188 -0
- ablation_workbench-0.2.0/tests/test_release_workflows.py +49 -0
- ablation_workbench-0.2.0/tests/test_runner.py +276 -0
- ablation_workbench-0.2.0/tests/test_server.py +188 -0
- ablation_workbench-0.2.0/tests/test_sources.py +294 -0
- ablation_workbench-0.2.0/tests/test_updates.py +118 -0
- ablation_workbench-0.2.0/ui/appearance.js +27 -0
- ablation_workbench-0.2.0/ui/messages-data.cjs +88 -0
- ablation_workbench-0.2.0/ui/messages.jsx +63 -0
- ablation_workbench-0.2.0/ui/theme.js +8 -0
- ablation_workbench-0.2.0/ui/vendor/bifrost/messages.css +63 -0
- ablation_workbench-0.2.0/ui/vendor/bifrost/portable.tsx +34 -0
- ablation_workbench-0.2.0/ui/vendor/bifrost/responsesItemRow.tsx +435 -0
- ablation_workbench-0.2.0/ui/vendor/bifrost/responsesItems.ts +98 -0
- ablation_workbench-0.2.0/ui/voyage-toolbar.jsx +52 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
<!-- version list -->
|
|
4
|
+
|
|
5
|
+
## v0.2.0 (2026-10-28)
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- Preserve legacy review anchors with fixed baseline
|
|
10
|
+
([#2](https://github.com/yiminspace/ablation/pull/2),
|
|
11
|
+
[`3b76cd0`](https://github.com/yiminspace/ablation/commit/3b76cd09a53277fb384136ac88bc51e38b20326f))
|
|
12
|
+
|
|
13
|
+
- Resolve exact external logs for replay evidence
|
|
14
|
+
([#1](https://github.com/yiminspace/ablation/pull/1),
|
|
15
|
+
[`149fccf`](https://github.com/yiminspace/ablation/commit/149fccfa5d4444ee16771bd2c64f8134e12bc2be))
|
|
16
|
+
|
|
17
|
+
- 保留旧版评论并校验导入分组和长 diff ([#3](https://github.com/yiminspace/ablation/pull/3),
|
|
18
|
+
[`dcdf8c9`](https://github.com/yiminspace/ablation/commit/dcdf8c969f96186e17ce96a617f6bb42927a8dea))
|
|
19
|
+
|
|
20
|
+
- 等待外部日志入库后自动关联测试记录 ([#5](https://github.com/yiminspace/ablation/pull/5),
|
|
21
|
+
[`d76308e`](https://github.com/yiminspace/ablation/commit/d76308e431d61a8e8dba81fdbaa2a12466856e80))
|
|
22
|
+
|
|
23
|
+
### Documentation
|
|
24
|
+
|
|
25
|
+
- Require replay log association before handoff
|
|
26
|
+
([#8](https://github.com/yiminspace/ablation/pull/8),
|
|
27
|
+
[`1f839ba`](https://github.com/yiminspace/ablation/commit/1f839ba70a61fbd190a3612778897fdcdc80ede2))
|
|
28
|
+
|
|
29
|
+
- 对齐 ablation 中英文 skill 指引 ([#6](https://github.com/yiminspace/ablation/pull/6),
|
|
30
|
+
[`a771914`](https://github.com/yiminspace/ablation/commit/a771914a49c1ec3cc62b03e73df2033cf0b1e8ba))
|
|
31
|
+
|
|
32
|
+
- 补齐中文版 skill 元数据和对应结构 ([#7](https://github.com/yiminspace/ablation/pull/7),
|
|
33
|
+
[`31bf4d9`](https://github.com/yiminspace/ablation/commit/31bf4d9ed9cc7bd5859cf2df9e3afe29a007182f))
|
|
34
|
+
|
|
35
|
+
### Features
|
|
36
|
+
|
|
37
|
+
- Add complete replay history and detail drawers
|
|
38
|
+
([#9](https://github.com/yiminspace/ablation/pull/9),
|
|
39
|
+
[`c6b849e`](https://github.com/yiminspace/ablation/commit/c6b849e5ab28bc62c0836d4dcedeb4ee00d1535a))
|
|
40
|
+
|
|
41
|
+
- Simplify original request reviews and source links
|
|
42
|
+
([#2](https://github.com/yiminspace/ablation/pull/2),
|
|
43
|
+
[`3b76cd0`](https://github.com/yiminspace/ablation/commit/3b76cd09a53277fb384136ac88bc51e38b20326f))
|
|
44
|
+
|
|
45
|
+
- Simplify request review and link rationale to source
|
|
46
|
+
([#2](https://github.com/yiminspace/ablation/pull/2),
|
|
47
|
+
[`3b76cd0`](https://github.com/yiminspace/ablation/commit/3b76cd09a53277fb384136ac88bc51e38b20326f))
|
|
48
|
+
|
|
49
|
+
- 在实验标题下实时展示测试日志 ([#4](https://github.com/yiminspace/ablation/pull/4),
|
|
50
|
+
[`8905d67`](https://github.com/yiminspace/ablation/commit/8905d67e8ace99f023985c15605e3ea30e3e1b31))
|
|
51
|
+
|
|
52
|
+
- 对齐 Quarry 的自动发布与版本更新流程 ([#10](https://github.com/yiminspace/ablation/pull/10),
|
|
53
|
+
[`52949cd`](https://github.com/yiminspace/ablation/commit/52949cd16c67051e1adb57a20066eaed6b5042a6))
|
|
54
|
+
|
|
55
|
+
- 按需求分组审阅提示词改动并保留原文 diff ([#3](https://github.com/yiminspace/ablation/pull/3),
|
|
56
|
+
[`dcdf8c9`](https://github.com/yiminspace/ablation/commit/dcdf8c969f96186e17ce96a617f6bb42927a8dea))
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
## Unreleased
|
|
60
|
+
|
|
61
|
+
- Align releases and update discovery with Quarry: automatically version main commits, publish validated tagged packages to PyPI, and show periodic GUI update notifications with explicit upgrade commands and release notes.
|
|
62
|
+
|
|
63
|
+
- Group related prompt edits by requirement, with rationale, expected effects and GitHub source links; keep original line diffs and comment anchors available in both views.
|
|
64
|
+
|
|
65
|
+
- Show only candidate prompt changes in the default diff, with decoded text, line and word differences, collapsed context, without duplicate summaries or replay status; show modification rationale directly below the diff. Keep input history and scenario changes in the full request evidence.
|
|
66
|
+
|
|
67
|
+
- Add optional platform-neutral replay tracing headers, response ID/link extraction, and independently authenticated log lookups.
|
|
68
|
+
- Save external evidence with each run and display log links in the GUI without treating association failure as model failure.
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
## 0.1.0 — development preview
|
|
72
|
+
|
|
73
|
+
Initial open-source preview, distributed through GitHub Releases. This preview did not publish to PyPI or enable registry updates.
|
|
74
|
+
|
|
75
|
+
- Import request files, JSON logs, and HTTP captures into portable experiments, with configurable source endpoints and field mappings.
|
|
76
|
+
- Preserve source evidence, normalization notes, candidates, synthetic scenarios, model outputs, and assertion results.
|
|
77
|
+
- Review prompt, input, request, response, and check differences in a local GitHub-style interface.
|
|
78
|
+
- Focus the initial view on prompt changes and rationale, with detailed evidence and comparison settings available on demand.
|
|
79
|
+
- Submit anchored comments, copy a portable handoff, or dispatch a configured local agent.
|
|
80
|
+
- Keep explanations in the current review and retain candidate history for requested changes.
|
|
81
|
+
- Preserve historical failure counts and let follow-up questions reference previously reviewed responses after another replay.
|
|
82
|
+
- Reject credential-bearing request patches and source URL queries, and validate imported experiment bundles before saving.
|
|
83
|
+
- Record oversized replay results as execution errors and terminate remaining Agent child processes on cancellation.
|
|
84
|
+
- Provide cached update discovery, explicit package-manager upgrades, and offline release notes.
|
|
85
|
+
|
|
86
|
+
Replays call a configured model endpoint. Returned tool calls are recorded but never executed. Agent execution is tested with local stubs; no real-model behavior or desktop-chat wakeup is claimed.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Use Python 3.11 or newer. Install the source into an isolated environment:
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
python -m venv .venv
|
|
7
|
+
.venv/bin/python -m pip install -e .
|
|
8
|
+
PYTHONPATH=src .venv/bin/python -m unittest discover -s tests -v
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Keep inference and agent tests offline: use local HTTP fixtures and child-process stubs. Do not check in captured company logs, credentials, personal filesystem paths, or model outputs containing private data. Synthetic demo results must remain visibly labelled.
|
|
12
|
+
|
|
13
|
+
CLI and GUI share the experiment engine. Changes to experiment formats need a migration or explicit version rejection, and a regression test using an older fixture. Comments bind to the reviewed content; explanation-only reviews must not silently create candidates or replays.
|
|
14
|
+
|
|
15
|
+
Use conventional commit titles (`feat:`, `fix:`, `docs:`, `test:`, `chore:`) and describe observable behavior and validation in pull requests. Update `CHANGELOG.md` for user-visible changes.
|
|
16
|
+
|
|
17
|
+
## Releases
|
|
18
|
+
|
|
19
|
+
Main commits use conventional commit titles. Semantic Release automatically updates the package version and changelog, creates the matching tag and GitHub Release, and dispatches the PyPI publication workflow, following Quarry's release pipeline.
|
|
20
|
+
|
|
21
|
+
Publication validates that exact tag through CI, builds the bundled UI and Python distributions, and rejects a package/tag mismatch before uploading. Manual dispatch remains available for an exact tag or a one-off forced version bump. Before the first publication, configure the `ablation-workbench` PyPI trusted publisher for `yiminspace/ablation`, `release.yml`, and the GitHub `pypi` environment. A local build does not publish anything.
|
|
22
|
+
|
|
23
|
+
Installed GUIs check PyPI in the background and show the upgrade command and release notes. They never install an update automatically. Source/editable installs skip checks; `ABLATION_UPDATE_CHECK=0` disables them. Restart the GUI after upgrading. Package upgrades do not install or synchronize personal skills. Release verification details are in [the release checklist](docs/release-review.md).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ablation contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: ablation-workbench
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: A local CLI and review GUI for reproducible prompt experiments
|
|
5
|
+
Project-URL: Homepage, https://github.com/yiminspace/ablation
|
|
6
|
+
Project-URL: Repository, https://github.com/yiminspace/ablation
|
|
7
|
+
Project-URL: Issues, https://github.com/yiminspace/ablation/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/yiminspace/ablation/blob/main/CHANGELOG.md
|
|
9
|
+
Author: Ablation contributors
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# Ablation
|
|
22
|
+
|
|
23
|
+
A local prompt debugging workbench. Import a model request or captured log, change a prompt, replay comparable cases, and review the evidence with GitHub-style diffs and inline discussions.
|
|
24
|
+
|
|
25
|
+
The CLI and browser GUI share one experiment store. The optional Agent skill uses conversation context to find the source; users can simply ask **“Use ablation to investigate this request.”** Import request files, exported logs, or HTTP captures, and configure field mappings for your source format.
|
|
26
|
+
|
|
27
|
+
[中文说明](README.zh-CN.md) · [Interface contract](docs/implementation-contract.md) · [Contributing](CONTRIBUTING.md) · [MIT license](LICENSE)
|
|
28
|
+
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
Supports macOS and Linux with Python 3.11 or later. The GUI is included; end users do not need Node.js. Versioned releases are distributed through PyPI and [GitHub Releases](https://github.com/yiminspace/ablation/releases). The first PyPI publication requires the repository trusted publisher described in the release checklist.
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
pipx install ablation-workbench
|
|
35
|
+
ablation --version
|
|
36
|
+
ablation demo --open
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Alternatively, `uv tool install ablation-workbench`, or download the wheel from GitHub Releases and run `uv tool install /path/to/ablation_workbench-0.1.0-py3-none-any.whl`. For development use `python -m venv .venv` followed by `.venv/bin/python -m pip install -e .`.
|
|
40
|
+
|
|
41
|
+
The demo uses synthetic inputs and makes no model requests. Its initial output panel is explicitly untested. It includes an over-specific candidate and a more general candidate to demonstrate comparisons without presenting fabricated performance claims.
|
|
42
|
+
|
|
43
|
+
## From a request to an experiment
|
|
44
|
+
|
|
45
|
+
Keep connection configuration and experiments in a workspace:
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
ablation --workspace ./experiments init
|
|
49
|
+
ablation --workspace ./experiments config profile model \
|
|
50
|
+
--base-url https://model.example.invalid \
|
|
51
|
+
--api-key-env MODEL_API_KEY
|
|
52
|
+
|
|
53
|
+
ablation --workspace ./experiments import request.json --format request
|
|
54
|
+
ablation --workspace ./experiments gui
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The example addresses are placeholders. Replace them with your own endpoints and supply credentials through the named environment variables. Configuration stores variable names, not secret values. Source retrieval and model inference use separate endpoint and credential settings.
|
|
58
|
+
|
|
59
|
+
Choose an explicit import format:
|
|
60
|
+
|
|
61
|
+
| Format | Input |
|
|
62
|
+
| --- | --- |
|
|
63
|
+
| `request` (default) | A Responses API or Chat Completions request object. Use `--response response.json` to attach a historical response. |
|
|
64
|
+
| `capture` | A JSON envelope containing `request` and optionally `response`; an HTTP envelope can place each JSON body in its `body` field. |
|
|
65
|
+
| `log` | A JSON log with request fields in `params`, optionally overridden by top-level `model`, `input`, `messages`, and `tools`; `response` is optional. Use mapping settings for other shapes. |
|
|
66
|
+
|
|
67
|
+
You can upload JSON through the GUI or pass a file or `-` for stdin to `ablation import`. Original evidence is retained separately from the replay request. Normalization notes and the source diff disclose reconstruction; missing mapped fields are errors rather than silently invented values.
|
|
68
|
+
|
|
69
|
+
For a log shaped as `{"payload":{"request":{...},"response":{...}}}`, configure JSON Pointers to those objects. The same mapping applies to a local export or a remote JSON API:
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
ablation --workspace ./experiments config profile logs \
|
|
73
|
+
--source-base-url https://logs.example.invalid \
|
|
74
|
+
--source-path '/records/{ref}' \
|
|
75
|
+
--source-request-pointer /payload/request \
|
|
76
|
+
--source-response-pointer /payload/response \
|
|
77
|
+
--token-env LOGS_TOKEN
|
|
78
|
+
|
|
79
|
+
ablation --workspace ./experiments import source-log.json --format log --profile logs
|
|
80
|
+
ablation --workspace ./experiments import record-123 --ref --format log --profile logs
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Omit `--source-response-pointer` when your export has no response. To map individual request fields, use `--source-fields-json '{"model":"/metadata/model","input":"/payload/messages"}'`; each pointer starts at the original source root and explicitly overrides that top-level request field. Fields in the selected request object or `params` remain intact unless explicitly overridden; other source fields remain in the original evidence.
|
|
84
|
+
|
|
85
|
+
Remote imports require an explicit `--source-base-url`. Supply a full JSON URL on the same origin, or a reference resolved by the configured `--source-path` template. `--ref` forces a positional value to be treated as a reference instead of a local file. Source authentication uses either `--token-env` or the pair `--source-user-env` / `--source-password-env`. It never falls back to the inference API key. A webpage sharing link is not necessarily a JSON endpoint; export its data with an existing tool, then import that JSON. Replay can independently use the `model` profile.
|
|
86
|
+
|
|
87
|
+
## Change, replay, compare
|
|
88
|
+
|
|
89
|
+
Candidates are immutable JSON patches with a rationale. Keep the explanation concise: why the change helps, then where it belongs and what it affects. Add verified GitHub source links using Markdown; identify unconfirmed locations or origins explicitly. Scenarios independently describe changed inputs and their expected behavior. Every candidate is derived from the fixed source; prior model responses never become the next baseline automatically.
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
[
|
|
93
|
+
{
|
|
94
|
+
"op": "replace",
|
|
95
|
+
"path": "/instructions",
|
|
96
|
+
"value": "Summarize the supplied evidence in three concise bullets. State when a requested fact is missing."
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Save that as `candidate.json`. Pass explanation text with `--rationale`, or use `--rationale-file rationale.md` to preserve multiline UTF-8 text and source links. Both store the same rationale displayed below the GUI diff. Then:
|
|
102
|
+
|
|
103
|
+
```sh
|
|
104
|
+
ablation --workspace ./experiments candidate EXPERIMENT_ID \
|
|
105
|
+
--label 'Concise evidence summary' --patch candidate.json \
|
|
106
|
+
--rationale 'Specify output structure and how to handle missing information.'
|
|
107
|
+
|
|
108
|
+
ablation --workspace ./experiments run EXPERIMENT_ID \
|
|
109
|
+
--candidate baseline --candidate CANDIDATE_ID \
|
|
110
|
+
--scenario original --repeats 3 --profile model
|
|
111
|
+
|
|
112
|
+
ablation --workspace ./experiments diff EXPERIMENT_ID \
|
|
113
|
+
--candidate CANDIDATE_ID --artifact response
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The GUI offers the same candidate/scenario creation and replay controls. Runs save the actual request, response, request hash, timing and assertion results. Compare prompt, scenario input, full request, response, checks, and source reconstruction. HTTP failures are separate from failed assertions. A run without checks is **unscored**, not passing. Repetition counts are not independent scenario counts or statistical reliability claims.
|
|
117
|
+
|
|
118
|
+
The initial view fixes the imported original request on the left and shows the modified request on the right. Both sides retain the original JSON structure and field order. Instructions, tool descriptions, and input-message changes appear together, with unchanged context collapsed. Older versions and candidate/scenario creation live in **运行记录**. The main view contains only actual changes and model outputs.
|
|
119
|
+
|
|
120
|
+
The summary counts historical runs for the selected versions and scenario, so a later passing replay does not hide earlier failures. The response diff shows the latest completed outputs; inspect individual runs for earlier evidence.
|
|
121
|
+
|
|
122
|
+
The sidebar starts collapsed and lists saved experiment sessions by title and full session ID, with search and replay counts. Each session retains all replay batches, scenarios, repeats, outcomes, and log links. The initial view prioritizes the diff, with the complete batch history on the later **运行记录** tab; **运行记录** lists all runs compactly. Clicking anywhere on a batch row opens a narrow, full-height right drawer with Messages, checks, and raw JSON views. A selector switches between the runs in that batch. Its timeline includes recorded inputs, tool calls/results, screenshot thumbnails that open at full size, and the new model output. Opening a run positions the timeline at its highlighted new output; a locate button returns to it. The timeline adapts Bifrost's Apache-2.0 components; the pinned source, modifications, and license ship with the web assets. External log links remain available for provenance. The GUI uses Voyage components with GitHub as the default theme. The top-right standard VoyageToolbar provides light/dark and theme selection. Its feedback and language placeholders remain disabled until those product capabilities are configured. All styles and the toolbar are bundled locally for offline use; `npm run build:ui` synchronizes the pinned assets and `npm run check:ui` verifies them.
|
|
123
|
+
|
|
124
|
+
Replay invokes a single model request. Returned tool calls are inspected as data and never executed. A model response does not prove that an external action occurred.
|
|
125
|
+
|
|
126
|
+
## Optional external log tracking
|
|
127
|
+
|
|
128
|
+
Replay profiles may configure independent observers through `config profile NAME --observers-json observers.json`. The file is an array, so a request passing through a proxy and a model gateway can retain both records. No tracking headers or external lookups are enabled by default.
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
[
|
|
132
|
+
{
|
|
133
|
+
"name": "Gateway logs",
|
|
134
|
+
"headers": {"X-Trace-Id": "{run_id}"},
|
|
135
|
+
"record_id_header": "X-Request-Id",
|
|
136
|
+
"url_template": "https://logs.example.invalid/records/{record_id}"
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"name": "Capture proxy",
|
|
140
|
+
"record_id_pointer": "/capture/entry_id",
|
|
141
|
+
"url_pointer": "/capture/view_url"
|
|
142
|
+
}
|
|
143
|
+
]
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
These are synthetic examples; select header names, response fields, and URL routes documented by your service. `headers` templates accept `{experiment_id}`, `{batch_id}`, and `{run_id}`. They cannot override authentication or transport headers. Response extraction supports JSON Pointers (`record_id_pointer`, `url_pointer`) and case-insensitive HTTP headers (`record_id_header`, `url_header`). Use `request_id_pointer` or `request_id_header` for transport correlation IDs that are not external log IDs; they remain separate and can be used as `{request_id}` in lookup templates. `url_template` and optional `batch_url_template` also accept `{record_id}`, `{response_id}`, `{start_time}`, and `{end_time}` (Unix seconds bounding this run); substituted values are URL-encoded. Escape literal JSON braces in templates as `{{` and `}}`.
|
|
147
|
+
|
|
148
|
+
For Bifrost, inject a unique run metadata header and configure an exact lookup against that metadata. Extract the actual log ID and construct its `selected_log` detail URL; do not use the transport `x-request-id` as the log ID. A metadata-filter search URL is only a list entry point. A TapeProxy target can extract an entry reference from its documented response header or API. Platform names are labels, not built-in routing: another service uses the same mappings without changing the replay engine.
|
|
149
|
+
|
|
150
|
+
An optional `lookup` reads a separate JSON log API after inference. It requires `source_base_url`, a relative `source_path` template, `match_pointer`, and `match_value`. Optional `records_pointer` selects the record array; `record_id_pointer` and `url_pointer` extract the uniquely matched record. Lookup authentication uses its own `token_env` or `source_user_env` / `source_password_env`, never the inference API key. For example:
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"name": "Separate log service",
|
|
155
|
+
"headers": {"X-Trace-Id": "{run_id}"},
|
|
156
|
+
"lookup": {
|
|
157
|
+
"source_base_url": "https://logs.example.invalid",
|
|
158
|
+
"source_path": "/api/logs?trace={run_id}",
|
|
159
|
+
"token_env": "LOG_READ_TOKEN",
|
|
160
|
+
"records_pointer": "/records",
|
|
161
|
+
"match_pointer": "/trace_id",
|
|
162
|
+
"match_value": "{run_id}",
|
|
163
|
+
"record_id_pointer": "/id"
|
|
164
|
+
},
|
|
165
|
+
"url_template": "https://logs.example.invalid/records/{record_id}"
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
A configured lookup is authoritative even when response extraction returns an ID or URL. Each lookup request has a 5-second timeout, requires one exact match, and follows no redirects. For delayed ingestion, set lookup `attempts` (1–5, default 1) and `interval_seconds` (0–5, default 1); only an empty exact-match result is retried, while ambiguous matches and request failures stop immediately. Missing or failed association is recorded as `unavailable` without changing the model result or assertion score. `available` means a record ID or link was obtained from the configured response or matching API record; `linked` means only a search/view URL was constructed, not that a log exists or is accessible.
|
|
170
|
+
|
|
171
|
+
Runs retain local tracking IDs, the injected non-secret headers, selected response headers, an observer configuration snapshot, and `external_evidence` records with `platform`, `status`, and optional `request_id`, `record_id`, `url`, `batch_url`, or `error`. The GUI displays links in run history and details; CLI JSON and exported bundles retain the same evidence. Profiles without observers still retain the model response ID and standard request-ID headers when supplied. Historical runs remain unchanged and import without the new optional fields.
|
|
172
|
+
|
|
173
|
+
## Review and continue
|
|
174
|
+
|
|
175
|
+
Click a diff line's **+**, add a comment, then finish the review. Comments retain the reviewed version, scenario, location and before/after snippets.
|
|
176
|
+
|
|
177
|
+
Use **继续追问** to ask about an existing comment. The follow-up preserves its original snapshot even if a newer replay has changed the response. Unsaved comments on changed responses still require reconciliation before submission.
|
|
178
|
+
|
|
179
|
+
- **复制到对话** (Copy to conversation) saves the review and copies a portable handoff. Paste it into the current Agent conversation. The handoff includes commands for writing an answer back to the experiment.
|
|
180
|
+
- **交给 Agent** (Send to Agent) invokes the configured local Agent and records a job. Configure Codex once with `ablation agent configure --backend codex --cwd /path/to/project`. Other Agents can use a trusted argv command that receives the handoff on stdin: `--backend command --command-json '["executable","argument"]'`.
|
|
181
|
+
|
|
182
|
+
**追问解释** (Comment) requests explanation only. Its replies appear below the reviewed change and do not produce a new candidate or replay. **请求修改** (Request changes) authorizes a new candidate and the requested verification within the experiment. Applying changes to a business repository remains an explicit user task for the Agent; this tool does not guess which source file generated a request field.
|
|
183
|
+
|
|
184
|
+
```sh
|
|
185
|
+
ablation review text EXPERIMENT_ID REVIEW_ID
|
|
186
|
+
ablation review reply EXPERIMENT_ID REVIEW_ID --comment-index 0 \
|
|
187
|
+
--text 'This change makes the output format explicit while keeping the same source evidence.'
|
|
188
|
+
ablation review dispatch EXPERIMENT_ID REVIEW_ID
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
CLI dispatch waits until completion; Ctrl-C requests cancellation. The GUI shows progress, errors and cancellation. A completed Agent process is not a passing replay: inspect the resulting experiment evidence. The runner manages its own CLI sessions; it does not claim to wake an existing desktop chat.
|
|
192
|
+
|
|
193
|
+
## Portable skill
|
|
194
|
+
|
|
195
|
+
Copy `skills/ablation` into your Agent's supported skill directory. The skill supplies context selection, experiment design and result interpretation; the executable supplies mechanics and also works without a skill. Skill installation and synchronization are not performed automatically.
|
|
196
|
+
|
|
197
|
+
## Persistence and updates
|
|
198
|
+
|
|
199
|
+
The default workspace is `~/.local/share/ablation`; override it with `--workspace` or `ABLATION_WORKSPACE`. Experiments and review replies persist on disk. `ablation export EXPERIMENT_ID --out experiment.json` and `ablation import-bundle experiment.json` move experiments between workspaces; imports get new IDs and retain provenance.
|
|
200
|
+
|
|
201
|
+
Software versions, experiment schema versions and candidate IDs are separate. Historical request/response records remain unchanged when software updates. Credentials remain in your environment. Exported evidence can contain prompt content and model responses; review the bundle before sharing it.
|
|
202
|
+
|
|
203
|
+
The GUI checks PyPI in the background, caches checks for 24 hours, and displays a newer version with an installation-aware upgrade command and release-note link. It does not install updates automatically. Editable/source-checkout installations are skipped; set `ABLATION_UPDATE_CHECK=0` to disable checks. `ablation update-check` reports availability, and an unavailable registry is not proof that the installed version is current. `ablation upgrade` shows the installation-aware plan; `ablation upgrade --yes` remains an explicit CLI operation and refuses to run while jobs are active. Restart the local GUI after upgrading. The changelog is bundled for offline viewing.
|
|
204
|
+
|
|
205
|
+
CLI stdout is JSON except for human review handoffs, changelogs and help. Errors go to stderr. Exit codes: `0` completed command (including unscored replay), `2` invalid input/configuration, `3` replay assertions failed, `4` execution or transport failure, `130` cancelled. Inspect saved per-run evidence even when the command returns nonzero.
|
|
206
|
+
|
|
207
|
+
## Development checks
|
|
208
|
+
|
|
209
|
+
```sh
|
|
210
|
+
PYTHONPATH=src python -m unittest discover -s tests -v
|
|
211
|
+
python -m pip wheel --no-deps . -w dist
|
|
212
|
+
npm ci
|
|
213
|
+
npx playwright install chromium
|
|
214
|
+
npm run test:browser
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Tests use synthetic fixtures and local source, model, and Agent substitutes. They do not establish compatibility with a particular live data service, model account, or desktop chat integration. Browser verification and release review details belong in `docs/release-review.md`.
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# Ablation
|
|
2
|
+
|
|
3
|
+
A local prompt debugging workbench. Import a model request or captured log, change a prompt, replay comparable cases, and review the evidence with GitHub-style diffs and inline discussions.
|
|
4
|
+
|
|
5
|
+
The CLI and browser GUI share one experiment store. The optional Agent skill uses conversation context to find the source; users can simply ask **“Use ablation to investigate this request.”** Import request files, exported logs, or HTTP captures, and configure field mappings for your source format.
|
|
6
|
+
|
|
7
|
+
[中文说明](README.zh-CN.md) · [Interface contract](docs/implementation-contract.md) · [Contributing](CONTRIBUTING.md) · [MIT license](LICENSE)
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
Supports macOS and Linux with Python 3.11 or later. The GUI is included; end users do not need Node.js. Versioned releases are distributed through PyPI and [GitHub Releases](https://github.com/yiminspace/ablation/releases). The first PyPI publication requires the repository trusted publisher described in the release checklist.
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
pipx install ablation-workbench
|
|
15
|
+
ablation --version
|
|
16
|
+
ablation demo --open
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Alternatively, `uv tool install ablation-workbench`, or download the wheel from GitHub Releases and run `uv tool install /path/to/ablation_workbench-0.1.0-py3-none-any.whl`. For development use `python -m venv .venv` followed by `.venv/bin/python -m pip install -e .`.
|
|
20
|
+
|
|
21
|
+
The demo uses synthetic inputs and makes no model requests. Its initial output panel is explicitly untested. It includes an over-specific candidate and a more general candidate to demonstrate comparisons without presenting fabricated performance claims.
|
|
22
|
+
|
|
23
|
+
## From a request to an experiment
|
|
24
|
+
|
|
25
|
+
Keep connection configuration and experiments in a workspace:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
ablation --workspace ./experiments init
|
|
29
|
+
ablation --workspace ./experiments config profile model \
|
|
30
|
+
--base-url https://model.example.invalid \
|
|
31
|
+
--api-key-env MODEL_API_KEY
|
|
32
|
+
|
|
33
|
+
ablation --workspace ./experiments import request.json --format request
|
|
34
|
+
ablation --workspace ./experiments gui
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The example addresses are placeholders. Replace them with your own endpoints and supply credentials through the named environment variables. Configuration stores variable names, not secret values. Source retrieval and model inference use separate endpoint and credential settings.
|
|
38
|
+
|
|
39
|
+
Choose an explicit import format:
|
|
40
|
+
|
|
41
|
+
| Format | Input |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| `request` (default) | A Responses API or Chat Completions request object. Use `--response response.json` to attach a historical response. |
|
|
44
|
+
| `capture` | A JSON envelope containing `request` and optionally `response`; an HTTP envelope can place each JSON body in its `body` field. |
|
|
45
|
+
| `log` | A JSON log with request fields in `params`, optionally overridden by top-level `model`, `input`, `messages`, and `tools`; `response` is optional. Use mapping settings for other shapes. |
|
|
46
|
+
|
|
47
|
+
You can upload JSON through the GUI or pass a file or `-` for stdin to `ablation import`. Original evidence is retained separately from the replay request. Normalization notes and the source diff disclose reconstruction; missing mapped fields are errors rather than silently invented values.
|
|
48
|
+
|
|
49
|
+
For a log shaped as `{"payload":{"request":{...},"response":{...}}}`, configure JSON Pointers to those objects. The same mapping applies to a local export or a remote JSON API:
|
|
50
|
+
|
|
51
|
+
```sh
|
|
52
|
+
ablation --workspace ./experiments config profile logs \
|
|
53
|
+
--source-base-url https://logs.example.invalid \
|
|
54
|
+
--source-path '/records/{ref}' \
|
|
55
|
+
--source-request-pointer /payload/request \
|
|
56
|
+
--source-response-pointer /payload/response \
|
|
57
|
+
--token-env LOGS_TOKEN
|
|
58
|
+
|
|
59
|
+
ablation --workspace ./experiments import source-log.json --format log --profile logs
|
|
60
|
+
ablation --workspace ./experiments import record-123 --ref --format log --profile logs
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Omit `--source-response-pointer` when your export has no response. To map individual request fields, use `--source-fields-json '{"model":"/metadata/model","input":"/payload/messages"}'`; each pointer starts at the original source root and explicitly overrides that top-level request field. Fields in the selected request object or `params` remain intact unless explicitly overridden; other source fields remain in the original evidence.
|
|
64
|
+
|
|
65
|
+
Remote imports require an explicit `--source-base-url`. Supply a full JSON URL on the same origin, or a reference resolved by the configured `--source-path` template. `--ref` forces a positional value to be treated as a reference instead of a local file. Source authentication uses either `--token-env` or the pair `--source-user-env` / `--source-password-env`. It never falls back to the inference API key. A webpage sharing link is not necessarily a JSON endpoint; export its data with an existing tool, then import that JSON. Replay can independently use the `model` profile.
|
|
66
|
+
|
|
67
|
+
## Change, replay, compare
|
|
68
|
+
|
|
69
|
+
Candidates are immutable JSON patches with a rationale. Keep the explanation concise: why the change helps, then where it belongs and what it affects. Add verified GitHub source links using Markdown; identify unconfirmed locations or origins explicitly. Scenarios independently describe changed inputs and their expected behavior. Every candidate is derived from the fixed source; prior model responses never become the next baseline automatically.
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
[
|
|
73
|
+
{
|
|
74
|
+
"op": "replace",
|
|
75
|
+
"path": "/instructions",
|
|
76
|
+
"value": "Summarize the supplied evidence in three concise bullets. State when a requested fact is missing."
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Save that as `candidate.json`. Pass explanation text with `--rationale`, or use `--rationale-file rationale.md` to preserve multiline UTF-8 text and source links. Both store the same rationale displayed below the GUI diff. Then:
|
|
82
|
+
|
|
83
|
+
```sh
|
|
84
|
+
ablation --workspace ./experiments candidate EXPERIMENT_ID \
|
|
85
|
+
--label 'Concise evidence summary' --patch candidate.json \
|
|
86
|
+
--rationale 'Specify output structure and how to handle missing information.'
|
|
87
|
+
|
|
88
|
+
ablation --workspace ./experiments run EXPERIMENT_ID \
|
|
89
|
+
--candidate baseline --candidate CANDIDATE_ID \
|
|
90
|
+
--scenario original --repeats 3 --profile model
|
|
91
|
+
|
|
92
|
+
ablation --workspace ./experiments diff EXPERIMENT_ID \
|
|
93
|
+
--candidate CANDIDATE_ID --artifact response
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The GUI offers the same candidate/scenario creation and replay controls. Runs save the actual request, response, request hash, timing and assertion results. Compare prompt, scenario input, full request, response, checks, and source reconstruction. HTTP failures are separate from failed assertions. A run without checks is **unscored**, not passing. Repetition counts are not independent scenario counts or statistical reliability claims.
|
|
97
|
+
|
|
98
|
+
The initial view fixes the imported original request on the left and shows the modified request on the right. Both sides retain the original JSON structure and field order. Instructions, tool descriptions, and input-message changes appear together, with unchanged context collapsed. Older versions and candidate/scenario creation live in **运行记录**. The main view contains only actual changes and model outputs.
|
|
99
|
+
|
|
100
|
+
The summary counts historical runs for the selected versions and scenario, so a later passing replay does not hide earlier failures. The response diff shows the latest completed outputs; inspect individual runs for earlier evidence.
|
|
101
|
+
|
|
102
|
+
The sidebar starts collapsed and lists saved experiment sessions by title and full session ID, with search and replay counts. Each session retains all replay batches, scenarios, repeats, outcomes, and log links. The initial view prioritizes the diff, with the complete batch history on the later **运行记录** tab; **运行记录** lists all runs compactly. Clicking anywhere on a batch row opens a narrow, full-height right drawer with Messages, checks, and raw JSON views. A selector switches between the runs in that batch. Its timeline includes recorded inputs, tool calls/results, screenshot thumbnails that open at full size, and the new model output. Opening a run positions the timeline at its highlighted new output; a locate button returns to it. The timeline adapts Bifrost's Apache-2.0 components; the pinned source, modifications, and license ship with the web assets. External log links remain available for provenance. The GUI uses Voyage components with GitHub as the default theme. The top-right standard VoyageToolbar provides light/dark and theme selection. Its feedback and language placeholders remain disabled until those product capabilities are configured. All styles and the toolbar are bundled locally for offline use; `npm run build:ui` synchronizes the pinned assets and `npm run check:ui` verifies them.
|
|
103
|
+
|
|
104
|
+
Replay invokes a single model request. Returned tool calls are inspected as data and never executed. A model response does not prove that an external action occurred.
|
|
105
|
+
|
|
106
|
+
## Optional external log tracking
|
|
107
|
+
|
|
108
|
+
Replay profiles may configure independent observers through `config profile NAME --observers-json observers.json`. The file is an array, so a request passing through a proxy and a model gateway can retain both records. No tracking headers or external lookups are enabled by default.
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
[
|
|
112
|
+
{
|
|
113
|
+
"name": "Gateway logs",
|
|
114
|
+
"headers": {"X-Trace-Id": "{run_id}"},
|
|
115
|
+
"record_id_header": "X-Request-Id",
|
|
116
|
+
"url_template": "https://logs.example.invalid/records/{record_id}"
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"name": "Capture proxy",
|
|
120
|
+
"record_id_pointer": "/capture/entry_id",
|
|
121
|
+
"url_pointer": "/capture/view_url"
|
|
122
|
+
}
|
|
123
|
+
]
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
These are synthetic examples; select header names, response fields, and URL routes documented by your service. `headers` templates accept `{experiment_id}`, `{batch_id}`, and `{run_id}`. They cannot override authentication or transport headers. Response extraction supports JSON Pointers (`record_id_pointer`, `url_pointer`) and case-insensitive HTTP headers (`record_id_header`, `url_header`). Use `request_id_pointer` or `request_id_header` for transport correlation IDs that are not external log IDs; they remain separate and can be used as `{request_id}` in lookup templates. `url_template` and optional `batch_url_template` also accept `{record_id}`, `{response_id}`, `{start_time}`, and `{end_time}` (Unix seconds bounding this run); substituted values are URL-encoded. Escape literal JSON braces in templates as `{{` and `}}`.
|
|
127
|
+
|
|
128
|
+
For Bifrost, inject a unique run metadata header and configure an exact lookup against that metadata. Extract the actual log ID and construct its `selected_log` detail URL; do not use the transport `x-request-id` as the log ID. A metadata-filter search URL is only a list entry point. A TapeProxy target can extract an entry reference from its documented response header or API. Platform names are labels, not built-in routing: another service uses the same mappings without changing the replay engine.
|
|
129
|
+
|
|
130
|
+
An optional `lookup` reads a separate JSON log API after inference. It requires `source_base_url`, a relative `source_path` template, `match_pointer`, and `match_value`. Optional `records_pointer` selects the record array; `record_id_pointer` and `url_pointer` extract the uniquely matched record. Lookup authentication uses its own `token_env` or `source_user_env` / `source_password_env`, never the inference API key. For example:
|
|
131
|
+
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"name": "Separate log service",
|
|
135
|
+
"headers": {"X-Trace-Id": "{run_id}"},
|
|
136
|
+
"lookup": {
|
|
137
|
+
"source_base_url": "https://logs.example.invalid",
|
|
138
|
+
"source_path": "/api/logs?trace={run_id}",
|
|
139
|
+
"token_env": "LOG_READ_TOKEN",
|
|
140
|
+
"records_pointer": "/records",
|
|
141
|
+
"match_pointer": "/trace_id",
|
|
142
|
+
"match_value": "{run_id}",
|
|
143
|
+
"record_id_pointer": "/id"
|
|
144
|
+
},
|
|
145
|
+
"url_template": "https://logs.example.invalid/records/{record_id}"
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
A configured lookup is authoritative even when response extraction returns an ID or URL. Each lookup request has a 5-second timeout, requires one exact match, and follows no redirects. For delayed ingestion, set lookup `attempts` (1–5, default 1) and `interval_seconds` (0–5, default 1); only an empty exact-match result is retried, while ambiguous matches and request failures stop immediately. Missing or failed association is recorded as `unavailable` without changing the model result or assertion score. `available` means a record ID or link was obtained from the configured response or matching API record; `linked` means only a search/view URL was constructed, not that a log exists or is accessible.
|
|
150
|
+
|
|
151
|
+
Runs retain local tracking IDs, the injected non-secret headers, selected response headers, an observer configuration snapshot, and `external_evidence` records with `platform`, `status`, and optional `request_id`, `record_id`, `url`, `batch_url`, or `error`. The GUI displays links in run history and details; CLI JSON and exported bundles retain the same evidence. Profiles without observers still retain the model response ID and standard request-ID headers when supplied. Historical runs remain unchanged and import without the new optional fields.
|
|
152
|
+
|
|
153
|
+
## Review and continue
|
|
154
|
+
|
|
155
|
+
Click a diff line's **+**, add a comment, then finish the review. Comments retain the reviewed version, scenario, location and before/after snippets.
|
|
156
|
+
|
|
157
|
+
Use **继续追问** to ask about an existing comment. The follow-up preserves its original snapshot even if a newer replay has changed the response. Unsaved comments on changed responses still require reconciliation before submission.
|
|
158
|
+
|
|
159
|
+
- **复制到对话** (Copy to conversation) saves the review and copies a portable handoff. Paste it into the current Agent conversation. The handoff includes commands for writing an answer back to the experiment.
|
|
160
|
+
- **交给 Agent** (Send to Agent) invokes the configured local Agent and records a job. Configure Codex once with `ablation agent configure --backend codex --cwd /path/to/project`. Other Agents can use a trusted argv command that receives the handoff on stdin: `--backend command --command-json '["executable","argument"]'`.
|
|
161
|
+
|
|
162
|
+
**追问解释** (Comment) requests explanation only. Its replies appear below the reviewed change and do not produce a new candidate or replay. **请求修改** (Request changes) authorizes a new candidate and the requested verification within the experiment. Applying changes to a business repository remains an explicit user task for the Agent; this tool does not guess which source file generated a request field.
|
|
163
|
+
|
|
164
|
+
```sh
|
|
165
|
+
ablation review text EXPERIMENT_ID REVIEW_ID
|
|
166
|
+
ablation review reply EXPERIMENT_ID REVIEW_ID --comment-index 0 \
|
|
167
|
+
--text 'This change makes the output format explicit while keeping the same source evidence.'
|
|
168
|
+
ablation review dispatch EXPERIMENT_ID REVIEW_ID
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
CLI dispatch waits until completion; Ctrl-C requests cancellation. The GUI shows progress, errors and cancellation. A completed Agent process is not a passing replay: inspect the resulting experiment evidence. The runner manages its own CLI sessions; it does not claim to wake an existing desktop chat.
|
|
172
|
+
|
|
173
|
+
## Portable skill
|
|
174
|
+
|
|
175
|
+
Copy `skills/ablation` into your Agent's supported skill directory. The skill supplies context selection, experiment design and result interpretation; the executable supplies mechanics and also works without a skill. Skill installation and synchronization are not performed automatically.
|
|
176
|
+
|
|
177
|
+
## Persistence and updates
|
|
178
|
+
|
|
179
|
+
The default workspace is `~/.local/share/ablation`; override it with `--workspace` or `ABLATION_WORKSPACE`. Experiments and review replies persist on disk. `ablation export EXPERIMENT_ID --out experiment.json` and `ablation import-bundle experiment.json` move experiments between workspaces; imports get new IDs and retain provenance.
|
|
180
|
+
|
|
181
|
+
Software versions, experiment schema versions and candidate IDs are separate. Historical request/response records remain unchanged when software updates. Credentials remain in your environment. Exported evidence can contain prompt content and model responses; review the bundle before sharing it.
|
|
182
|
+
|
|
183
|
+
The GUI checks PyPI in the background, caches checks for 24 hours, and displays a newer version with an installation-aware upgrade command and release-note link. It does not install updates automatically. Editable/source-checkout installations are skipped; set `ABLATION_UPDATE_CHECK=0` to disable checks. `ablation update-check` reports availability, and an unavailable registry is not proof that the installed version is current. `ablation upgrade` shows the installation-aware plan; `ablation upgrade --yes` remains an explicit CLI operation and refuses to run while jobs are active. Restart the local GUI after upgrading. The changelog is bundled for offline viewing.
|
|
184
|
+
|
|
185
|
+
CLI stdout is JSON except for human review handoffs, changelogs and help. Errors go to stderr. Exit codes: `0` completed command (including unscored replay), `2` invalid input/configuration, `3` replay assertions failed, `4` execution or transport failure, `130` cancelled. Inspect saved per-run evidence even when the command returns nonzero.
|
|
186
|
+
|
|
187
|
+
## Development checks
|
|
188
|
+
|
|
189
|
+
```sh
|
|
190
|
+
PYTHONPATH=src python -m unittest discover -s tests -v
|
|
191
|
+
python -m pip wheel --no-deps . -w dist
|
|
192
|
+
npm ci
|
|
193
|
+
npx playwright install chromium
|
|
194
|
+
npm run test:browser
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Tests use synthetic fixtures and local source, model, and Agent substitutes. They do not establish compatibility with a particular live data service, model account, or desktop chat integration. Browser verification and release review details belong in `docs/release-review.md`.
|