DeepFabric 4.11.0__tar.gz → 4.12.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.
- {deepfabric-4.11.0 → deepfabric-4.12.0}/PKG-INFO +1 -1
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/cli.py +541 -6
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/config.py +8 -1
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/config_manager.py +6 -1
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/graph.py +177 -1
- deepfabric-4.12.0/deepfabric/graph_pruner.py +122 -0
- deepfabric-4.12.0/deepfabric/topic_inspector.py +237 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/topic_manager.py +32 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/tree.py +40 -25
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/cli/generate.md +20 -3
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/cli/index.md +8 -0
- deepfabric-4.12.0/docs/cli/topic-inspect.md +162 -0
- deepfabric-4.12.0/docs/cli/topic-prune.md +120 -0
- deepfabric-4.12.0/docs/cli/topic.md +50 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/dataset-generation/agent.md +1 -1
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/dataset-generation/basic.md +1 -1
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/dataset-generation/configuration.md +14 -1
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/dataset-generation/reasoning.md +1 -1
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/index.md +2 -2
- {deepfabric-4.11.0 → deepfabric-4.12.0}/mkdocs.yml +4 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/pyproject.toml +1 -1
- deepfabric-4.12.0/tests/unit/test_graph_pruner.py +397 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/unit/test_topic_graph.py +120 -0
- deepfabric-4.12.0/tests/unit/test_topic_inspector.py +294 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/uv.lock +1 -1
- {deepfabric-4.11.0 → deepfabric-4.12.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/.github/config.yml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/.github/dependabot.yml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/.github/workflows/docs.yml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/.github/workflows/integration.yml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/.github/workflows/publish.yml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/.github/workflows/test.yml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/.github/workflows/tools-sdk-docker.yml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/.gitignore +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/CLAUDE.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/CODE_OF_CONDUCT.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/CONTRIBUTING.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/LICENSE +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/Makefile +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/README.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/assets/df-demo.gif +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/assets/logo-light-hols.png +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/assets/logo-light.png +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/assets/star.gif +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/coverage.xml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/__init__.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/__main__.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/auth.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/builders.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/builders_agent.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/cloud_upload.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/constants.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/dataset.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/dataset_manager.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/error_codes.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/evaluation/__init__.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/evaluation/backends/__init__.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/evaluation/backends/llm_eval_backend.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/evaluation/backends/ollama_backend.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/evaluation/backends/tool_call_parsers.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/evaluation/backends/transformers_backend.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/evaluation/evaluator.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/evaluation/evaluators/__init__.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/evaluation/evaluators/base.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/evaluation/evaluators/builtin/__init__.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/evaluation/evaluators/builtin/tool_calling.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/evaluation/evaluators/registry.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/evaluation/inference.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/evaluation/metrics.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/evaluation/parser.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/evaluation/reporters/__init__.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/evaluation/reporters/base.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/evaluation/reporters/cloud_reporter.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/evaluation/reporters/file_reporter.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/evaluation/reporters/multi_reporter.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/exceptions.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/factory.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/generator.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/hf_hub.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/kaggle_hub.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/llm/__init__.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/llm/api_key_verifier.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/llm/client.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/llm/errors.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/llm/rate_limit_config.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/llm/rate_limit_detector.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/llm/retry_handler.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/loader.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/metrics.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/progress.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/prompts.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/schemas.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/spin/__init__.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/spin/client.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/spin/models.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/stream_simulator.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/tools/__init__.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/tools/defaults.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/tools/loader.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/tools/mcp_client.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/topic_model.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/training/__init__.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/training/api_key_prompt.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/training/callback.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/training/dataset_utils.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/training/metrics_sender.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/tui.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/update_checker.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/utils.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/deepfabric/validation.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/cli/evaluate.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/cli/import-tools.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/cli/info.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/cli/upload-hf.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/cli/upload-kaggle.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/cli/upload.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/cli/validate.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/cli/visualize.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/dataset-generation/index.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/dataset-generation/rate-limiting.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/evaluation/index.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/evaluation/metrics.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/evaluation/running.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/images/logo-light.png +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/images/python-spin.png +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/tools/custom.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/tools/index.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/tools/mock.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/tools/spin.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/tools/tutorials/go.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/tools/tutorials/index.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/tools/tutorials/python.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/tools/tutorials/rust.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/tools/tutorials/typescript.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/tools/vfs.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/training/chat-templates.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/training/dataset-preparation.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/training/frameworks.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/training/index.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/docs/training/loading.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/examples/agent-tools.yaml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/examples/basic-anthropic.yaml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/examples/basic-gemini.yaml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/examples/basic-graph.yaml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/examples/basic-ollama.yaml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/examples/basic-openai.yaml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/examples/basic-openrouter.yaml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/examples/basic-tree.yaml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/examples/coding-agent.yaml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/examples/complete.yaml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/examples/custom-tools.yaml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/examples/github-mock-tools.yaml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/examples/reasoning.yaml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/examples/spin-vfs-tools.yaml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/examples/tools-sdk-examples/blender/load-blender-mock-data.sh +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/examples/tools-sdk-examples/blender/spin-blender.yaml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/examples/tools-sdk-examples/figma/load-figma-mock-data.sh +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/examples/tools-sdk-examples/figma/spin-figma.yaml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/examples/tools-sdk-examples/github/load-github-mock-data.sh +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/examples/tools-sdk-examples/github/spin-github-tools.yaml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/examples/tools-sdk-examples/kubernetes/load-kubernetes-mock-data.sh +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/examples/tools-sdk-examples/kubernetes/spin-kubernetes.yaml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/misc/test_update_manual.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/notebooks/Train_and_Evaluate_Qwen3_4B_Thinking_as_a_Blender_MCP_Agent.ipynb +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/notebooks/dataset-compatibility-check.ipynb +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/notebooks/evaluations.ipynb +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/test-run/01-alpaca.txt +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/test-run/01-chatml.txt +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/test-run/01-grpo.txt +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/test-run/01-xlam_v2.txt +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/test-run/02-trl2.txt +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/test-run/02-xlam_v2.txt +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/test-run/04-agent-tool-conversations.jsnl +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/test-run/04-single-agent-tools +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/__init__.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/integration/__init__.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/integration/conftest.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/integration/test_generator_integration.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/integration/test_graph_integration.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/integration/test_llm_client_integration.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/integration/test_spin_integration.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/integration/test_tree_integration.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/unit/__init__.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/unit/conftest.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/unit/test_api_key_validation.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/unit/test_checkpoint.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/unit/test_cli.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/unit/test_cloud_upload.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/unit/test_config.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/unit/test_dataset.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/unit/test_error_codes.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/unit/test_gemini_schema.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/unit/test_generator.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/unit/test_hf_hub.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/unit/test_kaggle_hub.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/unit/test_llm_eval_backend.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/unit/test_loader.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/unit/test_modular_config.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/unit/test_rate_limiting.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/unit/test_schemas.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/unit/test_tool_call_parsers.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/unit/test_training_callback.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/unit/test_tui.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tests/unit/test_update_checker.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tools/extract_messages.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tools/function.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tools/yaml_to_openai_tools.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tools-sdk/.dockerignore +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tools-sdk/Dockerfile +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tools-sdk/README.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tools-sdk/components/github/README.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tools-sdk/components/github/app.py +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tools-sdk/components/github/github.wasm +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tools-sdk/components/github/pyproject.toml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tools-sdk/components/github/requirements.txt +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tools-sdk/components/github/spin.toml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tools-sdk/components/github/uv.lock +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tools-sdk/components/mock/Cargo.lock +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tools-sdk/components/mock/Cargo.toml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tools-sdk/components/mock/README.md +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tools-sdk/components/mock/src/lib.rs +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tools-sdk/components/vfs/Cargo.lock +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tools-sdk/components/vfs/Cargo.toml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tools-sdk/components/vfs/src/lib.rs +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tools-sdk/docker-compose.yaml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tools-sdk/runtime-config.toml +0 -0
- {deepfabric-4.11.0 → deepfabric-4.12.0}/tools-sdk/spin.toml +0 -0
|
@@ -8,7 +8,13 @@ import signal
|
|
|
8
8
|
import sys
|
|
9
9
|
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
from typing import Literal, NoReturn, cast
|
|
11
|
+
from typing import TYPE_CHECKING, Literal, NoReturn, cast
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from rich.tree import Tree as RichTree
|
|
15
|
+
|
|
16
|
+
from .topic_inspector import TopicInspectionResult
|
|
17
|
+
from .tui import DeepFabricTUI
|
|
12
18
|
|
|
13
19
|
import click
|
|
14
20
|
import yaml
|
|
@@ -139,7 +145,7 @@ class GenerateOptions(BaseModel):
|
|
|
139
145
|
batch_size: int | None = None
|
|
140
146
|
base_url: str | None = None
|
|
141
147
|
include_system_message: bool | None = None
|
|
142
|
-
mode: Literal["tree", "graph"] = Field(default=
|
|
148
|
+
mode: Literal["tree", "graph"] | None = Field(default=None)
|
|
143
149
|
debug: bool = False
|
|
144
150
|
topic_only: bool = False
|
|
145
151
|
tui: Literal["rich", "simple"] = Field(default="rich")
|
|
@@ -332,7 +338,7 @@ def _load_and_prepare_generation_context(
|
|
|
332
338
|
# Skip path validation for topic-only mode since we're not generating dataset samples
|
|
333
339
|
if not skip_path_validation:
|
|
334
340
|
validate_path_requirements(
|
|
335
|
-
mode=
|
|
341
|
+
mode=config.topics.mode,
|
|
336
342
|
depth=final_depth,
|
|
337
343
|
degree=final_degree,
|
|
338
344
|
num_samples=final_num_samples,
|
|
@@ -341,7 +347,7 @@ def _load_and_prepare_generation_context(
|
|
|
341
347
|
)
|
|
342
348
|
|
|
343
349
|
show_validation_success(
|
|
344
|
-
mode=
|
|
350
|
+
mode=config.topics.mode,
|
|
345
351
|
depth=final_depth,
|
|
346
352
|
degree=final_degree,
|
|
347
353
|
num_samples=final_num_samples,
|
|
@@ -655,8 +661,8 @@ def _run_generation(
|
|
|
655
661
|
@click.option(
|
|
656
662
|
"--mode",
|
|
657
663
|
type=click.Choice(["tree", "graph"]),
|
|
658
|
-
default=
|
|
659
|
-
help="Topic generation mode (default:
|
|
664
|
+
default=None,
|
|
665
|
+
help="Topic generation mode (default: graph)",
|
|
660
666
|
)
|
|
661
667
|
@click.option(
|
|
662
668
|
"--debug",
|
|
@@ -2050,5 +2056,534 @@ def checkpoint_status(config_file: str) -> None:
|
|
|
2050
2056
|
)
|
|
2051
2057
|
|
|
2052
2058
|
|
|
2059
|
+
# Topic inspection command group
|
|
2060
|
+
@click.group()
|
|
2061
|
+
def topic() -> None:
|
|
2062
|
+
"""Topic management commands."""
|
|
2063
|
+
pass
|
|
2064
|
+
|
|
2065
|
+
|
|
2066
|
+
@topic.command("inspect")
|
|
2067
|
+
@click.argument("file", type=click.Path(exists=True))
|
|
2068
|
+
@click.option(
|
|
2069
|
+
"--level",
|
|
2070
|
+
"-l",
|
|
2071
|
+
type=int,
|
|
2072
|
+
default=None,
|
|
2073
|
+
help="Show topics at a specific depth level (0=root, 1=first children, etc.)",
|
|
2074
|
+
)
|
|
2075
|
+
@click.option(
|
|
2076
|
+
"--expand",
|
|
2077
|
+
"-e",
|
|
2078
|
+
type=int,
|
|
2079
|
+
default=None,
|
|
2080
|
+
is_flag=False,
|
|
2081
|
+
flag_value=-1, # -1 means expand all levels
|
|
2082
|
+
help="Show subtopics in tree format. Use alone for all levels, or specify depth (e.g., --expand 2)",
|
|
2083
|
+
)
|
|
2084
|
+
@click.option(
|
|
2085
|
+
"--all",
|
|
2086
|
+
"-a",
|
|
2087
|
+
"show_all",
|
|
2088
|
+
is_flag=True,
|
|
2089
|
+
help="Show the entire tree structure with indentation",
|
|
2090
|
+
)
|
|
2091
|
+
@click.option(
|
|
2092
|
+
"--format",
|
|
2093
|
+
"-f",
|
|
2094
|
+
"output_format",
|
|
2095
|
+
type=click.Choice(["tree", "table", "json"]),
|
|
2096
|
+
default="tree",
|
|
2097
|
+
help="Output format (default: tree)",
|
|
2098
|
+
)
|
|
2099
|
+
@click.option(
|
|
2100
|
+
"--uuid",
|
|
2101
|
+
"-u",
|
|
2102
|
+
"show_uuid",
|
|
2103
|
+
is_flag=True,
|
|
2104
|
+
help="Show UUID/topic_id for each leaf node",
|
|
2105
|
+
)
|
|
2106
|
+
def topic_inspect(
|
|
2107
|
+
file: str,
|
|
2108
|
+
level: int | None,
|
|
2109
|
+
expand: int | None,
|
|
2110
|
+
show_all: bool,
|
|
2111
|
+
output_format: str,
|
|
2112
|
+
show_uuid: bool,
|
|
2113
|
+
) -> None:
|
|
2114
|
+
"""Inspect a topic tree or graph file.
|
|
2115
|
+
|
|
2116
|
+
Displays metadata and structure of topic files generated by DeepFabric.
|
|
2117
|
+
Supports both Tree (JSONL) and Graph (JSON) formats with auto-detection.
|
|
2118
|
+
|
|
2119
|
+
Examples:
|
|
2120
|
+
|
|
2121
|
+
\b
|
|
2122
|
+
# Show file metadata and summary
|
|
2123
|
+
deepfabric topic inspect topic_tree.jsonl
|
|
2124
|
+
|
|
2125
|
+
\b
|
|
2126
|
+
# Show topics at depth level 2 (just topic names)
|
|
2127
|
+
deepfabric topic inspect topic_tree.jsonl --level 2
|
|
2128
|
+
|
|
2129
|
+
\b
|
|
2130
|
+
# Show level 2 topics and all subtopics (tree format)
|
|
2131
|
+
deepfabric topic inspect topic_tree.jsonl --level 2 --expand
|
|
2132
|
+
|
|
2133
|
+
\b
|
|
2134
|
+
# Show level 2 topics and 1 sublevel only (tree format)
|
|
2135
|
+
deepfabric topic inspect topic_tree.jsonl --level 2 --expand 1
|
|
2136
|
+
|
|
2137
|
+
\b
|
|
2138
|
+
# Show entire tree with indentation
|
|
2139
|
+
deepfabric topic inspect topic_graph.json --all
|
|
2140
|
+
|
|
2141
|
+
\b
|
|
2142
|
+
# Output as JSON for scripting
|
|
2143
|
+
deepfabric topic inspect topic_tree.jsonl --format json
|
|
2144
|
+
|
|
2145
|
+
\b
|
|
2146
|
+
# Show UUIDs for each leaf node
|
|
2147
|
+
deepfabric topic inspect topic_tree.jsonl --all --uuid
|
|
2148
|
+
"""
|
|
2149
|
+
from .topic_inspector import inspect_topic_file # noqa: PLC0415
|
|
2150
|
+
|
|
2151
|
+
tui = get_tui()
|
|
2152
|
+
|
|
2153
|
+
try:
|
|
2154
|
+
# Perform inspection
|
|
2155
|
+
result = inspect_topic_file(file, level=level, expand_depth=expand, show_all=show_all)
|
|
2156
|
+
|
|
2157
|
+
# Handle JSON output format
|
|
2158
|
+
if output_format == "json":
|
|
2159
|
+
output = {
|
|
2160
|
+
"format": result.format,
|
|
2161
|
+
"source_file": result.source_file,
|
|
2162
|
+
"total_paths": result.total_paths,
|
|
2163
|
+
"max_depth": result.max_depth,
|
|
2164
|
+
"metadata": result.metadata,
|
|
2165
|
+
}
|
|
2166
|
+
if result.paths_at_level is not None:
|
|
2167
|
+
output["paths_at_level"] = result.paths_at_level
|
|
2168
|
+
if result.expanded_paths is not None:
|
|
2169
|
+
output["expanded_paths"] = result.expanded_paths
|
|
2170
|
+
if result.all_paths is not None:
|
|
2171
|
+
output["all_paths"] = result.all_paths
|
|
2172
|
+
tui.console.print_json(json.dumps(output))
|
|
2173
|
+
return
|
|
2174
|
+
|
|
2175
|
+
# Rich output (tree or table format)
|
|
2176
|
+
_display_inspection_result(tui, result, output_format, level, expand, show_all, show_uuid)
|
|
2177
|
+
|
|
2178
|
+
except FileNotFoundError as e:
|
|
2179
|
+
tui.error(str(e))
|
|
2180
|
+
sys.exit(1)
|
|
2181
|
+
except ValueError as e:
|
|
2182
|
+
tui.error(f"Invalid file: {e}")
|
|
2183
|
+
sys.exit(1)
|
|
2184
|
+
except Exception as e:
|
|
2185
|
+
tui.error(f"Error inspecting file: {e}")
|
|
2186
|
+
sys.exit(1)
|
|
2187
|
+
|
|
2188
|
+
|
|
2189
|
+
def _display_inspection_result(
|
|
2190
|
+
tui: "DeepFabricTUI",
|
|
2191
|
+
result: "TopicInspectionResult",
|
|
2192
|
+
output_format: str,
|
|
2193
|
+
level: int | None,
|
|
2194
|
+
expand: int | None,
|
|
2195
|
+
show_all: bool,
|
|
2196
|
+
show_uuid: bool = False,
|
|
2197
|
+
) -> None:
|
|
2198
|
+
"""Display inspection result using rich formatting."""
|
|
2199
|
+
from rich.panel import Panel # noqa: PLC0415
|
|
2200
|
+
from rich.table import Table # noqa: PLC0415
|
|
2201
|
+
|
|
2202
|
+
# Header with file info
|
|
2203
|
+
format_label = "Graph (JSON)" if result.format == "graph" else "Tree (JSONL)"
|
|
2204
|
+
|
|
2205
|
+
tui.console.print()
|
|
2206
|
+
tui.console.print("[bold cyan]Topic Inspector[/bold cyan]")
|
|
2207
|
+
tui.console.print(f"[dim]{result.source_file}[/dim]")
|
|
2208
|
+
tui.console.print()
|
|
2209
|
+
|
|
2210
|
+
# Statistics panel
|
|
2211
|
+
stats_table = Table(show_header=False, box=None, padding=(0, 1))
|
|
2212
|
+
stats_table.add_column(style="cyan", no_wrap=True)
|
|
2213
|
+
stats_table.add_column(style="white")
|
|
2214
|
+
|
|
2215
|
+
stats_table.add_row("Format:", format_label)
|
|
2216
|
+
stats_table.add_row("Total Paths:", str(result.total_paths))
|
|
2217
|
+
stats_table.add_row("Max Depth:", str(result.max_depth))
|
|
2218
|
+
|
|
2219
|
+
if result.metadata.get("root_topic"):
|
|
2220
|
+
root = result.metadata["root_topic"]
|
|
2221
|
+
if len(root) > 60: # noqa: PLR2004
|
|
2222
|
+
root = root[:57] + "..."
|
|
2223
|
+
stats_table.add_row("Root Topic:", root)
|
|
2224
|
+
|
|
2225
|
+
if result.metadata.get("total_nodes"):
|
|
2226
|
+
stats_table.add_row("Total Nodes:", str(result.metadata["total_nodes"]))
|
|
2227
|
+
|
|
2228
|
+
if result.metadata.get("has_cycles") is not None:
|
|
2229
|
+
has_cycles = "Yes" if result.metadata["has_cycles"] else "No"
|
|
2230
|
+
stats_table.add_row("Has Cycles:", has_cycles)
|
|
2231
|
+
|
|
2232
|
+
if result.metadata.get("provider"):
|
|
2233
|
+
stats_table.add_row("Provider:", result.metadata["provider"])
|
|
2234
|
+
|
|
2235
|
+
if result.metadata.get("model"):
|
|
2236
|
+
stats_table.add_row("Model:", result.metadata["model"])
|
|
2237
|
+
|
|
2238
|
+
if result.metadata.get("created_at"):
|
|
2239
|
+
stats_table.add_row("Created:", result.metadata["created_at"])
|
|
2240
|
+
|
|
2241
|
+
tui.console.print(Panel(stats_table, title="Statistics", border_style="dim"))
|
|
2242
|
+
|
|
2243
|
+
# Show level-specific topics (without expand) - simple list of topic names
|
|
2244
|
+
if level is not None and expand is None and result.paths_at_level is not None:
|
|
2245
|
+
tui.console.print()
|
|
2246
|
+
tui.console.print(f"[cyan bold]Topics at Level {level}:[/cyan bold]")
|
|
2247
|
+
|
|
2248
|
+
if not result.paths_at_level:
|
|
2249
|
+
tui.console.print(f" [dim]No topics at level {level}[/dim]")
|
|
2250
|
+
else:
|
|
2251
|
+
# Display as simple list of topic names (with UUIDs)
|
|
2252
|
+
for topic_path in result.paths_at_level:
|
|
2253
|
+
topic_name = topic_path[0] if topic_path else ""
|
|
2254
|
+
if show_uuid:
|
|
2255
|
+
# For graph format, use topic_to_uuid (node UUIDs)
|
|
2256
|
+
# For tree format, use path_to_uuid (leaf UUIDs only)
|
|
2257
|
+
uuid = ""
|
|
2258
|
+
if result.topic_to_uuid:
|
|
2259
|
+
uuid = result.topic_to_uuid.get(topic_name, "")
|
|
2260
|
+
if not uuid and result.path_to_uuid:
|
|
2261
|
+
uuid = result.path_to_uuid.get(tuple(topic_path), "")
|
|
2262
|
+
if uuid:
|
|
2263
|
+
tui.console.print(
|
|
2264
|
+
f" • {topic_name} [dim](UUID: {uuid})[/dim]", highlight=False
|
|
2265
|
+
)
|
|
2266
|
+
else:
|
|
2267
|
+
tui.console.print(f" • {topic_name}")
|
|
2268
|
+
else:
|
|
2269
|
+
tui.console.print(f" • {topic_name}")
|
|
2270
|
+
|
|
2271
|
+
# Show expanded subtree from level (with --expand)
|
|
2272
|
+
if level is not None and expand is not None and result.expanded_paths is not None:
|
|
2273
|
+
tui.console.print()
|
|
2274
|
+
depth_info = "all sublevels" if expand == -1 else f"{expand} sublevel(s)"
|
|
2275
|
+
tui.console.print(f"[cyan bold]Subtree from Level {level} ({depth_info}):[/cyan bold]")
|
|
2276
|
+
|
|
2277
|
+
if not result.expanded_paths:
|
|
2278
|
+
tui.console.print(f" [dim]No topics at or below level {level}[/dim]")
|
|
2279
|
+
elif output_format == "table":
|
|
2280
|
+
_display_paths_as_table(tui, result.expanded_paths)
|
|
2281
|
+
else:
|
|
2282
|
+
_display_paths_as_tree(
|
|
2283
|
+
tui,
|
|
2284
|
+
result.expanded_paths,
|
|
2285
|
+
result.path_to_uuid if show_uuid else None,
|
|
2286
|
+
result.topic_to_uuid if show_uuid else None,
|
|
2287
|
+
)
|
|
2288
|
+
|
|
2289
|
+
# Show all paths with tree structure
|
|
2290
|
+
if show_all and result.all_paths:
|
|
2291
|
+
tui.console.print()
|
|
2292
|
+
tui.console.print("[cyan bold]Full Tree Structure:[/cyan bold]")
|
|
2293
|
+
|
|
2294
|
+
if output_format == "table":
|
|
2295
|
+
_display_paths_as_table(tui, result.all_paths)
|
|
2296
|
+
else:
|
|
2297
|
+
_display_paths_as_tree(
|
|
2298
|
+
tui,
|
|
2299
|
+
result.all_paths,
|
|
2300
|
+
result.path_to_uuid if show_uuid else None,
|
|
2301
|
+
result.topic_to_uuid if show_uuid else None,
|
|
2302
|
+
)
|
|
2303
|
+
|
|
2304
|
+
|
|
2305
|
+
def _display_paths_as_table(tui: "DeepFabricTUI", paths: list[list[str]]) -> None:
|
|
2306
|
+
"""Display paths in a table format."""
|
|
2307
|
+
from rich.table import Table # noqa: PLC0415
|
|
2308
|
+
|
|
2309
|
+
table = Table(show_header=True, header_style="bold cyan")
|
|
2310
|
+
table.add_column("#", style="dim")
|
|
2311
|
+
table.add_column("Path", style="white")
|
|
2312
|
+
table.add_column("Depth", style="green")
|
|
2313
|
+
|
|
2314
|
+
for i, path in enumerate(paths[:100], 1):
|
|
2315
|
+
path_str = " > ".join(path)
|
|
2316
|
+
if len(path_str) > 80: # noqa: PLR2004
|
|
2317
|
+
path_str = path_str[:77] + "..."
|
|
2318
|
+
table.add_row(str(i), path_str, str(len(path)))
|
|
2319
|
+
|
|
2320
|
+
if len(paths) > 100: # noqa: PLR2004
|
|
2321
|
+
table.add_row("...", f"[dim]{len(paths) - 100} more paths[/dim]", "")
|
|
2322
|
+
|
|
2323
|
+
tui.console.print(table)
|
|
2324
|
+
|
|
2325
|
+
|
|
2326
|
+
def _display_paths_as_tree(
|
|
2327
|
+
tui: "DeepFabricTUI",
|
|
2328
|
+
paths: list[list[str]],
|
|
2329
|
+
path_to_uuid: dict[tuple[str, ...], str] | None = None,
|
|
2330
|
+
topic_to_uuid: dict[str, str] | None = None,
|
|
2331
|
+
) -> None:
|
|
2332
|
+
"""Display paths in an indented tree format."""
|
|
2333
|
+
from rich.tree import Tree as RichTree # noqa: PLC0415
|
|
2334
|
+
|
|
2335
|
+
if not paths:
|
|
2336
|
+
return
|
|
2337
|
+
|
|
2338
|
+
# Build a tree structure from paths
|
|
2339
|
+
# Group paths by their root topic
|
|
2340
|
+
root_groups: dict[str, list[list[str]]] = {}
|
|
2341
|
+
for path in paths:
|
|
2342
|
+
if path:
|
|
2343
|
+
root = path[0]
|
|
2344
|
+
if root not in root_groups:
|
|
2345
|
+
root_groups[root] = []
|
|
2346
|
+
root_groups[root].append(path)
|
|
2347
|
+
|
|
2348
|
+
if len(root_groups) == 1:
|
|
2349
|
+
# Single root - show directly
|
|
2350
|
+
root_topic = paths[0][0]
|
|
2351
|
+
# Show UUID for root if available (graph format)
|
|
2352
|
+
root_label = f"[bold]{root_topic}[/bold]"
|
|
2353
|
+
if topic_to_uuid and root_topic in topic_to_uuid:
|
|
2354
|
+
root_label += f" [dim](UUID: {topic_to_uuid[root_topic]})[/dim]"
|
|
2355
|
+
tree = RichTree(root_label)
|
|
2356
|
+
_add_children_to_tree(
|
|
2357
|
+
tree, paths, 1, path_to_uuid=path_to_uuid, topic_to_uuid=topic_to_uuid
|
|
2358
|
+
)
|
|
2359
|
+
tui.console.print(tree)
|
|
2360
|
+
else:
|
|
2361
|
+
# Multiple roots - show each as a separate tree
|
|
2362
|
+
for root_topic, root_paths in list(root_groups.items())[:20]:
|
|
2363
|
+
root_label = f"[bold]{root_topic}[/bold]"
|
|
2364
|
+
if topic_to_uuid and root_topic in topic_to_uuid:
|
|
2365
|
+
root_label += f" [dim](UUID: {topic_to_uuid[root_topic]})[/dim]"
|
|
2366
|
+
tree = RichTree(root_label)
|
|
2367
|
+
_add_children_to_tree(
|
|
2368
|
+
tree, root_paths, 1, path_to_uuid=path_to_uuid, topic_to_uuid=topic_to_uuid
|
|
2369
|
+
)
|
|
2370
|
+
tui.console.print(tree)
|
|
2371
|
+
if len(root_groups) > 20: # noqa: PLR2004
|
|
2372
|
+
tui.console.print(f"[dim]... and {len(root_groups) - 20} more topics[/dim]")
|
|
2373
|
+
|
|
2374
|
+
|
|
2375
|
+
def _add_children_to_tree(
|
|
2376
|
+
parent: "RichTree",
|
|
2377
|
+
paths: list[list[str]],
|
|
2378
|
+
depth: int,
|
|
2379
|
+
max_depth: int = 5,
|
|
2380
|
+
path_to_uuid: dict[tuple[str, ...], str] | None = None,
|
|
2381
|
+
topic_to_uuid: dict[str, str] | None = None,
|
|
2382
|
+
) -> None:
|
|
2383
|
+
"""Recursively add children to a rich tree (limited depth for display)."""
|
|
2384
|
+
if depth > max_depth:
|
|
2385
|
+
remaining = len([p for p in paths if len(p) > depth])
|
|
2386
|
+
if remaining > 0:
|
|
2387
|
+
parent.add(f"[dim]... {remaining} more levels[/dim]")
|
|
2388
|
+
return
|
|
2389
|
+
|
|
2390
|
+
# Group paths by their element at current depth
|
|
2391
|
+
children: dict[str, list[list[str]]] = {}
|
|
2392
|
+
for path in paths:
|
|
2393
|
+
if len(path) > depth:
|
|
2394
|
+
child_topic = path[depth]
|
|
2395
|
+
if child_topic not in children:
|
|
2396
|
+
children[child_topic] = []
|
|
2397
|
+
children[child_topic].append(path)
|
|
2398
|
+
|
|
2399
|
+
# Add children to tree
|
|
2400
|
+
for child_topic, child_paths in list(children.items())[:20]:
|
|
2401
|
+
# Check for UUID: first try topic_to_uuid (graph nodes), then path_to_uuid (leaves)
|
|
2402
|
+
uuid = ""
|
|
2403
|
+
if topic_to_uuid and child_topic in topic_to_uuid:
|
|
2404
|
+
uuid = topic_to_uuid[child_topic]
|
|
2405
|
+
elif path_to_uuid:
|
|
2406
|
+
# Check if this child is a leaf (path ends at depth + 1)
|
|
2407
|
+
is_leaf = any(len(p) == depth + 1 for p in child_paths)
|
|
2408
|
+
if is_leaf:
|
|
2409
|
+
leaf_path = next((p for p in child_paths if len(p) == depth + 1), None)
|
|
2410
|
+
if leaf_path:
|
|
2411
|
+
uuid = path_to_uuid.get(tuple(leaf_path), "")
|
|
2412
|
+
|
|
2413
|
+
if uuid:
|
|
2414
|
+
child_node = parent.add(f"{child_topic} [dim](UUID: {uuid})[/dim]")
|
|
2415
|
+
else:
|
|
2416
|
+
child_node = parent.add(child_topic)
|
|
2417
|
+
_add_children_to_tree(
|
|
2418
|
+
child_node, child_paths, depth + 1, max_depth, path_to_uuid, topic_to_uuid
|
|
2419
|
+
)
|
|
2420
|
+
|
|
2421
|
+
if len(children) > 20: # noqa: PLR2004
|
|
2422
|
+
parent.add(f"[dim]... and {len(children) - 20} more siblings[/dim]")
|
|
2423
|
+
|
|
2424
|
+
|
|
2425
|
+
@topic.command("prune")
|
|
2426
|
+
@click.argument("file", type=click.Path(exists=True))
|
|
2427
|
+
@click.option(
|
|
2428
|
+
"--level",
|
|
2429
|
+
"-l",
|
|
2430
|
+
type=int,
|
|
2431
|
+
default=None,
|
|
2432
|
+
help="Prune all nodes below this depth level (0=root, 1=children, etc.)",
|
|
2433
|
+
)
|
|
2434
|
+
@click.option(
|
|
2435
|
+
"--uuid",
|
|
2436
|
+
"-u",
|
|
2437
|
+
type=str,
|
|
2438
|
+
default=None,
|
|
2439
|
+
help="Remove the node with this UUID and its entire subtree",
|
|
2440
|
+
)
|
|
2441
|
+
@click.option(
|
|
2442
|
+
"--output",
|
|
2443
|
+
"-o",
|
|
2444
|
+
type=click.Path(),
|
|
2445
|
+
default=None,
|
|
2446
|
+
help="Output file path (default: auto-generated from input filename)",
|
|
2447
|
+
)
|
|
2448
|
+
@click.option(
|
|
2449
|
+
"--force",
|
|
2450
|
+
"-f",
|
|
2451
|
+
is_flag=True,
|
|
2452
|
+
help="Overwrite the input file instead of creating a new one",
|
|
2453
|
+
)
|
|
2454
|
+
@click.option(
|
|
2455
|
+
"--dry-run",
|
|
2456
|
+
is_flag=True,
|
|
2457
|
+
help="Show what would be removed without making changes",
|
|
2458
|
+
)
|
|
2459
|
+
def topic_prune(
|
|
2460
|
+
file: str,
|
|
2461
|
+
level: int | None,
|
|
2462
|
+
uuid: str | None,
|
|
2463
|
+
output: str | None,
|
|
2464
|
+
force: bool,
|
|
2465
|
+
dry_run: bool,
|
|
2466
|
+
) -> None:
|
|
2467
|
+
"""Prune a topic graph by removing nodes.
|
|
2468
|
+
|
|
2469
|
+
Supports two modes:
|
|
2470
|
+
|
|
2471
|
+
\b
|
|
2472
|
+
# Remove all nodes below depth level 2
|
|
2473
|
+
deepfabric topic prune topic_graph.json --level 2
|
|
2474
|
+
|
|
2475
|
+
\b
|
|
2476
|
+
# Remove a specific node and its subtree by UUID
|
|
2477
|
+
deepfabric topic prune topic_graph.json --uuid abc-123-def
|
|
2478
|
+
|
|
2479
|
+
\b
|
|
2480
|
+
# Preview what would be removed (no file written)
|
|
2481
|
+
deepfabric topic prune topic_graph.json --level 1 --dry-run
|
|
2482
|
+
|
|
2483
|
+
\b
|
|
2484
|
+
# Overwrite the original file
|
|
2485
|
+
deepfabric topic prune topic_graph.json --uuid abc-123 --force
|
|
2486
|
+
"""
|
|
2487
|
+
from .graph_pruner import ( # noqa: PLC0415
|
|
2488
|
+
load_graph_for_pruning,
|
|
2489
|
+
prune_graph_at_level,
|
|
2490
|
+
prune_graph_by_uuid,
|
|
2491
|
+
)
|
|
2492
|
+
|
|
2493
|
+
tui = get_tui()
|
|
2494
|
+
|
|
2495
|
+
# Validate: exactly one mode must be specified
|
|
2496
|
+
if level is None and uuid is None:
|
|
2497
|
+
tui.error("Specify either --level or --uuid")
|
|
2498
|
+
sys.exit(1)
|
|
2499
|
+
if level is not None and uuid is not None:
|
|
2500
|
+
tui.error("Cannot use --level and --uuid together")
|
|
2501
|
+
sys.exit(1)
|
|
2502
|
+
|
|
2503
|
+
try:
|
|
2504
|
+
if dry_run:
|
|
2505
|
+
graph = load_graph_for_pruning(file)
|
|
2506
|
+
total_nodes = len(graph.nodes)
|
|
2507
|
+
|
|
2508
|
+
tui.console.print()
|
|
2509
|
+
tui.console.print("[bold]DRY RUN[/bold] — no changes will be made")
|
|
2510
|
+
tui.console.print()
|
|
2511
|
+
|
|
2512
|
+
if level is not None:
|
|
2513
|
+
# BFS to compute node depths
|
|
2514
|
+
node_depths: dict[int, int] = {}
|
|
2515
|
+
queue: list[tuple] = [(graph.root, 0)]
|
|
2516
|
+
visited: set[int] = set()
|
|
2517
|
+
while queue:
|
|
2518
|
+
current, d = queue.pop(0)
|
|
2519
|
+
if current.id in visited:
|
|
2520
|
+
continue
|
|
2521
|
+
visited.add(current.id)
|
|
2522
|
+
node_depths[current.id] = d
|
|
2523
|
+
for child in current.children:
|
|
2524
|
+
if child.id not in visited:
|
|
2525
|
+
queue.append((child, d + 1))
|
|
2526
|
+
|
|
2527
|
+
to_remove = {nid for nid, d in node_depths.items() if d > level}
|
|
2528
|
+
tui.console.print(f" Graph: {total_nodes} unique nodes")
|
|
2529
|
+
tui.console.print(f" Would remove: {len(to_remove)} nodes below level {level}")
|
|
2530
|
+
tui.console.print(f" Would keep: {total_nodes - len(to_remove)} nodes")
|
|
2531
|
+
else:
|
|
2532
|
+
target = graph.find_node_by_uuid(uuid)
|
|
2533
|
+
if target is None:
|
|
2534
|
+
tui.error(f"No node found with UUID: {uuid}")
|
|
2535
|
+
sys.exit(1)
|
|
2536
|
+
|
|
2537
|
+
# BFS to count subtree
|
|
2538
|
+
subtree_count = 0
|
|
2539
|
+
bfs_queue = [target]
|
|
2540
|
+
visited_ids: set[int] = set()
|
|
2541
|
+
while bfs_queue:
|
|
2542
|
+
current = bfs_queue.pop(0)
|
|
2543
|
+
if current.id in visited_ids:
|
|
2544
|
+
continue
|
|
2545
|
+
visited_ids.add(current.id)
|
|
2546
|
+
subtree_count += 1
|
|
2547
|
+
for child in current.children:
|
|
2548
|
+
if child.id not in visited_ids:
|
|
2549
|
+
bfs_queue.append(child)
|
|
2550
|
+
|
|
2551
|
+
tui.console.print(f" Graph: {total_nodes} unique nodes")
|
|
2552
|
+
tui.console.print(
|
|
2553
|
+
f" Target: {target.topic}",
|
|
2554
|
+
highlight=False,
|
|
2555
|
+
)
|
|
2556
|
+
tui.console.print(f" Would remove: {subtree_count} nodes (including subtree)")
|
|
2557
|
+
tui.console.print(f" Would keep: {total_nodes - subtree_count} nodes")
|
|
2558
|
+
return
|
|
2559
|
+
|
|
2560
|
+
# Determine output path
|
|
2561
|
+
output_path = file if force else output
|
|
2562
|
+
|
|
2563
|
+
if level is not None:
|
|
2564
|
+
result = prune_graph_at_level(file, level, output_path)
|
|
2565
|
+
else:
|
|
2566
|
+
result = prune_graph_by_uuid(file, uuid, output_path)
|
|
2567
|
+
|
|
2568
|
+
tui.console.print()
|
|
2569
|
+
tui.success("Graph pruned successfully")
|
|
2570
|
+
tui.console.print(f" Removed: {result.removed_count} nodes")
|
|
2571
|
+
tui.console.print(
|
|
2572
|
+
f" Remaining: {result.remaining_nodes} nodes, {result.remaining_paths} paths"
|
|
2573
|
+
)
|
|
2574
|
+
tui.console.print(f" Saved to: {result.output_path}")
|
|
2575
|
+
|
|
2576
|
+
except FileNotFoundError as e:
|
|
2577
|
+
tui.error(str(e))
|
|
2578
|
+
sys.exit(1)
|
|
2579
|
+
except ValueError as e:
|
|
2580
|
+
tui.error(str(e))
|
|
2581
|
+
sys.exit(1)
|
|
2582
|
+
|
|
2583
|
+
|
|
2584
|
+
# Register the topic command group
|
|
2585
|
+
cli.add_command(topic)
|
|
2586
|
+
|
|
2587
|
+
|
|
2053
2588
|
if __name__ == "__main__":
|
|
2054
2589
|
cli()
|
|
@@ -8,6 +8,7 @@ from pydantic import BaseModel, Field, field_validator, model_validator
|
|
|
8
8
|
|
|
9
9
|
from .constants import (
|
|
10
10
|
DEFAULT_MAX_RETRIES,
|
|
11
|
+
DEFAULT_MAX_TOKENS,
|
|
11
12
|
DEFAULT_MODEL,
|
|
12
13
|
DEFAULT_PROVIDER,
|
|
13
14
|
DEFAULT_SAMPLE_RETRIES,
|
|
@@ -86,7 +87,7 @@ class TopicsConfig(BaseModel):
|
|
|
86
87
|
..., min_length=1, description="The initial prompt to start topic generation"
|
|
87
88
|
)
|
|
88
89
|
mode: Literal["tree", "graph"] = Field(
|
|
89
|
-
default="
|
|
90
|
+
default="graph", description="Topic generation mode: tree or graph"
|
|
90
91
|
)
|
|
91
92
|
system_prompt: str = Field(
|
|
92
93
|
default="", description="System prompt for topic exploration and generation"
|
|
@@ -109,6 +110,11 @@ class TopicsConfig(BaseModel):
|
|
|
109
110
|
le=20,
|
|
110
111
|
description="Maximum concurrent LLM calls during graph expansion (helps avoid rate limits)",
|
|
111
112
|
)
|
|
113
|
+
max_tokens: int = Field(
|
|
114
|
+
default=DEFAULT_MAX_TOKENS,
|
|
115
|
+
ge=1,
|
|
116
|
+
description="Maximum tokens for topic generation LLM calls",
|
|
117
|
+
)
|
|
112
118
|
save_as: str | None = Field(default=None, description="Where to save the generated topics")
|
|
113
119
|
prompt_style: Literal["default", "isolated", "anchored"] = Field(
|
|
114
120
|
default="default",
|
|
@@ -589,6 +595,7 @@ See documentation for full examples.
|
|
|
589
595
|
"depth": self.topics.depth,
|
|
590
596
|
"degree": self.topics.degree,
|
|
591
597
|
"max_concurrent": self.topics.max_concurrent,
|
|
598
|
+
"max_tokens": self.topics.max_tokens,
|
|
592
599
|
"prompt_style": self.topics.prompt_style,
|
|
593
600
|
}
|
|
594
601
|
|
|
@@ -37,7 +37,7 @@ def load_config( # noqa: PLR0913
|
|
|
37
37
|
topics_save_as: str | None = None,
|
|
38
38
|
output_save_as: str | None = None,
|
|
39
39
|
include_system_message: bool | None = None,
|
|
40
|
-
mode: str =
|
|
40
|
+
mode: str | None = None,
|
|
41
41
|
# Modular conversation configuration
|
|
42
42
|
conversation_type: str | None = None,
|
|
43
43
|
reasoning_style: str | None = None,
|
|
@@ -83,6 +83,8 @@ def load_config( # noqa: PLR0913
|
|
|
83
83
|
except Exception as e:
|
|
84
84
|
raise ConfigurationError(f"Error loading config file: {str(e)}") from e
|
|
85
85
|
else:
|
|
86
|
+
if mode is not None:
|
|
87
|
+
config.topics.mode = mode
|
|
86
88
|
return config
|
|
87
89
|
|
|
88
90
|
# No config file provided - create minimal configuration from CLI args
|
|
@@ -92,6 +94,9 @@ def load_config( # noqa: PLR0913
|
|
|
92
94
|
tui = get_tui()
|
|
93
95
|
tui.info("No config file provided - using CLI parameters")
|
|
94
96
|
|
|
97
|
+
# Default to graph mode when no config file and no explicit mode
|
|
98
|
+
mode = mode or "graph"
|
|
99
|
+
|
|
95
100
|
# Create minimal config dict with new structure
|
|
96
101
|
default_prompt = generation_system_prompt or "You are a helpful AI assistant."
|
|
97
102
|
|