agent-tune-kit 2.3.2__tar.gz → 2.3.4__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.
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/.codex-plugin/plugin.json +1 -1
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/PKG-INFO +10 -3
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/README.en.md +9 -2
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/README.md +9 -2
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/__init__.py +1 -1
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/cli/trace.py +17 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/traces/archive.py +1 -1
- agent_tune_kit-2.3.4/agent_tune_kit/traces/projects.py +201 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/traces/records.py +23 -2
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/traces/store.py +1 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/assets/shared/base.css +9 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/assets/trace/app.js +41 -1
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/assets/trace/page.html +2 -1
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/assets/trace/styles.css +3 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/assets/traces/app.js +131 -63
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/assets/traces/page.html +17 -11
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/assets/traces/styles.css +53 -12
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/trace.py +15 -2
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/traces.py +16 -29
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/docs/trace-dashboard-design.md +19 -9
- agent_tune_kit-2.3.4/docs/trace-project-attribution-design.md +246 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/docs/trace-tuning.md +19 -3
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/pyproject.toml +1 -1
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/scripts/validate_skill_pack.py +1 -1
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/skills/atk-trace-detect/SKILL.md +12 -0
- agent_tune_kit-2.3.4/skills/atk-trace-diagnose/SKILL.md +83 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/skills/atk-trace-init/SKILL.md +14 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/skills/atk-trace-optimize/SKILL.md +12 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/skills/atk-trace-verify/SKILL.md +12 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/skills/atk-visualize-trace/SKILL.md +16 -4
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_install_plugin.py +1 -1
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_release_scripts.py +1 -1
- agent_tune_kit-2.3.4/tests/test_trace_projects.py +65 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_visualize_traces.py +8 -8
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/trace-dashboard.cjs +176 -16
- agent_tune_kit-2.3.2/skills/atk-trace-diagnose/SKILL.md +0 -62
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/.gitignore +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/cli/__init__.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/cli/__main__.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/cli/dataset.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/cli/evaluation.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/cli/main.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/cli/output.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/cli/results.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/cli/visualize.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/datasets/__init__.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/datasets/prepare.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/datasets/truth.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/datasets/updates.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/datasets/validation.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/errors.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/execution/__init__.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/execution/calibration.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/execution/logs.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/execution/rules.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/execution/runner.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/execution/runtime.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/execution/tracing.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/installer.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/results/__init__.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/results/assessment.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/results/evidence.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/results/judgments.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/results/summary.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/results/versions.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/traces/__init__.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/traces/capture.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/traces/categories.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/traces/langfuse.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/traces/migrate.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/traces/progress.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/traces/query.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/traces/segments.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/utils/__init__.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/utils/csv_io.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/utils/files.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/__init__.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/assets/dataset/app.js +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/assets/dataset/page.html +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/assets/dataset/styles.css +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/assets/dataset/vendor/echarts.min.js +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/assets/failures/app.js +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/assets/failures/page.html +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/assets/failures/styles.css +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/assets/trace/lanes.js +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/assets/trace/vendor/markdown-it.LICENSE +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/assets/trace/vendor/markdown-it.min.js +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/dataset.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/failures.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/fields.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/history.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/render.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/timeline.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/workspace.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/docs/assets/agent_tune_kit_evaluation.png +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/docs/assets/agent_tune_kit_trace.png +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/docs/assets/arch-en.png +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/docs/assets/arch.png +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/docs/assets/architecture.en.svg +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/docs/assets/architecture.svg +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/docs/ato-atk-project-boundary-recommendation-2026-11-05.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/docs/cli-skill-modularization-plan.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/docs/codex_agent_tuning_prd.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/docs/execution-evidence-and-tracing-plan.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/docs/ground-truth-and-grading-assessment-2026-10-25.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/docs/local-context.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/docs/shared-versioning-and-confirmation.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/docs/skill-template-pack-usage.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/docs/surginame-atk-capability-review-2026-10-27.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/docs/trace-change-verification-readability-diagnosis.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/docs/trace-swimlane-design.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/docs/trace-tuning-validation.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/docs/truth-and-assessment.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/scripts/check-release.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/scripts/dev-refresh-install.sh +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/scripts/install_plugin.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/scripts/publish-pypi.sh +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/scripts/publish-release.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/scripts/release-version.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/scripts/release-version.sh +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/skills/atk-dataset/SKILL.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/skills/atk-dataset/scripts/update_dataset.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/skills/atk-diagnose/SKILL.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/skills/atk-eval/SKILL.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/skills/atk-init/SKILL.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/skills/atk-optimize/SKILL.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/skills/atk-report/SKILL.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/skills/atk-trace-capture/SKILL.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/skills/atk-visualize-dataset/SKILL.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/skills/atk-visualize-dataset/scripts/generate_dataset_browser.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/skills/atk-visualize-failures/SKILL.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/skills/atk-visualize-failures/scripts/generate_failure_browser.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/templates/.atk/runner/eval_runner.py.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/templates/.atk/runner/failure_rule.py.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/templates/.atk/runner/import_evidence.py.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/templates/.gitkeep +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/__init__.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/conftest.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/fixtures/legacy_eval_runner.py.txt +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/fixtures/managed_v1.py.md +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_assessment_contract.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_atk_init_contract.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_cli_workflow.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_dataset_updates.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_diagnosis.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_evidence_import.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_evidence_judgments.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_evidence_packaging.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_evidence_versions.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_execution_evidence.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_execution_outcomes.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_execution_tracing.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_generate_dataset_browser.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_generate_failure_browser.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_judge_calibration.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_local_context.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_plugin_cache.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_runner_output_columns.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_runner_template_row_logging.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_runtime_contracts.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_snapshot_reads.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_trace_capture.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_trace_categories.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_trace_cli.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_trace_langfuse.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_trace_progress.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_trace_query.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_trace_records.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_trace_segments.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_trace_store.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_truth_browser.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_truth_cli.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_truth_contract.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_truth_runner.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_v2_progress.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/test_visualize_trace.py +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/trace-event-wheel.cjs +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/trace-preview-scroll.cjs +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/trace-selection-reason.cjs +0 -0
- {agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/tests/trace-stage-cards.cjs +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-tune-kit",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.4",
|
|
4
4
|
"description": "Local Codex plugin for batch Agent evaluation and session trace tuning with evidence-backed issues, focused changes, verification and offline review.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "hustyichi",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: agent-tune-kit
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.4
|
|
4
4
|
Summary: Local Codex plugin for iterative Agent tuning with guided Skills, reusable runner templates, versioned results, and static validation.
|
|
5
5
|
Project-URL: Homepage, https://github.com/hustyichi/agent-tune-kit
|
|
6
6
|
Project-URL: Repository, https://github.com/hustyichi/agent-tune-kit
|
|
@@ -171,15 +171,18 @@ These stages also refresh the project dashboard `.atk/traces/index.html`, which
|
|
|
171
171
|
|
|
172
172
|
Use Trace IDs to locate evidence within the session and open issue details to read the retention reason. Review any retained content in the HTML before sharing it.
|
|
173
173
|
|
|
174
|
-
### 3. Investigate, Fix
|
|
174
|
+
### 3. Investigate a Session or Specific Issues, Then Fix and Verify as Needed
|
|
175
175
|
|
|
176
176
|
```text
|
|
177
|
+
$atk-trace-diagnose Investigate session <session-id> and propose repair and verification plans.
|
|
177
178
|
$atk-trace-diagnose Investigate ISSUE-001 in session <session-id> and propose a repair and verification plan.
|
|
178
179
|
$atk-trace-optimize Implement the selected plan for ISSUE-001 in session <session-id>.
|
|
179
180
|
$atk-trace-verify Verify the candidate for ISSUE-001 in session <session-id> and check relevant behavior that should still work.
|
|
180
181
|
```
|
|
181
182
|
|
|
182
|
-
|
|
183
|
+
Without specified issues, diagnosis reviews all available session traces and works through existing and newly found anomalies, prioritizing causes directly related to project code, configuration, tool contracts, Prompt or Skill. Findings established as unrelated to the existing implementation may be skipped with an explanation. Findings with uncertain relevance remain open for investigation. Specified issues or concrete symptoms limit the investigation scope. You can start directly with diagnosis without a separate detection invocation.
|
|
184
|
+
|
|
185
|
+
Diagnoses and verification conclusions are saved per issue. If the evidence cannot establish which candidate loaded or whether key verification conditions were met, the verification outcome is `inconclusive`. Investigation results identify unread ranges and evidence gaps. As new issues surface, work through them individually or start another analysis with a new session trace.
|
|
183
186
|
|
|
184
187
|
### Where to Find Trace Outputs
|
|
185
188
|
|
|
@@ -192,3 +195,7 @@ Each session archive is stored under `.atk/traces/<session_id>/` in your Agent p
|
|
|
192
195
|
| `issues/<issue-id>/` | Issue evidence, diagnoses, and changes. Each verification's `result.json` records its status, conclusion, and evidence references |
|
|
193
196
|
|
|
194
197
|
[Trace tuning guide for source configuration, supported formats, and archive layout](docs/trace-tuning.md)
|
|
198
|
+
|
|
199
|
+
[Multi-project attribution and filtering proposal (not yet implemented, Chinese)](docs/trace-project-attribution-design.md)
|
|
200
|
+
|
|
201
|
+
Use `atk trace project` to register workspace projects and submodules. Issues can have multiple root-cause projects, filterable in the dashboard and session issue list. Repair details describe modification locations.
|
|
@@ -157,15 +157,18 @@ These stages also refresh the project dashboard `.atk/traces/index.html`, which
|
|
|
157
157
|
|
|
158
158
|
Use Trace IDs to locate evidence within the session and open issue details to read the retention reason. Review any retained content in the HTML before sharing it.
|
|
159
159
|
|
|
160
|
-
### 3. Investigate, Fix
|
|
160
|
+
### 3. Investigate a Session or Specific Issues, Then Fix and Verify as Needed
|
|
161
161
|
|
|
162
162
|
```text
|
|
163
|
+
$atk-trace-diagnose Investigate session <session-id> and propose repair and verification plans.
|
|
163
164
|
$atk-trace-diagnose Investigate ISSUE-001 in session <session-id> and propose a repair and verification plan.
|
|
164
165
|
$atk-trace-optimize Implement the selected plan for ISSUE-001 in session <session-id>.
|
|
165
166
|
$atk-trace-verify Verify the candidate for ISSUE-001 in session <session-id> and check relevant behavior that should still work.
|
|
166
167
|
```
|
|
167
168
|
|
|
168
|
-
|
|
169
|
+
Without specified issues, diagnosis reviews all available session traces and works through existing and newly found anomalies, prioritizing causes directly related to project code, configuration, tool contracts, Prompt or Skill. Findings established as unrelated to the existing implementation may be skipped with an explanation. Findings with uncertain relevance remain open for investigation. Specified issues or concrete symptoms limit the investigation scope. You can start directly with diagnosis without a separate detection invocation.
|
|
170
|
+
|
|
171
|
+
Diagnoses and verification conclusions are saved per issue. If the evidence cannot establish which candidate loaded or whether key verification conditions were met, the verification outcome is `inconclusive`. Investigation results identify unread ranges and evidence gaps. As new issues surface, work through them individually or start another analysis with a new session trace.
|
|
169
172
|
|
|
170
173
|
### Where to Find Trace Outputs
|
|
171
174
|
|
|
@@ -178,3 +181,7 @@ Each session archive is stored under `.atk/traces/<session_id>/` in your Agent p
|
|
|
178
181
|
| `issues/<issue-id>/` | Issue evidence, diagnoses, and changes. Each verification's `result.json` records its status, conclusion, and evidence references |
|
|
179
182
|
|
|
180
183
|
[Trace tuning guide for source configuration, supported formats, and archive layout](docs/trace-tuning.md)
|
|
184
|
+
|
|
185
|
+
[Multi-project attribution and filtering proposal (not yet implemented, Chinese)](docs/trace-project-attribution-design.md)
|
|
186
|
+
|
|
187
|
+
Use `atk trace project` to register workspace projects and submodules. Issues can have multiple root-cause projects, filterable in the dashboard and session issue list. Repair details describe modification locations.
|
|
@@ -157,15 +157,18 @@ $atk-visualize-trace 打开 <session-id> 的执行泳道,从问题跳到相关
|
|
|
157
157
|
|
|
158
158
|
可用 Trace ID 定位会话内的证据,在问题详情中查看保留理由。分享 HTML 前请核对其中留存的正文。
|
|
159
159
|
|
|
160
|
-
### 3.
|
|
160
|
+
### 3. 调查会话或指定问题,按需修复和验证
|
|
161
161
|
|
|
162
162
|
```text
|
|
163
|
+
$atk-trace-diagnose 调查 <session-id>,给出修复和验证方案。
|
|
163
164
|
$atk-trace-diagnose 调查 <session-id> 的 ISSUE-001,给出修复和验证方案。
|
|
164
165
|
$atk-trace-optimize 实施 <session-id> 的 ISSUE-001 已选定的方案。
|
|
165
166
|
$atk-trace-verify 验证 <session-id> 的 ISSUE-001 对应候选,并检查相关正常行为。
|
|
166
167
|
```
|
|
167
168
|
|
|
168
|
-
|
|
169
|
+
未指定异常时,调查默认检查会话中可用的全部轨迹,逐项处理已记录和新发现的异常,优先定位与项目代码、配置、工具契约、Prompt 或 Skill 直接相关的原因。证据确认与现有实现无关的异常可以忽略,并说明理由。关联尚不明确的异常保留待查。指定异常或具体症状时,按指定范围调查。可以直接从调查开始,无需先单独执行检测。
|
|
170
|
+
|
|
171
|
+
诊断和验证结论分别按问题保存。证据不足以确认实际加载的候选或关键验证条件时,验证效果记为 `inconclusive`(无法判断)。调查结果会说明未检查的范围和证据缺口。后续发现新的问题,可继续按问题处理,或用新会话的轨迹开始下一次分析。
|
|
169
172
|
|
|
170
173
|
### 查看轨迹产物
|
|
171
174
|
|
|
@@ -178,3 +181,7 @@ $atk-trace-verify 验证 <session-id> 的 ISSUE-001 对应候选,并检查相
|
|
|
178
181
|
| `issues/<issue-id>/` | 查看问题证据、诊断和改动。各次验证的 `result.json` 记录验证状态、结论和证据引用 |
|
|
179
182
|
|
|
180
183
|
[轨迹调优指南,包含来源配置、支持格式和归档结构](docs/trace-tuning.md)
|
|
184
|
+
|
|
185
|
+
[多工程关联与项目筛选方案(待实现)](docs/trace-project-attribution-design.md)
|
|
186
|
+
|
|
187
|
+
支持通过 `atk trace project` 登记工作区及子模块;诊断可记录多个根因项目,大盘与会话问题栏按根因项目筛选。修改位置在修复详情中说明。
|
|
@@ -34,6 +34,13 @@ def register(subparsers):
|
|
|
34
34
|
init.add_argument("--config", help="non-secret configuration JSON file")
|
|
35
35
|
init.add_argument("--project-file", help="project context Markdown file")
|
|
36
36
|
init.add_argument("--json", action="store_true")
|
|
37
|
+
project = actions.add_parser("project", help="discover, list or update workspace projects")
|
|
38
|
+
project.add_argument("--project-root", default=".")
|
|
39
|
+
mode = project.add_mutually_exclusive_group(required=True)
|
|
40
|
+
mode.add_argument("--discover", action="store_true")
|
|
41
|
+
mode.add_argument("--list", action="store_true")
|
|
42
|
+
mode.add_argument("--data")
|
|
43
|
+
project.add_argument("--json", action="store_true")
|
|
37
44
|
category = actions.add_parser("category", help="list or update the project issue category vocabulary")
|
|
38
45
|
category.add_argument("--project-root", default=".")
|
|
39
46
|
mode = category.add_mutually_exclusive_group(required=True)
|
|
@@ -100,9 +107,18 @@ def register(subparsers):
|
|
|
100
107
|
parser.add_argument("--issue-id", required=True)
|
|
101
108
|
parser.add_argument("--file", required=True, help="root cause and repair/verification plan Markdown")
|
|
102
109
|
parser.add_argument("--diagnosis-id")
|
|
110
|
+
parser.add_argument("--expected-revision", type=int)
|
|
103
111
|
|
|
104
112
|
|
|
105
113
|
def execute(args):
|
|
114
|
+
if args.action == "project":
|
|
115
|
+
from agent_tune_kit.traces.projects import discover_projects, load_projects, save_project
|
|
116
|
+
|
|
117
|
+
if args.discover:
|
|
118
|
+
return discover_projects(args.project_root)
|
|
119
|
+
if args.list:
|
|
120
|
+
return load_projects(store.trace_root(args.project_root))
|
|
121
|
+
return save_project(args.project_root, read_json(args.data))
|
|
106
122
|
if args.action == "init":
|
|
107
123
|
text = Path(args.project_file).read_text(encoding="utf-8") if args.project_file else None
|
|
108
124
|
return store.init_workspace(args.project_root, config=read_json(args.config), project_text=text)
|
|
@@ -162,6 +178,7 @@ def execute(args):
|
|
|
162
178
|
args.issue_id,
|
|
163
179
|
Path(args.file).read_text(encoding="utf-8"),
|
|
164
180
|
diagnosis_id=args.diagnosis_id,
|
|
181
|
+
expected_revision=args.expected_revision,
|
|
165
182
|
)
|
|
166
183
|
data = read_json(args.data)
|
|
167
184
|
if args.action == "issue":
|
|
@@ -19,7 +19,7 @@ def component(value):
|
|
|
19
19
|
raise UserActionRequired("An explicit nonempty native ID is required.")
|
|
20
20
|
name = quote(value, safe="")
|
|
21
21
|
# Names of the files that live beside session directories at the archive root.
|
|
22
|
-
reserved = {"project.md", "config.json", "categories.json", "index.html", "_export_summary"}
|
|
22
|
+
reserved = {"project.md", "config.json", "categories.json", "projects.json", "index.html", "_export_summary"}
|
|
23
23
|
if name.startswith(".") or name.casefold() in reserved:
|
|
24
24
|
name = "%" + format(ord(name[0]), "02X") + name[1:]
|
|
25
25
|
if len(name) > 200:
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"""Workspace project registry and evidence-backed attribution."""
|
|
2
|
+
|
|
3
|
+
import configparser
|
|
4
|
+
import hashlib
|
|
5
|
+
import subprocess
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from agent_tune_kit.errors import UserActionRequired
|
|
9
|
+
from agent_tune_kit.results.evidence import safe_path, write_manifest
|
|
10
|
+
|
|
11
|
+
from .store import ensure_workspace, read_json, session_write_lock, validate_ref
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def load_projects(root):
|
|
15
|
+
path = safe_path(Path(root), "projects.json")
|
|
16
|
+
if not path.exists():
|
|
17
|
+
return {"schema_version": 1, "revision": 0, "projects": []}
|
|
18
|
+
value = read_json(path)
|
|
19
|
+
if (
|
|
20
|
+
value.get("schema_version") != 1
|
|
21
|
+
or type(value.get("revision")) is not int
|
|
22
|
+
or not isinstance(value.get("projects"), list)
|
|
23
|
+
):
|
|
24
|
+
raise UserActionRequired("Invalid project registry.")
|
|
25
|
+
seen = set()
|
|
26
|
+
for item in value["projects"]:
|
|
27
|
+
if (
|
|
28
|
+
not isinstance(item, dict)
|
|
29
|
+
or any(not isinstance(item.get(k), str) or not item[k] for k in ("id", "name", "path"))
|
|
30
|
+
or item["id"] in seen
|
|
31
|
+
):
|
|
32
|
+
raise UserActionRequired("Invalid project entry.")
|
|
33
|
+
seen.add(item["id"])
|
|
34
|
+
return value
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def project_map(root):
|
|
38
|
+
try:
|
|
39
|
+
return {item["id"]: item for item in load_projects(root)["projects"]}
|
|
40
|
+
except (UserActionRequired, KeyError, TypeError):
|
|
41
|
+
return {}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def save_project(project_root, data):
|
|
45
|
+
if not isinstance(data, dict) or not isinstance(data.get("id"), str) or not data["id"].strip():
|
|
46
|
+
raise UserActionRequired("Project needs a stable id.")
|
|
47
|
+
root, _ = ensure_workspace(project_root)
|
|
48
|
+
with session_write_lock(root):
|
|
49
|
+
catalog = load_projects(root)
|
|
50
|
+
if type(data.get("revision", 0)) is not int or data.get("revision", 0) != catalog["revision"]:
|
|
51
|
+
raise UserActionRequired("Stale project registry revision.")
|
|
52
|
+
entries = {item["id"]: item for item in catalog["projects"]}
|
|
53
|
+
entry = {**entries.get(data["id"], {}), **{k: v for k, v in data.items() if k != "revision"}}
|
|
54
|
+
for key in ("name", "path"):
|
|
55
|
+
if not isinstance(entry.get(key), str) or not entry[key].strip():
|
|
56
|
+
raise UserActionRequired(f"Project needs {key}.")
|
|
57
|
+
base = Path(project_root).resolve()
|
|
58
|
+
target = (base / entry["path"]).resolve()
|
|
59
|
+
if Path(entry["path"]).is_absolute() or not target.is_relative_to(base):
|
|
60
|
+
raise UserActionRequired("Project path must stay within workspace.")
|
|
61
|
+
entry["path"] = target.relative_to(base).as_posix()
|
|
62
|
+
if entry.get("kind", "directory") not in {"repository", "submodule", "directory"}:
|
|
63
|
+
raise UserActionRequired("Invalid project kind.")
|
|
64
|
+
for key in ("abbreviation", "description"):
|
|
65
|
+
if key in entry and not isinstance(entry[key], str):
|
|
66
|
+
raise UserActionRequired(f"Project {key} must be text.")
|
|
67
|
+
for key in ("aliases", "entrypoints"):
|
|
68
|
+
if key in entry and (not isinstance(entry[key], list) or not all(isinstance(v, str) for v in entry[key])):
|
|
69
|
+
raise UserActionRequired(f"Project {key} must be a list of strings.")
|
|
70
|
+
if entry.get("parent_id") is not None and not isinstance(entry["parent_id"], str):
|
|
71
|
+
raise UserActionRequired("Invalid parent project.")
|
|
72
|
+
if "deprecated" in entry and not isinstance(entry["deprecated"], bool):
|
|
73
|
+
raise UserActionRequired("deprecated must be boolean.")
|
|
74
|
+
entries[entry["id"]] = entry
|
|
75
|
+
for item in entries.values():
|
|
76
|
+
seen = {item["id"]}
|
|
77
|
+
parent = item.get("parent_id")
|
|
78
|
+
while parent:
|
|
79
|
+
if parent in seen or parent not in entries:
|
|
80
|
+
raise UserActionRequired("Unknown or cyclic parent project.")
|
|
81
|
+
seen.add(parent)
|
|
82
|
+
parent = entries[parent].get("parent_id")
|
|
83
|
+
if len({e["path"] for e in entries.values()}) != len(entries):
|
|
84
|
+
raise UserActionRequired("Project path already registered.")
|
|
85
|
+
catalog.update(revision=catalog["revision"] + 1, projects=list(entries.values()))
|
|
86
|
+
write_manifest(root / "projects.json", catalog)
|
|
87
|
+
return catalog
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def discover_projects(project_root):
|
|
91
|
+
base = Path(project_root).resolve()
|
|
92
|
+
found = []
|
|
93
|
+
visited = set()
|
|
94
|
+
|
|
95
|
+
def visit(path, parent=None):
|
|
96
|
+
if path in visited:
|
|
97
|
+
return
|
|
98
|
+
visited.add(path)
|
|
99
|
+
relative = path.relative_to(base).as_posix()
|
|
100
|
+
project_id = "project-" + hashlib.sha256(relative.encode()).hexdigest()[:16]
|
|
101
|
+
readable = path.is_dir() and (parent is None or (path / ".git").exists())
|
|
102
|
+
found.append(
|
|
103
|
+
{
|
|
104
|
+
"id": project_id,
|
|
105
|
+
"name": path.name,
|
|
106
|
+
"path": relative,
|
|
107
|
+
"parent_id": parent,
|
|
108
|
+
"kind": "submodule" if parent else "repository",
|
|
109
|
+
"readable": readable,
|
|
110
|
+
"entrypoints": [
|
|
111
|
+
str(f.relative_to(base))
|
|
112
|
+
for f in path.iterdir()
|
|
113
|
+
if f.is_file() and f.name.lower() in {"readme.md", "claude.md", "agents.md", "rules.md"}
|
|
114
|
+
]
|
|
115
|
+
if readable
|
|
116
|
+
else [],
|
|
117
|
+
}
|
|
118
|
+
)
|
|
119
|
+
modules = path / ".gitmodules"
|
|
120
|
+
children = set()
|
|
121
|
+
if modules.is_file():
|
|
122
|
+
config = configparser.ConfigParser()
|
|
123
|
+
config.read(modules)
|
|
124
|
+
for section in config.sections():
|
|
125
|
+
child = (path / config.get(section, "path")).resolve()
|
|
126
|
+
if not child.is_relative_to(base) or child == path or path.is_relative_to(child):
|
|
127
|
+
raise UserActionRequired("Submodule path escapes project.")
|
|
128
|
+
children.add(child)
|
|
129
|
+
|
|
130
|
+
if readable:
|
|
131
|
+
result = subprocess.run(
|
|
132
|
+
["git", "-C", str(path), "ls-files", "--stage", "-z"], capture_output=True, check=False
|
|
133
|
+
)
|
|
134
|
+
if result.returncode == 0:
|
|
135
|
+
for row in result.stdout.decode("utf-8", errors="replace").split("\0"):
|
|
136
|
+
if row.startswith("160000 ") and "\t" in row:
|
|
137
|
+
children.add((path / row.split("\t", 1)[1]).resolve())
|
|
138
|
+
for child in sorted(children):
|
|
139
|
+
if not child.is_relative_to(base) or child == path or path.is_relative_to(child):
|
|
140
|
+
raise UserActionRequired("Submodule path escapes project.")
|
|
141
|
+
visit(child, project_id)
|
|
142
|
+
|
|
143
|
+
visit(base)
|
|
144
|
+
return {"projects": found}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def validate_links(session_dir, links):
|
|
148
|
+
if not isinstance(links, list):
|
|
149
|
+
raise UserActionRequired("project_links must be a list.")
|
|
150
|
+
projects = project_map(Path(session_dir).parent)
|
|
151
|
+
seen = set()
|
|
152
|
+
for link in links:
|
|
153
|
+
if not isinstance(link, dict):
|
|
154
|
+
raise UserActionRequired("Invalid project link.")
|
|
155
|
+
key = (link.get("project_id"), link.get("role"))
|
|
156
|
+
if not all(isinstance(k, str) for k in key) or key[0] not in projects or key in seen:
|
|
157
|
+
raise UserActionRequired("Unknown or duplicate project link.")
|
|
158
|
+
seen.add(key)
|
|
159
|
+
if key[1] not in {"root_cause", "improvement"} or link.get("evidence_state") not in {"hypothesis", "supported"}:
|
|
160
|
+
raise UserActionRequired("Invalid project attribution state.")
|
|
161
|
+
if (
|
|
162
|
+
not isinstance(link.get("reason"), str)
|
|
163
|
+
or not link["reason"].strip()
|
|
164
|
+
or not isinstance(link.get("evidence"), list)
|
|
165
|
+
or not link["evidence"]
|
|
166
|
+
):
|
|
167
|
+
raise UserActionRequired("Project attribution needs reason and retained evidence.")
|
|
168
|
+
for ref in link["evidence"]:
|
|
169
|
+
validate_ref(session_dir, ref)
|
|
170
|
+
if not isinstance(link.get("source_paths", []), list):
|
|
171
|
+
raise UserActionRequired("source_paths must be a list.")
|
|
172
|
+
for path in link.get("source_paths", []):
|
|
173
|
+
if not isinstance(path, str):
|
|
174
|
+
raise UserActionRequired("Source path must be workspace relative text.")
|
|
175
|
+
safe_path(Path(session_dir).parent.parent.parent, path)
|
|
176
|
+
return links
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def root_projects(root, issue):
|
|
180
|
+
projects = project_map(root)
|
|
181
|
+
result = []
|
|
182
|
+
links = issue.get("project_links", [])
|
|
183
|
+
if not isinstance(links, list):
|
|
184
|
+
return result
|
|
185
|
+
for link in links:
|
|
186
|
+
if (
|
|
187
|
+
not isinstance(link, dict)
|
|
188
|
+
or not isinstance(link.get("project_id"), str)
|
|
189
|
+
or link.get("role") != "root_cause"
|
|
190
|
+
):
|
|
191
|
+
continue
|
|
192
|
+
entry = projects.get(link["project_id"], {})
|
|
193
|
+
result.append(
|
|
194
|
+
{
|
|
195
|
+
**entry,
|
|
196
|
+
"id": link["project_id"],
|
|
197
|
+
"name": entry.get("abbreviation") or entry.get("name") or link["project_id"],
|
|
198
|
+
"pending": link.get("evidence_state") != "supported",
|
|
199
|
+
}
|
|
200
|
+
)
|
|
201
|
+
return result
|
|
@@ -10,6 +10,7 @@ from agent_tune_kit.results.evidence import json_bytes, now, safe_path, write_ma
|
|
|
10
10
|
from agent_tune_kit.utils.files import write_text_atomic
|
|
11
11
|
|
|
12
12
|
from .categories import check_issue_category
|
|
13
|
+
from .projects import load_projects, validate_links
|
|
13
14
|
from .segments import resolve_segments, segments_for_storage
|
|
14
15
|
from .store import (
|
|
15
16
|
STATES,
|
|
@@ -173,6 +174,8 @@ def prepare_issue(session_dir, data, *, dry_run=False):
|
|
|
173
174
|
"segments": [],
|
|
174
175
|
}
|
|
175
176
|
)
|
|
177
|
+
if "project_links" in data:
|
|
178
|
+
issue["project_links"] = validate_links(directory, data["project_links"])
|
|
176
179
|
if "category" in data:
|
|
177
180
|
data["category"] = check_issue_category(
|
|
178
181
|
directory.parent, data["category"], previous.get("category") if previous else None
|
|
@@ -227,6 +230,7 @@ def prepare_issue(session_dir, data, *, dry_run=False):
|
|
|
227
230
|
"description",
|
|
228
231
|
"selection_reason",
|
|
229
232
|
"category",
|
|
233
|
+
"project_links",
|
|
230
234
|
"evidence",
|
|
231
235
|
"segments",
|
|
232
236
|
"status",
|
|
@@ -325,9 +329,11 @@ def save_detection(session_dir, data):
|
|
|
325
329
|
|
|
326
330
|
|
|
327
331
|
@_locked_write
|
|
328
|
-
def save_diagnosis(session_dir, issue_id, text, diagnosis_id=None):
|
|
332
|
+
def save_diagnosis(session_dir, issue_id, text, diagnosis_id=None, expected_revision=None):
|
|
329
333
|
directory = Path(session_dir)
|
|
330
334
|
issue = load_issue(directory, issue_id)
|
|
335
|
+
if expected_revision is not None and expected_revision != issue["revision"]:
|
|
336
|
+
raise UserActionRequired("Stale diagnosis issue revision.")
|
|
331
337
|
if not isinstance(text, str) or not text.strip():
|
|
332
338
|
raise UserActionRequired("Diagnosis must contain an explanation and a plan.")
|
|
333
339
|
diagnosis_id = _id(diagnosis_id, "DIA")
|
|
@@ -343,9 +349,11 @@ def save_diagnosis(session_dir, issue_id, text, diagnosis_id=None):
|
|
|
343
349
|
"segments": issue.get("segments", []),
|
|
344
350
|
"created_at": now(),
|
|
345
351
|
}
|
|
346
|
-
for optional in ("selection_reason", "category"):
|
|
352
|
+
for optional in ("selection_reason", "category", "project_links"):
|
|
347
353
|
if optional in issue:
|
|
348
354
|
snapshot[optional] = issue[optional]
|
|
355
|
+
if issue.get("project_links"):
|
|
356
|
+
snapshot["project_registry"] = load_projects(directory.parent)
|
|
349
357
|
_refs(directory, issue["evidence"])
|
|
350
358
|
for segment in snapshot["segments"]:
|
|
351
359
|
_refs(directory, segment["evidence"])
|
|
@@ -502,6 +510,19 @@ def save_change(session_dir, issue_id, data):
|
|
|
502
510
|
if not previous and change["status"] != "running":
|
|
503
511
|
raise UserActionRequired("Save a running change before applying the implementation.")
|
|
504
512
|
_validate_change_summary(change)
|
|
513
|
+
for summary in change.get("change_summary", []):
|
|
514
|
+
if isinstance(summary, dict) and "project_id" in summary:
|
|
515
|
+
from .projects import project_map
|
|
516
|
+
|
|
517
|
+
entry = project_map(directory.parent).get(summary["project_id"])
|
|
518
|
+
if entry is None:
|
|
519
|
+
raise UserActionRequired("Unknown modification project.")
|
|
520
|
+
base = directory.parent.parent.parent.resolve()
|
|
521
|
+
project_path = (base / entry["path"]).resolve()
|
|
522
|
+
for file in summary.get("files", []):
|
|
523
|
+
target = safe_path(base, file)
|
|
524
|
+
if not target.resolve().is_relative_to(project_path):
|
|
525
|
+
raise UserActionRequired("Modification file is outside its project.")
|
|
505
526
|
for field in ("verifications", "schema_version", "owner_issue", "created_at"):
|
|
506
527
|
if field in data and (not previous or data[field] != previous.get(field)):
|
|
507
528
|
raise UserActionRequired(f"Change {field} is managed by its dedicated operation.")
|
|
@@ -199,6 +199,7 @@ def load_session(session_dir):
|
|
|
199
199
|
manifest = value.get("archive")
|
|
200
200
|
if (
|
|
201
201
|
directory.name != archive.component(value.get("session_id"))
|
|
202
|
+
and not (directory.name == "projects.json" and value.get("session_id") == "projects.json")
|
|
202
203
|
or value.get("source") != normalize_source(value.get("source"))
|
|
203
204
|
or not isinstance(manifest, dict)
|
|
204
205
|
or not isinstance(manifest.get("files"), list)
|
{agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/assets/shared/base.css
RENAMED
|
@@ -93,3 +93,12 @@ select:hover { border-color: #9baebb }
|
|
|
93
93
|
.drawer.above-record { inset: 0 0 auto; border-radius: 0 0 12px 12px; border-top: 0; border-bottom: 1px solid var(--line) }
|
|
94
94
|
.drawer-resizer { display: none }
|
|
95
95
|
}
|
|
96
|
+
|
|
97
|
+
/* Project attribution belongs to issues; the menu is shared by both issue views. */
|
|
98
|
+
.project-choice { position: relative; margin-bottom: 7px; font-size: 13px }
|
|
99
|
+
.project-choice summary { height: 34px; padding: 6px 12px; border: 1px solid #cdd8e1; border-radius: 6px; background: white }
|
|
100
|
+
.project-choice summary:hover { border-color: #9baebb }
|
|
101
|
+
.project-menu { position: absolute; right: 0; z-index: 20; width: min(300px, 80vw); max-height: 320px; overflow: auto; padding: 12px; border: 1px solid var(--line); border-radius: 6px; background: white; box-shadow: 0 6px 20px #0002 }
|
|
102
|
+
.project-menu p { margin: 0 0 8px }
|
|
103
|
+
#project-filter label { display: flex; align-items: center; gap: 8px; padding: 6px 0 }
|
|
104
|
+
#project-filter input { width: 16px; height: 16px; min-width: 16px; padding: 0 }
|
|
@@ -21,6 +21,33 @@
|
|
|
21
21
|
let investigation = null, scopeBefore = null, previewIssue = null, expandedFolds = new Set(), railFilter = null;
|
|
22
22
|
const captureById = new Map(data.captures.map(c => [c.id, c]));
|
|
23
23
|
const issueById = new Map(data.issues.map(item => [item.record.id, item]));
|
|
24
|
+
|
|
25
|
+
const projectSelection = new Set(new URLSearchParams(location.hash.slice(1)).getAll("project"));
|
|
26
|
+
const projectMatches = item => !projectSelection.size || [...projectSelection].some(id => {
|
|
27
|
+
const roots = item.root_projects || [];
|
|
28
|
+
if (id === "~unattributed") return !roots.length;
|
|
29
|
+
return roots.some(root => { let current = root.id; const seen = new Set(); while (current && !seen.has(current)) { if (current === id) return true; seen.add(current); current = data.projects?.[current]?.parent_id; } return false; });
|
|
30
|
+
});
|
|
31
|
+
const projectText = item => (item.root_projects || []).map(p => p.name + (p.pending ? "(待确认)" : "")).join("、") || "待归因";
|
|
32
|
+
const projectInputs = [];
|
|
33
|
+
for (const p of [{id: "~unattributed", name: "待归因"}, ...Object.values(data.projects || {})]) {
|
|
34
|
+
const label = el("label"), input = el("input");
|
|
35
|
+
input.type = "checkbox"; input.value = p.id;
|
|
36
|
+
input.checked = projectSelection.has(p.id);
|
|
37
|
+
label.append(input, document.createTextNode(p.abbreviation || p.name));
|
|
38
|
+
$("project-filter").append(label); projectInputs.push(input);
|
|
39
|
+
input.onchange = () => $("project-filter").onchange();
|
|
40
|
+
}
|
|
41
|
+
const updateProjectSummary = () => {
|
|
42
|
+
$("project-summary").textContent = projectSelection.size ? `关联项目:已选 ${projectSelection.size} 项` : "关联项目:全部";
|
|
43
|
+
};
|
|
44
|
+
updateProjectSummary();
|
|
45
|
+
$("project-clear").onclick = () => { projectInputs.forEach(input => { input.checked = false; }); $("project-filter").onchange(); };
|
|
46
|
+
$("project-choice").onkeydown = event => { if (event.key === "Escape") { $("project-choice").open = false; $("project-summary").focus(); } };
|
|
47
|
+
document.addEventListener("click", event => {
|
|
48
|
+
if (!event.target.closest("#project-choice")) $("project-choice").open = false;
|
|
49
|
+
});
|
|
50
|
+
|
|
24
51
|
const filters = ["trace-filter", "type-filter", "trace-search", "record-mode"];
|
|
25
52
|
const list = $("trace-list"), scroller = $("trace-scroll");
|
|
26
53
|
const scope = () => $("trace-filter").value === "" ? null : Number($("trace-filter").value);
|
|
@@ -257,6 +284,7 @@
|
|
|
257
284
|
return;
|
|
258
285
|
}
|
|
259
286
|
for (const [index, diagnosis] of item.diagnoses.slice().reverse().entries()) {
|
|
287
|
+
const snapshot = diagnosis.snapshot;
|
|
260
288
|
const body = diagnosis.error ? el("p", diagnosis.error, "warning") : renderDiagnosis(diagnosis.text);
|
|
261
289
|
const headings = [...body.children].filter(node => node.tagName === "H2").map(node => node.textContent);
|
|
262
290
|
const structured = headings.join("|") === "异常描述|异常根因|最小修复方案"
|
|
@@ -275,6 +303,11 @@
|
|
|
275
303
|
container.append(description);
|
|
276
304
|
}
|
|
277
305
|
const details = el("details", undefined, "detail-section");
|
|
306
|
+
if (snapshot?.project_links) {
|
|
307
|
+
const entries = new Map((snapshot.project_registry?.projects || []).map(p => [p.id, p]));
|
|
308
|
+
const names = snapshot.project_links.filter(p => p.role === "root_cause").map(p => { const entry = entries.get(p.project_id); return (entry?.abbreviation || entry?.name || p.project_id) + (p.evidence_state === "supported" ? "" : "(待确认)"); });
|
|
309
|
+
body.prepend(el("p", `诊断时的关联项目:${names.join("、") || "待归因"}`));
|
|
310
|
+
}
|
|
278
311
|
const name = diagnosis.reference.path.split("/").pop();
|
|
279
312
|
details.append(el("summary", `展开原诊断 · ${name}`), body);
|
|
280
313
|
container.append(details);
|
|
@@ -373,7 +406,7 @@
|
|
|
373
406
|
$("drawer-content").append(tabs);
|
|
374
407
|
if (stage === "issue") {
|
|
375
408
|
const description = section("问题描述");
|
|
376
|
-
description.append(el("p", issue.description || issue.title));
|
|
409
|
+
description.append(el("p", `关联项目:${projectText(item)}`), el("p", issue.description || issue.title));
|
|
377
410
|
$("drawer-content").append(description);
|
|
378
411
|
if (typeof issue.selection_reason === "string" && issue.selection_reason.trim()) {
|
|
379
412
|
const reason = section("保留理由");
|
|
@@ -969,6 +1002,7 @@
|
|
|
969
1002
|
const text = $("issue-search").value.toLocaleLowerCase();
|
|
970
1003
|
const status = $("issue-status").value;
|
|
971
1004
|
const filtered = data.issues.filter(item => {
|
|
1005
|
+
if (!projectMatches(item) && new URLSearchParams(location.hash.slice(1)).get("issue") !== item.record.id) return false;
|
|
972
1006
|
if (railFilter && !railFilter.ids.includes(item.record.id)) return false;
|
|
973
1007
|
const progress = progressOf(item).label;
|
|
974
1008
|
if (status && progress !== status) return false;
|
|
@@ -994,6 +1028,11 @@
|
|
|
994
1028
|
const head = el("div", undefined, "issue-card-head");
|
|
995
1029
|
head.append(el("span", issue.id, "issue-id-text"), el("span", undefined, `progress-dot ${progress.klass}`));
|
|
996
1030
|
const body = el("div", undefined, "issue-card-body");
|
|
1031
|
+
const projects = el("p", `关联项目:${projectText(item)}`);
|
|
1032
|
+
if (data.dashboard.available) for (const project of item.root_projects || []) {
|
|
1033
|
+
const link = el("a", project.name); link.href = dashboardHash(`view=category&project=${encodeURIComponent(project.id)}`); projects.append(link);
|
|
1034
|
+
}
|
|
1035
|
+
body.append(projects);
|
|
997
1036
|
body.append(el("h3", issue.title || "问题"), el("div", progress.label, "issue-progress"));
|
|
998
1037
|
const tag = categoryTag(issue.category);
|
|
999
1038
|
if (tag) body.append(tag);
|
|
@@ -1083,6 +1122,7 @@
|
|
|
1083
1122
|
$("capture-filter").closest("label").hidden = Boolean(currentCapture?.current);
|
|
1084
1123
|
options($("capture-filter"), data.captures.map(c => c.id));
|
|
1085
1124
|
if (currentCapture) $("capture-filter").value = currentCapture.id;
|
|
1125
|
+
$("project-filter").onchange = () => { projectSelection.clear(); for (const input of projectInputs) if (input.checked) projectSelection.add(input.value); updateProjectSummary(); const params = new URLSearchParams(location.hash.slice(1)); params.delete("project"); for (const id of projectSelection) params.append("project", id); history.replaceState(null, "", `#${params}`); renderIssueRail(); };
|
|
1086
1126
|
$("capture-filter").onchange = () => { investigation = null; scopeBefore = null; railFilter = null; chooseCapture(); renderIssueRail(); renderTraces(); };
|
|
1087
1127
|
$("trace-filter").onchange = () => focusTrace(scope());
|
|
1088
1128
|
for (const id of ["trace-search","type-filter","record-mode"]) $(id).addEventListener(id === "trace-search" ? "input" : "change", () => renderTraces());
|
{agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/assets/trace/page.html
RENAMED
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
</div>
|
|
22
22
|
<div class="rail-filters">
|
|
23
23
|
<label class="search-label"><span class="sr-only">搜索问题</span><input id="issue-search" type="search" placeholder="搜索问题"></label>
|
|
24
|
-
<
|
|
24
|
+
<details id="project-choice" class="project-choice"><summary id="project-summary">关联项目:全部</summary><div class="project-menu"><p>含子项目</p><button id="project-clear" type="button">清空筛选</button><div id="project-filter" role="group" aria-label="关联项目"></div></div></details>
|
|
25
|
+
<label><span class="sr-only">状态</span><select id="issue-status"></select></label>
|
|
25
26
|
</div>
|
|
26
27
|
<div id="issue-rail-list" class="rail-list"></div>
|
|
27
28
|
</aside>
|
{agent_tune_kit-2.3.2 → agent_tune_kit-2.3.4}/agent_tune_kit/visualize/assets/trace/styles.css
RENAMED
|
@@ -30,6 +30,9 @@ body.rail-collapsed #rail-toggle { transform: rotate(180deg) }
|
|
|
30
30
|
.rail-filters .search-label { flex: 1; min-width: 0 }
|
|
31
31
|
.rail-filters input, .rail-filters select { width: 100%; height: 32px; font-size: 12px; padding: 0 8px }
|
|
32
32
|
.rail-filters select { width: auto; min-width: 88px }
|
|
33
|
+
.rail-filters .project-choice { margin-bottom: 0; font-size: 12px }
|
|
34
|
+
.rail-filters .project-choice summary { height: 32px; padding: 6px 8px; white-space: nowrap }
|
|
35
|
+
.rail-filters .project-menu { left: 0; right: auto }
|
|
33
36
|
.rail-list { flex: 1; min-height: 0; overflow: auto; padding: 8px; display: flex; flex-direction: column; gap: 8px }
|
|
34
37
|
.issue-card { display: flex; flex-direction: column; gap: 6px; width: 100%; text-align: left; padding: 10px }
|
|
35
38
|
.issue-card-head { justify-content: space-between; gap: 6px; width: 100% }
|