specsmith 0.7.0.dev236__tar.gz → 0.10.0.dev238__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.7.0.dev236/src/specsmith.egg-info → specsmith-0.10.0.dev238}/PKG-INFO +1 -1
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/pyproject.toml +4 -1
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/__init__.py +1 -1
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/chat_runner.py +98 -1
- specsmith-0.10.0.dev238/src/specsmith/agent/core.py +98 -0
- specsmith-0.10.0.dev238/src/specsmith/agent/endpoints.py +493 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/events.py +58 -0
- specsmith-0.10.0.dev238/src/specsmith/agent/fallback.py +142 -0
- specsmith-0.10.0.dev238/src/specsmith/agent/profiles.py +569 -0
- specsmith-0.10.0.dev238/src/specsmith/agent/runner.py +399 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/cli.py +848 -109
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/vcs_commands.py +1 -1
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238/src/specsmith.egg-info}/PKG-INFO +1 -1
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith.egg-info/SOURCES.txt +11 -1
- specsmith-0.10.0.dev238/tests/test_agent_profiles.py +70 -0
- specsmith-0.10.0.dev238/tests/test_agent_runner_ready.py +75 -0
- specsmith-0.10.0.dev238/tests/test_chat_runner_openai_compat.py +195 -0
- specsmith-0.10.0.dev238/tests/test_endpoints_cli.py +244 -0
- specsmith-0.10.0.dev238/tests/test_endpoints_store.py +350 -0
- specsmith-0.10.0.dev238/tests/test_fallback_chain.py +343 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_phase34_completion.py +4 -36
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_warp_parity.py +4 -115
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_warp_parity_followup.py +0 -95
- specsmith-0.7.0.dev236/src/specsmith/cloud_serve.py +0 -150
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/LICENSE +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/README.md +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/setup.cfg +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/epistemic/__init__.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/epistemic/belief.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/epistemic/certainty.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/epistemic/failure_graph.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/epistemic/py.typed +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/epistemic/recovery.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/epistemic/session.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/epistemic/stress_tester.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/epistemic/trace.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/__main__.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/__init__.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/broker.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/cleanup.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/indexer.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/mcp.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/memory.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/orchestrator.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/repl.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/router.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/rules.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/safety.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/suggester.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/tools.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/verifier.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/voice.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/architect.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/auditor.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/auth.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/block_export.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/commands/__init__.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/compressor.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/config.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/console_utils.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/credit_analyzer.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/credits.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/differ.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/doctor.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/drive.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/epistemic/__init__.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/epistemic/belief.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/epistemic/certainty.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/epistemic/failure_graph.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/epistemic/recovery.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/epistemic/stress_tester.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/executor.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/exporter.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/__init__.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/app.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/main_window.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/session_tab.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/theme.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/widgets/__init__.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/widgets/chat_view.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/widgets/input_bar.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/widgets/provider_bar.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/widgets/token_meter.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/widgets/tool_panel.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/widgets/update_checker.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/worker.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/history_search.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/importer.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/integrations/__init__.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/integrations/agent_skill.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/integrations/aider.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/integrations/base.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/integrations/claude_code.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/integrations/copilot.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/integrations/cursor.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/integrations/gemini.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/integrations/windsurf.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/languages.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/ledger.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/patent.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/phase.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/plugins.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/profiles.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/rate_limits.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/releaser.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/requirements.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/requirements_parser.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/retrieval.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/scaffolder.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/serve.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/session.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/skills.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/agents.md.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/community/contributing.md.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/community/license-MIT.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/community/security.md.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/editorconfig.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/gitattributes.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/gitignore.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/go/go.mod.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/go/main.go.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/governance/lifecycle.md.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/governance/roles.md.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/governance/rules.md.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/governance/session-protocol.md.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/governance/verification.md.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/js/package.json.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/ledger.md.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/python/cli.py.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/python/init.py.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/readme.md.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/rust/main.rs.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/tool_installer.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/toolrules.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/tools.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/trace.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/updater.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/upgrader.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/validator.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/vcs/__init__.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/vcs/base.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/vcs/bitbucket.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/vcs/github.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/vcs/gitlab.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/wireframes.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/workspace.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith.egg-info/dependency_links.txt +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith.egg-info/entry_points.txt +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith.egg-info/requires.txt +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith.egg-info/top_level.txt +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_CMD_001.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_auditor.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_chat_diff_decision.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_chat_stdin_protocol.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_cli.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_cli_workflows_history_drive.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_compressor.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_e2e_nexus.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_epistemic.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_importer.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_integrations.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_mcp_client.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_nexus.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_phase1_4_new.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_rate_limits.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_scaffolder.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_skill_marketplace.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_smoke.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_suggester.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_tools.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_validator.py +0 -0
- {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_vcs.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: specsmith
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.0.dev238
|
|
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
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "specsmith"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.10.0.dev238"
|
|
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"
|
|
@@ -171,6 +171,9 @@ module = [
|
|
|
171
171
|
"specsmith.importer",
|
|
172
172
|
"specsmith.agent.providers.gemini",
|
|
173
173
|
"specsmith.agent.runner",
|
|
174
|
+
"specsmith.agent.profiles",
|
|
175
|
+
"specsmith.agent.fallback",
|
|
176
|
+
"specsmith.agent.core",
|
|
174
177
|
"specsmith.agent.cleanup",
|
|
175
178
|
"specsmith.agent.orchestrator",
|
|
176
179
|
"specsmith.agent.repl",
|
|
@@ -8,4 +8,4 @@ from importlib.metadata import version as _pkg_version
|
|
|
8
8
|
try:
|
|
9
9
|
__version__: str = _pkg_version("specsmith")
|
|
10
10
|
except PackageNotFoundError: # running from source without install
|
|
11
|
-
__version__ = "0.
|
|
11
|
+
__version__ = "0.10.0" # fallback: keep in sync with pyproject.toml
|
|
@@ -80,11 +80,35 @@ def run_chat(
|
|
|
80
80
|
history: list[dict[str, Any]] | None = None,
|
|
81
81
|
confidence_target: float = 0.7,
|
|
82
82
|
rules_prefix: str = "",
|
|
83
|
+
endpoint_id: str | None = None,
|
|
83
84
|
) -> ChatRunResult | None:
|
|
84
|
-
"""Drive a real LLM turn. Return ``None`` if no provider is reachable.
|
|
85
|
+
"""Drive a real LLM turn. Return ``None`` if no provider is reachable.
|
|
86
|
+
|
|
87
|
+
When ``endpoint_id`` is set, the BYOE store (REQ-142) is consulted and
|
|
88
|
+
the resolved :class:`Endpoint` short-circuits the provider chain via
|
|
89
|
+
the new :func:`_run_openai_compat` driver. Any error during endpoint
|
|
90
|
+
resolution falls back to the legacy auto-detect chain so an offline
|
|
91
|
+
misconfigured endpoint never breaks `specsmith chat`.
|
|
92
|
+
"""
|
|
85
93
|
history = history or []
|
|
86
94
|
messages = _build_messages(utterance, history, rules_prefix)
|
|
87
95
|
|
|
96
|
+
# REQ-142: explicit endpoint override.
|
|
97
|
+
if endpoint_id:
|
|
98
|
+
try:
|
|
99
|
+
from specsmith.agent.endpoints import EndpointStore
|
|
100
|
+
|
|
101
|
+
endpoint = EndpointStore.load().resolve(endpoint_id)
|
|
102
|
+
except Exception: # noqa: BLE001 - any failure → fall back to auto-detect
|
|
103
|
+
endpoint = None
|
|
104
|
+
if endpoint is not None:
|
|
105
|
+
try:
|
|
106
|
+
full_text = _run_openai_compat(messages, emitter, msg_block, endpoint=endpoint)
|
|
107
|
+
except Exception: # noqa: BLE001 - degrade to auto-detect
|
|
108
|
+
full_text = None
|
|
109
|
+
if full_text is not None:
|
|
110
|
+
return _finalize(full_text, "openai_compat", project_dir, confidence_target)
|
|
111
|
+
|
|
88
112
|
# Order matters: Ollama first because it's local-first and free.
|
|
89
113
|
for provider in (_run_ollama, _run_anthropic, _run_openai, _run_gemini):
|
|
90
114
|
try:
|
|
@@ -228,6 +252,79 @@ def _run_openai(
|
|
|
228
252
|
return "".join(pieces) if pieces else None
|
|
229
253
|
|
|
230
254
|
|
|
255
|
+
def _run_openai_compat(
|
|
256
|
+
messages: list[dict[str, str]],
|
|
257
|
+
emitter: EventEmitter,
|
|
258
|
+
block_id: str,
|
|
259
|
+
*,
|
|
260
|
+
endpoint: Any,
|
|
261
|
+
) -> str | None:
|
|
262
|
+
"""Stream from a user-registered OpenAI-v1-compatible endpoint (REQ-142).
|
|
263
|
+
|
|
264
|
+
Uses raw stdlib HTTP so the openai SDK is not a hard dependency for
|
|
265
|
+
BYOE. Sends a streaming ``/chat/completions`` request, decodes the
|
|
266
|
+
Server-Sent-Events ``data:`` lines, and forwards each ``content``
|
|
267
|
+
delta as a ``token`` event on ``block_id``.
|
|
268
|
+
"""
|
|
269
|
+
base_url = endpoint.base_url.rstrip("/")
|
|
270
|
+
url = f"{base_url}/chat/completions"
|
|
271
|
+
model = endpoint.default_model or os.environ.get("SPECSMITH_OPENAI_COMPAT_MODEL", "")
|
|
272
|
+
if not model:
|
|
273
|
+
# The endpoint did not pin a default model and the env override is
|
|
274
|
+
# absent. We cannot fabricate one; fall back to the auto-detect chain.
|
|
275
|
+
return None
|
|
276
|
+
|
|
277
|
+
headers: dict[str, str] = {
|
|
278
|
+
"Content-Type": "application/json",
|
|
279
|
+
"Accept": "text/event-stream",
|
|
280
|
+
}
|
|
281
|
+
try:
|
|
282
|
+
token = endpoint.resolve_token()
|
|
283
|
+
except Exception: # noqa: BLE001 - fall back to auto-detect chain
|
|
284
|
+
return None
|
|
285
|
+
if token:
|
|
286
|
+
headers["Authorization"] = f"Bearer {token}"
|
|
287
|
+
|
|
288
|
+
body = json.dumps({"model": model, "messages": messages, "stream": True}).encode("utf-8")
|
|
289
|
+
req = Request(url, data=body, headers=headers, method="POST") # noqa: S310 - user-supplied
|
|
290
|
+
|
|
291
|
+
ctx = None
|
|
292
|
+
if not endpoint.verify_tls and url.startswith("https://"):
|
|
293
|
+
import ssl
|
|
294
|
+
|
|
295
|
+
ctx = ssl.create_default_context()
|
|
296
|
+
ctx.check_hostname = False
|
|
297
|
+
ctx.verify_mode = ssl.CERT_NONE
|
|
298
|
+
|
|
299
|
+
pieces: list[str] = []
|
|
300
|
+
try:
|
|
301
|
+
with urlopen(req, timeout=120, context=ctx) as resp: # noqa: S310 - user-supplied
|
|
302
|
+
for raw_line in resp:
|
|
303
|
+
line = raw_line.decode("utf-8", errors="replace").rstrip("\n\r")
|
|
304
|
+
if not line.startswith("data:"):
|
|
305
|
+
continue
|
|
306
|
+
payload = line[len("data:") :].strip()
|
|
307
|
+
if not payload or payload == "[DONE]":
|
|
308
|
+
if payload == "[DONE]":
|
|
309
|
+
break
|
|
310
|
+
continue
|
|
311
|
+
try:
|
|
312
|
+
obj = json.loads(payload)
|
|
313
|
+
except ValueError:
|
|
314
|
+
continue
|
|
315
|
+
choices = obj.get("choices") or []
|
|
316
|
+
if not choices:
|
|
317
|
+
continue
|
|
318
|
+
delta = (choices[0] or {}).get("delta") or {}
|
|
319
|
+
chunk = str(delta.get("content") or "")
|
|
320
|
+
if chunk:
|
|
321
|
+
emitter.token(block_id, chunk)
|
|
322
|
+
pieces.append(chunk)
|
|
323
|
+
except (URLError, TimeoutError, OSError):
|
|
324
|
+
return None
|
|
325
|
+
return "".join(pieces) if pieces else None
|
|
326
|
+
|
|
327
|
+
|
|
231
328
|
def _run_gemini(
|
|
232
329
|
messages: list[dict[str, str]],
|
|
233
330
|
emitter: EventEmitter,
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2026 BitConcepts, LLC. All rights reserved.
|
|
3
|
+
"""Shared agent runtime primitives (REQ-145).
|
|
4
|
+
|
|
5
|
+
Hosts low-level enums and dataclasses that span :mod:`specsmith.agent.runner`,
|
|
6
|
+
:mod:`specsmith.serve`, :mod:`specsmith.agent.profiles`, and
|
|
7
|
+
:mod:`specsmith.agent.fallback` without forcing them to import each other.
|
|
8
|
+
|
|
9
|
+
The historical ``cli.py`` referenced ``ModelTier`` from this module before
|
|
10
|
+
it existed in the source tree (the file was lost in an earlier refactor),
|
|
11
|
+
which produced an ``ImportError`` the moment ``specsmith run`` was
|
|
12
|
+
invoked. Restoring the symbol here is the prerequisite for the bridge
|
|
13
|
+
``ready`` event handshake to land before the VS Code extension's 20 s
|
|
14
|
+
startup timeout fires.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import enum
|
|
20
|
+
from dataclasses import dataclass, field
|
|
21
|
+
from typing import Any
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ModelTier(str, enum.Enum):
|
|
25
|
+
"""Capability tier for an LLM call.
|
|
26
|
+
|
|
27
|
+
Ordered cheapest → most capable so that a fallback chain can iterate
|
|
28
|
+
in declaration order without external metadata.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
FAST = "fast"
|
|
32
|
+
BALANCED = "balanced"
|
|
33
|
+
POWERFUL = "powerful"
|
|
34
|
+
|
|
35
|
+
@classmethod
|
|
36
|
+
def parse(
|
|
37
|
+
cls,
|
|
38
|
+
value: str | ModelTier | None,
|
|
39
|
+
default: ModelTier | None = None,
|
|
40
|
+
) -> ModelTier:
|
|
41
|
+
"""Tolerant parser used by CLI option handlers."""
|
|
42
|
+
if value is None or value == "":
|
|
43
|
+
return default or cls.BALANCED
|
|
44
|
+
if isinstance(value, cls):
|
|
45
|
+
return value
|
|
46
|
+
try:
|
|
47
|
+
return cls(str(value).strip().lower())
|
|
48
|
+
except ValueError:
|
|
49
|
+
return default or cls.BALANCED
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@dataclass
|
|
53
|
+
class AgentState:
|
|
54
|
+
"""Mutable per-session metrics surfaced via ``specsmith serve``'s
|
|
55
|
+
``GET /api/status`` endpoint and the VS Code TokenMeter chip.
|
|
56
|
+
|
|
57
|
+
Field names mirror what :class:`specsmith.serve._AgentThread` reads off
|
|
58
|
+
``runner._state``; do not rename without updating that consumer.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
provider_name: str = ""
|
|
62
|
+
model_name: str = ""
|
|
63
|
+
profile_id: str = ""
|
|
64
|
+
session_tokens: int = 0
|
|
65
|
+
tokens_in: int = 0
|
|
66
|
+
tokens_out: int = 0
|
|
67
|
+
total_cost_usd: float = 0.0
|
|
68
|
+
tool_calls_made: int = 0
|
|
69
|
+
elapsed_minutes: float = 0.0
|
|
70
|
+
by_profile: dict[str, dict[str, Any]] = field(default_factory=dict)
|
|
71
|
+
|
|
72
|
+
def credit(
|
|
73
|
+
self,
|
|
74
|
+
*,
|
|
75
|
+
profile_id: str,
|
|
76
|
+
tokens_in: int = 0,
|
|
77
|
+
tokens_out: int = 0,
|
|
78
|
+
cost_usd: float = 0.0,
|
|
79
|
+
tool_calls: int = 0,
|
|
80
|
+
) -> None:
|
|
81
|
+
"""Aggregate one turn's metrics into the running totals."""
|
|
82
|
+
self.tokens_in += int(tokens_in)
|
|
83
|
+
self.tokens_out += int(tokens_out)
|
|
84
|
+
self.session_tokens = self.tokens_in + self.tokens_out
|
|
85
|
+
self.total_cost_usd += float(cost_usd)
|
|
86
|
+
self.tool_calls_made += int(tool_calls)
|
|
87
|
+
bucket = self.by_profile.setdefault(
|
|
88
|
+
profile_id or "(default)",
|
|
89
|
+
{"tokens_in": 0, "tokens_out": 0, "cost_usd": 0.0, "tool_calls": 0, "turns": 0},
|
|
90
|
+
)
|
|
91
|
+
bucket["tokens_in"] += int(tokens_in)
|
|
92
|
+
bucket["tokens_out"] += int(tokens_out)
|
|
93
|
+
bucket["cost_usd"] = round(bucket["cost_usd"] + float(cost_usd), 6)
|
|
94
|
+
bucket["tool_calls"] += int(tool_calls)
|
|
95
|
+
bucket["turns"] += 1
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
__all__ = ["AgentState", "ModelTier"]
|