datoon 1.9.1__tar.gz → 3.0.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.
- {datoon-1.9.1 → datoon-3.0.0}/.github/workflows/package-installer-smoke.yml +2 -2
- {datoon-1.9.1 → datoon-3.0.0}/.github/workflows/pages.yml +1 -1
- {datoon-1.9.1 → datoon-3.0.0}/.github/workflows/pre-commit.yml +1 -1
- {datoon-1.9.1 → datoon-3.0.0}/.github/workflows/publish-mcp.yml +1 -1
- {datoon-1.9.1 → datoon-3.0.0}/.github/workflows/publish.yml +1 -1
- {datoon-1.9.1 → datoon-3.0.0}/.github/workflows/release.yml +3 -3
- datoon-3.0.0/.github/workflows/tests.yml +24 -0
- {datoon-1.9.1 → datoon-3.0.0}/.github/workflows/validate-artifacts.yml +2 -2
- {datoon-1.9.1 → datoon-3.0.0}/.github/workflows/workflow-lint.yml +2 -2
- {datoon-1.9.1 → datoon-3.0.0}/.gitignore +1 -0
- {datoon-1.9.1 → datoon-3.0.0}/CHANGELOG.md +39 -0
- {datoon-1.9.1 → datoon-3.0.0}/CLAUDE.md +8 -5
- {datoon-1.9.1 → datoon-3.0.0}/CONTRIBUTING.md +2 -8
- {datoon-1.9.1 → datoon-3.0.0}/INSTALL.md +24 -17
- {datoon-1.9.1 → datoon-3.0.0}/PKG-INFO +35 -12
- {datoon-1.9.1 → datoon-3.0.0}/README.md +28 -10
- {datoon-1.9.1/plugins/datoon/skills/datoon → datoon-3.0.0}/SKILL.md +1 -1
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/generate_payloads.py +3 -6
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/run.py +17 -5
- {datoon-1.9.1 → datoon-3.0.0/datoon}/SKILL.md +1 -1
- datoon-3.0.0/datoon.skill +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/docs/index.html +2 -3
- {datoon-1.9.1 → datoon-3.0.0/plugins/datoon}/skills/datoon/SKILL.md +1 -1
- {datoon-1.9.1 → datoon-3.0.0}/pyproject.toml +6 -5
- {datoon-1.9.1 → datoon-3.0.0}/scripts/ab_skill_benchmark.py +3 -4
- {datoon-1.9.1 → datoon-3.0.0}/scripts/install.py +3 -4
- {datoon-1.9.1 → datoon-3.0.0}/scripts/summarize_agent_skill_eval.py +0 -1
- {datoon-1.9.1 → datoon-3.0.0}/scripts/validate_plugin_metadata.py +1 -2
- {datoon-1.9.1 → datoon-3.0.0}/scripts/validate_skill_sync.py +1 -3
- {datoon-1.9.1 → datoon-3.0.0}/setup.sh +5 -15
- {datoon-1.9.1 → datoon-3.0.0}/skills/datoon/README.md +1 -2
- {datoon-1.9.1 → datoon-3.0.0/skills}/datoon/SKILL.md +1 -1
- {datoon-1.9.1 → datoon-3.0.0}/smithery.yaml +1 -2
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon/__init__.py +9 -5
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon/_version.py +3 -3
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon/cli.py +13 -13
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon/converter.py +26 -55
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon/mcp_server.py +40 -10
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon/models.py +9 -10
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon/readers/columnar.py +1 -1
- datoon-3.0.0/src/datoon/tokenizers.py +298 -0
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon.egg-info/PKG-INFO +35 -12
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon.egg-info/SOURCES.txt +4 -1
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon.egg-info/requires.txt +8 -1
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon.egg-info/scm_file_list.json +100 -97
- datoon-3.0.0/src/datoon.egg-info/scm_version.json +8 -0
- datoon-3.0.0/tests/conftest.py +11 -0
- datoon-3.0.0/tests/integration/test_toon_roundtrip.py +56 -0
- {datoon-1.9.1 → datoon-3.0.0}/tests/unit/test_cli.py +52 -27
- datoon-3.0.0/tests/unit/test_converter_policy.py +272 -0
- {datoon-1.9.1 → datoon-3.0.0}/tests/unit/test_errors.py +1 -1
- {datoon-1.9.1 → datoon-3.0.0}/tests/unit/test_mcp_server.py +58 -18
- {datoon-1.9.1 → datoon-3.0.0}/tests/unit/test_models.py +15 -7
- {datoon-1.9.1 → datoon-3.0.0}/tests/unit/test_readers.py +2 -10
- datoon-3.0.0/tests/unit/test_tokenizers.py +366 -0
- datoon-3.0.0/tests/unit/test_tokens.py +75 -0
- {datoon-1.9.1 → datoon-3.0.0}/uv.lock +537 -231
- datoon-1.9.1/.github/workflows/tests.yml +0 -43
- datoon-1.9.1/datoon.skill +0 -0
- datoon-1.9.1/src/datoon.egg-info/scm_version.json +0 -8
- datoon-1.9.1/tests/integration/test_toon_cli_integration.py +0 -68
- datoon-1.9.1/tests/unit/test_converter_policy.py +0 -191
- datoon-1.9.1/tests/unit/test_tokens.py +0 -43
- {datoon-1.9.1 → datoon-3.0.0}/.agents/plugins/marketplace.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/.claude-plugin/marketplace.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/.claude-plugin/plugin.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/.editorconfig +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/.gitattributes +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/.github/dependabot.yml +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/.pre-commit-config.yaml +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/.releaserc.yaml +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/LICENSE +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/MARKETPLACES.md +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/SECURITY.md +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/assets/datoon-banner.svg +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/REPORT.md +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/agent_results.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/expected_answers.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/payloads/1_large.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/payloads/1_medium.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/payloads/1_small.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/payloads/2_large.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/payloads/2_medium.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/payloads/2_small.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/payloads/3_large.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/payloads/3_medium.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/payloads/3_small.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/reports/1_large.report.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/reports/1_medium.report.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/reports/1_small.report.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/reports/2_large.report.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/reports/2_medium.report.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/reports/2_small.report.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/reports/3_large.report.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/reports/3_medium.report.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/reports/3_small.report.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/scored_agent_results.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/toon/1_large.toon +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/toon/1_medium.toon +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/toon/1_small.toon +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/toon/2_large.toon +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/toon/2_medium.toon +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/toon/2_small.toon +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/toon/3_large.toon +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/toon/3_medium.toon +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/agent_skill_eval/toon/3_small.toon +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/payloads.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/benchmarks/results/.gitkeep +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/docs/.nojekyll +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/docs/app.js +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/docs/assets/datoon-banner.svg +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/docs/styles.css +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/glama.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/install.sh +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/plugins/datoon/.codex-plugin/plugin.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/server.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/setup.cfg +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon/analyzer.py +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon/errors.py +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon/py.typed +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon/readers/__init__.py +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon/readers/_coerce.py +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon/readers/_tabular.py +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon/readers/csv.py +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon/readers/excel.py +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon/readers/jsonl.py +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon/readers/numbers.py +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon/readers/xml.py +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon/readers/yaml.py +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon.egg-info/dependency_links.txt +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon.egg-info/entry_points.txt +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/src/datoon.egg-info/top_level.txt +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/tests/fixtures/users.expected.toon +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/tests/fixtures/users.json +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/tests/unit/test_analyzer.py +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/tests/unit/test_benchmark_readme.py +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/tests/unit/test_installer.py +0 -0
- {datoon-1.9.1 → datoon-3.0.0}/tests/unit/test_tabular_rows.py +0 -0
|
@@ -15,10 +15,10 @@ jobs:
|
|
|
15
15
|
runs-on: ubuntu-latest
|
|
16
16
|
steps:
|
|
17
17
|
- name: Checkout
|
|
18
|
-
uses: actions/checkout@v7
|
|
18
|
+
uses: actions/checkout@v7.0.1
|
|
19
19
|
|
|
20
20
|
- name: Setup Python
|
|
21
|
-
uses: actions/setup-python@
|
|
21
|
+
uses: actions/setup-python@v7
|
|
22
22
|
with:
|
|
23
23
|
python-version: "3.12"
|
|
24
24
|
|
|
@@ -15,17 +15,17 @@ jobs:
|
|
|
15
15
|
runs-on: ubuntu-latest
|
|
16
16
|
steps:
|
|
17
17
|
- name: Checkout
|
|
18
|
-
uses: actions/checkout@v7
|
|
18
|
+
uses: actions/checkout@v7.0.1
|
|
19
19
|
with:
|
|
20
20
|
fetch-depth: 0
|
|
21
21
|
|
|
22
22
|
- name: Setup Node.js
|
|
23
|
-
uses: actions/setup-node@
|
|
23
|
+
uses: actions/setup-node@v7
|
|
24
24
|
with:
|
|
25
25
|
node-version: "22"
|
|
26
26
|
|
|
27
27
|
- name: Setup Python
|
|
28
|
-
uses: actions/setup-python@
|
|
28
|
+
uses: actions/setup-python@v7
|
|
29
29
|
with:
|
|
30
30
|
python-version: "3.12"
|
|
31
31
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches:
|
|
7
|
+
- main
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: tests-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
unit-tests:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- name: Checkout
|
|
18
|
+
uses: actions/checkout@v7.0.1
|
|
19
|
+
|
|
20
|
+
- name: Setup uv
|
|
21
|
+
uses: astral-sh/setup-uv@v7
|
|
22
|
+
|
|
23
|
+
- name: Run tests
|
|
24
|
+
run: uv run --with ".[dev]" pytest
|
|
@@ -18,10 +18,10 @@ jobs:
|
|
|
18
18
|
runs-on: ubuntu-latest
|
|
19
19
|
steps:
|
|
20
20
|
- name: Checkout
|
|
21
|
-
uses: actions/checkout@v7
|
|
21
|
+
uses: actions/checkout@v7.0.1
|
|
22
22
|
|
|
23
23
|
- name: Setup Python
|
|
24
|
-
uses: actions/setup-python@
|
|
24
|
+
uses: actions/setup-python@v7
|
|
25
25
|
with:
|
|
26
26
|
python-version: "3.12"
|
|
27
27
|
|
|
@@ -22,7 +22,7 @@ jobs:
|
|
|
22
22
|
runs-on: ubuntu-latest
|
|
23
23
|
steps:
|
|
24
24
|
- name: Checkout
|
|
25
|
-
uses: actions/checkout@
|
|
25
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
26
26
|
with:
|
|
27
27
|
persist-credentials: false
|
|
28
28
|
|
|
@@ -35,7 +35,7 @@ jobs:
|
|
|
35
35
|
runs-on: ubuntu-latest
|
|
36
36
|
steps:
|
|
37
37
|
- name: Checkout
|
|
38
|
-
uses: actions/checkout@
|
|
38
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
39
39
|
with:
|
|
40
40
|
persist-credentials: false
|
|
41
41
|
|
|
@@ -1,3 +1,42 @@
|
|
|
1
|
+
# [3.0.0](https://github.com/andrii-su/datoon/compare/v2.0.0...v3.0.0) (2026-11-11)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
* feat!: selectable token counters (auto, chars, tiktoken, claude, hf, callable) ([cab2bfb](https://github.com/andrii-su/datoon/commit/cab2bfb9f1106f2a4cf40122588249acb0371f94))
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
* **mcp:** accept only local token counters as a tool argument ([1f2e54d](https://github.com/andrii-su/datoon/commit/1f2e54d4f83ea266590933f0762019d2d37f7270))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### BREAKING CHANGES
|
|
13
|
+
|
|
14
|
+
* `ConversionConfig.token_encoding` is replaced by
|
|
15
|
+
`tokenizer`; the CLI flag `--encoding` and the MCP `encoding` argument are
|
|
16
|
+
replaced by `--tokenizer` / `tokenizer` (default from `DATOON_TOKENIZER`,
|
|
17
|
+
else `auto`). `ConversionReport` gains a `tokenizer` field. Every counter
|
|
18
|
+
returns at least 1, including for empty text.
|
|
19
|
+
|
|
20
|
+
# [2.0.0](https://github.com/andrii-su/datoon/compare/v1.9.1...v2.0.0) (2026-11-11)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
* feat!: encode TOON in pure Python, drop the Node.js CLI ([1bffef7](https://github.com/andrii-su/datoon/commit/1bffef7c068cd3f2a73df80a9348f0af28dd3040))
|
|
24
|
+
* feat!: encode TOON in pure Python, drop the Node.js CLI ([#69](https://github.com/andrii-su/datoon/issues/69)) ([7e28513](https://github.com/andrii-su/datoon/commit/7e28513aa1fb0cf0be315d8e09586eedb0ce6800))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### BREAKING CHANGES
|
|
28
|
+
|
|
29
|
+
* `toon-format` is a required dependency; the
|
|
30
|
+
`ConversionConfig.toon_cli_timeout` field, the `--timeout` CLI flag and
|
|
31
|
+
the `timeout` argument of the `convert_json` / `convert_text` MCP tools
|
|
32
|
+
are removed. The skip reason for a failed conversion is now
|
|
33
|
+
"TOON encoding failed; falling back to JSON."
|
|
34
|
+
* `toon-format` is a required dependency; the
|
|
35
|
+
`ConversionConfig.toon_cli_timeout` field, the `--timeout` CLI flag and
|
|
36
|
+
the `timeout` argument of the `convert_json` / `convert_text` MCP tools
|
|
37
|
+
are removed. The skip reason for a failed conversion is now
|
|
38
|
+
"TOON encoding failed; falling back to JSON."
|
|
39
|
+
|
|
1
40
|
## [1.9.1](https://github.com/andrii-su/datoon/compare/v1.9.0...v1.9.1) (2026-07-07)
|
|
2
41
|
|
|
3
42
|
|
|
@@ -30,8 +30,9 @@ datoon/
|
|
|
30
30
|
│
|
|
31
31
|
├── src/datoon/ # Python package source
|
|
32
32
|
│ ├── analyzer.py # Payload structure suitability checks
|
|
33
|
-
│ ├── converter.py # JSON normalization, TOON
|
|
33
|
+
│ ├── converter.py # JSON normalization, TOON encoder call, policy gating
|
|
34
34
|
│ ├── models.py # Config/report/outcome dataclasses
|
|
35
|
+
│ ├── tokenizers.py # Token counter specs and estimates
|
|
35
36
|
│ ├── cli.py # CLI entrypoint
|
|
36
37
|
│ └── mcp_server.py # MCP server tools
|
|
37
38
|
│
|
|
@@ -68,6 +69,7 @@ Edit these files directly:
|
|
|
68
69
|
| Conversion policy | `src/datoon/converter.py` |
|
|
69
70
|
| Payload analysis | `src/datoon/analyzer.py` |
|
|
70
71
|
| Public data contracts | `src/datoon/models.py` |
|
|
72
|
+
| Token counters | `src/datoon/tokenizers.py` |
|
|
71
73
|
| CLI behavior | `src/datoon/cli.py` |
|
|
72
74
|
| MCP behavior | `src/datoon/mcp_server.py` |
|
|
73
75
|
| Skill behavior | `skills/datoon/SKILL.md` |
|
|
@@ -105,11 +107,12 @@ It runs on pull requests and pushes to `main`. The old auto-sync-on-main flow wa
|
|
|
105
107
|
|
|
106
108
|
- Never change semantic values or key names during conversion.
|
|
107
109
|
- Invalid JSON must fail loudly.
|
|
108
|
-
-
|
|
110
|
+
- An encoder failure must not break auto mode; fallback to JSON unless `force=True`.
|
|
109
111
|
- `--force` is for controlled experiments and should bypass gating, not hide conversion errors.
|
|
110
112
|
- Auto mode skips before conversion when analysis rejects the payload, and skips after conversion when estimated savings are below `min_savings_ratio`.
|
|
111
113
|
- Keep skip reasons user-facing, specific, and stable enough for CLI/MCP troubleshooting.
|
|
112
|
-
- Token counts are estimates. Be precise about whether a number is payload-token estimate, visible output estimate, or real model usage.
|
|
114
|
+
- Token counts are estimates, whichever tokenizer produced them (`claude:` counts included). Be precise about whether a number is payload-token estimate, visible output estimate, or real model usage, and name the tokenizer it came from.
|
|
115
|
+
- Only the `auto` tokenizer falls back silently; an explicit spec with a missing package or credentials must raise `DatoonError`, in auto and force mode alike.
|
|
113
116
|
- Benchmarks in README must come from committed scripts/artifacts.
|
|
114
117
|
- Keep generated caches out of commits: `.venv/`, `.pytest_cache/`, `.ruff_cache/`, `__pycache__/`, local benchmark result JSON under `benchmarks/results/`.
|
|
115
118
|
|
|
@@ -122,7 +125,7 @@ python scripts/validate_plugin_metadata.py
|
|
|
122
125
|
uvx pre-commit run --all-files
|
|
123
126
|
```
|
|
124
127
|
|
|
125
|
-
|
|
128
|
+
Conversion is pure Python (`toon-format`); no Node.js is needed for tests.
|
|
126
129
|
|
|
127
130
|
## Benchmark Commands
|
|
128
131
|
|
|
@@ -168,7 +171,7 @@ Config writes must:
|
|
|
168
171
|
- remove only `datoon`-owned entries on uninstall;
|
|
169
172
|
- keep dry-run side-effect free.
|
|
170
173
|
|
|
171
|
-
Security and privacy docs should state that the installer does not read or upload user payloads, but selected targets may call external tooling: Claude Code through `claude plugin ...`, Python package resolution through `uvx
|
|
174
|
+
Security and privacy docs should state that the installer does not read or upload user payloads, but selected targets may call external tooling: Claude Code through `claude plugin ...`, Python package resolution through `uvx`; TOON conversion runs in-process through the `toon-format` package and calls no external tooling.
|
|
172
175
|
|
|
173
176
|
## Known Gaps
|
|
174
177
|
|
|
@@ -15,7 +15,7 @@ python scripts/validate_skill_sync.py
|
|
|
15
15
|
python scripts/validate_plugin_metadata.py
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
Conversion is pure Python (the `toon-format` package); no Node.js is required for tests.
|
|
19
19
|
|
|
20
20
|
## What To Edit
|
|
21
21
|
|
|
@@ -67,12 +67,6 @@ Run the full suite:
|
|
|
67
67
|
uv run pytest
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
Run unit tests only:
|
|
71
|
-
|
|
72
|
-
```bash
|
|
73
|
-
uv run pytest -m "not integration"
|
|
74
|
-
```
|
|
75
|
-
|
|
76
70
|
Run pre-commit locally:
|
|
77
71
|
|
|
78
72
|
```bash
|
|
@@ -112,7 +106,7 @@ Use Conventional Commit subjects:
|
|
|
112
106
|
|
|
113
107
|
```text
|
|
114
108
|
feat: add MCP analyze_json tool
|
|
115
|
-
fix: preserve JSON fallback on
|
|
109
|
+
fix: preserve JSON fallback on encoder failure
|
|
116
110
|
docs: clarify Claude Code plugin install
|
|
117
111
|
test: cover non-uniform arrays
|
|
118
112
|
```
|
|
@@ -16,7 +16,6 @@ The setup script:
|
|
|
16
16
|
|
|
17
17
|
- checks for Python 3.12+;
|
|
18
18
|
- installs `uv` if it is missing;
|
|
19
|
-
- warns if Node.js is missing;
|
|
20
19
|
- runs `uv sync --extra dev`;
|
|
21
20
|
- installs the editable `datoon` CLI globally through `uv tool install`.
|
|
22
21
|
|
|
@@ -43,9 +42,29 @@ Optional extras:
|
|
|
43
42
|
|
|
44
43
|
```bash
|
|
45
44
|
pip install "datoon[tokens]" # tiktoken token estimates
|
|
45
|
+
pip install "datoon[claude]" # Claude token counts via the Anthropic API
|
|
46
|
+
pip install "datoon[hf]" # Hugging Face tokenizers
|
|
46
47
|
pip install "datoon[mcp]" # MCP server dependencies
|
|
47
48
|
```
|
|
48
49
|
|
|
50
|
+
### Choosing a tokenizer
|
|
51
|
+
|
|
52
|
+
Select the token counter with `--tokenizer <spec>` (CLI), the `tokenizer` argument (MCP tools), or `DATOON_TOKENIZER`; the default is `auto`. The MCP tools accept only local counters (`auto`, `chars`, `tiktoken`) per call; `claude:` and `hf:` reach the network, so only the server operator can enable them through `DATOON_TOKENIZER`.
|
|
53
|
+
|
|
54
|
+
| Spec | Counts with | Needs |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| `auto` | `tiktoken:o200k_base` when tiktoken is installed, else `chars:3` | — |
|
|
57
|
+
| `chars` / `chars:<N>` | `ceil(len(text) / N)`, default `N = 3` | — |
|
|
58
|
+
| `tiktoken` / `tiktoken:<encoding>` | tiktoken, default `o200k_base` | `datoon[tokens]` |
|
|
59
|
+
| `claude:<model-id>` | Anthropic token counting API | `datoon[claude]`, Anthropic credentials (e.g. `ANTHROPIC_API_KEY`) |
|
|
60
|
+
| `hf:<repo-id>` | Hugging Face `tokenizers` tokenizer | `datoon[hf]` |
|
|
61
|
+
|
|
62
|
+
Local counters suit runtime gating; `claude:` and `hf:` suit benchmarks and evals where counts for the target model matter. `claude:` makes network calls, and Anthropic documents its counts as estimates. `hf:` downloads the tokenizer from the Hugging Face Hub on first use.
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
datoon input.json --tokenizer claude:claude-opus-5-5 --report-stdout
|
|
66
|
+
```
|
|
67
|
+
|
|
49
68
|
## CLI
|
|
50
69
|
|
|
51
70
|
Read from stdin:
|
|
@@ -69,21 +88,16 @@ datoon input.json --force --report-stdout
|
|
|
69
88
|
|
|
70
89
|
## TOON Dependency
|
|
71
90
|
|
|
72
|
-
`datoon`
|
|
73
|
-
|
|
74
|
-
Required for conversion:
|
|
91
|
+
`datoon` converts to TOON in pure Python using the official [`toon-format`](https://pypi.org/project/toon-format/) package, which is installed automatically as a dependency. No Node.js is needed.
|
|
75
92
|
|
|
76
|
-
|
|
77
|
-
- `npx` in `PATH`
|
|
78
|
-
|
|
79
|
-
Without Node.js, structure analysis still works, but conversion falls back to JSON in auto mode. Forced conversion fails loudly.
|
|
93
|
+
If the encoder fails, auto mode falls back to JSON. Forced conversion fails loudly.
|
|
80
94
|
|
|
81
95
|
In auto mode, `datoon` skips conversion and returns compact JSON when:
|
|
82
96
|
|
|
83
97
|
- the payload has no uniform object array with at least the configured row count;
|
|
84
98
|
- the payload exceeds the configured maximum nesting depth;
|
|
85
99
|
- estimated TOON savings are below `--min-savings`;
|
|
86
|
-
-
|
|
100
|
+
- the TOON encoder fails.
|
|
87
101
|
|
|
88
102
|
Invalid JSON never falls back silently. It raises an error.
|
|
89
103
|
|
|
@@ -232,12 +246,7 @@ echo '{"users":[{"id":1,"name":"Ada"},{"id":2,"name":"Lin"},{"id":3,"name":"Grac
|
|
|
232
246
|
| datoon --report-stdout
|
|
233
247
|
```
|
|
234
248
|
|
|
235
|
-
If the reason
|
|
236
|
-
|
|
237
|
-
```bash
|
|
238
|
-
node --version
|
|
239
|
-
npx --version
|
|
240
|
-
```
|
|
249
|
+
If the reason says TOON encoding failed, rerun with `--force` to see the underlying encoder error.
|
|
241
250
|
|
|
242
251
|
If the reason mentions structure or savings, the skip is expected auto-mode behavior. Use `--force` only for controlled experiments where a failed TOON conversion should fail the command.
|
|
243
252
|
|
|
@@ -264,8 +273,6 @@ python scripts/validate_skill_sync.py
|
|
|
264
273
|
PYTHONPATH=src python benchmarks/run.py --dry-run
|
|
265
274
|
```
|
|
266
275
|
|
|
267
|
-
Full integration tests require Node.js and `npx`.
|
|
268
|
-
|
|
269
276
|
## Uninstall
|
|
270
277
|
|
|
271
278
|
For the editable CLI installed by `setup.sh`:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: datoon
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0
|
|
4
4
|
Summary: Smart structured-data-to-TOON gateway with pragmatic auto-gating for LLM prompts.
|
|
5
5
|
Author-email: Andrii Suruhov <andrii.suruhov@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -37,12 +37,17 @@ Classifier: Operating System :: OS Independent
|
|
|
37
37
|
Requires-Python: >=3.12
|
|
38
38
|
Description-Content-Type: text/markdown
|
|
39
39
|
License-File: LICENSE
|
|
40
|
+
Requires-Dist: toon-format>=1.2.0
|
|
40
41
|
Provides-Extra: dev
|
|
41
42
|
Requires-Dist: pytest>=9.0.3; extra == "dev"
|
|
42
43
|
Requires-Dist: pre-commit>=4.6.0; extra == "dev"
|
|
43
44
|
Requires-Dist: pyyaml>=6.0; extra == "dev"
|
|
44
45
|
Provides-Extra: tokens
|
|
45
46
|
Requires-Dist: tiktoken>=0.13.0; extra == "tokens"
|
|
47
|
+
Provides-Extra: claude
|
|
48
|
+
Requires-Dist: anthropic>=2.0.0; extra == "claude"
|
|
49
|
+
Provides-Extra: hf
|
|
50
|
+
Requires-Dist: tokenizers>=0.23.0; extra == "hf"
|
|
46
51
|
Provides-Extra: mcp
|
|
47
52
|
Requires-Dist: mcp>=1.28.0; extra == "mcp"
|
|
48
53
|
Provides-Extra: yaml
|
|
@@ -55,7 +60,7 @@ Requires-Dist: fastavro>=1.9; extra == "columnar"
|
|
|
55
60
|
Provides-Extra: numbers
|
|
56
61
|
Requires-Dist: numbers-parser>=4.4; extra == "numbers"
|
|
57
62
|
Provides-Extra: all
|
|
58
|
-
Requires-Dist: datoon[columnar,excel,mcp,numbers,tokens,yaml]; extra == "all"
|
|
63
|
+
Requires-Dist: datoon[claude,columnar,excel,hf,mcp,numbers,tokens,yaml]; extra == "all"
|
|
59
64
|
Dynamic: license-file
|
|
60
65
|
|
|
61
66
|
<p align="center">
|
|
@@ -169,7 +174,7 @@ Same result. Zero JSON serialization in your code.
|
|
|
169
174
|
{"decision":"skip","reason":"No uniform object arrays found with at least 3 rows."}
|
|
170
175
|
```
|
|
171
176
|
|
|
172
|
-
No
|
|
177
|
+
No silent corruption.
|
|
173
178
|
|
|
174
179
|
</td>
|
|
175
180
|
</tr>
|
|
@@ -211,6 +216,10 @@ pip install "datoon[numbers]"
|
|
|
211
216
|
# with tiktoken-based token counting
|
|
212
217
|
pip install "datoon[tokens]"
|
|
213
218
|
|
|
219
|
+
# with Claude token counting (Anthropic API) / Hugging Face tokenizers
|
|
220
|
+
pip install "datoon[claude]"
|
|
221
|
+
pip install "datoon[hf]"
|
|
222
|
+
|
|
214
223
|
# with MCP server
|
|
215
224
|
pip install "datoon[mcp]"
|
|
216
225
|
|
|
@@ -218,7 +227,7 @@ pip install "datoon[mcp]"
|
|
|
218
227
|
pip install "datoon[all]"
|
|
219
228
|
```
|
|
220
229
|
|
|
221
|
-
Requires Python 3.12+. TOON conversion
|
|
230
|
+
Requires Python 3.12+. TOON conversion is pure Python (official [`toon-format`](https://pypi.org/project/toon-format/) encoder, installed automatically) — no Node.js needed.
|
|
222
231
|
|
|
223
232
|
For Claude Code plugin, Codex, and MCP config → [**INSTALL.md**](./INSTALL.md).
|
|
224
233
|
|
|
@@ -252,11 +261,26 @@ For Claude Code plugin, Codex, and MCP config → [**INSTALL.md**](./INSTALL.md)
|
|
|
252
261
|
1. **Detect format** — from `--format` flag, file extension, or default to JSON for stdin
|
|
253
262
|
1. **Read + normalize** — parse source into list of row dicts; serialize to compact JSON
|
|
254
263
|
1. **Analyze structure** — uniform object arrays? acceptable depth? minimum rows?
|
|
255
|
-
1. **Gate early** — non-candidates skip before any
|
|
256
|
-
1. **Convert + estimate** — TOON
|
|
264
|
+
1. **Gate early** — non-candidates skip before any TOON encoding
|
|
265
|
+
1. **Convert + estimate** — TOON encoder runs in-process, token savings calculated
|
|
257
266
|
1. **Gate savings** — below threshold → return JSON; above → return TOON with report
|
|
258
267
|
|
|
259
|
-
Every path returns a `ConversionReport` with `decision`, `reason`, and
|
|
268
|
+
Every path returns a `ConversionReport` with `decision`, `reason`, token estimates, and the `tokenizer` that produced them. Pipelines never get silent surprises.
|
|
269
|
+
|
|
270
|
+
## Choosing a tokenizer
|
|
271
|
+
|
|
272
|
+
Token estimates drive the savings gate, so pick the counter that fits the job. Pass one spec with `--tokenizer`, the `tokenizer` MCP argument, `ConversionConfig(tokenizer=...)`, or the `DATOON_TOKENIZER` environment variable; in Python any callable `str -> int` works too. The MCP tools accept only local counters (`auto`, `chars`, `tiktoken`) per call; `claude:` and `hf:` reach the network, so only the server operator can enable them through `DATOON_TOKENIZER`.
|
|
273
|
+
|
|
274
|
+
| Spec | Counts with | Needs |
|
|
275
|
+
|---|---|---|
|
|
276
|
+
| `auto` (default) | `tiktoken:o200k_base` when tiktoken is installed, else `chars:3` | — |
|
|
277
|
+
| `chars` / `chars:<N>` | `ceil(len(text) / N)`, default `N = 3` | — |
|
|
278
|
+
| `tiktoken` / `tiktoken:<encoding>` | tiktoken, default `o200k_base` | `datoon[tokens]` |
|
|
279
|
+
| `claude:<model-id>` | Anthropic token counting API for that model | `datoon[claude]`, Anthropic credentials (e.g. `ANTHROPIC_API_KEY`) |
|
|
280
|
+
| `hf:<repo-id>` | Hugging Face `tokenizers` tokenizer from the Hub | `datoon[hf]` |
|
|
281
|
+
| a callable (Python) | your own function, reported as `custom` | — |
|
|
282
|
+
|
|
283
|
+
Use the local counters (`auto`, `chars`, `tiktoken`) to gate payloads at runtime: they are fast and run locally (tiktoken fetches its encoding file once on first use). Use `claude:` or `hf:` in benchmarks and evals where counts for the target model matter. `claude:` makes network calls, and Anthropic documents its counts as estimates. Only `auto` falls back silently: an explicit spec with a missing package fails with an error that names the extra to install, and `claude:` without Anthropic credentials fails too. Every report records the resolved name in `tokenizer`.
|
|
260
284
|
|
|
261
285
|
______________________________________________________________________
|
|
262
286
|
|
|
@@ -344,7 +368,7 @@ outcome = convert_json_for_llm(json_text, ConversionConfig())
|
|
|
344
368
|
send_to_model(outcome.payload_text)
|
|
345
369
|
```
|
|
346
370
|
|
|
347
|
-
**Structure-only analysis
|
|
371
|
+
**Structure-only analysis:**
|
|
348
372
|
|
|
349
373
|
```python
|
|
350
374
|
from datoon.analyzer import analyze_payload
|
|
@@ -366,7 +390,7 @@ ______________________________________________________________________
|
|
|
366
390
|
|---|---|
|
|
367
391
|
| `convert_json` | Full JSON conversion with policy gating |
|
|
368
392
|
| `convert_text` | Converts CSV, YAML, XML, or JSONL text with policy gating |
|
|
369
|
-
| `analyze_json` | Structure analysis only — no
|
|
393
|
+
| `analyze_json` | Structure analysis only — no conversion |
|
|
370
394
|
|
|
371
395
|
**Claude Desktop / Cursor / Windsurf config:**
|
|
372
396
|
|
|
@@ -419,7 +443,7 @@ ______________________________________________________________________
|
|
|
419
443
|
| `--min-savings` | `0.15` | Minimum relative token savings required |
|
|
420
444
|
| `--max-depth` | `6` | Maximum nesting depth for auto-conversion |
|
|
421
445
|
| `--min-uniform-rows` | `3` | Minimum rows in uniform object arrays |
|
|
422
|
-
| `--
|
|
446
|
+
| `--tokenizer <spec>` | `$DATOON_TOKENIZER`, else `auto` | Token counter for estimates — see [Choosing a tokenizer](#choosing-a-tokenizer) |
|
|
423
447
|
| `--report <path>` | — | Write JSON conversion report to file |
|
|
424
448
|
| `--report-stdout` | — | Print JSON conversion report to stderr |
|
|
425
449
|
| `-o <path>` | stdout | Output file path |
|
|
@@ -514,8 +538,7 @@ uvx pre-commit install
|
|
|
514
538
|
**Tests:**
|
|
515
539
|
|
|
516
540
|
```bash
|
|
517
|
-
pytest
|
|
518
|
-
pytest # with integration (requires Node.js + npx)
|
|
541
|
+
pytest
|
|
519
542
|
```
|
|
520
543
|
|
|
521
544
|
**Skill sync + plugin metadata:**
|
|
@@ -109,7 +109,7 @@ Same result. Zero JSON serialization in your code.
|
|
|
109
109
|
{"decision":"skip","reason":"No uniform object arrays found with at least 3 rows."}
|
|
110
110
|
```
|
|
111
111
|
|
|
112
|
-
No
|
|
112
|
+
No silent corruption.
|
|
113
113
|
|
|
114
114
|
</td>
|
|
115
115
|
</tr>
|
|
@@ -151,6 +151,10 @@ pip install "datoon[numbers]"
|
|
|
151
151
|
# with tiktoken-based token counting
|
|
152
152
|
pip install "datoon[tokens]"
|
|
153
153
|
|
|
154
|
+
# with Claude token counting (Anthropic API) / Hugging Face tokenizers
|
|
155
|
+
pip install "datoon[claude]"
|
|
156
|
+
pip install "datoon[hf]"
|
|
157
|
+
|
|
154
158
|
# with MCP server
|
|
155
159
|
pip install "datoon[mcp]"
|
|
156
160
|
|
|
@@ -158,7 +162,7 @@ pip install "datoon[mcp]"
|
|
|
158
162
|
pip install "datoon[all]"
|
|
159
163
|
```
|
|
160
164
|
|
|
161
|
-
Requires Python 3.12+. TOON conversion
|
|
165
|
+
Requires Python 3.12+. TOON conversion is pure Python (official [`toon-format`](https://pypi.org/project/toon-format/) encoder, installed automatically) — no Node.js needed.
|
|
162
166
|
|
|
163
167
|
For Claude Code plugin, Codex, and MCP config → [**INSTALL.md**](./INSTALL.md).
|
|
164
168
|
|
|
@@ -192,11 +196,26 @@ For Claude Code plugin, Codex, and MCP config → [**INSTALL.md**](./INSTALL.md)
|
|
|
192
196
|
1. **Detect format** — from `--format` flag, file extension, or default to JSON for stdin
|
|
193
197
|
1. **Read + normalize** — parse source into list of row dicts; serialize to compact JSON
|
|
194
198
|
1. **Analyze structure** — uniform object arrays? acceptable depth? minimum rows?
|
|
195
|
-
1. **Gate early** — non-candidates skip before any
|
|
196
|
-
1. **Convert + estimate** — TOON
|
|
199
|
+
1. **Gate early** — non-candidates skip before any TOON encoding
|
|
200
|
+
1. **Convert + estimate** — TOON encoder runs in-process, token savings calculated
|
|
197
201
|
1. **Gate savings** — below threshold → return JSON; above → return TOON with report
|
|
198
202
|
|
|
199
|
-
Every path returns a `ConversionReport` with `decision`, `reason`, and
|
|
203
|
+
Every path returns a `ConversionReport` with `decision`, `reason`, token estimates, and the `tokenizer` that produced them. Pipelines never get silent surprises.
|
|
204
|
+
|
|
205
|
+
## Choosing a tokenizer
|
|
206
|
+
|
|
207
|
+
Token estimates drive the savings gate, so pick the counter that fits the job. Pass one spec with `--tokenizer`, the `tokenizer` MCP argument, `ConversionConfig(tokenizer=...)`, or the `DATOON_TOKENIZER` environment variable; in Python any callable `str -> int` works too. The MCP tools accept only local counters (`auto`, `chars`, `tiktoken`) per call; `claude:` and `hf:` reach the network, so only the server operator can enable them through `DATOON_TOKENIZER`.
|
|
208
|
+
|
|
209
|
+
| Spec | Counts with | Needs |
|
|
210
|
+
|---|---|---|
|
|
211
|
+
| `auto` (default) | `tiktoken:o200k_base` when tiktoken is installed, else `chars:3` | — |
|
|
212
|
+
| `chars` / `chars:<N>` | `ceil(len(text) / N)`, default `N = 3` | — |
|
|
213
|
+
| `tiktoken` / `tiktoken:<encoding>` | tiktoken, default `o200k_base` | `datoon[tokens]` |
|
|
214
|
+
| `claude:<model-id>` | Anthropic token counting API for that model | `datoon[claude]`, Anthropic credentials (e.g. `ANTHROPIC_API_KEY`) |
|
|
215
|
+
| `hf:<repo-id>` | Hugging Face `tokenizers` tokenizer from the Hub | `datoon[hf]` |
|
|
216
|
+
| a callable (Python) | your own function, reported as `custom` | — |
|
|
217
|
+
|
|
218
|
+
Use the local counters (`auto`, `chars`, `tiktoken`) to gate payloads at runtime: they are fast and run locally (tiktoken fetches its encoding file once on first use). Use `claude:` or `hf:` in benchmarks and evals where counts for the target model matter. `claude:` makes network calls, and Anthropic documents its counts as estimates. Only `auto` falls back silently: an explicit spec with a missing package fails with an error that names the extra to install, and `claude:` without Anthropic credentials fails too. Every report records the resolved name in `tokenizer`.
|
|
200
219
|
|
|
201
220
|
______________________________________________________________________
|
|
202
221
|
|
|
@@ -284,7 +303,7 @@ outcome = convert_json_for_llm(json_text, ConversionConfig())
|
|
|
284
303
|
send_to_model(outcome.payload_text)
|
|
285
304
|
```
|
|
286
305
|
|
|
287
|
-
**Structure-only analysis
|
|
306
|
+
**Structure-only analysis:**
|
|
288
307
|
|
|
289
308
|
```python
|
|
290
309
|
from datoon.analyzer import analyze_payload
|
|
@@ -306,7 +325,7 @@ ______________________________________________________________________
|
|
|
306
325
|
|---|---|
|
|
307
326
|
| `convert_json` | Full JSON conversion with policy gating |
|
|
308
327
|
| `convert_text` | Converts CSV, YAML, XML, or JSONL text with policy gating |
|
|
309
|
-
| `analyze_json` | Structure analysis only — no
|
|
328
|
+
| `analyze_json` | Structure analysis only — no conversion |
|
|
310
329
|
|
|
311
330
|
**Claude Desktop / Cursor / Windsurf config:**
|
|
312
331
|
|
|
@@ -359,7 +378,7 @@ ______________________________________________________________________
|
|
|
359
378
|
| `--min-savings` | `0.15` | Minimum relative token savings required |
|
|
360
379
|
| `--max-depth` | `6` | Maximum nesting depth for auto-conversion |
|
|
361
380
|
| `--min-uniform-rows` | `3` | Minimum rows in uniform object arrays |
|
|
362
|
-
| `--
|
|
381
|
+
| `--tokenizer <spec>` | `$DATOON_TOKENIZER`, else `auto` | Token counter for estimates — see [Choosing a tokenizer](#choosing-a-tokenizer) |
|
|
363
382
|
| `--report <path>` | — | Write JSON conversion report to file |
|
|
364
383
|
| `--report-stdout` | — | Print JSON conversion report to stderr |
|
|
365
384
|
| `-o <path>` | stdout | Output file path |
|
|
@@ -454,8 +473,7 @@ uvx pre-commit install
|
|
|
454
473
|
**Tests:**
|
|
455
474
|
|
|
456
475
|
```bash
|
|
457
|
-
pytest
|
|
458
|
-
pytest # with integration (requires Node.js + npx)
|
|
476
|
+
pytest
|
|
459
477
|
```
|
|
460
478
|
|
|
461
479
|
**Skill sync + plugin metadata:**
|
|
@@ -50,7 +50,7 @@ Skip conversion when any condition fails:
|
|
|
50
50
|
|
|
51
51
|
- Never change semantic values or key names.
|
|
52
52
|
- Fail loudly for invalid JSON.
|
|
53
|
-
- If TOON
|
|
53
|
+
- If TOON encoding fails, keep JSON and report fallback reason.
|
|
54
54
|
- Use `--force` only for controlled experiments.
|
|
55
55
|
|
|
56
56
|
## Boundaries
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
1
|
"""Generate deterministic JSON payloads for agent skill evaluation."""
|
|
3
2
|
|
|
4
3
|
from __future__ import annotations
|
|
@@ -67,12 +66,10 @@ def expected_for(payload: dict[str, object]) -> dict[str, object]:
|
|
|
67
66
|
region_totals[region] = region_totals.get(region, 0) + revenue
|
|
68
67
|
category_totals[category] = category_totals.get(category, 0) + revenue
|
|
69
68
|
|
|
70
|
-
top_region =
|
|
69
|
+
top_region = min(region_totals.items(), key=lambda item: (-item[1], item[0]))[0][0]
|
|
70
|
+
top_category = min(category_totals.items(), key=lambda item: (-item[1], item[0]))[
|
|
71
71
|
0
|
|
72
|
-
]
|
|
73
|
-
top_category = sorted(
|
|
74
|
-
category_totals.items(), key=lambda item: (-item[1], item[0])
|
|
75
|
-
)[0][0]
|
|
72
|
+
][0]
|
|
76
73
|
|
|
77
74
|
return {
|
|
78
75
|
"scenario": payload["scenario"],
|