tuningfork-lab 0.6.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.
- tuningfork_lab-0.6.0/.gitattributes +3 -0
- tuningfork_lab-0.6.0/.github/workflows/tests.yml +35 -0
- tuningfork_lab-0.6.0/.gitignore +19 -0
- tuningfork_lab-0.6.0/CHANGELOG.md +566 -0
- tuningfork_lab-0.6.0/CLAUDE.md +722 -0
- tuningfork_lab-0.6.0/CONTRIBUTING.md +52 -0
- tuningfork_lab-0.6.0/LICENSE +201 -0
- tuningfork_lab-0.6.0/NOTICE +23 -0
- tuningfork_lab-0.6.0/PKG-INFO +315 -0
- tuningfork_lab-0.6.0/README.md +293 -0
- tuningfork_lab-0.6.0/SECURITY.md +43 -0
- tuningfork_lab-0.6.0/benchmark/architecture-diagram/LICENSE-hermes +21 -0
- tuningfork_lab-0.6.0/benchmark/architecture-diagram/architecture-diagram/SKILL.md +148 -0
- tuningfork_lab-0.6.0/benchmark/architecture-diagram/architecture-diagram/templates/template.html +319 -0
- tuningfork_lab-0.6.0/benchmark/architecture-diagram/checks/diagram.py +331 -0
- tuningfork_lab-0.6.0/benchmark/architecture-diagram/evals.json +24 -0
- tuningfork_lab-0.6.0/benchmark/driver/run.py +1157 -0
- tuningfork_lab-0.6.0/docs/adapters/TEMPLATE.md +115 -0
- tuningfork_lab-0.6.0/docs/adapters/claude-code.md +209 -0
- tuningfork_lab-0.6.0/docs/adapters/hermes.md +321 -0
- tuningfork_lab-0.6.0/docs/agents.md +197 -0
- tuningfork_lab-0.6.0/docs/commands.md +616 -0
- tuningfork_lab-0.6.0/docs/images/README.md +109 -0
- tuningfork_lab-0.6.0/docs/images/hero-dark.svg +168 -0
- tuningfork_lab-0.6.0/docs/images/hero-light.svg +168 -0
- tuningfork_lab-0.6.0/docs/images/hero.py +308 -0
- tuningfork_lab-0.6.0/docs/images/shots.mjs +447 -0
- tuningfork_lab-0.6.0/docs/images/ui-ab.png +0 -0
- tuningfork_lab-0.6.0/docs/images/ui-demo.gif +0 -0
- tuningfork_lab-0.6.0/docs/images/ui-divergence.png +0 -0
- tuningfork_lab-0.6.0/docs/images/ui-guide.png +0 -0
- tuningfork_lab-0.6.0/docs/images/ui-live.png +0 -0
- tuningfork_lab-0.6.0/docs/images/ui-refine.png +0 -0
- tuningfork_lab-0.6.0/docs/images/ui-run.png +0 -0
- tuningfork_lab-0.6.0/docs/images/ui-scenario.png +0 -0
- tuningfork_lab-0.6.0/docs/images/ui-tokens.png +0 -0
- tuningfork_lab-0.6.0/docs/setup.md +428 -0
- tuningfork_lab-0.6.0/docs/web-ui.md +46 -0
- tuningfork_lab-0.6.0/examples/README.md +2702 -0
- tuningfork_lab-0.6.0/examples/find-the-file/README.md +429 -0
- tuningfork_lab-0.6.0/examples/find-the-file/evals.json +33 -0
- tuningfork_lab-0.6.0/examples/find-the-file/fix/SKILL.md +29 -0
- tuningfork_lab-0.6.0/examples/find-the-file/tally-report/SKILL.md +29 -0
- tuningfork_lab-0.6.0/examples/hermes-architecture-diagram/LICENSE-hermes +21 -0
- tuningfork_lab-0.6.0/examples/hermes-architecture-diagram/README.md +200 -0
- tuningfork_lab-0.6.0/examples/hermes-architecture-diagram/evidence/diagrams/after-e4b3bec5.html +307 -0
- tuningfork_lab-0.6.0/examples/hermes-architecture-diagram/evidence/diagrams/after-e4b3bec5.png +0 -0
- tuningfork_lab-0.6.0/examples/hermes-architecture-diagram/evidence/diagrams/before-0fa851af.html +309 -0
- tuningfork_lab-0.6.0/examples/hermes-architecture-diagram/evidence/diagrams/before-0fa851af.png +0 -0
- tuningfork_lab-0.6.0/examples/hermes-architecture-diagram/evidence/diffs/H.diff +69 -0
- tuningfork_lab-0.6.0/examples/hermes-architecture-diagram/evidence/diffs/T.diff +33 -0
- tuningfork_lab-0.6.0/examples/hermes-architecture-diagram/evidence/diffs/X.diff +27 -0
- tuningfork_lab-0.6.0/examples/hermes-architecture-diagram/evidence/h-added/references/common-patterns.md +36 -0
- tuningfork_lab-0.6.0/examples/hermes-architecture-diagram/evidence/h-added/references/layout-patterns.md +34 -0
- tuningfork_lab-0.6.0/examples/hermes-architecture-diagram/evidence/h-added/references/service-mapping.md +19 -0
- tuningfork_lab-0.6.0/examples/hermes-architecture-diagram/evidence/h-added/templates/aws-web-app-layout.html +225 -0
- tuningfork_lab-0.6.0/examples/hermes-architecture-diagram/evidence/h-added/templates/aws-web-app-standard.html +216 -0
- tuningfork_lab-0.6.0/examples/hermes-architecture-diagram/evidence/h-chain.md +48 -0
- tuningfork_lab-0.6.0/examples/hermes-architecture-diagram/evidence/results.json +339 -0
- tuningfork_lab-0.6.0/examples/hermes-architecture-diagram/evidence/t-session.md +54 -0
- tuningfork_lab-0.6.0/examples/hermes-architecture-diagram/evidence/task-words.md +28 -0
- tuningfork_lab-0.6.0/examples/hermes-design-md/LICENSE-hermes +21 -0
- tuningfork_lab-0.6.0/examples/hermes-design-md/README.md +638 -0
- tuningfork_lab-0.6.0/examples/hermes-design-md/checks/design.py +114 -0
- tuningfork_lab-0.6.0/examples/hermes-design-md/design-md/SKILL.md +199 -0
- tuningfork_lab-0.6.0/examples/hermes-design-md/design-md/templates/starter.md +99 -0
- tuningfork_lab-0.6.0/examples/hermes-design-md/evals.json +43 -0
- tuningfork_lab-0.6.0/examples/hermes-design-md/fix/SKILL-section.md +204 -0
- tuningfork_lab-0.6.0/examples/hermes-design-md/fix/SKILL.md +201 -0
- tuningfork_lab-0.6.0/examples/tally-report/SKILL.md +16 -0
- tuningfork_lab-0.6.0/examples/tally-report.evals.json +54 -0
- tuningfork_lab-0.6.0/examples/variants/tally-report/SKILL.v2.md +29 -0
- tuningfork_lab-0.6.0/pyproject.toml +93 -0
- tuningfork_lab-0.6.0/scripts/tuningfork +33 -0
- tuningfork_lab-0.6.0/scripts/tuningfork.ps1 +35 -0
- tuningfork_lab-0.6.0/src/tuningfork/__init__.py +3 -0
- tuningfork_lab-0.6.0/src/tuningfork/__main__.py +6 -0
- tuningfork_lab-0.6.0/src/tuningfork/access.py +129 -0
- tuningfork_lab-0.6.0/src/tuningfork/analysis/__init__.py +53 -0
- tuningfork_lab-0.6.0/src/tuningfork/analysis/conditions.py +149 -0
- tuningfork_lab-0.6.0/src/tuningfork/analysis/distribution.py +511 -0
- tuningfork_lab-0.6.0/src/tuningfork/analysis/divergence.py +177 -0
- tuningfork_lab-0.6.0/src/tuningfork/analysis/forking.py +304 -0
- tuningfork_lab-0.6.0/src/tuningfork/analysis/normalize.py +423 -0
- tuningfork_lab-0.6.0/src/tuningfork/analysis/reasoning.py +87 -0
- tuningfork_lab-0.6.0/src/tuningfork/analysis/screen.py +300 -0
- tuningfork_lab-0.6.0/src/tuningfork/analysis/stats.py +171 -0
- tuningfork_lab-0.6.0/src/tuningfork/analysis/tokens.py +623 -0
- tuningfork_lab-0.6.0/src/tuningfork/analysis/validation.py +323 -0
- tuningfork_lab-0.6.0/src/tuningfork/api/__init__.py +6 -0
- tuningfork_lab-0.6.0/src/tuningfork/api/connections.py +183 -0
- tuningfork_lab-0.6.0/src/tuningfork/api/control.py +179 -0
- tuningfork_lab-0.6.0/src/tuningfork/api/data.py +429 -0
- tuningfork_lab-0.6.0/src/tuningfork/api/guard.py +218 -0
- tuningfork_lab-0.6.0/src/tuningfork/api/imports.py +159 -0
- tuningfork_lab-0.6.0/src/tuningfork/api/jobs.py +118 -0
- tuningfork_lab-0.6.0/src/tuningfork/api/refinements.py +214 -0
- tuningfork_lab-0.6.0/src/tuningfork/api/scenarios.py +158 -0
- tuningfork_lab-0.6.0/src/tuningfork/api/skills.py +130 -0
- tuningfork_lab-0.6.0/src/tuningfork/api/trash.py +87 -0
- tuningfork_lab-0.6.0/src/tuningfork/backends/__init__.py +24 -0
- tuningfork_lab-0.6.0/src/tuningfork/backends/base.py +192 -0
- tuningfork_lab-0.6.0/src/tuningfork/backends/formats/__init__.py +47 -0
- tuningfork_lab-0.6.0/src/tuningfork/backends/formats/base.py +79 -0
- tuningfork_lab-0.6.0/src/tuningfork/backends/formats/gemma4.py +258 -0
- tuningfork_lab-0.6.0/src/tuningfork/backends/formats/qwen3_coder.py +506 -0
- tuningfork_lab-0.6.0/src/tuningfork/backends/formats/qwen_json.py +412 -0
- tuningfork_lab-0.6.0/src/tuningfork/backends/llamacpp/__init__.py +108 -0
- tuningfork_lab-0.6.0/src/tuningfork/backends/llamacpp/anthropic.py +149 -0
- tuningfork_lab-0.6.0/src/tuningfork/backends/llamacpp/raw.py +272 -0
- tuningfork_lab-0.6.0/src/tuningfork/backends/probe.py +844 -0
- tuningfork_lab-0.6.0/src/tuningfork/backends/raw.py +103 -0
- tuningfork_lab-0.6.0/src/tuningfork/breakpoints/__init__.py +27 -0
- tuningfork_lab-0.6.0/src/tuningfork/breakpoints/conditions.py +369 -0
- tuningfork_lab-0.6.0/src/tuningfork/breakpoints/engine.py +441 -0
- tuningfork_lab-0.6.0/src/tuningfork/breakpoints/events.py +71 -0
- tuningfork_lab-0.6.0/src/tuningfork/cli.py +5210 -0
- tuningfork_lab-0.6.0/src/tuningfork/config.py +747 -0
- tuningfork_lab-0.6.0/src/tuningfork/control.py +334 -0
- tuningfork_lab-0.6.0/src/tuningfork/demo/__init__.py +7 -0
- tuningfork_lab-0.6.0/src/tuningfork/demo/agent.py +137 -0
- tuningfork_lab-0.6.0/src/tuningfork/demo/lab.py +523 -0
- tuningfork_lab-0.6.0/src/tuningfork/demo/mock.py +434 -0
- tuningfork_lab-0.6.0/src/tuningfork/demo/task.py +123 -0
- tuningfork_lab-0.6.0/src/tuningfork/demo/toy.py +309 -0
- tuningfork_lab-0.6.0/src/tuningfork/endpoints.py +213 -0
- tuningfork_lab-0.6.0/src/tuningfork/experiment/__init__.py +55 -0
- tuningfork_lab-0.6.0/src/tuningfork/experiment/forking.py +253 -0
- tuningfork_lab-0.6.0/src/tuningfork/experiment/sampling.py +926 -0
- tuningfork_lab-0.6.0/src/tuningfork/experiment/scoring.py +254 -0
- tuningfork_lab-0.6.0/src/tuningfork/experiment/skill.py +448 -0
- tuningfork_lab-0.6.0/src/tuningfork/harness/__init__.py +31 -0
- tuningfork_lab-0.6.0/src/tuningfork/harness/base.py +194 -0
- tuningfork_lab-0.6.0/src/tuningfork/harness/claude_code.py +314 -0
- tuningfork_lab-0.6.0/src/tuningfork/harness/hermes.py +599 -0
- tuningfork_lab-0.6.0/src/tuningfork/jobs.py +571 -0
- tuningfork_lab-0.6.0/src/tuningfork/launches.py +189 -0
- tuningfork_lab-0.6.0/src/tuningfork/mcp/__init__.py +10 -0
- tuningfork_lab-0.6.0/src/tuningfork/mcp/backend.py +167 -0
- tuningfork_lab-0.6.0/src/tuningfork/mcp/http.py +100 -0
- tuningfork_lab-0.6.0/src/tuningfork/mcp/schema.py +164 -0
- tuningfork_lab-0.6.0/src/tuningfork/mcp/server.py +414 -0
- tuningfork_lab-0.6.0/src/tuningfork/mcp/stdio.py +98 -0
- tuningfork_lab-0.6.0/src/tuningfork/mcp/tools.py +1591 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/__init__.py +36 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/addskill.py +396 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/approve.py +619 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/batch.py +487 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/catalog.py +985 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/chain.py +501 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/checks.py +461 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/common.py +319 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/compact.py +1198 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/connections.py +506 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/diff.py +339 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/experiments.py +922 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/forking.py +317 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/forks.py +707 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/glossary.py +351 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/holds.py +271 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/imports.py +1485 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/inspect.py +978 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/launch.py +80 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/packet.py +270 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/private.py +245 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/proposer.py +433 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/refine.py +796 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/scenarios.py +503 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/screen.py +910 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/skills.py +539 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/spend.py +209 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/tally.py +338 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/targets.py +251 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/timeline.py +732 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/tokens.py +335 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/trash.py +606 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/validate.py +486 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/variants.py +134 -0
- tuningfork_lab-0.6.0/src/tuningfork/ops/where.py +592 -0
- tuningfork_lab-0.6.0/src/tuningfork/owners.py +50 -0
- tuningfork_lab-0.6.0/src/tuningfork/paths.py +160 -0
- tuningfork_lab-0.6.0/src/tuningfork/proxy/__init__.py +1 -0
- tuningfork_lab-0.6.0/src/tuningfork/proxy/app.py +988 -0
- tuningfork_lab-0.6.0/src/tuningfork/proxy/held.py +446 -0
- tuningfork_lab-0.6.0/src/tuningfork/proxy/launches.py +210 -0
- tuningfork_lab-0.6.0/src/tuningfork/proxy/local.py +148 -0
- tuningfork_lab-0.6.0/src/tuningfork/proxy/recorder.py +386 -0
- tuningfork_lab-0.6.0/src/tuningfork/proxy/replay.py +99 -0
- tuningfork_lab-0.6.0/src/tuningfork/proxy/sse.py +346 -0
- tuningfork_lab-0.6.0/src/tuningfork/replay.py +490 -0
- tuningfork_lab-0.6.0/src/tuningfork/runner.py +1156 -0
- tuningfork_lab-0.6.0/src/tuningfork/sandbox.py +339 -0
- tuningfork_lab-0.6.0/src/tuningfork/snapshots.py +270 -0
- tuningfork_lab-0.6.0/src/tuningfork/specs.py +724 -0
- tuningfork_lab-0.6.0/src/tuningfork/store/__init__.py +6 -0
- tuningfork_lab-0.6.0/src/tuningfork/store/blobs.py +88 -0
- tuningfork_lab-0.6.0/src/tuningfork/store/db.py +2817 -0
- tuningfork_lab-0.6.0/src/tuningfork/store/masking.py +156 -0
- tuningfork_lab-0.6.0/src/tuningfork/store/tree.py +118 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/__init__.py +33 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/app.css +1745 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/index.html +104 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/api.js +92 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/app.js +415 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/auth.js +88 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/checktry.js +258 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/cost.js +23 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/dom.js +308 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/forms.js +246 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/holdtools.js +131 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/jobs.js +332 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/launcher.js +95 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/live.js +129 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/markdown.js +306 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/nav.js +30 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/payload.js +287 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/results.js +587 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/start.js +593 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/stepinfo.js +231 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/targets.js +144 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/timeline.js +1002 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/tokens.js +412 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/trash.js +113 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/variants.js +197 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/views/batch.js +194 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/views/chains.js +91 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/views/compare.js +305 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/views/connections.js +555 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/views/experiments.js +365 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/views/home.js +397 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/views/import.js +570 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/views/jobs.js +446 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/views/live.js +848 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/views/refine.js +1352 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/views/run.js +246 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/views/runs.js +264 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/views/scenarios.js +574 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/views/skills.js +466 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/views/step.js +144 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/views/trash.js +90 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/where.js +141 -0
- tuningfork_lab-0.6.0/src/tuningfork/ui/static/js/words.js +55 -0
- tuningfork_lab-0.6.0/src/tuningfork/wire/__init__.py +28 -0
- tuningfork_lab-0.6.0/src/tuningfork/wire/anthropic.py +605 -0
- tuningfork_lab-0.6.0/src/tuningfork/wire/base.py +176 -0
- tuningfork_lab-0.6.0/src/tuningfork/wire/completion.py +136 -0
- tuningfork_lab-0.6.0/src/tuningfork/wire/openai.py +162 -0
- tuningfork_lab-0.6.0/tests/__init__.py +0 -0
- tuningfork_lab-0.6.0/tests/browser/README.md +201 -0
- tuningfork_lab-0.6.0/tests/browser/cdp.mjs +174 -0
- tuningfork_lab-0.6.0/tests/browser/jobs_ui.mjs +2194 -0
- tuningfork_lab-0.6.0/tests/browser/live_ui.mjs +170 -0
- tuningfork_lab-0.6.0/tests/conftest.py +133 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/capture.py +150 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/gemma4/braces-1.json +71 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/gemma4/braces-2.json +176 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/gemma4/nested-1.json +219 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/gemma4/nested-2.json +229 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/gemma4/no-call-with-tools-1.json +105 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/gemma4/no-call-with-tools-2.json +59 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/gemma4/numbers-1.json +171 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/gemma4/numbers-2.json +159 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/gemma4/one-call-1.json +85 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/gemma4/one-call-2.json +93 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/gemma4/parallel-1.json +166 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/gemma4/parallel-2.json +158 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/gemma4/text-1.json +122 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/gemma4/text-2.json +138 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/gemma4/text-nothink-1.json +18 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/gemma4/text-nothink-2.json +18 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/gemma4/text-then-call-1.json +112 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/gemma4/text-then-call-2.json +113 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/gemma4/unicode-1.json +129 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/gemma4/unicode-2.json +158 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/braces-1.json +96 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/braces-2.json +96 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/call-nothink-1.json +63 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/call-nothink-2.json +63 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/multiline-1.json +78 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/multiline-2.json +78 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/nested-1.json +126 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/nested-2.json +126 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/no-call-with-tools-1.json +45 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/no-call-with-tools-2.json +40 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/no-think-switch-1.json +20 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/no-think-switch-2.json +20 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/numbers-1.json +87 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/numbers-2.json +87 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/one-call-1.json +62 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/one-call-2.json +62 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/parallel-1.json +87 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/parallel-2.json +87 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/text-1.json +29 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/text-2.json +29 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/text-nothink-1.json +20 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/text-nothink-2.json +20 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/text-then-call-1.json +73 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/text-then-call-2.json +74 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/unicode-1.json +84 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen2.5/qwen2.5-32b-instruct/unicode-2.json +84 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/braces-1.json +371 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/braces-2.json +522 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/call-nothink-1.json +63 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/call-nothink-2.json +63 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/multiline-1.json +275 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/multiline-2.json +333 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/nested-1.json +340 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/nested-2.json +347 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/no-call-with-tools-1.json +135 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/no-call-with-tools-2.json +146 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/no-think-switch-1.json +24 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/no-think-switch-2.json +24 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/numbers-1.json +231 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/numbers-2.json +184 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/one-call-1.json +134 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/one-call-2.json +135 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/parallel-1.json +197 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/parallel-2.json +215 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/text-1.json +233 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/text-2.json +186 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/text-nothink-1.json +20 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/text-nothink-2.json +20 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/text-then-call-1.json +461 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/text-then-call-2.json +318 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/unicode-1.json +202 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b/unicode-2.json +207 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/braces-1.json +96 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/braces-2.json +96 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/call-nothink-1.json +63 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/call-nothink-2.json +63 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/multiline-1.json +78 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/multiline-2.json +78 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/nested-1.json +126 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/nested-2.json +126 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/no-call-with-tools-1.json +47 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/no-call-with-tools-2.json +47 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/no-think-switch-1.json +20 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/no-think-switch-2.json +20 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/numbers-1.json +87 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/numbers-2.json +87 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/one-call-1.json +62 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/one-call-2.json +62 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/parallel-1.json +87 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/parallel-2.json +87 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/text-1.json +29 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/text-2.json +29 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/text-nothink-1.json +20 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/text-nothink-2.json +20 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/text-then-call-1.json +74 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/text-then-call-2.json +74 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/unicode-1.json +84 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-30b-a3b-instruct-2507/unicode-2.json +84 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/braces-1.json +5132 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/braces-2.json +469 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/call-nothink-1.json +156 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/call-nothink-2.json +150 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/multiline-1.json +261 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/multiline-2.json +2905 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/nested-1.json +656 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/nested-2.json +630 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/no-call-with-tools-1.json +286 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/no-call-with-tools-2.json +207 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/no-think-switch-1.json +1711 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/no-think-switch-2.json +466 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/numbers-1.json +374 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/numbers-2.json +384 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/one-call-1.json +182 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/one-call-2.json +172 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/parallel-1.json +477 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/parallel-2.json +463 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/text-1.json +249 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/text-2.json +742 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/text-nothink-1.json +265 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/text-nothink-2.json +272 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/text-then-call-1.json +2898 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/text-then-call-2.json +3475 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/unicode-1.json +643 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3/qwen3-4b-thinking-2507/unicode-2.json +878 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/braces-1.json +101 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/braces-2.json +101 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/call-nothink-1.json +65 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/call-nothink-2.json +65 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/multiline-1.json +83 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/multiline-2.json +83 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/nested-1.json +146 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/nested-2.json +146 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/no-call-with-tools-1.json +48 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/no-call-with-tools-2.json +40 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/no-marker-1.json +63 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/no-marker-2.json +63 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/no-think-switch-1.json +21 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/no-think-switch-2.json +20 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/numbers-1.json +89 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/numbers-2.json +89 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/one-call-1.json +64 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/one-call-2.json +64 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/parallel-1.json +91 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/parallel-2.json +91 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/text-1.json +29 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/text-2.json +29 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/text-nothink-1.json +21 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/text-nothink-2.json +21 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/text-then-call-1.json +91 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/text-then-call-2.json +95 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/text-then-no-marker-1.json +98 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/text-then-no-marker-2.json +98 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/unicode-1.json +90 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-30b-a3b-instruct/unicode-2.json +90 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/braces-1.json +101 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/braces-2.json +101 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/call-nothink-1.json +65 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/call-nothink-2.json +65 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/multiline-1.json +83 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/multiline-2.json +83 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/nested-1.json +146 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/nested-2.json +146 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/no-call-with-tools-1.json +47 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/no-call-with-tools-2.json +47 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/no-marker-1.json +51 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/no-marker-2.json +55 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/no-think-switch-1.json +20 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/no-think-switch-2.json +20 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/numbers-1.json +99 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/numbers-2.json +99 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/one-call-1.json +64 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/one-call-2.json +64 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/parallel-1.json +91 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/parallel-2.json +91 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/text-1.json +29 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/text-2.json +29 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/text-nothink-1.json +20 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/text-nothink-2.json +20 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/text-then-call-1.json +65 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/text-then-call-2.json +76 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/text-then-no-marker-1.json +1061 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/text-then-no-marker-2.json +94 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/unicode-1.json +90 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3-coder/qwen3-coder-next/unicode-2.json +90 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/braces-1.json +199 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/braces-2.json +197 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/call-nothink-1.json +69 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/call-nothink-2.json +69 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/multiline-1.json +186 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/multiline-2.json +171 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/nested-1.json +312 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/nested-2.json +312 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/no-call-with-tools-1.json +89 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/no-call-with-tools-2.json +94 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/numbers-1.json +205 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/numbers-2.json +220 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/one-call-1.json +114 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/one-call-2.json +114 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/parallel-1.json +163 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/parallel-2.json +190 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/text-1.json +252 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/text-2.json +253 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/text-nothink-1.json +20 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/text-nothink-2.json +20 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/text-then-call-1.json +160 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/text-then-call-2.json +154 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/unicode-1.json +218 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.5-27b/unicode-2.json +200 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/braces-1.json +523 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/braces-2.json +861 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/call-nothink-1.json +69 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/call-nothink-2.json +69 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/multiline-1.json +191 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/multiline-2.json +393 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/nested-1.json +325 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/nested-2.json +884 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/no-call-with-tools-1.json +222 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/no-call-with-tools-2.json +310 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/numbers-1.json +395 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/numbers-2.json +297 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/one-call-1.json +114 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/one-call-2.json +111 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/parallel-1.json +169 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/parallel-2.json +251 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/text-1.json +495 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/text-2.json +219 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/text-nothink-1.json +21 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/text-nothink-2.json +20 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/text-then-call-1.json +448 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/text-then-call-2.json +737 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/unicode-1.json +445 -0
- tuningfork_lab-0.6.0/tests/fixtures/formats/qwen3.5/qwen3.6-27b/unicode-2.json +178 -0
- tuningfork_lab-0.6.0/tests/golden/ab-exploratory.txt +23 -0
- tuningfork_lab-0.6.0/tests/golden/ab.txt +28 -0
- tuningfork_lab-0.6.0/tests/golden/diff.txt +5 -0
- tuningfork_lab-0.6.0/tests/golden/divergence-lens.txt +10 -0
- tuningfork_lab-0.6.0/tests/golden/divergence.txt +10 -0
- tuningfork_lab-0.6.0/tests/golden/experiment-ab.txt +25 -0
- tuningfork_lab-0.6.0/tests/golden/experiment-resample-lens.txt +11 -0
- tuningfork_lab-0.6.0/tests/golden/experiment-resample.txt +10 -0
- tuningfork_lab-0.6.0/tests/golden/experiments.txt +6 -0
- tuningfork_lab-0.6.0/tests/golden/resample.txt +16 -0
- tuningfork_lab-0.6.0/tests/golden/runs-called.txt +4 -0
- tuningfork_lab-0.6.0/tests/golden/runs-quiet.txt +4 -0
- tuningfork_lab-0.6.0/tests/golden/runs.txt +7 -0
- tuningfork_lab-0.6.0/tests/golden/show.txt +7 -0
- tuningfork_lab-0.6.0/tests/golden/step-full.txt +33 -0
- tuningfork_lab-0.6.0/tests/golden/step.txt +12 -0
- tuningfork_lab-0.6.0/tests/golden/tasks.txt +9 -0
- tuningfork_lab-0.6.0/tests/golden/timeline-full.txt +33 -0
- tuningfork_lab-0.6.0/tests/golden/timeline.txt +14 -0
- tuningfork_lab-0.6.0/tests/helpers.py +337 -0
- tuningfork_lab-0.6.0/tests/test_access.py +192 -0
- tuningfork_lab-0.6.0/tests/test_addskill.py +222 -0
- tuningfork_lab-0.6.0/tests/test_analysis.py +318 -0
- tuningfork_lab-0.6.0/tests/test_api.py +379 -0
- tuningfork_lab-0.6.0/tests/test_approve.py +317 -0
- tuningfork_lab-0.6.0/tests/test_approve_front.py +163 -0
- tuningfork_lab-0.6.0/tests/test_batch.py +274 -0
- tuningfork_lab-0.6.0/tests/test_breakpoints.py +450 -0
- tuningfork_lab-0.6.0/tests/test_canaries.py +256 -0
- tuningfork_lab-0.6.0/tests/test_chain.py +355 -0
- tuningfork_lab-0.6.0/tests/test_chat_import.py +881 -0
- tuningfork_lab-0.6.0/tests/test_check_along.py +284 -0
- tuningfork_lab-0.6.0/tests/test_checks.py +169 -0
- tuningfork_lab-0.6.0/tests/test_claude_code.py +476 -0
- tuningfork_lab-0.6.0/tests/test_cli.py +580 -0
- tuningfork_lab-0.6.0/tests/test_cli_control.py +283 -0
- tuningfork_lab-0.6.0/tests/test_cli_golden.py +191 -0
- tuningfork_lab-0.6.0/tests/test_compact.py +287 -0
- tuningfork_lab-0.6.0/tests/test_connections.py +642 -0
- tuningfork_lab-0.6.0/tests/test_demo.py +191 -0
- tuningfork_lab-0.6.0/tests/test_diff.py +235 -0
- tuningfork_lab-0.6.0/tests/test_distribution.py +325 -0
- tuningfork_lab-0.6.0/tests/test_docs.py +68 -0
- tuningfork_lab-0.6.0/tests/test_endpoints.py +243 -0
- tuningfork_lab-0.6.0/tests/test_example_hermes_design_md.py +77 -0
- tuningfork_lab-0.6.0/tests/test_experiments.py +714 -0
- tuningfork_lab-0.6.0/tests/test_fork_variant.py +68 -0
- tuningfork_lab-0.6.0/tests/test_forking.py +443 -0
- tuningfork_lab-0.6.0/tests/test_forks.py +706 -0
- tuningfork_lab-0.6.0/tests/test_formats.py +691 -0
- tuningfork_lab-0.6.0/tests/test_guard.py +244 -0
- tuningfork_lab-0.6.0/tests/test_harness.py +426 -0
- tuningfork_lab-0.6.0/tests/test_held.py +595 -0
- tuningfork_lab-0.6.0/tests/test_held_out.py +182 -0
- tuningfork_lab-0.6.0/tests/test_hold_tools.py +240 -0
- tuningfork_lab-0.6.0/tests/test_imports.py +30 -0
- tuningfork_lab-0.6.0/tests/test_jobs.py +543 -0
- tuningfork_lab-0.6.0/tests/test_jobs_e2e.py +270 -0
- tuningfork_lab-0.6.0/tests/test_jobs_harness.py +134 -0
- tuningfork_lab-0.6.0/tests/test_launches.py +553 -0
- tuningfork_lab-0.6.0/tests/test_live_server.py +103 -0
- tuningfork_lab-0.6.0/tests/test_mcp_http.py +167 -0
- tuningfork_lab-0.6.0/tests/test_mcp_schema.py +149 -0
- tuningfork_lab-0.6.0/tests/test_mcp_stdio.py +206 -0
- tuningfork_lab-0.6.0/tests/test_mcp_tools.py +896 -0
- tuningfork_lab-0.6.0/tests/test_ops_common.py +192 -0
- tuningfork_lab-0.6.0/tests/test_packet.py +81 -0
- tuningfork_lab-0.6.0/tests/test_paths.py +102 -0
- tuningfork_lab-0.6.0/tests/test_private.py +160 -0
- tuningfork_lab-0.6.0/tests/test_probe.py +435 -0
- tuningfork_lab-0.6.0/tests/test_progress.py +105 -0
- tuningfork_lab-0.6.0/tests/test_proposer.py +186 -0
- tuningfork_lab-0.6.0/tests/test_proxy.py +1120 -0
- tuningfork_lab-0.6.0/tests/test_qwen3_coder_tokens.py +143 -0
- tuningfork_lab-0.6.0/tests/test_qwen3_tokens.py +412 -0
- tuningfork_lab-0.6.0/tests/test_qwen_tokens.py +148 -0
- tuningfork_lab-0.6.0/tests/test_reads.py +102 -0
- tuningfork_lab-0.6.0/tests/test_real_server.py +177 -0
- tuningfork_lab-0.6.0/tests/test_reasoning.py +151 -0
- tuningfork_lab-0.6.0/tests/test_refine.py +178 -0
- tuningfork_lab-0.6.0/tests/test_refine_front.py +282 -0
- tuningfork_lab-0.6.0/tests/test_reports.py +373 -0
- tuningfork_lab-0.6.0/tests/test_runner.py +830 -0
- tuningfork_lab-0.6.0/tests/test_sandbox.py +351 -0
- tuningfork_lab-0.6.0/tests/test_scenarios.py +284 -0
- tuningfork_lab-0.6.0/tests/test_scoring.py +223 -0
- tuningfork_lab-0.6.0/tests/test_screen.py +191 -0
- tuningfork_lab-0.6.0/tests/test_screen_stats.py +171 -0
- tuningfork_lab-0.6.0/tests/test_screen_to_end.py +380 -0
- tuningfork_lab-0.6.0/tests/test_servers.py +104 -0
- tuningfork_lab-0.6.0/tests/test_skill_substitution.py +336 -0
- tuningfork_lab-0.6.0/tests/test_skills.py +230 -0
- tuningfork_lab-0.6.0/tests/test_snapshots.py +132 -0
- tuningfork_lab-0.6.0/tests/test_specs.py +218 -0
- tuningfork_lab-0.6.0/tests/test_spend.py +92 -0
- tuningfork_lab-0.6.0/tests/test_sse.py +328 -0
- tuningfork_lab-0.6.0/tests/test_storage.py +557 -0
- tuningfork_lab-0.6.0/tests/test_store.py +547 -0
- tuningfork_lab-0.6.0/tests/test_store_masking.py +458 -0
- tuningfork_lab-0.6.0/tests/test_tally.py +232 -0
- tuningfork_lab-0.6.0/tests/test_targets.py +225 -0
- tuningfork_lab-0.6.0/tests/test_timeline.py +381 -0
- tuningfork_lab-0.6.0/tests/test_tokens.py +362 -0
- tuningfork_lab-0.6.0/tests/test_tokens_ops.py +170 -0
- tuningfork_lab-0.6.0/tests/test_trash.py +433 -0
- tuningfork_lab-0.6.0/tests/test_trash_refinements.py +162 -0
- tuningfork_lab-0.6.0/tests/test_ui.py +245 -0
- tuningfork_lab-0.6.0/tests/test_validate.py +319 -0
- tuningfork_lab-0.6.0/tests/test_validation_gate.py +146 -0
- tuningfork_lab-0.6.0/tests/test_variants.py +67 -0
- tuningfork_lab-0.6.0/tests/test_where.py +257 -0
- tuningfork_lab-0.6.0/tests/test_wire.py +571 -0
- tuningfork_lab-0.6.0/tests/test_words.py +38 -0
- tuningfork_lab-0.6.0/tests/test_wsl_wrapper.py +76 -0
- tuningfork_lab-0.6.0/uv.lock +918 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# The contribution gate: the whole suite, with no GPU and no model, on every supported Python.
|
|
2
|
+
name: tests
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main]
|
|
7
|
+
pull_request:
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: tests-${{ github.ref }}
|
|
15
|
+
cancel-in-progress: true
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
test:
|
|
19
|
+
name: Python ${{ matrix.python }}
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
timeout-minutes: 30
|
|
22
|
+
strategy:
|
|
23
|
+
fail-fast: false
|
|
24
|
+
matrix:
|
|
25
|
+
python: ["3.12", "3.13", "3.14"]
|
|
26
|
+
steps:
|
|
27
|
+
# Pinned to commits: a tag can move, and setup-uv publishes no major-version tag.
|
|
28
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
29
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
30
|
+
with:
|
|
31
|
+
python-version: ${{ matrix.python }}
|
|
32
|
+
- name: Install
|
|
33
|
+
run: uv sync --all-groups --locked
|
|
34
|
+
- name: Test
|
|
35
|
+
run: uv run pytest -q
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
.venv/
|
|
4
|
+
venv/
|
|
5
|
+
.pytest_cache/
|
|
6
|
+
.ruff_cache/
|
|
7
|
+
*.egg-info/
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
|
|
11
|
+
# Local notes and settings, never committed: CLAUDE.local.md, a probe's *.local.json
|
|
12
|
+
*.local.md
|
|
13
|
+
*.local.json
|
|
14
|
+
|
|
15
|
+
# Local recording state
|
|
16
|
+
*.db
|
|
17
|
+
*.db-wal
|
|
18
|
+
*.db-shm
|
|
19
|
+
.tuningfork/
|
|
@@ -0,0 +1,566 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.6.0 — on PyPI, a demo without a GPU, and redaction reworked
|
|
4
|
+
|
|
5
|
+
tuningfork is on PyPI as `tuningfork-lab`, and `tuningfork demo` shows the whole loop in the web
|
|
6
|
+
UI with no GPU and no model. The README is shorter. Redaction, which masks keys in what tuningfork
|
|
7
|
+
records, was reworked: it masks keys rather than code, never breaks the JSON it masks, and knows
|
|
8
|
+
more formats, and the recordings folder's store masks everything it keeps, once.
|
|
9
|
+
|
|
10
|
+
- **On PyPI as `tuningfork-lab`.** `uv tool install "tuningfork-lab[mcp]"` installs the
|
|
11
|
+
`tuningfork` command, its MCP server included; without `[mcp]`, the rest. The import stays
|
|
12
|
+
`tuningfork`. The name `tuningfork` is too close to an existing project's to register.
|
|
13
|
+
- **`tuningfork demo`** opens the web UI on made-up runs, which tuningfork's own proxy serves in
|
|
14
|
+
front of a scripted model, so every button works without a GPU:
|
|
15
|
+
`uvx --from tuningfork-lab tuningfork demo`. It records only into a folder of its own, never
|
|
16
|
+
into `~/.tuningfork`.
|
|
17
|
+
- **The README** says what tuningfork is, why, and how to start: the demo first, then your own
|
|
18
|
+
agent. Its command tables lead to `docs/commands.md`, and the web UI's pictures moved to
|
|
19
|
+
`docs/web-ui.md`.
|
|
20
|
+
- **Redaction masks keys, not code.** A value under a secret's name is masked only where it reads
|
|
21
|
+
as a key: a name, a call, a path or a number is kept. Hermes's own source, read as tool results,
|
|
22
|
+
had 731 masks in 147 of its 877 files, and has 2 now, both example keys. Its dependencies went
|
|
23
|
+
from 273 masks to 7, and Python's standard library from 27 to none. A mask still costs a step
|
|
24
|
+
its scoring and its forking tokens, and a resample sends `<redacted>` where the model saw the
|
|
25
|
+
text: a plan says so now.
|
|
26
|
+
- **More formats are masked by their shape:** provider tokens (`gsk_`, `hf_`, `glpat-`,
|
|
27
|
+
`github_pat_`, `AIza…` and more), Stripe's keys, JWTs, Discord and Telegram bot tokens, private
|
|
28
|
+
keys, a URL's password, HTTP Basic credentials, AWS's and Azure's secret keys, and Slack
|
|
29
|
+
webhooks. Of 47 key formats in 12 places a key stands, 537 are masked, against 258.
|
|
30
|
+
- **A mask never breaks JSON.** A number is never masked, and of 30,000 fuzzed payloads none is
|
|
31
|
+
dropped, against 2,459. JSON written inside a string stays JSON.
|
|
32
|
+
- **A key the model streams in pieces** is no longer kept in the raw bytes beside its answer,
|
|
33
|
+
which a fork read back and gave its harness again. Bytes that hold a secret are written again
|
|
34
|
+
from the masked answer, and a fork refuses to replay that step.
|
|
35
|
+
- **The store masks everything it keeps, once.** A check's output in a run's result and a
|
|
36
|
+
launch's exit, a job's plan and result, an imported chat's steps, a step's error text, a label
|
|
37
|
+
queued for the next run, and an upstream's password were kept in clear. A value masked in one form of a
|
|
38
|
+
step is masked in its others, so a server's error that quotes a password is masked, and so is a
|
|
39
|
+
key the model writes in its own call syntax, in its tokens. An answer sent at once keeps no
|
|
40
|
+
logprobs that spell a key, and a stream labelled otherwise is read as a stream. What a run is
|
|
41
|
+
given is kept as given: its task, a wording tried, a scenario's conversation.
|
|
42
|
+
|
|
43
|
+
Changed:
|
|
44
|
+
|
|
45
|
+
- **`/_tuningfork/health`, Connections and `serve`** show an upstream's user and password as
|
|
46
|
+
`<redacted>`, and Connections says to type them back into its restart command.
|
|
47
|
+
- **A step's parameters** count its masks (`masked`) and name the patterns that made them
|
|
48
|
+
(`redaction`), which `tuningfork step` prints.
|
|
49
|
+
- **`Settings.redaction_patterns` is gone:** a `Store` holds its patterns.
|
|
50
|
+
|
|
51
|
+
Recordings made before keep what they stored: masking them again with today's rules is planned. A
|
|
52
|
+
fork of a run recorded before still matches its calls, each mask standing for what it hid.
|
|
53
|
+
|
|
54
|
+
## 0.5.0 — Qwen models, token by token
|
|
55
|
+
|
|
56
|
+
Token-level work — scoring an answer, forking tokens, a resample's kept tokens marked by part,
|
|
57
|
+
the model's own odds of each tool — reads Qwen3.5 and 3.6, Qwen3, Qwen2.5 and Qwen3-Coder now,
|
|
58
|
+
beside Gemma 4, each as llama.cpp reads it. A Claude Code step is scored on the tokens the model
|
|
59
|
+
wrote, and a recorded request or answer no longer keeps a key on a line of its own in clear. The
|
|
60
|
+
README opens in plainer words.
|
|
61
|
+
|
|
62
|
+
- **Qwen3.5 and Qwen3.6** (`qwen3.5`, as the server check names the format), read as llama.cpp's
|
|
63
|
+
Qwen3-Coder parser reads them: an answer can begin inside a reasoning its prompt opened, and
|
|
64
|
+
each argument is typed by the tool's schema, as the server types it.
|
|
65
|
+
- **Qwen3, the 2507 updates included, and Qwen2.5** (`qwen3`, `qwen2.5`), whose calls are JSON
|
|
66
|
+
inside `<tool_call>`, read as the parser llama.cpp builds from their templates reads them. A
|
|
67
|
+
Qwen3 template that renders no reasoning, as ggml-org's for Qwen3-2507 Instruct does, gets
|
|
68
|
+
Qwen2.5's parser from the server, and is named `qwen2.5`.
|
|
69
|
+
- **Qwen3-Coder** (`qwen3-coder`), read by the same parser of llama.cpp's as Qwen3.5, in its
|
|
70
|
+
other setting: no reasoning, and a first call with its `<tool_call>` or without it.
|
|
71
|
+
- **Texts the server reads alike** give the same parsed answer: for Qwen3, an empty reasoning
|
|
72
|
+
and none; for Qwen3 and Qwen2.5, a newline and a blank line between calls; for Qwen3-Coder, a
|
|
73
|
+
first call with its `<tool_call>` and one without. Scoring keeps the text with the recorded
|
|
74
|
+
number of tokens, and where several have it, the one the model finds likelier where they part.
|
|
75
|
+
`tuningfork tokens` and a step's *Tokens* view then say "rebuilt as the likelier of 2 texts the
|
|
76
|
+
server reads alike", and a forking probe from it warns.
|
|
77
|
+
- **Checked on real servers:** Qwen3.5 27B and Qwen3.6 27B; Qwen3-30B-A3B,
|
|
78
|
+
Qwen3-30B-A3B-Instruct-2507 and Qwen3-4B-Thinking-2507; Qwen2.5-32B-Instruct;
|
|
79
|
+
Qwen3-Coder-30B-A3B-Instruct and Qwen3-Coder-Next. On each, the server's own answers were read
|
|
80
|
+
as it read them and written back token for token, and the real-server tests
|
|
81
|
+
(`tests/test_real_server.py`) pass.
|
|
82
|
+
- **A character written in two tokens.** llama.cpp can report it as one probability entry, which
|
|
83
|
+
holds the whole character, and Qwen does this. Scoring and a forking probe's continuations split
|
|
84
|
+
it back into one entry a token, by the token ids the server returns: a token merged away has no
|
|
85
|
+
probability of its own, shown as "—". Without this, scoring would refuse such an answer. A
|
|
86
|
+
resample's kept tokens keep the one entry: the chat endpoint returns no ids to split it by.
|
|
87
|
+
- **Setting up a server for them** (`docs/setup.md`): a command for Qwen3.6 27B,
|
|
88
|
+
Qwen3-30B-A3B-Instruct-2507 and Qwen3-Coder-30B-A3B, how Qwen3-Coder-Next fits one 32 GB GPU,
|
|
89
|
+
and how to extend a model file whose context is too short for Hermes Agent. Qwen3.5 and 3.6
|
|
90
|
+
need `--ctx-checkpoints 0`, and `--swa-full`, an alternative for Gemma 4, does not help them.
|
|
91
|
+
The glossary and the Guide's banner say so.
|
|
92
|
+
- **A Claude Code step is scored on the tokens the model wrote.** A streamed tool call's
|
|
93
|
+
arguments are kept as the server sent them. They were written again from the parsed input, with
|
|
94
|
+
characters outside ASCII escaped, numbers normalized (`61.50` became `61.5`) and the model's
|
|
95
|
+
spacing lost. Scoring could then rebuild other tokens than the model's, and said "rebuilt
|
|
96
|
+
approximately". A step recorded before is scored from the stream the server sent, which the
|
|
97
|
+
recording kept. An answer that was not streamed comes parsed, and its arguments are still
|
|
98
|
+
written from it.
|
|
99
|
+
- **The README** opens in plain words, and its quickstart comes early: install, a five-minute
|
|
100
|
+
walkthrough without a GPU, then your own agent. Its figure is redrawn as the loop in four steps,
|
|
101
|
+
with counts only, and its tagline is now "Tune agent skills to your own model." The worked
|
|
102
|
+
example, *See it work*, now follows *Let an agent drive it*.
|
|
103
|
+
- **find-the-file's forking token, measured again** with 40 continuations a word, where the
|
|
104
|
+
earlier probe drew 10: after "Wait", 30 searched for the file, and after "According", none
|
|
105
|
+
(p = 1.9 × 10⁻¹³). Its section 4 now calls "Wait" a forking token.
|
|
106
|
+
- **The examples guide's Claude Code steps**, recorded again with the arguments kept as sent.
|
|
107
|
+
|
|
108
|
+
Changed:
|
|
109
|
+
|
|
110
|
+
- **Redaction reads stored text as it reads.** It matched its patterns against JSON as written,
|
|
111
|
+
where a newline is a backslash and an `n`: an `sk-` key or a `Bearer` token on a line of its
|
|
112
|
+
own, or after a tab, then followed a letter, and was stored in clear in every harness's
|
|
113
|
+
recordings. Nor did an assignment whose value is in double quotes, such as `api_key = "…"` or
|
|
114
|
+
`"token": "…"`, match inside a message, a call's arguments or a tool's result, where JSON
|
|
115
|
+
escapes every quote. The patterns now also run over the text with its JSON escapes read, three
|
|
116
|
+
levels deep: a payload, the arguments or JSON result in it, and a JSON file that result shows.
|
|
117
|
+
A key with an escape inside it is masked whole, in a Claude Code call's arguments too. A token
|
|
118
|
+
stream reads the model's own escapes the same way. Recordings made before keep what they
|
|
119
|
+
stored, and a streamed answer's raw bytes, kept beside it, can still hold a key the server sent
|
|
120
|
+
in pieces.
|
|
121
|
+
- **A Claude Code step's arguments read as the server sent them** wherever they are printed as
|
|
122
|
+
text: `tuningfork step` and `timeline`, a held call, and MCP's `show_step`. Before, they read as
|
|
123
|
+
Python's `json.dumps` of the input, with a space after each `:` and `,`, characters outside
|
|
124
|
+
ASCII escaped and numbers normalized. The web UI shows each argument as a field, as before.
|
|
125
|
+
Steps recorded before keep what they stored. A behaviour, a target and a breakpoint read the
|
|
126
|
+
parsed arguments, so none of them changes.
|
|
127
|
+
|
|
128
|
+
Nothing already in the recordings folder changes: no new columns, nothing to migrate.
|
|
129
|
+
|
|
130
|
+
QwQ is not read yet: llama.cpp reads it with a parser of its own.
|
|
131
|
+
|
|
132
|
+
## 0.4.0 — the web UI, redesigned
|
|
133
|
+
|
|
134
|
+
The web UI, page by page, after a review of it: a sidebar in the loop's order, plainer words, one
|
|
135
|
+
meaning a colour, each page leading with its take-away, and the work on a step beside the run.
|
|
136
|
+
The CLI, MCP and the docs keep tuningfork's precise words.
|
|
137
|
+
|
|
138
|
+
- **A sidebar in the loop's order**, where the top bar's ten tabs were: the Guide and its Words,
|
|
139
|
+
Connections; then Start (Scenarios, Run a task…, Import a chat, Live, Skills, Jobs), Record
|
|
140
|
+
(Runs, Chains), Measure (Experiments), Improve (Refine) and the Trash. Its foot says how the
|
|
141
|
+
proxy, the server and the harnesses are. What needs a running proxy stays in it, greyed, saying
|
|
142
|
+
why. Narrower, it shows only its icons; on a phone, it opens from a bar across the top.
|
|
143
|
+
- **Plain words on the pages**: an arm is a *wording*, a target *what you count* (a refinement's,
|
|
144
|
+
*what the model should do*), a screen a *test at this step*, a validation *full test runs*, the
|
|
145
|
+
gate the *approval checks*, a spec a *task file*. The CLI, MCP, the docs and every sentence the
|
|
146
|
+
server writes keep the precise words. The glossary holds both: the Words page (`#/words`, where
|
|
147
|
+
older `#/guide?term=` links land) shows them side by side, and `tuningfork glossary` finds a
|
|
148
|
+
term by either and prints the page's phrase.
|
|
149
|
+
- **One meaning a colour**: green and red for a check's verdict — a run's, a fork's, a gate's, a
|
|
150
|
+
significant change in how often a task's check passes; amber a caution; the accent what can be
|
|
151
|
+
acted on, what is current or significant, the model's own answer and every rate, a pass rate
|
|
152
|
+
included; purple a skill's own words; teal, with ✎, what a person or tuningfork changed; grey
|
|
153
|
+
everything else. Red keeps only what every page means by it besides: a diff's removed lines
|
|
154
|
+
beside its green added ones, a button that deletes, a field to put right. The Guide shows the
|
|
155
|
+
legend in a line.
|
|
156
|
+
- **Each page leads with its take-away**: a run's verdict in a strip under its title, with the
|
|
157
|
+
call that made the check's complaint where the check was run along the run; on the divergence
|
|
158
|
+
page, the step whose behaviour best predicts a pass; Connections' setup at a glance; a
|
|
159
|
+
refinement's four stages in a line.
|
|
160
|
+
- **A run's page reads top to bottom, its work beside it.** Every step's row has *Show details*
|
|
161
|
+
and *Work from here*. One step's details are open at a time. A step's actions, and the forms
|
|
162
|
+
they open, sit in a column beside the run, each step's kept as it was left, and the address
|
|
163
|
+
names that work, so a reload brings it back; Escape hides it. The rail's lines move you through
|
|
164
|
+
the run and open nothing. On an imported or live run, *Fork from here…* is greyed, and points to
|
|
165
|
+
a scenario of the run instead.
|
|
166
|
+
- **A refinement's page has a section for each stage**, numbered as the stepper numbers it: the
|
|
167
|
+
two ways to propose side by side; the proposals, with the screen of the ticked ones (a *test at
|
|
168
|
+
this step*) under them; the validations (*full test runs*); approval. The current stage's form
|
|
169
|
+
is open as the page opens, and no form opens by itself after.
|
|
170
|
+
- **A finished job hands off to what it made**: its page says what it found in a line and leads
|
|
171
|
+
there, its log folded. The Jobs list is in three parts — running and queued, each queued job
|
|
172
|
+
saying its place in its line; finished; stopped or failed — and names each job by the section
|
|
173
|
+
of its work, links what it made, and says who started it: you, from which page, or an agent
|
|
174
|
+
over MCP. `tuningfork jobs list` and `jobs show` say who started it too. A job's link to the
|
|
175
|
+
step it worked at opens that step.
|
|
176
|
+
- **Add a skill** (`tuningfork add-skill`, `forget-skill`, the Skills page's *Add a skill…*, a
|
|
177
|
+
run's *Keep its skill…*): a folder on this machine, remembered where it is, or an uploaded
|
|
178
|
+
folder or a run's skill, kept as tuningfork's own copy. An approved edit is written to the
|
|
179
|
+
folder, or to the copy. Forgetting one drops its record and never deletes: a copy is moved aside
|
|
180
|
+
to `<home>/skills/.forgotten/`. No MCP tool adds one. A skill's page and `tuningfork skill` say
|
|
181
|
+
how its folder was added, and its page runs it again from the scenarios that name it.
|
|
182
|
+
- **Token work is held to the server check.** Scoring an answer and finding forking tokens are
|
|
183
|
+
greyed on the page, and refused before anything is sent, where the check found the server
|
|
184
|
+
without what they need. The check now measures the chat endpoint's logprobs too, which a
|
|
185
|
+
resample's kept tokens need (*Keep each sample's tokens*, new on its form), in one more short
|
|
186
|
+
call. A server on the internet that asks for a key, or is not llama.cpp's, is said to be a
|
|
187
|
+
hosted model's API: tuningfork records your agent's calls through it, its own key passed on.
|
|
188
|
+
The switch on Connections takes one that asks for a key, where it refused it before.
|
|
189
|
+
- **The forking-token probe says what reached each behaviour**: whether the target counts it,
|
|
190
|
+
and which tokens led to it — its page, `tuningfork experiment`, MCP. A flip is the accent's
|
|
191
|
+
colour, its direction said in words. Where the step's answer is a tool call, the form offers
|
|
192
|
+
that tool, with any arguments, as the target first.
|
|
193
|
+
- **Forms**: one nobody has touched says what it needs as a note, not in red. *Make a scenario…*
|
|
194
|
+
shows what it will make first, and chooses its check as a new scenario's editor does. *Run a
|
|
195
|
+
task…* takes a task file's path beside the scenario, greyed while a scenario is chosen.
|
|
196
|
+
- **The README's pictures**, retaken in the redesigned pages, with a new one: a chat had
|
|
197
|
+
elsewhere, made a scenario. `docs/images/shots.mjs` takes them all, the GIF included, in one
|
|
198
|
+
command, and keeps back any picture that shows a path naming a person or a place, or a word you
|
|
199
|
+
list (`TUNINGFORK_SHOTS_PRIVATE`).
|
|
200
|
+
|
|
201
|
+
Changed:
|
|
202
|
+
|
|
203
|
+
- **An A/B is judged at the α it was declared with** wherever it is reported again — its page,
|
|
204
|
+
`tuningfork experiment`, MCP's `show_experiment` — where 0.05 was used whatever was declared.
|
|
205
|
+
An A/B made before its α was kept takes its job's, else 0.05; `--alpha` judges at another
|
|
206
|
+
level, and says so.
|
|
207
|
+
- **Letters agree with the resample a target came from**: an A/B, a screen or a probe of a letter
|
|
208
|
+
target letters its behaviours as that resample did, so its B is the resample's B. One stored
|
|
209
|
+
before finds its resample by its target's description, so read again, its behaviours may take
|
|
210
|
+
new letters.
|
|
211
|
+
- **A resample that asked for each sample's tokens and got none says so**: its page said every
|
|
212
|
+
sample had kept them. The page now counts only the samples that did.
|
|
213
|
+
- **A dry run's refusal is an answer**: asked `quiet`, as the web UI's forms ask, `POST /jobs`
|
|
214
|
+
and the scenario endpoint refuse with `200 {refused}`, not an HTTP error. Without `quiet`,
|
|
215
|
+
nothing changes.
|
|
216
|
+
- **A plan gives its notes apart from its warnings**: an import's and a scenario's (`notes` in
|
|
217
|
+
the API, `note` lines in the terminal).
|
|
218
|
+
- **A scenario's batch or chain names the scenario when refused** for the task file the scenario
|
|
219
|
+
keeps: the field is `scenario`, the one filled in, never `spec`, which nobody typed.
|
|
220
|
+
- **Every job under way is listed** by `GET /jobs`, `tuningfork jobs list` and MCP's `list_jobs`,
|
|
221
|
+
however many came after it: the list was cut at the newest 50 (`list_jobs`: 20, or as many as
|
|
222
|
+
it asked for), so a running job with that many newer ones dropped out. Over MCP's stdio
|
|
223
|
+
transport, `list_jobs` still gives at most the 50 newest beside them, whatever it asks for.
|
|
224
|
+
- **A launch is refused where the server asks for a key**: a harness tuningfork launches carries
|
|
225
|
+
none, and each harness's card on Connections says so. The server check says such a server
|
|
226
|
+
cannot be checked.
|
|
227
|
+
- **A proposing model's address that cannot be read is refused** when it is set: a mistyped port
|
|
228
|
+
was kept, and failed only when the proposer was asked. One saved before is shown as another
|
|
229
|
+
machine's until it is set again. `GET` and `PUT /proposer` give `remote`.
|
|
230
|
+
|
|
231
|
+
## 0.3.0 — chats your agent already had, and any run as a scenario
|
|
232
|
+
|
|
233
|
+
A conversation your agent had elsewhere comes in as a run, and any run becomes a scenario: a task
|
|
234
|
+
whose runs continue its conversation, so a skill is measured where it was really used.
|
|
235
|
+
|
|
236
|
+
- **A chat, imported** (`tuningfork import`, the Runs page's **Import a chat…**): Hermes Agent's
|
|
237
|
+
session file or its export, or a list of OpenAI-style messages, becomes a run whose every
|
|
238
|
+
assistant turn is a step, so resample, A/B, the token tools and a refinement work at it. Each
|
|
239
|
+
step's request is rebuilt as the harness sends one: the system prompt, everything before it,
|
|
240
|
+
each message as Hermes cleans its own copy before a call. A file that kept no tools (Hermes's
|
|
241
|
+
export keeps none) takes them from a run recorded through the same harness (`--tools-from`,
|
|
242
|
+
**Tools from**). Every skill the chat shows is kept with the run, and an A/B, a refinement or
|
|
243
|
+
a scenario names the one it studies (`--skill`, a **Skill** picker).
|
|
244
|
+
- **Any run as a scenario** (`tuningfork scenario <run> <name>`, a run page's **Make a
|
|
245
|
+
scenario…**, the Scenarios page's **From a run…**): an imported run, one tuningfork launched,
|
|
246
|
+
or one recorded live.
|
|
247
|
+
- **Its prompt** is the person's message the skill came in after, in their words or yours
|
|
248
|
+
(`--prompt`), and the conversation before it is each run's context. The proxy puts it after
|
|
249
|
+
the harness's own instructions in every call (`tuningfork.context`; harnesses that speak
|
|
250
|
+
OpenAI chat), so the skill still comes in live and an edited version reaches it.
|
|
251
|
+
- **Several skills in one chat:** the steps of that turn before the studied skill came in,
|
|
252
|
+
another skill's among them, go to each run as done. Where the chat went on to another skill,
|
|
253
|
+
each run stops there and the check judges the workspace as it is then
|
|
254
|
+
(`tuningfork.stop_at_next_skill`).
|
|
255
|
+
- **A launched run's scenario** takes the run's workspace there as its input files, from the
|
|
256
|
+
snapshots, and its task's check, with the files that check reads. Any other run lists the
|
|
257
|
+
files its calls named, for you to add.
|
|
258
|
+
- **Its eval is named by the scenario:** its runs are a task of their own, never counted with
|
|
259
|
+
the task of the run it came from.
|
|
260
|
+
- **The form** asks for the skill first, then sets each run beside the chat: what each run is
|
|
261
|
+
given (its harness's own system prompt and tools, the conversation before, the prompt),
|
|
262
|
+
then each step, given as done, made by its model, or past where it stops.
|
|
263
|
+
- **A run's page:** the tools the run was offered, above its system prompt; each tool's result
|
|
264
|
+
under the step that called it in the rail; a person's turn told apart from the notes a harness
|
|
265
|
+
writes itself (Hermes's nudge after a cut reply, Claude Code's reminders).
|
|
266
|
+
- **A run recorded live says so**, where a label would name it: the Runs list, its page,
|
|
267
|
+
`tuningfork runs` and `show`. When its first call continued a conversation already going on, a
|
|
268
|
+
long session, its rail lists that conversation first, and each of the person's turns there
|
|
269
|
+
folds to its line.
|
|
270
|
+
- **The README says where your harness points**, what `--upstream` is, and how to change the
|
|
271
|
+
port.
|
|
272
|
+
|
|
273
|
+
Changed:
|
|
274
|
+
|
|
275
|
+
- **A new run is marked a branch of another only where the two share more than their first
|
|
276
|
+
message**, at the message where they part. Two sessions of one harness can share a system
|
|
277
|
+
prompt and nothing else: one was marked a fork of the other, at its own length. Marks recorded
|
|
278
|
+
before stay as they were.
|
|
279
|
+
- **The recordings' database gains a column**, each step's context: it is added when an older
|
|
280
|
+
folder is opened.
|
|
281
|
+
|
|
282
|
+
Claude Code's calls cannot yet carry a conversation before the prompt, so a scenario of a Claude
|
|
283
|
+
Code run starts at its first turn.
|
|
284
|
+
|
|
285
|
+
## 0.2.3 — on Windows, and a code review's fixes
|
|
286
|
+
|
|
287
|
+
Three rules changed in review, and what was recorded before reads by them now:
|
|
288
|
+
|
|
289
|
+
- **A fork run to the end that timed out counts as a failure**, in a screen, an A/B and a
|
|
290
|
+
resample to the end, as the validation gate already counted it. Left out, an edit that made
|
|
291
|
+
the agent loop until it was stopped counted only its forks that finished, and could survive
|
|
292
|
+
its screen. A screen read again counts its timed-out forks, and its report says how many.
|
|
293
|
+
- **Gate G0 reads a proposal's latest complete screen**, not any screen it survived: a screen
|
|
294
|
+
of more proposals, or one run to the end, can undo an earlier survival. Validation refuses a
|
|
295
|
+
proposal its latest screen dropped, and a validation's gate, read again, fails G0 when a
|
|
296
|
+
screen since has dropped it, and says which.
|
|
297
|
+
- **A fork an experiment drew goes to the trash, and is deleted, only with its experiment**, as
|
|
298
|
+
a thread goes with its run: its verdict is the experiment's. Trashed alone, even deleted for
|
|
299
|
+
good, it still counted. One trashed alone before can be restored, and is never deleted alone.
|
|
300
|
+
|
|
301
|
+
**On Windows** (`docs/setup.md`): installing WSL and a distro, working inside it as on Linux,
|
|
302
|
+
the web UI in the Windows browser, and a model server running on Windows itself. Or keep the
|
|
303
|
+
checkout where Windows editors see it: `scripts/tuningfork.ps1` (PowerShell) and
|
|
304
|
+
`scripts/tuningfork` (Git Bash) run any tuningfork command inside WSL, the venv and the
|
|
305
|
+
recordings in the distro's Linux file system. They run nothing until `TUNINGFORK_WSL_DISTRO`
|
|
306
|
+
names the distro, and hand each argument over as it was typed.
|
|
307
|
+
|
|
308
|
+
Fixed, each found in a review of the code and reproduced before it was fixed:
|
|
309
|
+
|
|
310
|
+
- **The proxy:** a harness that hung up before its answer began kept its slot in the gate for
|
|
311
|
+
good, and with `--max-inflight 1` every later call waited for a restart. `serve --max-output`
|
|
312
|
+
raised a limit written as a float (`1024.0`) to the cap. Ctrl-C continued a cancelled job's
|
|
313
|
+
held calls before dropping them, so a fork killed at a breakpoint still sent its call.
|
|
314
|
+
- **Recording and forks:** a call refused while the proxy was paused kept its step number: the
|
|
315
|
+
run skipped a number, forks of later steps went live a call late, and its last step could not
|
|
316
|
+
be forked. A fork's call at its step, refused that way, lost its "live from here" note.
|
|
317
|
+
- **The trash:** deleting a run for good while a fork of it still ran took the fork's folders
|
|
318
|
+
from under its harness. A launch a batch killed hard stayed running for good and held back
|
|
319
|
+
the trash: launches record the process running them now, and read as interrupted once it has
|
|
320
|
+
gone. Deleting a chain link's run for good deleted the skill the link left.
|
|
321
|
+
- **Counting:** gate G2's "enough runs" counted runs the infrastructure broke. A screen to the
|
|
322
|
+
end from several checkpoints could tilt the original's rate toward one of them. The tally
|
|
323
|
+
named a mistake every run kept as one the passing runs repaired, and counted the half line a
|
|
324
|
+
cut output starts with as a finding. A check output longer than the 2,000 characters a
|
|
325
|
+
verdict keeps says so now: on the run's page, in MCP's `show_run`, in the tally and in a trial
|
|
326
|
+
of the check.
|
|
327
|
+
- **Refinements and approvals:** a record cut off mid-write stayed truncated, and a truncated
|
|
328
|
+
`approval.json` blocked its refinement for good. A crash between an approval's last two
|
|
329
|
+
writes left it open for good: it is reported (`unmarked`) and finished by repair. A changelog
|
|
330
|
+
that is not UTF-8 stopped approvals. A file that mixes line endings was written back all
|
|
331
|
+
CRLF: it takes the ending most of its lines use now, and the plan says so first. A proposal's
|
|
332
|
+
edit matched with its indentation ignored turned that line of a CRLF skill into LF.
|
|
333
|
+
- **Jobs and scenarios:** two cancels of a queued job at once left it queued until a restart;
|
|
334
|
+
the same work submitted twice at once started two jobs; a scenario deleted twice in one
|
|
335
|
+
second landed in the first copy's trash folder.
|
|
336
|
+
- **MCP and the CLI:** `job_status` showed a held-out task's jobs whole, and `list_scenarios`
|
|
337
|
+
its pass rates. Pointed at a proxy on another machine, the CLI read the local file its
|
|
338
|
+
`/health` named and sent it there as the token.
|
|
339
|
+
- **The web UI:** the batch form kept the old spec's task list; a stopped run read "no check";
|
|
340
|
+
a live run's timeline drew its "not recorded" rows again at every update; on the Live page, a
|
|
341
|
+
question still being answered at a held call showed as an error; on the Jobs page, a late
|
|
342
|
+
answer filled the step list of the run chosen last; "Where does it hold?" lost what was typed
|
|
343
|
+
when the page redrew; a job's page could go back to "running" after the job ended; and two
|
|
344
|
+
step forms asked for quickly could leave the wrong one open, or both.
|
|
345
|
+
|
|
346
|
+
## 0.2.2 — a README for newcomers, and what its pictures showed
|
|
347
|
+
|
|
348
|
+
- **The README, rebuilt for someone deciding in a few minutes whether to try tuningfork:** what
|
|
349
|
+
it does in one figure drawn from real runs, a quickstart with no GPU on the demo lab, where
|
|
350
|
+
every button works, the commands by the question each answers, and the web UI in screenshots
|
|
351
|
+
and a GIF. Reference moves to `docs/setup.md` (installing, the model server's flags and why,
|
|
352
|
+
the harnesses, the sandbox, a task's format), `docs/commands.md` (every command, by the
|
|
353
|
+
question it answers) and `docs/agents.md` (the MCP server, client by client);
|
|
354
|
+
`docs/images/README.md` says how each picture is taken. `tests/test_docs.py` fails on a
|
|
355
|
+
command the reference does not name, and on a link, to a page or an image, that leads nowhere.
|
|
356
|
+
- **`examples/find-the-file/`: a step where the model wavers**, the runs behind the figure,
|
|
357
|
+
Hermes Agent on Gemma 4 31B: ten runs pass 4, the step where they split resampled, the
|
|
358
|
+
model's odds for the words where its reasoning forks, one line of the skill tested there,
|
|
359
|
+
and ten runs with it passing 10, each command shown with its output.
|
|
360
|
+
- **An A/B shows the edit it tested:** its report starts with a line diff of the two texts,
|
|
361
|
+
read back from what it recorded rather than from files that can change since (its page,
|
|
362
|
+
`tuningfork experiment`, MCP's `show_experiment`), where one text holds the skill twice too.
|
|
363
|
+
The demo's seeded A/B swaps a real saved variant.
|
|
364
|
+
- **Green and red only for a check's verdict.** A run's page ends with its verdict, coloured by
|
|
365
|
+
it, where a failed run used to end in a green reply. Any other significant result, an A/B's
|
|
366
|
+
shift or a step screen's survivor, is the accent's colour, its direction said in words, and
|
|
367
|
+
the behaviours a declared target counts are badged *target*, the others *not target*. The
|
|
368
|
+
divergence page colours each run by its own verdict.
|
|
369
|
+
- **A refinement's page leads with its evidence:** where it stands, each proposal's screen and
|
|
370
|
+
the approved one's validation, linked to the detail below. What a proposer is shown moves
|
|
371
|
+
under the proposals, and the skill's paths into a closed *About this refinement*.
|
|
372
|
+
- **A forking-token probe that found nothing says what it could have seen:** "No forced token
|
|
373
|
+
decided what the model did", and the smallest change its continuations would show
|
|
374
|
+
(`detectable`), on its page, the token panel and the CLI.
|
|
375
|
+
- **The server advice is current:** the front page and the glossary recommend
|
|
376
|
+
`--no-cache-prompt`, and `--ctx-checkpoints 0` or `--swa-full`.
|
|
377
|
+
- **Start takes the first click after typing in a field.** The field's change as it lost the
|
|
378
|
+
focus disabled Start under the click, on every form that starts work.
|
|
379
|
+
- **A run stopped before it finished says so,** not that its task defines no check, and a run
|
|
380
|
+
launched from the command line shows its verdict without a reload.
|
|
381
|
+
- **p-values below 0.01 print by their first figure** (`0.005`), never `0.00`. The tally's
|
|
382
|
+
footer, in `tuningfork tally` and MCP's `tally_failures`, says in plain words how it counts:
|
|
383
|
+
an agent reads new words there.
|
|
384
|
+
|
|
385
|
+
## 0.2.1 — the web UI catches up
|
|
386
|
+
|
|
387
|
+
- **Screens run to the end, from the refinement page.** Its screen form asks how each sample
|
|
388
|
+
is judged — an answer at the step, or a fork run from the step to the end, the task's check
|
|
389
|
+
deciding — and to the end takes the runs to fork from, a quick look, and drawing the
|
|
390
|
+
original anew. A refinement can be started with the task's check as its target. A quick look
|
|
391
|
+
reads as one wherever it shows — the refinement's page and its screens, the screen's own page,
|
|
392
|
+
`refine show` — its rates and never a verdict, not "not significant" against an original of
|
|
393
|
+
0/0. A screen to the end shows each run it forked from, with each arm's passes there and
|
|
394
|
+
whether the effect held at every one; its page asks Where does it hold? of its forks, arm by
|
|
395
|
+
arm, and folds away the step's behaviours, which are each fork's own. A proposal's chip says
|
|
396
|
+
it survived when any screen found so: it showed the oldest screen's verdict.
|
|
397
|
+
- **What goes with passing**, on the divergence page: the step whose behaviour best predicts
|
|
398
|
+
the verdict, and the tool whose use does, at whatever step a run called it — or that no run
|
|
399
|
+
passed, and where to look then. The divergence report carries the step's split for every
|
|
400
|
+
front end (`verdict_split`), with a run that took the behaviour to look at.
|
|
401
|
+
- **The check run along the runs**, started from the divergence page (the `check-along` job):
|
|
402
|
+
the tally beside it then names the call that made each finding.
|
|
403
|
+
- **A chain, link by link** (the Chains page, `GET /chains`, `/chains/{id}`): how it ran, what
|
|
404
|
+
each link's harness was told, its verdict (or none, where the check never ran), who changed
|
|
405
|
+
the skill after it and the lines they changed. A chain job's page leads to it.
|
|
406
|
+
- **What work cost** beside a run, a job and an experiment (`GET /spend`).
|
|
407
|
+
- **A run's sandbox** on its page: where its harness worked, the folders hidden from it, the
|
|
408
|
+
instant its clock started at, and how the harness was set up.
|
|
409
|
+
- A running job says about how long it has left. The Connections page shows the cap on output,
|
|
410
|
+
and its restart command keeps the cap and the MCP route's settings.
|
|
411
|
+
|
|
412
|
+
## 0.2.0 — agents that refine skills, and loops to compare them with
|
|
413
|
+
|
|
414
|
+
- **A chain of runs** (`tuningfork chain run`, the Run a task form, the `chain` job kind):
|
|
415
|
+
a task run N times in order, each run given the skill as the run before left it — how a
|
|
416
|
+
harness's own self-improvement accumulates. Each link is recorded and judged as a batch's
|
|
417
|
+
run is; the chain keeps every version of the skill, who changed it, the lines that
|
|
418
|
+
changed, and the last link's folder as what the loop made. With `--tell`, each link's
|
|
419
|
+
harness is given the check's verdict and output as the user's next turn of the same
|
|
420
|
+
session, before its own review: the signal a person who looked at the result would give,
|
|
421
|
+
which a harness's loop otherwise never has. With `--budget-seconds`, the chain stops once
|
|
422
|
+
its links' model calls have taken that long, and a link that could outrun the budget is
|
|
423
|
+
cut to what is left of it, so two loops given the same seconds spend the same seconds.
|
|
424
|
+
- **Options a launch of Hermes takes** (`--harness-option`, `harness_options`): turn its
|
|
425
|
+
self-improvement off (a plugin written into the launch's home removes its skill-editing
|
|
426
|
+
tool, so a run cannot change the skill it is measured with), let its background review
|
|
427
|
+
finish before the process exits (in one-shot mode the review was cut off at exit), make
|
|
428
|
+
the skill review due after every turn, and give it MCP servers — tuningfork's own tools
|
|
429
|
+
among them. Recorded with each run.
|
|
430
|
+
- **The MCP surface oriented for a weak reader.** A 26B driving the refine loop looked for the
|
|
431
|
+
skill as a file, aimed its targets at the first place tool calls differed, and never read a
|
|
432
|
+
failed run's check output; Hermes shows the model no server instructions, so the tools'
|
|
433
|
+
descriptions and answers now say it: show_skill is the only way to read the skill, show_run
|
|
434
|
+
leads with what a failed run's check said and names its last tool call, `show_files` (new)
|
|
435
|
+
shows what a run wrote, find_divergence names the step whose behaviour best predicts the
|
|
436
|
+
verdict or says the difference is in the content, start_refinement refuses a target no
|
|
437
|
+
recorded answer at the step satisfies (`unseen_ok` allows new behaviour) and says when the
|
|
438
|
+
refinement was open already, and the refine toolset's hints walk the refine loop. An edit
|
|
439
|
+
whose old text matches the skill once indentation is ignored is applied with the skill's
|
|
440
|
+
indentation, and a refusal quotes the closest lines as they stand. A refusal is returned as an
|
|
441
|
+
answer, not an error result: Hermes counts error results toward a circuit breaker that cuts a
|
|
442
|
+
server off after three in a row, and an agent that fumbled three edits lost every tool for a
|
|
443
|
+
minute; only tuningfork's own failure is an error result now.
|
|
444
|
+
- **A target a screen can move, and the check as a target.** Each behaviour seen at a step
|
|
445
|
+
now comes with how the recorded runs that took it fared, and a target tried against them
|
|
446
|
+
(step_behaviours, the targets page) says how many passing runs' answers it counts and how
|
|
447
|
+
many failing runs': what a 26B driving the refine loop lacked, having declared a target
|
|
448
|
+
every answer satisfied (20/20 against 20/20) and one no answer could contain (the check's
|
|
449
|
+
own sentence). start_refinement refuses the first as it did the second, and a target the
|
|
450
|
+
failing runs' answers satisfy as readily as the passing runs' (its screen would move nothing
|
|
451
|
+
the verdict follows), with the failing runs' check output in the hint. A fork is now set up
|
|
452
|
+
as its source's launch was (Hermes's `self_improvement`, which changes its system prompt):
|
|
453
|
+
before, a fork of a run recorded with the option departed from the recording at its first
|
|
454
|
+
step, and every sample of a screen to the end was excluded. For a failure only the check can see — a computed property
|
|
455
|
+
of what the run wrote — a refinement's target may be the task's check (`--target-check`,
|
|
456
|
+
`target_check`), and a screen may run to the end (`refine screen --to-end`, the
|
|
457
|
+
`screen-to-end` job kind, `--mcp-tools refine-to-end`): each arm's samples forks from the
|
|
458
|
+
checkpoint through the harness, the check deciding, Fisher and Holm as at the step; the
|
|
459
|
+
record says which measured.
|
|
460
|
+
- **An answer once, for a client that shows both.** A tool result carries its text (the
|
|
461
|
+
sentences, then the JSON) and its structured content (the JSON, led by the sentences)
|
|
462
|
+
because a client shows the model one of them — Claude Code the structured content,
|
|
463
|
+
OpenJarvis the text. Hermes puts both in the tool message, every answer twice, and a 26B
|
|
464
|
+
driving the loop in a 64k context spent it in twenty-two calls, the harness's compaction
|
|
465
|
+
unable to drop a turn of tool calls. `serve --mcp-results text` and `mcp --results text`
|
|
466
|
+
send the text alone (`mcp.server.RESULTS`); the default is unchanged. The same 26B then
|
|
467
|
+
sent an edit without its old text twenty-seven times running, reading each refusal as the
|
|
468
|
+
first: an edit missing a key is now told the shape and the skill's closest line to copy,
|
|
469
|
+
and the same refusal three times running carries the tool's description again, from the
|
|
470
|
+
sixth time with "if it cannot be done, say so and stop" (`ToolServer._repeated`).
|
|
471
|
+
- **Folders hidden from every launch** (`TUNINGFORK_SANDBOX_HIDE`): the sandbox hides a
|
|
472
|
+
launch's own recordings, runs and spec folder; the person can name more, where a
|
|
473
|
+
benchmark keeps the keys its checks read — an agent given the file system was seen to
|
|
474
|
+
find a task's check script. What a launch could not see is kept in its record.
|
|
475
|
+
- **What work cost** (`tuningfork spend`): model calls, tokens in and out, and time, counted
|
|
476
|
+
from the records for a run, an experiment, a job, a chain or a task — the same count for a
|
|
477
|
+
harness's runs and an experiment's samples.
|
|
478
|
+
- **What the checks said, counted, and where it was made.** `tuningfork tally` (MCP's
|
|
479
|
+
tally_failures) reads every failed run's check output at once: each line a check prints is one
|
|
480
|
+
finding, lines that differ only in their numbers or colours are one, each counted once a run
|
|
481
|
+
with its interval, the most common first; a screen run to the end is tallied by arm. An agent
|
|
482
|
+
that opened failed runs one at a time aimed at the first failure it read, not the most common.
|
|
483
|
+
`tuningfork check-along` (the `check-along` job kind) runs the check on a run's workspace as it
|
|
484
|
+
started, after each call that changed it, and at its end, so each finding comes with the call
|
|
485
|
+
that made it — a mistake every run made, and some repaired later, is named as one, with where
|
|
486
|
+
to refine it. `tuningfork where` (MCP's where_it_holds) asks one question of every run — a
|
|
487
|
+
target tried at every step, or a file's pattern at each state of its workspace — lined up with
|
|
488
|
+
the verdicts, with the call that made the difference: what a check that prints only its verdict
|
|
489
|
+
leaves to go on.
|
|
490
|
+
- **The step to refine, chosen by what the run did.** A step can be named by what the run did
|
|
491
|
+
there (`write_file`, `changed:<path>`, `made:<words>`) and is found in each run.
|
|
492
|
+
find_divergence names the tool whose use goes with passing (runs that called it against runs
|
|
493
|
+
that never did), and step_behaviours gives the model's own chance of each tool at the step,
|
|
494
|
+
from scored answers. A screen to the end draws its forks from several runs at the same step
|
|
495
|
+
(`--checkpoints`), passing and failing by turns, and says whether the effect held at each: one
|
|
496
|
+
that lived in a single prefix is one fresh runs draw anew. A refinement at a passing run's
|
|
497
|
+
step is told so, a step screen whose original is at the ceiling says no gain could show there,
|
|
498
|
+
and a refinement toward the check and a screen's plan warn when a call before the step changed
|
|
499
|
+
the workspace, which a fork replays as recorded.
|
|
500
|
+
- **Screens that cost less.** A refinement's original is forked once: a later screen to the end
|
|
501
|
+
counts the original's forks its earlier screens drew at the same checkpoints and draws only
|
|
502
|
+
what its n still needs (`--fresh-original` draws anew). A quick look (`--quick`, `quick`)
|
|
503
|
+
forks each proposal eight times and the original not at all: rates, never a verdict, and a
|
|
504
|
+
lead for the next edit.
|
|
505
|
+
- **Edits and long texts as an agent sends and reads them.** propose_edit takes a line by its
|
|
506
|
+
number — `{line, new}`, `{line, through, new}`, `{after, insert}` — beside `{old, new}`, each
|
|
507
|
+
resolved to an exact replacement, so several in one proposal do not shift each other, and text
|
|
508
|
+
whose line breaks were escaped twice is read as the lines it meant. show_files reads a file or
|
|
509
|
+
a diff from an offset, and show_step one message of a step whole, a page at a time: a file cut
|
|
510
|
+
with no way past the cut had hidden what the check failed. Refusals say more plainly what to
|
|
511
|
+
send: an edit that changes nothing is told what `new` is, and the sixth identical refusal says
|
|
512
|
+
to try another edit, step or tool rather than to stop. A running job says how long is left,
|
|
513
|
+
and `serve --mcp-max-wait` sets how long one MCP call may wait for it.
|
|
514
|
+
- **A cap on output for every call through the proxy** (`serve --max-output N`): a harness's
|
|
515
|
+
call asking for more than N output tokens, or naming no limit, is sent with N — a call a
|
|
516
|
+
person edits at a breakpoint, and a validation's held-out runs, included; the step records
|
|
517
|
+
what the model was sent and what the harness asked, and a fork's replay matches the
|
|
518
|
+
harness's own request. Hermes answers a reply cut at its limit by asking again for more, so
|
|
519
|
+
the cap has to be the proxy's: an agent's reply looped to Hermes's 65,536 tokens for 35
|
|
520
|
+
minutes of one GPU.
|
|
521
|
+
- **Every launch's clock can be pinned** (`TUNINGFORK_CLOCK`): the harness reads the same date
|
|
522
|
+
whichever day a run is made, and a fork starts where its source did.
|
|
523
|
+
- **Fixed:** a line of the original that a longer line of the variant contains is no longer taken
|
|
524
|
+
for a leak (it had voided twenty forks of one screen); a tally masks a hex colour whole; parsing
|
|
525
|
+
a recorded script for its digest no longer prints its warnings.
|
|
526
|
+
- **The guides on Gemma 4 31B.** `examples/README.md` was run again as written on one 32 GB card,
|
|
527
|
+
every output captured there, and every step of Parts 2 to 4 now has a "With Hermes Agent" block:
|
|
528
|
+
Hermes's own edit validated three ways and approved.
|
|
529
|
+
- **A benchmark driver** (`benchmark/driver/run.py`): Hermes's own self-improvement loop, as a
|
|
530
|
+
told chain, against Hermes with tuningfork's tools over MCP — the same task, model and server,
|
|
531
|
+
each arm's final skill judged by fresh runs — with one task, `benchmark/architecture-diagram/`.
|
|
532
|
+
- **A case study** (`examples/hermes-architecture-diagram/`): on Hermes's `architecture-diagram`
|
|
533
|
+
skill, its own loop reached 9/10 by growing the skill, templates of the training answer
|
|
534
|
+
included; Hermes with tuningfork's tools reached 8/10 with an 8-line edit, kept only after it
|
|
535
|
+
beat the original in forks. A demonstration of the tools, with an agent standing in for a
|
|
536
|
+
person.
|
|
537
|
+
|
|
538
|
+
## 0.1.0 — the first public release
|
|
539
|
+
|
|
540
|
+
A step debugger and experiment lab for agent skills on local LLMs, pre-alpha. What it does:
|
|
541
|
+
|
|
542
|
+
- **Records** every model call of an agent harness, through a proxy that speaks OpenAI
|
|
543
|
+
chat-completions and Anthropic Messages, with no change to the harness. Hermes Agent and
|
|
544
|
+
Claude Code have adapters; any harness that takes a base URL can be recorded.
|
|
545
|
+
- **Finds where runs part**: a batch of runs of a task, judged by the task's check, and the
|
|
546
|
+
first step where they stopped agreeing.
|
|
547
|
+
- **Tests a step, not a whole run**: resamples a step with its history held fixed, swaps an
|
|
548
|
+
edited skill in at that step (an A/B with its target declared before sampling), and follows
|
|
549
|
+
either to the end of the run, where the task's check decides. Every rate comes with its
|
|
550
|
+
interval.
|
|
551
|
+
- **Stops a run where it matters**: live breakpoints before or after the model, at a call that
|
|
552
|
+
matches, with the call held to read, edit, step or drop.
|
|
553
|
+
- **Restarts a run from any step**: the workspace as each call found it, kept in snapshots;
|
|
554
|
+
forks replayed from the recording up to a step and live from there; every launch in a
|
|
555
|
+
bubblewrap sandbox that looks the same each time.
|
|
556
|
+
- **Reads inside a step**, on llama.cpp: how sure the model was of each token of an answer,
|
|
557
|
+
and which token decided the step.
|
|
558
|
+
- **Refines a skill at the step that fails**: a target declared first; edits proposed by a
|
|
559
|
+
person, an agent or the built-in proposer; each screened against the original; a survivor
|
|
560
|
+
validated with full runs, held-out tasks included; and written to the skill only when a
|
|
561
|
+
person approves, typing a code.
|
|
562
|
+
- **All of it from a web UI**, or as tools for an agent over MCP.
|
|
563
|
+
|
|
564
|
+
Two guides walk through it on real runs: `examples/README.md`, a toy skill made to fail one
|
|
565
|
+
way, and `examples/hermes-design-md/`, Hermes Agent's own design-md skill fixed from its
|
|
566
|
+
failing step to an approved edit.
|