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.
Files changed (197) hide show
  1. {specsmith-0.7.0.dev236/src/specsmith.egg-info → specsmith-0.10.0.dev238}/PKG-INFO +1 -1
  2. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/pyproject.toml +4 -1
  3. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/__init__.py +1 -1
  4. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/chat_runner.py +98 -1
  5. specsmith-0.10.0.dev238/src/specsmith/agent/core.py +98 -0
  6. specsmith-0.10.0.dev238/src/specsmith/agent/endpoints.py +493 -0
  7. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/events.py +58 -0
  8. specsmith-0.10.0.dev238/src/specsmith/agent/fallback.py +142 -0
  9. specsmith-0.10.0.dev238/src/specsmith/agent/profiles.py +569 -0
  10. specsmith-0.10.0.dev238/src/specsmith/agent/runner.py +399 -0
  11. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/cli.py +848 -109
  12. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/vcs_commands.py +1 -1
  13. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238/src/specsmith.egg-info}/PKG-INFO +1 -1
  14. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith.egg-info/SOURCES.txt +11 -1
  15. specsmith-0.10.0.dev238/tests/test_agent_profiles.py +70 -0
  16. specsmith-0.10.0.dev238/tests/test_agent_runner_ready.py +75 -0
  17. specsmith-0.10.0.dev238/tests/test_chat_runner_openai_compat.py +195 -0
  18. specsmith-0.10.0.dev238/tests/test_endpoints_cli.py +244 -0
  19. specsmith-0.10.0.dev238/tests/test_endpoints_store.py +350 -0
  20. specsmith-0.10.0.dev238/tests/test_fallback_chain.py +343 -0
  21. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_phase34_completion.py +4 -36
  22. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_warp_parity.py +4 -115
  23. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_warp_parity_followup.py +0 -95
  24. specsmith-0.7.0.dev236/src/specsmith/cloud_serve.py +0 -150
  25. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/LICENSE +0 -0
  26. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/README.md +0 -0
  27. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/setup.cfg +0 -0
  28. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/epistemic/__init__.py +0 -0
  29. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/epistemic/belief.py +0 -0
  30. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/epistemic/certainty.py +0 -0
  31. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/epistemic/failure_graph.py +0 -0
  32. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/epistemic/py.typed +0 -0
  33. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/epistemic/recovery.py +0 -0
  34. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/epistemic/session.py +0 -0
  35. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/epistemic/stress_tester.py +0 -0
  36. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/epistemic/trace.py +0 -0
  37. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/__main__.py +0 -0
  38. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/__init__.py +0 -0
  39. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/broker.py +0 -0
  40. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/cleanup.py +0 -0
  41. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/indexer.py +0 -0
  42. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/mcp.py +0 -0
  43. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/memory.py +0 -0
  44. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/orchestrator.py +0 -0
  45. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/repl.py +0 -0
  46. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/router.py +0 -0
  47. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/rules.py +0 -0
  48. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/safety.py +0 -0
  49. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/suggester.py +0 -0
  50. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/tools.py +0 -0
  51. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/verifier.py +0 -0
  52. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/agent/voice.py +0 -0
  53. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/architect.py +0 -0
  54. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/auditor.py +0 -0
  55. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/auth.py +0 -0
  56. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/block_export.py +0 -0
  57. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/commands/__init__.py +0 -0
  58. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/compressor.py +0 -0
  59. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/config.py +0 -0
  60. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/console_utils.py +0 -0
  61. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/credit_analyzer.py +0 -0
  62. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/credits.py +0 -0
  63. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/differ.py +0 -0
  64. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/doctor.py +0 -0
  65. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/drive.py +0 -0
  66. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/epistemic/__init__.py +0 -0
  67. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/epistemic/belief.py +0 -0
  68. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/epistemic/certainty.py +0 -0
  69. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/epistemic/failure_graph.py +0 -0
  70. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/epistemic/recovery.py +0 -0
  71. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/epistemic/stress_tester.py +0 -0
  72. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/executor.py +0 -0
  73. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/exporter.py +0 -0
  74. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/__init__.py +0 -0
  75. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/app.py +0 -0
  76. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/main_window.py +0 -0
  77. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/session_tab.py +0 -0
  78. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/theme.py +0 -0
  79. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/widgets/__init__.py +0 -0
  80. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/widgets/chat_view.py +0 -0
  81. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/widgets/input_bar.py +0 -0
  82. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/widgets/provider_bar.py +0 -0
  83. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/widgets/token_meter.py +0 -0
  84. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/widgets/tool_panel.py +0 -0
  85. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/widgets/update_checker.py +0 -0
  86. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/gui/worker.py +0 -0
  87. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/history_search.py +0 -0
  88. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/importer.py +0 -0
  89. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/integrations/__init__.py +0 -0
  90. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/integrations/agent_skill.py +0 -0
  91. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/integrations/aider.py +0 -0
  92. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/integrations/base.py +0 -0
  93. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/integrations/claude_code.py +0 -0
  94. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/integrations/copilot.py +0 -0
  95. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/integrations/cursor.py +0 -0
  96. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/integrations/gemini.py +0 -0
  97. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/integrations/windsurf.py +0 -0
  98. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/languages.py +0 -0
  99. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/ledger.py +0 -0
  100. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/patent.py +0 -0
  101. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/phase.py +0 -0
  102. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/plugins.py +0 -0
  103. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/profiles.py +0 -0
  104. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/rate_limits.py +0 -0
  105. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/releaser.py +0 -0
  106. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/requirements.py +0 -0
  107. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/requirements_parser.py +0 -0
  108. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/retrieval.py +0 -0
  109. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/scaffolder.py +0 -0
  110. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/serve.py +0 -0
  111. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/session.py +0 -0
  112. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/skills.py +0 -0
  113. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/agents.md.j2 +0 -0
  114. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
  115. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
  116. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/community/contributing.md.j2 +0 -0
  117. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
  118. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
  119. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/community/license-MIT.j2 +0 -0
  120. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
  121. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/community/security.md.j2 +0 -0
  122. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
  123. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
  124. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
  125. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
  126. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
  127. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/editorconfig.j2 +0 -0
  128. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/gitattributes.j2 +0 -0
  129. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/gitignore.j2 +0 -0
  130. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/go/go.mod.j2 +0 -0
  131. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/go/main.go.j2 +0 -0
  132. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
  133. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
  134. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
  135. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
  136. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
  137. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/governance/lifecycle.md.j2 +0 -0
  138. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/governance/roles.md.j2 +0 -0
  139. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/governance/rules.md.j2 +0 -0
  140. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/governance/session-protocol.md.j2 +0 -0
  141. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
  142. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/governance/verification.md.j2 +0 -0
  143. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/js/package.json.j2 +0 -0
  144. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/ledger.md.j2 +0 -0
  145. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/python/cli.py.j2 +0 -0
  146. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/python/init.py.j2 +0 -0
  147. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
  148. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/readme.md.j2 +0 -0
  149. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
  150. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/rust/main.rs.j2 +0 -0
  151. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
  152. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
  153. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
  154. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
  155. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
  156. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
  157. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
  158. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/tool_installer.py +0 -0
  159. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/toolrules.py +0 -0
  160. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/tools.py +0 -0
  161. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/trace.py +0 -0
  162. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/updater.py +0 -0
  163. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/upgrader.py +0 -0
  164. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/validator.py +0 -0
  165. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/vcs/__init__.py +0 -0
  166. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/vcs/base.py +0 -0
  167. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/vcs/bitbucket.py +0 -0
  168. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/vcs/github.py +0 -0
  169. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/vcs/gitlab.py +0 -0
  170. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/wireframes.py +0 -0
  171. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith/workspace.py +0 -0
  172. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith.egg-info/dependency_links.txt +0 -0
  173. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith.egg-info/entry_points.txt +0 -0
  174. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith.egg-info/requires.txt +0 -0
  175. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/src/specsmith.egg-info/top_level.txt +0 -0
  176. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_CMD_001.py +0 -0
  177. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_auditor.py +0 -0
  178. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_chat_diff_decision.py +0 -0
  179. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_chat_stdin_protocol.py +0 -0
  180. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_cli.py +0 -0
  181. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_cli_workflows_history_drive.py +0 -0
  182. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_compressor.py +0 -0
  183. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_e2e_nexus.py +0 -0
  184. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_epistemic.py +0 -0
  185. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_importer.py +0 -0
  186. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_integrations.py +0 -0
  187. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_mcp_client.py +0 -0
  188. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_nexus.py +0 -0
  189. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_phase1_4_new.py +0 -0
  190. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_rate_limits.py +0 -0
  191. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_scaffolder.py +0 -0
  192. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_skill_marketplace.py +0 -0
  193. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_smoke.py +0 -0
  194. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_suggester.py +0 -0
  195. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_tools.py +0 -0
  196. {specsmith-0.7.0.dev236 → specsmith-0.10.0.dev238}/tests/test_validator.py +0 -0
  197. {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.7.0.dev236
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.0.dev236"
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.3.6" # fallback: keep in sync with pyproject.toml
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"]