specsmith 0.3.10.dev198__tar.gz → 0.3.13.dev211__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.
- {specsmith-0.3.10.dev198/src/specsmith.egg-info → specsmith-0.3.13.dev211}/PKG-INFO +40 -2
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/README.md +37 -1
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/pyproject.toml +5 -1
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/agent/providers/ollama.py +5 -2
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/agent/runner.py +10 -0
- specsmith-0.3.13.dev211/src/specsmith/agents/__init__.py +7 -0
- specsmith-0.3.13.dev211/src/specsmith/agents/cli.py +233 -0
- specsmith-0.3.13.dev211/src/specsmith/agents/config.py +74 -0
- specsmith-0.3.13.dev211/src/specsmith/agents/reports.py +77 -0
- specsmith-0.3.13.dev211/src/specsmith/agents/roles.py +208 -0
- specsmith-0.3.13.dev211/src/specsmith/agents/tools/__init__.py +34 -0
- specsmith-0.3.13.dev211/src/specsmith/agents/tools/filesystem.py +187 -0
- specsmith-0.3.13.dev211/src/specsmith/agents/tools/git.py +70 -0
- specsmith-0.3.13.dev211/src/specsmith/agents/tools/shell.py +69 -0
- specsmith-0.3.13.dev211/src/specsmith/agents/tools/tests.py +59 -0
- specsmith-0.3.13.dev211/src/specsmith/agents/workflows/__init__.py +3 -0
- specsmith-0.3.13.dev211/src/specsmith/agents/workflows/improve.py +179 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/auditor.py +67 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/cli.py +12 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211/src/specsmith.egg-info}/PKG-INFO +40 -2
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith.egg-info/SOURCES.txt +13 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith.egg-info/requires.txt +3 -0
- specsmith-0.3.13.dev211/tests/test_agent.py +293 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/LICENSE +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/setup.cfg +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/epistemic/__init__.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/epistemic/belief.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/epistemic/certainty.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/epistemic/failure_graph.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/epistemic/py.typed +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/epistemic/recovery.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/epistemic/session.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/epistemic/stress_tester.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/epistemic/trace.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/__init__.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/__main__.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/agent/__init__.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/agent/core.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/agent/hooks.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/agent/optimizer.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/agent/profiles/epistemic-auditor.md +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/agent/profiles/planner.md +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/agent/profiles/verifier.md +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/agent/providers/__init__.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/agent/providers/anthropic.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/agent/providers/gemini.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/agent/providers/mistral.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/agent/providers/openai.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/agent/skills.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/agent/tools.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/architect.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/auth.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/commands/__init__.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/compressor.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/config.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/credit_analyzer.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/credits.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/differ.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/doctor.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/epistemic/__init__.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/epistemic/belief.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/epistemic/certainty.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/epistemic/failure_graph.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/epistemic/recovery.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/epistemic/stress_tester.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/executor.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/exporter.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/gui/__init__.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/gui/app.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/gui/main_window.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/gui/session_tab.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/gui/theme.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/gui/widgets/__init__.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/gui/widgets/chat_view.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/gui/widgets/input_bar.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/gui/widgets/provider_bar.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/gui/widgets/token_meter.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/gui/widgets/tool_panel.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/gui/widgets/update_checker.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/gui/worker.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/importer.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/integrations/__init__.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/integrations/aider.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/integrations/base.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/integrations/claude_code.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/integrations/copilot.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/integrations/cursor.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/integrations/gemini.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/integrations/warp.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/integrations/windsurf.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/languages.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/ledger.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/ollama_cmds.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/patent.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/phase.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/plugins.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/profiles.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/rate_limits.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/releaser.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/requirements.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/retrieval.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/scaffolder.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/session.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/agents.md.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/community/contributing.md.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/community/license-MIT.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/community/security.md.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/editorconfig.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/gitattributes.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/gitignore.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/go/go.mod.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/go/main.go.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/governance/lifecycle.md.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/governance/roles.md.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/governance/rules.md.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/governance/session-protocol.md.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/governance/verification.md.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/js/package.json.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/ledger.md.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/python/cli.py.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/python/init.py.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/readme.md.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/rust/main.rs.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/tool_installer.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/toolrules.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/tools.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/trace.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/updater.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/upgrader.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/validator.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/vcs/__init__.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/vcs/base.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/vcs/bitbucket.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/vcs/github.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/vcs/gitlab.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/vcs_commands.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/wireframes.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith/workspace.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith.egg-info/dependency_links.txt +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith.egg-info/entry_points.txt +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/src/specsmith.egg-info/top_level.txt +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/tests/test_auditor.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/tests/test_cli.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/tests/test_compressor.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/tests/test_epistemic.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/tests/test_importer.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/tests/test_integrations.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/tests/test_optimizer.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/tests/test_rate_limits.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/tests/test_scaffolder.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/tests/test_smoke.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/tests/test_tools.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/tests/test_validator.py +0 -0
- {specsmith-0.3.10.dev198 → specsmith-0.3.13.dev211}/tests/test_vcs.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: specsmith
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.13.dev211
|
|
4
4
|
Summary: Applied Epistemic Engineering toolkit — AEE agent sessions, execution profiles, FPGA/HDL governance, tool installer, 50+ CLI commands.
|
|
5
5
|
Author: BitConcepts
|
|
6
6
|
License-Expression: MIT
|
|
@@ -51,6 +51,8 @@ Provides-Extra: mistral
|
|
|
51
51
|
Requires-Dist: openai>=1.0; extra == "mistral"
|
|
52
52
|
Provides-Extra: gui
|
|
53
53
|
Requires-Dist: PySide6>=6.6; extra == "gui"
|
|
54
|
+
Provides-Extra: ag2
|
|
55
|
+
Requires-Dist: ag2[ollama]; extra == "ag2"
|
|
54
56
|
Provides-Extra: agent
|
|
55
57
|
Requires-Dist: anthropic>=0.56; extra == "agent"
|
|
56
58
|
Requires-Dist: openai>=1.0; extra == "agent"
|
|
@@ -186,12 +188,45 @@ specsmith epistemic-audit --project-dir ./my-project
|
|
|
186
188
|
# Start the agentic REPL
|
|
187
189
|
specsmith run --project-dir ./my-project
|
|
188
190
|
|
|
191
|
+
# AG2 agent shell — Planner/Builder/Verifier over Ollama
|
|
192
|
+
specsmith agent status # check agent config + Ollama
|
|
193
|
+
specsmith agent plan "add logging" # plan only (no execution)
|
|
194
|
+
specsmith agent run "fix lint errors" # full Plan → Build → Verify
|
|
195
|
+
specsmith agent improve "add tests" # self-improvement with reports
|
|
196
|
+
specsmith agent verify # run Verifier on current state
|
|
197
|
+
specsmith agent reports # list improvement reports
|
|
198
|
+
|
|
189
199
|
# Check current AEE workflow phase
|
|
190
200
|
specsmith phase --project-dir ./my-project
|
|
191
201
|
```
|
|
192
202
|
|
|
193
203
|
---
|
|
194
204
|
|
|
205
|
+
## AG2 Agent Shell — Local AI Agents over Ollama
|
|
206
|
+
|
|
207
|
+
specsmith includes an AG2-based agent shell with three specialized agents:
|
|
208
|
+
|
|
209
|
+
- **Planner** — inspects repo, generates execution plans with acceptance criteria
|
|
210
|
+
- **Builder** — makes code/doc changes following the plan
|
|
211
|
+
- **Verifier** — runs tests, accepts or rejects changes
|
|
212
|
+
|
|
213
|
+
All agents run locally on Ollama (default: `qwen2.5:14b`). Zero cloud cost.
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
pip install "specsmith[ag2]" # install AG2 + Ollama support
|
|
217
|
+
specsmith agent status # verify config + Ollama running
|
|
218
|
+
specsmith agent run "fix lint errors" # Plan → Build → Verify pipeline
|
|
219
|
+
specsmith agent improve "add tests for config.py" # self-improvement with reports
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
The agent shell stores structured reports at `.specsmith/agent-reports/` with task ID,
|
|
223
|
+
files changed, test results, verdict (ACCEPT/REJECT), and follow-up tasks.
|
|
224
|
+
|
|
225
|
+
Configurable per-project in `scaffold.yml` under `agents:` or via the VS Code
|
|
226
|
+
Project Settings → Agent tab.
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
195
230
|
## VS Code Extension
|
|
196
231
|
|
|
197
232
|
The **specsmith AEE Workbench** VS Code extension is the flagship client:
|
|
@@ -211,7 +246,10 @@ The **specsmith AEE Workbench** VS Code extension is the flagship client:
|
|
|
211
246
|
- **Execution profiles** — safe / standard / open / admin; custom allow/block command lists
|
|
212
247
|
- **AEE phase indicator** — shows current phase with readiness %, Next Phase button, phase selector
|
|
213
248
|
- **AI agent sessions** — independent process per project, JSONL bridge, chat with file injection
|
|
249
|
+
- **AG2 agent shell** — Planner/Builder/Verifier agents over Ollama in Actions tab
|
|
250
|
+
- **Agent tab** — per-project provider/model/context/iteration config (overrides global defaults)
|
|
214
251
|
- **Live model listing** — Anthropic, OpenAI, Gemini, Mistral, local Ollama (GPU-aware)
|
|
252
|
+
- **Ollama model catalog** — 16 models, 4 tiers, GPU-aware recommendations, filter by installed/available
|
|
215
253
|
- **Ollama integration** — model manager (update/remove/update-all), version check, upgrade
|
|
216
254
|
- **FPGA/HDL tool support** — vivado, gtkwave, vsg, ghdl, verilator, yosys, nextpnr, and 15 more
|
|
217
255
|
- **Tool installer** — scan installed tools; one-click install via winget/brew/apt for missing tools
|
|
@@ -284,7 +322,7 @@ Supported tools: **Synthesis:** vivado, quartus, radiant, diamond, gowin.
|
|
|
284
322
|
|
|
285
323
|
**Workflow:** `phase show/set/next/list` `ledger add/list` `req list/add/gaps/trace`
|
|
286
324
|
|
|
287
|
-
**Agent:** `run` `agent providers/tools/skills`
|
|
325
|
+
**Agent:** `run` `agent run/plan/status/verify/improve/reports` `agent providers/tools/skills`
|
|
288
326
|
|
|
289
327
|
**Ollama:** `ollama list/available/gpu/pull/suggest`
|
|
290
328
|
|
|
@@ -121,12 +121,45 @@ specsmith epistemic-audit --project-dir ./my-project
|
|
|
121
121
|
# Start the agentic REPL
|
|
122
122
|
specsmith run --project-dir ./my-project
|
|
123
123
|
|
|
124
|
+
# AG2 agent shell — Planner/Builder/Verifier over Ollama
|
|
125
|
+
specsmith agent status # check agent config + Ollama
|
|
126
|
+
specsmith agent plan "add logging" # plan only (no execution)
|
|
127
|
+
specsmith agent run "fix lint errors" # full Plan → Build → Verify
|
|
128
|
+
specsmith agent improve "add tests" # self-improvement with reports
|
|
129
|
+
specsmith agent verify # run Verifier on current state
|
|
130
|
+
specsmith agent reports # list improvement reports
|
|
131
|
+
|
|
124
132
|
# Check current AEE workflow phase
|
|
125
133
|
specsmith phase --project-dir ./my-project
|
|
126
134
|
```
|
|
127
135
|
|
|
128
136
|
---
|
|
129
137
|
|
|
138
|
+
## AG2 Agent Shell — Local AI Agents over Ollama
|
|
139
|
+
|
|
140
|
+
specsmith includes an AG2-based agent shell with three specialized agents:
|
|
141
|
+
|
|
142
|
+
- **Planner** — inspects repo, generates execution plans with acceptance criteria
|
|
143
|
+
- **Builder** — makes code/doc changes following the plan
|
|
144
|
+
- **Verifier** — runs tests, accepts or rejects changes
|
|
145
|
+
|
|
146
|
+
All agents run locally on Ollama (default: `qwen2.5:14b`). Zero cloud cost.
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
pip install "specsmith[ag2]" # install AG2 + Ollama support
|
|
150
|
+
specsmith agent status # verify config + Ollama running
|
|
151
|
+
specsmith agent run "fix lint errors" # Plan → Build → Verify pipeline
|
|
152
|
+
specsmith agent improve "add tests for config.py" # self-improvement with reports
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The agent shell stores structured reports at `.specsmith/agent-reports/` with task ID,
|
|
156
|
+
files changed, test results, verdict (ACCEPT/REJECT), and follow-up tasks.
|
|
157
|
+
|
|
158
|
+
Configurable per-project in `scaffold.yml` under `agents:` or via the VS Code
|
|
159
|
+
Project Settings → Agent tab.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
130
163
|
## VS Code Extension
|
|
131
164
|
|
|
132
165
|
The **specsmith AEE Workbench** VS Code extension is the flagship client:
|
|
@@ -146,7 +179,10 @@ The **specsmith AEE Workbench** VS Code extension is the flagship client:
|
|
|
146
179
|
- **Execution profiles** — safe / standard / open / admin; custom allow/block command lists
|
|
147
180
|
- **AEE phase indicator** — shows current phase with readiness %, Next Phase button, phase selector
|
|
148
181
|
- **AI agent sessions** — independent process per project, JSONL bridge, chat with file injection
|
|
182
|
+
- **AG2 agent shell** — Planner/Builder/Verifier agents over Ollama in Actions tab
|
|
183
|
+
- **Agent tab** — per-project provider/model/context/iteration config (overrides global defaults)
|
|
149
184
|
- **Live model listing** — Anthropic, OpenAI, Gemini, Mistral, local Ollama (GPU-aware)
|
|
185
|
+
- **Ollama model catalog** — 16 models, 4 tiers, GPU-aware recommendations, filter by installed/available
|
|
150
186
|
- **Ollama integration** — model manager (update/remove/update-all), version check, upgrade
|
|
151
187
|
- **FPGA/HDL tool support** — vivado, gtkwave, vsg, ghdl, verilator, yosys, nextpnr, and 15 more
|
|
152
188
|
- **Tool installer** — scan installed tools; one-click install via winget/brew/apt for missing tools
|
|
@@ -219,7 +255,7 @@ Supported tools: **Synthesis:** vivado, quartus, radiant, diamond, gowin.
|
|
|
219
255
|
|
|
220
256
|
**Workflow:** `phase show/set/next/list` `ledger add/list` `req list/add/gaps/trace`
|
|
221
257
|
|
|
222
|
-
**Agent:** `run` `agent providers/tools/skills`
|
|
258
|
+
**Agent:** `run` `agent run/plan/status/verify/improve/reports` `agent providers/tools/skills`
|
|
223
259
|
|
|
224
260
|
**Ollama:** `ollama list/available/gpu/pull/suggest`
|
|
225
261
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "specsmith"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.13.dev211"
|
|
8
8
|
description = "Applied Epistemic Engineering toolkit — AEE agent sessions, execution profiles, FPGA/HDL governance, tool installer, 50+ CLI commands."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -65,6 +65,8 @@ openai = ["openai>=1.0"]
|
|
|
65
65
|
gemini = ["google-genai>=1.0"]
|
|
66
66
|
mistral = ["openai>=1.0"] # Mistral uses the openai SDK pointed at api.mistral.ai
|
|
67
67
|
gui = ["PySide6>=6.6"]
|
|
68
|
+
# AG2 agent shell (Planner/Builder/Verifier over Ollama)
|
|
69
|
+
ag2 = ["ag2[ollama]"]
|
|
68
70
|
# Install all optional LLM providers
|
|
69
71
|
agent = ["anthropic>=0.56", "openai>=1.0"]
|
|
70
72
|
# Convenience bundle: everything
|
|
@@ -121,6 +123,8 @@ exclude = ["src/specsmith/gui"]
|
|
|
121
123
|
module = [
|
|
122
124
|
"anthropic",
|
|
123
125
|
"anthropic.*",
|
|
126
|
+
"autogen", # AG2 agent shell — optional extra
|
|
127
|
+
"autogen.*",
|
|
124
128
|
"openai",
|
|
125
129
|
"openai.*",
|
|
126
130
|
"google",
|
|
@@ -226,7 +226,8 @@ class OllamaProvider:
|
|
|
226
226
|
data=json.dumps(payload).encode(),
|
|
227
227
|
headers={"Content-Type": "application/json"},
|
|
228
228
|
)
|
|
229
|
-
|
|
229
|
+
# 300s: streaming responses arrive incrementally, but model load can take time
|
|
230
|
+
with urllib.request.urlopen(req, timeout=300) as resp: # noqa: S310
|
|
230
231
|
for line in resp:
|
|
231
232
|
line = line.strip()
|
|
232
233
|
if not line:
|
|
@@ -294,7 +295,9 @@ class OllamaProvider:
|
|
|
294
295
|
headers={"Content-Type": "application/json"},
|
|
295
296
|
)
|
|
296
297
|
try:
|
|
297
|
-
|
|
298
|
+
# 600s timeout: Ollama needs time to load model (first call) + inference.
|
|
299
|
+
# 120s was too short and caused frequent "timed out" errors in VS Code.
|
|
300
|
+
with urllib.request.urlopen(req, timeout=600) as resp: # noqa: S310
|
|
298
301
|
result: dict[str, Any] = json.loads(resp.read())
|
|
299
302
|
return result
|
|
300
303
|
except urllib.error.HTTPError as e:
|
|
@@ -224,6 +224,16 @@ If a command fails (non-zero exit, "not recognized", "not found"):
|
|
|
224
224
|
"I couldn’t find [tool] on your PATH. Please tell me the full path or add it to PATH."
|
|
225
225
|
5. NEVER loop between retrying and suggesting installation.
|
|
226
226
|
|
|
227
|
+
## EXEC-001 — NO INLINE PYTHON EXECUTION:
|
|
228
|
+
NEVER run non-trivial Python code via `python -c "..."` or `python -c '...'`.
|
|
229
|
+
Always write Python code to a file first, then execute the file:
|
|
230
|
+
1. Use write_file to create the script (e.g. /tmp/task.py or .specsmith/scripts/task.py)
|
|
231
|
+
2. Use run_command to execute: `python task.py`
|
|
232
|
+
The ONLY exception: single-line import/version checks
|
|
233
|
+
(e.g. `python -c "import sys; print(sys.version)"`).
|
|
234
|
+
Reason: inline python -c cannot be interrupted, does not stream output,
|
|
235
|
+
and fails silently on Windows.
|
|
236
|
+
|
|
227
237
|
## TOOL CALL FORMAT RULE:
|
|
228
238
|
NEVER output raw JSON tool calls as text. Use ONLY the native tool_use mechanism.
|
|
229
239
|
Do NOT write <tools>, <tool_call>, or JSON blocks in your response text.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2026 BitConcepts, LLC. All rights reserved.
|
|
3
|
+
"""specsmith AG2 agent shell — Planner/Builder/Verifier over Ollama."""
|
|
4
|
+
|
|
5
|
+
from specsmith.agents.config import AgentConfig, load_agent_config
|
|
6
|
+
|
|
7
|
+
__all__ = ["AgentConfig", "load_agent_config"]
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2026 BitConcepts, LLC. All rights reserved.
|
|
3
|
+
"""CLI commands for the AG2 agent shell.
|
|
4
|
+
|
|
5
|
+
Wired into the main specsmith CLI as the ``agent`` command group.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
import click
|
|
13
|
+
from rich.console import Console
|
|
14
|
+
|
|
15
|
+
console = Console()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@click.group()
|
|
19
|
+
def agent() -> None:
|
|
20
|
+
"""AG2 agent shell — Planner/Builder/Verifier over Ollama."""
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@agent.command()
|
|
24
|
+
@click.argument("task")
|
|
25
|
+
@click.option("--project-dir", default=".", help="Project root directory.")
|
|
26
|
+
@click.option("--max-turns", default=6, help="Maximum conversation turns per agent.")
|
|
27
|
+
def run(task: str, project_dir: str, max_turns: int) -> None:
|
|
28
|
+
"""Execute a task through the full Planner → Builder → Verifier pipeline."""
|
|
29
|
+
try:
|
|
30
|
+
from autogen import ConversableAgent # noqa: F401 — verify AG2 is installed
|
|
31
|
+
except ImportError:
|
|
32
|
+
console.print("[red]AG2 is not installed.[/red] Run: pip install ag2[ollama]")
|
|
33
|
+
raise SystemExit(1) # noqa: B904
|
|
34
|
+
|
|
35
|
+
from specsmith.agents.config import load_agent_config
|
|
36
|
+
from specsmith.agents.roles import create_builder, create_planner, create_verifier
|
|
37
|
+
|
|
38
|
+
project_dir = str(Path(project_dir).resolve())
|
|
39
|
+
config = load_agent_config(project_dir)
|
|
40
|
+
|
|
41
|
+
console.print(
|
|
42
|
+
f"\n[bold cyan]specsmith agent shell[/bold cyan] — {config.primary_model} via Ollama"
|
|
43
|
+
)
|
|
44
|
+
console.print(f"Task: [bold]{task}[/bold]\n")
|
|
45
|
+
|
|
46
|
+
# Phase 1: Plan
|
|
47
|
+
console.print("[dim]─── Phase 1: Planning ───[/dim]")
|
|
48
|
+
planner = create_planner(config, project_dir)
|
|
49
|
+
plan_result = planner.run(message=f"Plan this task:\n{task}", max_turns=max_turns)
|
|
50
|
+
plan_result.process()
|
|
51
|
+
|
|
52
|
+
plan_text = ""
|
|
53
|
+
for msg in plan_result.messages:
|
|
54
|
+
if msg.get("role") == "assistant" and msg.get("content"):
|
|
55
|
+
plan_text = msg["content"]
|
|
56
|
+
|
|
57
|
+
if not plan_text:
|
|
58
|
+
console.print("[yellow]Planner produced no output.[/yellow]")
|
|
59
|
+
return
|
|
60
|
+
|
|
61
|
+
# Phase 2: Build
|
|
62
|
+
console.print("\n[dim]─── Phase 2: Building ───[/dim]")
|
|
63
|
+
builder = create_builder(config, project_dir)
|
|
64
|
+
build_result = builder.run(
|
|
65
|
+
message=f"Execute this plan:\n\n{plan_text}",
|
|
66
|
+
max_turns=max_turns,
|
|
67
|
+
)
|
|
68
|
+
build_result.process()
|
|
69
|
+
|
|
70
|
+
build_text = ""
|
|
71
|
+
for msg in build_result.messages:
|
|
72
|
+
if msg.get("role") == "assistant" and msg.get("content"):
|
|
73
|
+
build_text = msg["content"]
|
|
74
|
+
|
|
75
|
+
# Phase 3: Verify
|
|
76
|
+
console.print("\n[dim]─── Phase 3: Verifying ───[/dim]")
|
|
77
|
+
verifier = create_verifier(config, project_dir)
|
|
78
|
+
verify_result = verifier.run(
|
|
79
|
+
message=(
|
|
80
|
+
f"Verify the following changes:\n\n{build_text}"
|
|
81
|
+
"\n\nRun the relevant tests and report ACCEPT or REJECT."
|
|
82
|
+
),
|
|
83
|
+
max_turns=max_turns,
|
|
84
|
+
)
|
|
85
|
+
verify_result.process()
|
|
86
|
+
|
|
87
|
+
# Summary
|
|
88
|
+
console.print("\n[bold cyan]─── Done ───[/bold cyan]")
|
|
89
|
+
for msg in verify_result.messages:
|
|
90
|
+
if msg.get("role") == "assistant" and msg.get("content"):
|
|
91
|
+
content = msg["content"]
|
|
92
|
+
if "ACCEPT" in content.upper():
|
|
93
|
+
console.print("[bold green]✓ ACCEPTED[/bold green]")
|
|
94
|
+
elif "REJECT" in content.upper():
|
|
95
|
+
console.print("[bold red]✗ REJECTED[/bold red]")
|
|
96
|
+
break
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@agent.command()
|
|
100
|
+
@click.argument("task")
|
|
101
|
+
@click.option("--project-dir", default=".", help="Project root directory.")
|
|
102
|
+
@click.option("--max-turns", default=6, help="Maximum conversation turns.")
|
|
103
|
+
def plan(task: str, project_dir: str, max_turns: int) -> None:
|
|
104
|
+
"""Generate a plan without executing it."""
|
|
105
|
+
try:
|
|
106
|
+
from autogen import ConversableAgent # noqa: F401
|
|
107
|
+
except ImportError:
|
|
108
|
+
console.print("[red]AG2 is not installed.[/red] Run: pip install ag2[ollama]")
|
|
109
|
+
raise SystemExit(1) # noqa: B904
|
|
110
|
+
|
|
111
|
+
from specsmith.agents.config import load_agent_config
|
|
112
|
+
from specsmith.agents.roles import create_planner
|
|
113
|
+
|
|
114
|
+
project_dir = str(Path(project_dir).resolve())
|
|
115
|
+
config = load_agent_config(project_dir)
|
|
116
|
+
|
|
117
|
+
console.print(f"\n[bold cyan]specsmith agent plan[/bold cyan] — {config.primary_model}")
|
|
118
|
+
planner = create_planner(config, project_dir)
|
|
119
|
+
result = planner.run(message=f"Plan this task:\n{task}", max_turns=max_turns)
|
|
120
|
+
result.process()
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@agent.command()
|
|
124
|
+
@click.option("--project-dir", default=".", help="Project root directory.")
|
|
125
|
+
def status(project_dir: str) -> None:
|
|
126
|
+
"""Show agent configuration and Ollama status."""
|
|
127
|
+
from specsmith.agents.config import load_agent_config
|
|
128
|
+
|
|
129
|
+
config = load_agent_config(project_dir)
|
|
130
|
+
console.print("[bold]Agent Configuration[/bold]")
|
|
131
|
+
console.print(f" Primary model: {config.primary_model}")
|
|
132
|
+
console.print(f" Utility model: {config.utility_model}")
|
|
133
|
+
console.print(f" Ollama URL: {config.ollama_base_url}")
|
|
134
|
+
console.print(f" Max iterations: {config.max_iterations}")
|
|
135
|
+
console.print(f" Context length: {config.num_ctx}")
|
|
136
|
+
console.print(f" Tools enabled: {', '.join(config.tools_enabled)}")
|
|
137
|
+
|
|
138
|
+
# Check Ollama
|
|
139
|
+
try:
|
|
140
|
+
from specsmith.agent.providers.ollama import OllamaProvider
|
|
141
|
+
|
|
142
|
+
p = OllamaProvider(base_url=config.ollama_base_url)
|
|
143
|
+
if p.is_available():
|
|
144
|
+
console.print(" Ollama: [green]running[/green]")
|
|
145
|
+
else:
|
|
146
|
+
console.print(" Ollama: [red]not available[/red]")
|
|
147
|
+
except Exception: # noqa: BLE001
|
|
148
|
+
console.print(" Ollama: [yellow]unknown[/yellow]")
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@agent.command()
|
|
152
|
+
@click.option("--project-dir", default=".", help="Project root directory.")
|
|
153
|
+
@click.option("--max-turns", default=4, help="Maximum conversation turns.")
|
|
154
|
+
def verify(project_dir: str, max_turns: int) -> None:
|
|
155
|
+
"""Run the Verifier agent on the current project state."""
|
|
156
|
+
try:
|
|
157
|
+
from autogen import ConversableAgent # noqa: F401
|
|
158
|
+
except ImportError:
|
|
159
|
+
console.print("[red]AG2 is not installed.[/red] Run: pip install ag2[ollama]")
|
|
160
|
+
raise SystemExit(1) # noqa: B904
|
|
161
|
+
|
|
162
|
+
from specsmith.agents.config import load_agent_config
|
|
163
|
+
from specsmith.agents.roles import create_verifier
|
|
164
|
+
|
|
165
|
+
project_dir = str(Path(project_dir).resolve())
|
|
166
|
+
config = load_agent_config(project_dir)
|
|
167
|
+
|
|
168
|
+
console.print(f"\n[bold cyan]specsmith agent verify[/bold cyan] — {config.utility_model}")
|
|
169
|
+
verifier = create_verifier(config, project_dir)
|
|
170
|
+
result = verifier.run(
|
|
171
|
+
message=(
|
|
172
|
+
"Run the full test suite and report the current project health."
|
|
173
|
+
" Report ACCEPT or REJECT."
|
|
174
|
+
),
|
|
175
|
+
max_turns=max_turns,
|
|
176
|
+
)
|
|
177
|
+
result.process()
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
@agent.command()
|
|
181
|
+
@click.argument("task")
|
|
182
|
+
@click.option("--project-dir", default=".", help="Project root directory.")
|
|
183
|
+
@click.option("--max-turns", default=6, help="Maximum conversation turns.")
|
|
184
|
+
def improve(task: str, project_dir: str, max_turns: int) -> None:
|
|
185
|
+
"""Run the self-improvement workflow (Plan → Build → Verify → Report)."""
|
|
186
|
+
try:
|
|
187
|
+
from autogen import ConversableAgent # noqa: F401
|
|
188
|
+
except ImportError:
|
|
189
|
+
console.print("[red]AG2 is not installed.[/red] Run: pip install ag2[ollama]")
|
|
190
|
+
raise SystemExit(1) # noqa: B904
|
|
191
|
+
|
|
192
|
+
from specsmith.agents.workflows.improve import run_improvement
|
|
193
|
+
|
|
194
|
+
project_dir = str(Path(project_dir).resolve())
|
|
195
|
+
console.print("\n[bold cyan]specsmith agent improve[/bold cyan]")
|
|
196
|
+
console.print(f"Task: [bold]{task}[/bold]\n")
|
|
197
|
+
|
|
198
|
+
report = run_improvement(task, project_dir, max_turns=max_turns)
|
|
199
|
+
|
|
200
|
+
console.print(f"\n[bold]Report:[/bold] {report.summary}")
|
|
201
|
+
if report.verdict == "ACCEPT":
|
|
202
|
+
console.print("[bold green]✓ ACCEPTED[/bold green]")
|
|
203
|
+
elif report.verdict == "REJECT":
|
|
204
|
+
console.print("[bold red]✗ REJECTED[/bold red]")
|
|
205
|
+
else:
|
|
206
|
+
console.print(f"[yellow]Verdict: {report.verdict}[/yellow]")
|
|
207
|
+
|
|
208
|
+
if report.follow_up_tasks:
|
|
209
|
+
console.print("\n[bold]Follow-up tasks:[/bold]")
|
|
210
|
+
for ft in report.follow_up_tasks:
|
|
211
|
+
console.print(f" - {ft}")
|
|
212
|
+
|
|
213
|
+
console.print(f"\n[dim]Report saved to .specsmith/agent-reports/{report.task_id}.json[/dim]")
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
@agent.command()
|
|
217
|
+
@click.option("--project-dir", default=".", help="Project root directory.")
|
|
218
|
+
def reports(project_dir: str) -> None:
|
|
219
|
+
"""List recent improvement reports."""
|
|
220
|
+
from specsmith.agents.reports import list_reports
|
|
221
|
+
|
|
222
|
+
all_reports = list_reports(project_dir)
|
|
223
|
+
if not all_reports:
|
|
224
|
+
console.print("[yellow]No improvement reports found.[/yellow]")
|
|
225
|
+
return
|
|
226
|
+
|
|
227
|
+
for r in all_reports[:10]:
|
|
228
|
+
icon = {
|
|
229
|
+
"accepted": "[green]✓[/green]",
|
|
230
|
+
"rejected": "[red]✗[/red]",
|
|
231
|
+
"failed": "[red]![/red]",
|
|
232
|
+
}.get(r.status, "[yellow]?[/yellow]")
|
|
233
|
+
console.print(f" {icon} {r.task_id} — {r.summary}")
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2026 BitConcepts, LLC. All rights reserved.
|
|
3
|
+
"""Agent configuration — loaded from scaffold.yml ``agents:`` key."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class AgentConfig:
|
|
14
|
+
"""Configuration for the AG2 agent shell."""
|
|
15
|
+
|
|
16
|
+
primary_model: str = "qwen2.5:14b"
|
|
17
|
+
utility_model: str = "" # empty = same as primary_model
|
|
18
|
+
ollama_base_url: str = "http://localhost:11434"
|
|
19
|
+
max_iterations: int = 10
|
|
20
|
+
stream: bool = False
|
|
21
|
+
num_ctx: int = 4096
|
|
22
|
+
tools_enabled: list[str] = field(
|
|
23
|
+
default_factory=lambda: ["filesystem", "shell", "git", "tests", "docs"]
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def effective_utility_model(self) -> str:
|
|
28
|
+
"""Utility model, defaulting to primary if not set."""
|
|
29
|
+
return self.utility_model or self.primary_model
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def effective_max_iterations(self) -> int:
|
|
33
|
+
"""0 means unlimited (use 999 as practical ceiling)."""
|
|
34
|
+
return self.max_iterations if self.max_iterations > 0 else 999
|
|
35
|
+
|
|
36
|
+
def llm_config_dict(self, model: str | None = None) -> dict[str, Any]:
|
|
37
|
+
"""Return an AG2-compatible LLM config dict for Ollama."""
|
|
38
|
+
return {
|
|
39
|
+
"model": model or self.primary_model,
|
|
40
|
+
"api_type": "ollama",
|
|
41
|
+
"client_host": self.ollama_base_url,
|
|
42
|
+
"stream": self.stream,
|
|
43
|
+
"num_ctx": self.num_ctx,
|
|
44
|
+
"native_tool_calls": True,
|
|
45
|
+
"hide_tools": "if_any_run",
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def load_agent_config(project_dir: str | Path) -> AgentConfig:
|
|
50
|
+
"""Load agent config from scaffold.yml ``agents:`` section.
|
|
51
|
+
|
|
52
|
+
Falls back to defaults if scaffold.yml doesn't exist or has no agents key.
|
|
53
|
+
"""
|
|
54
|
+
scaffold_path = Path(project_dir) / "scaffold.yml"
|
|
55
|
+
if not scaffold_path.exists():
|
|
56
|
+
return AgentConfig()
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
import yaml
|
|
60
|
+
|
|
61
|
+
with open(scaffold_path, encoding="utf-8") as f:
|
|
62
|
+
raw = yaml.safe_load(f) or {}
|
|
63
|
+
agents_raw = raw.get("agents", {}) or {}
|
|
64
|
+
return AgentConfig(
|
|
65
|
+
primary_model=agents_raw.get("primary_model", AgentConfig.primary_model),
|
|
66
|
+
utility_model=agents_raw.get("utility_model", AgentConfig.utility_model),
|
|
67
|
+
ollama_base_url=agents_raw.get("ollama_base_url", AgentConfig.ollama_base_url),
|
|
68
|
+
max_iterations=agents_raw.get("max_iterations", AgentConfig.max_iterations),
|
|
69
|
+
stream=agents_raw.get("stream", AgentConfig.stream),
|
|
70
|
+
num_ctx=agents_raw.get("num_ctx", AgentConfig.num_ctx),
|
|
71
|
+
tools_enabled=agents_raw.get("tools_enabled", AgentConfig().tools_enabled),
|
|
72
|
+
)
|
|
73
|
+
except Exception: # noqa: BLE001
|
|
74
|
+
return AgentConfig()
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2026 BitConcepts, LLC. All rights reserved.
|
|
3
|
+
"""Change reports — structured artifacts from improvement runs.
|
|
4
|
+
|
|
5
|
+
Every improvement run produces a ChangeReport stored as JSON at
|
|
6
|
+
``.specsmith/agent-reports/<task_id>.json``.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
from dataclasses import asdict, dataclass, field
|
|
13
|
+
from datetime import datetime, timezone
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class ChangeReport:
|
|
20
|
+
"""Structured output from an improvement run."""
|
|
21
|
+
|
|
22
|
+
task_id: str = ""
|
|
23
|
+
task_description: str = ""
|
|
24
|
+
project_dir: str = "."
|
|
25
|
+
status: str = "pending" # pending, accepted, rejected, failed, unclear
|
|
26
|
+
verdict: str = "" # ACCEPT, REJECT, UNCLEAR
|
|
27
|
+
plan: str = ""
|
|
28
|
+
build_output: str = ""
|
|
29
|
+
verify_output: str = ""
|
|
30
|
+
files_changed: list[str] = field(default_factory=list)
|
|
31
|
+
tests_run: int = 0
|
|
32
|
+
tests_passed: int = 0
|
|
33
|
+
tests_failed: int = 0
|
|
34
|
+
summary: str = ""
|
|
35
|
+
follow_up_tasks: list[str] = field(default_factory=list)
|
|
36
|
+
created: str = field(default_factory=lambda: datetime.now(tz=timezone.utc).isoformat())
|
|
37
|
+
|
|
38
|
+
def to_dict(self) -> dict[str, Any]:
|
|
39
|
+
"""Convert to a JSON-serializable dict (excludes verbose fields)."""
|
|
40
|
+
d = asdict(self)
|
|
41
|
+
# Truncate verbose fields for the summary view
|
|
42
|
+
for key in ("plan", "build_output", "verify_output"):
|
|
43
|
+
if len(d.get(key, "")) > 500:
|
|
44
|
+
d[key] = d[key][:500] + "...(truncated)"
|
|
45
|
+
return d
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def save_report(report: ChangeReport) -> Path:
|
|
49
|
+
"""Save a change report to ``.specsmith/agent-reports/``."""
|
|
50
|
+
root = Path(report.project_dir).resolve()
|
|
51
|
+
reports_dir = root / ".specsmith" / "agent-reports"
|
|
52
|
+
reports_dir.mkdir(parents=True, exist_ok=True)
|
|
53
|
+
path = reports_dir / f"{report.task_id}.json"
|
|
54
|
+
path.write_text(
|
|
55
|
+
json.dumps(report.to_dict(), indent=2, ensure_ascii=False),
|
|
56
|
+
encoding="utf-8",
|
|
57
|
+
)
|
|
58
|
+
return path
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def list_reports(project_dir: str = ".") -> list[ChangeReport]:
|
|
62
|
+
"""List all change reports, newest first."""
|
|
63
|
+
reports_dir = Path(project_dir).resolve() / ".specsmith" / "agent-reports"
|
|
64
|
+
if not reports_dir.exists():
|
|
65
|
+
return []
|
|
66
|
+
reports: list[ChangeReport] = []
|
|
67
|
+
for path in sorted(reports_dir.glob("*.json"), reverse=True):
|
|
68
|
+
try:
|
|
69
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
70
|
+
reports.append(
|
|
71
|
+
ChangeReport(
|
|
72
|
+
**{k: v for k, v in data.items() if k in ChangeReport.__dataclass_fields__}
|
|
73
|
+
)
|
|
74
|
+
)
|
|
75
|
+
except Exception: # noqa: BLE001
|
|
76
|
+
pass
|
|
77
|
+
return reports
|