rtxclaw 0.7.2__tar.gz → 0.7.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (269) hide show
  1. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/MANIFEST.in +7 -4
  2. {rtxclaw-0.7.2/src/rtxclaw.egg-info → rtxclaw-0.7.4}/PKG-INFO +5 -1
  3. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/pyproject.toml +20 -1
  4. {rtxclaw-0.7.2 → rtxclaw-0.7.4/src/rtxclaw.egg-info}/PKG-INFO +5 -1
  5. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw.egg-info/SOURCES.txt +37 -1
  6. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw.egg-info/entry_points.txt +1 -0
  7. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw.egg-info/requires.txt +5 -0
  8. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw.egg-info/top_level.txt +1 -0
  9. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/acp_bridge.py +80 -3
  10. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/control_endpoint.py +13 -3
  11. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/web_cli.py +38 -27
  12. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agent.py +27 -3
  13. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agent_profiles.py +7 -1
  14. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agents/acp_engine.py +5 -0
  15. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agents/agent.py +93 -28
  16. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agents/delegate_shims.py +60 -0
  17. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agents/engine_pidfile.py +29 -8
  18. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agents/external_cli.py +99 -0
  19. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agents/local_llm.py +275 -8
  20. rtxclaw-0.7.4/src/rtxclaw_core/builtin_skills/skill-builder/SKILL.md +135 -0
  21. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/command_runtime.py +2 -2
  22. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/continuation.py +28 -1
  23. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/goal_registry.py +4 -4
  24. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/goal_service.py +2 -2
  25. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/goal_supervisor.py +0 -5
  26. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/metrics_format.py +17 -0
  27. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/session_index.py +62 -11
  28. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/session_reader.py +16 -3
  29. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/skills.py +8 -0
  30. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/sqlite_facts.py +2 -2
  31. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/tools/registry.py +23 -0
  32. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/tools/runners.py +34 -0
  33. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/turn_runtime.py +2 -1
  34. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/usage_ledger.py +15 -0
  35. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/usage_pricing.py +27 -8
  36. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_realtime/server.py +17 -3
  37. rtxclaw-0.7.4/src/rtxclaw_web/README.md +72 -0
  38. rtxclaw-0.7.4/src/rtxclaw_web/__init__.py +21 -0
  39. rtxclaw-0.7.4/src/rtxclaw_web/__main__.py +6 -0
  40. rtxclaw-0.7.4/src/rtxclaw_web/server.py +2625 -0
  41. rtxclaw-0.7.4/src/rtxclaw_web/static/agent_mon_mini.js +237 -0
  42. rtxclaw-0.7.4/src/rtxclaw_web/static/agents.css +543 -0
  43. rtxclaw-0.7.4/src/rtxclaw_web/static/agents.js +799 -0
  44. rtxclaw-0.7.4/src/rtxclaw_web/static/app.js +7225 -0
  45. rtxclaw-0.7.4/src/rtxclaw_web/static/favicon.svg +8 -0
  46. rtxclaw-0.7.4/src/rtxclaw_web/static/goals.css +573 -0
  47. rtxclaw-0.7.4/src/rtxclaw_web/static/goals.js +571 -0
  48. rtxclaw-0.7.4/src/rtxclaw_web/static/models/embedding_model.onnx +0 -0
  49. rtxclaw-0.7.4/src/rtxclaw_web/static/models/hey_jarvis_v0.1.onnx +0 -0
  50. rtxclaw-0.7.4/src/rtxclaw_web/static/models/melspectrogram.onnx +0 -0
  51. rtxclaw-0.7.4/src/rtxclaw_web/static/models/silero_vad.onnx +0 -0
  52. rtxclaw-0.7.4/src/rtxclaw_web/static/nav.js +139 -0
  53. rtxclaw-0.7.4/src/rtxclaw_web/static/realtime.html +97 -0
  54. rtxclaw-0.7.4/src/rtxclaw_web/static/realtime.js +671 -0
  55. rtxclaw-0.7.4/src/rtxclaw_web/static/style.css +3195 -0
  56. rtxclaw-0.7.4/src/rtxclaw_web/static/topics.css +471 -0
  57. rtxclaw-0.7.4/src/rtxclaw_web/static/topics.js +408 -0
  58. rtxclaw-0.7.4/src/rtxclaw_web/static/vendor/github-dark.min.css +10 -0
  59. rtxclaw-0.7.4/src/rtxclaw_web/static/vendor/highlight.min.js +1213 -0
  60. rtxclaw-0.7.4/src/rtxclaw_web/static/vendor/marked.min.js +69 -0
  61. rtxclaw-0.7.4/src/rtxclaw_web/static/vendor/onnxruntime/ort-wasm-simd-threaded.mjs +68 -0
  62. rtxclaw-0.7.4/src/rtxclaw_web/static/vendor/onnxruntime/ort-wasm-simd-threaded.wasm +0 -0
  63. rtxclaw-0.7.4/src/rtxclaw_web/static/vendor/onnxruntime/ort.wasm.min.js +8 -0
  64. rtxclaw-0.7.4/src/rtxclaw_web/static/vendor/purify.min.js +3 -0
  65. rtxclaw-0.7.4/src/rtxclaw_web/static/wakeword.js +281 -0
  66. rtxclaw-0.7.4/src/rtxclaw_web/templates/_nav.html +35 -0
  67. rtxclaw-0.7.4/src/rtxclaw_web/templates/_nav_items.html +29 -0
  68. rtxclaw-0.7.4/src/rtxclaw_web/templates/agents.html +125 -0
  69. rtxclaw-0.7.4/src/rtxclaw_web/templates/goals.html +109 -0
  70. rtxclaw-0.7.4/src/rtxclaw_web/templates/index.html +348 -0
  71. rtxclaw-0.7.4/src/rtxclaw_web/templates/topics.html +70 -0
  72. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/LICENSE +0 -0
  73. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/README.md +0 -0
  74. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/setup.cfg +0 -0
  75. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/requirements.txt +0 -0
  76. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw.egg-info/dependency_links.txt +0 -0
  77. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_acp/__init__.py +0 -0
  78. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_acp/client/__init__.py +0 -0
  79. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_acp/client/client.py +0 -0
  80. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_acp/client/handlers.py +0 -0
  81. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_acp/client/http_spawn.py +0 -0
  82. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_acp/client/spawn.py +0 -0
  83. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_acp/client/ws_spawn.py +0 -0
  84. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_acp/protocol/__init__.py +0 -0
  85. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_acp/protocol/http.py +0 -0
  86. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_acp/protocol/jsonrpc.py +0 -0
  87. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_acp/protocol/schema.py +0 -0
  88. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_acp/protocol/transport.py +0 -0
  89. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_acp/protocol/ws.py +0 -0
  90. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_acp/server/__init__.py +0 -0
  91. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_acp/server/backend.py +0 -0
  92. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_acp/server/http_server.py +0 -0
  93. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_acp/server/server.py +0 -0
  94. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_acp/server/spawn.py +0 -0
  95. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_acp/server/ws_server.py +0 -0
  96. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/__init__.py +0 -0
  97. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/__main__.py +0 -0
  98. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/acp_stdio_main.py +0 -0
  99. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/agent_cli.py +0 -0
  100. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/cli.py +0 -0
  101. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/config.py +0 -0
  102. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/doctor.py +0 -0
  103. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/gateway.py +0 -0
  104. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/gateway_cli.py +0 -0
  105. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/gitea_issues.py +0 -0
  106. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/heartbeat.py +0 -0
  107. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/kanban_cli.py +0 -0
  108. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/kanban_worker.py +0 -0
  109. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/migrate_layout.py +0 -0
  110. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/openai_endpoint.py +0 -0
  111. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/py.typed +0 -0
  112. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/remote_backend.py +0 -0
  113. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/runtime.py +0 -0
  114. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/self_improver_cli.py +0 -0
  115. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/self_improver_fix.py +0 -0
  116. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/self_improver_incident.py +0 -0
  117. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/self_improver_install.py +0 -0
  118. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/self_improver_ledger.py +0 -0
  119. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/self_improver_meta.py +0 -0
  120. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/self_improver_replay.py +0 -0
  121. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/self_improver_session.py +0 -0
  122. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/self_improver_status.py +0 -0
  123. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/self_improver_supervisor.py +0 -0
  124. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/self_improver_triage.py +0 -0
  125. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/session_live.py +0 -0
  126. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_agent/worker.py +0 -0
  127. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/__init__.py +0 -0
  128. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agents/__init__.py +0 -0
  129. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agents/acp_translation.py +0 -0
  130. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agents/antigravity_engine.py +0 -0
  131. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agents/async_delegate_runner.py +0 -0
  132. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agents/async_jobs.py +0 -0
  133. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agents/claude_engine.py +0 -0
  134. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agents/codex_engine.py +0 -0
  135. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agents/cursor_acp_engine.py +0 -0
  136. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agents/default_scaffolds.py +0 -0
  137. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agents/engine.py +0 -0
  138. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agents/factory.py +0 -0
  139. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agents/gateway_shim.py +0 -0
  140. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agents/model_discovery.py +0 -0
  141. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agents/opencode_acp_engine.py +0 -0
  142. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agents/permissions_integration.py +0 -0
  143. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/agents/session_log.py +0 -0
  144. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/backpressure.py +0 -0
  145. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/builtin_commands/__init__.py +0 -0
  146. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/builtin_commands/goal.md +0 -0
  147. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/builtin_skills/__init__.py +0 -0
  148. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/builtin_skills/config-setup/SKILL.md +0 -0
  149. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/builtin_skills/delegate-strategy/SKILL.md +0 -0
  150. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/builtin_skills/delegation-patterns/SKILL.md +0 -0
  151. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/builtin_skills/nodriver-browser/SKILL.md +0 -0
  152. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/builtin_skills/nodriver-browser/bootstrap.sh +0 -0
  153. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/builtin_skills/nodriver-browser/browser +0 -0
  154. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/builtin_skills/nodriver-browser/scripts/browser.py +0 -0
  155. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/builtin_skills/nodriver-browser/scripts/requirements.txt +0 -0
  156. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/builtin_skills/sglang-install/SKILL.md +0 -0
  157. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/builtin_skills/telegram-render-verify/SKILL.md +0 -0
  158. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/builtin_skills/telegram-render-verify/drive.py +0 -0
  159. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/builtin_skills/telegram-render-verify/spawn_test_bot.sh +0 -0
  160. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/builtin_skills/vast-ai-rent/SKILL.md +0 -0
  161. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/builtin_skills/vllm-install/SKILL.md +0 -0
  162. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/coder_gate/__init__.py +0 -0
  163. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/coder_gate/artifact_store.py +0 -0
  164. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/coder_gate/blast_radius.py +0 -0
  165. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/coder_gate/coder_review.py +0 -0
  166. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/coder_gate/evidence.py +0 -0
  167. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/coder_gate/gate.py +0 -0
  168. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/coder_gate/models.py +0 -0
  169. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/coder_gate/policy.py +0 -0
  170. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/coder_gate/requirement_challenge.py +0 -0
  171. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/coder_gate/requirement_retriever.py +0 -0
  172. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/coder_gate/retry.py +0 -0
  173. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/coder_gate/set_goal.py +0 -0
  174. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/coder_gate/tdd_guard.py +0 -0
  175. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/coder_gate/types.py +0 -0
  176. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/commands.py +0 -0
  177. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/config.py +0 -0
  178. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/context.py +0 -0
  179. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/context_report.py +0 -0
  180. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/cwdutil.py +0 -0
  181. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/delegation_patterns.py +0 -0
  182. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/delivery.py +0 -0
  183. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/errors.py +0 -0
  184. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/event_bus.py +0 -0
  185. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/file_commands.py +0 -0
  186. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/hooks.py +0 -0
  187. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/injection_guard.py +0 -0
  188. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/json_repair.py +0 -0
  189. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/jsonlog.py +0 -0
  190. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/kanban_db.py +0 -0
  191. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/kanban_recovery.py +0 -0
  192. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/kanban_scheduler.py +0 -0
  193. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/layout.py +0 -0
  194. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/local_gpu.py +0 -0
  195. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/models.py +0 -0
  196. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/orchestrator.py +0 -0
  197. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/plan_steps.py +0 -0
  198. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/plugins.py +0 -0
  199. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/profile_agents/build/AGENTS.md +0 -0
  200. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/profile_agents/coder/AGENTS.md +0 -0
  201. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/profile_agents/compaction/AGENTS.md +0 -0
  202. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/profile_agents/explore/AGENTS.md +0 -0
  203. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/profile_agents/general/AGENTS.md +0 -0
  204. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/profile_agents/main/AGENTS.md +0 -0
  205. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/profile_agents/plan/AGENTS.md +0 -0
  206. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/profile_agents/summary/AGENTS.md +0 -0
  207. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/profile_agents/title/AGENTS.md +0 -0
  208. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/provider_presets.py +0 -0
  209. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/providers.py +0 -0
  210. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/provision_worker.py +0 -0
  211. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/restart.py +0 -0
  212. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/sandbox_broker.py +0 -0
  213. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/secrets_scrubber.py +0 -0
  214. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/services.py +0 -0
  215. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/session.py +0 -0
  216. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/session_title.py +0 -0
  217. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/session_writer.py +0 -0
  218. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/skill_index.py +0 -0
  219. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/splitter.py +0 -0
  220. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/subagent_policy.py +0 -0
  221. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/system_prompt.py +0 -0
  222. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/teacher_supervisor.py +0 -0
  223. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/tool_runner.py +0 -0
  224. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/tools/__init__.py +0 -0
  225. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/tools/_log.py +0 -0
  226. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/tools/harness_task_mirror.py +0 -0
  227. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/tools/monitor.py +0 -0
  228. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/tools/permissions.py +0 -0
  229. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/tools/prompt.py +0 -0
  230. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_core/tools/safety.py +0 -0
  231. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_mcp/__init__.py +0 -0
  232. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_mcp/mcp_client.py +0 -0
  233. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_mcp/youtube_mcp_server.py +0 -0
  234. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_memory/__init__.py +0 -0
  235. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_memory/memory_embed.py +0 -0
  236. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_memory/memory_index.py +0 -0
  237. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_memory/memory_manager.py +0 -0
  238. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_memory/memory_primitives.py +0 -0
  239. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_memory/memory_provider.py +0 -0
  240. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_memory/memory_rerank.py +0 -0
  241. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_memory/memory_synth.py +0 -0
  242. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_memory/memory_tools.py +0 -0
  243. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_memory/memory_write.py +0 -0
  244. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_realtime/__init__.py +0 -0
  245. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_realtime/__main__.py +0 -0
  246. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_realtime/audio.py +0 -0
  247. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_realtime/cascade.py +0 -0
  248. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_realtime/config.py +0 -0
  249. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_realtime/endword.py +0 -0
  250. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_realtime/gateway_client.py +0 -0
  251. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_realtime/session.py +0 -0
  252. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_realtime/vad.py +0 -0
  253. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_realtime/wake.py +0 -0
  254. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_telegram/__init__.py +0 -0
  255. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_telegram/bot.py +0 -0
  256. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_telegram/cli.py +0 -0
  257. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_telegram/config.py +0 -0
  258. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_telegram/forum_topics.py +0 -0
  259. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_telegram/py.typed +0 -0
  260. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_telegram/serve_stt.py +0 -0
  261. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_tui/__init__.py +0 -0
  262. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_tui/__main__.py +0 -0
  263. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_tui/agent_client.py +0 -0
  264. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_tui/app.py +0 -0
  265. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_tui/commands.py +0 -0
  266. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_tui/input_hardening.py +0 -0
  267. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_tui/kanban_panel.py +0 -0
  268. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_tui/monitor_view.py +0 -0
  269. {rtxclaw-0.7.2 → rtxclaw-0.7.4}/src/rtxclaw_tui/py.typed +0 -0
@@ -10,16 +10,19 @@ include LICENSE
10
10
  include pyproject.toml
11
11
  include src/requirements.txt
12
12
  recursive-include src/rtxclaw_core/builtin_skills *
13
- # py.typed markers only from the shipping packages under src/ — a bare
14
- # `global-include py.typed` also sweeps the local web/venv tree.
13
+ # The web frontend now ships INSIDE the package tree (src/rtxclaw_web);
14
+ # its templates/static assets are pulled in via package-data, but list
15
+ # them here too so a `--sdist` carries the full asset tree.
16
+ recursive-include src/rtxclaw_web/templates *
17
+ recursive-include src/rtxclaw_web/static *
18
+ # py.typed markers only from the shipping packages under src/.
15
19
  recursive-include src py.typed
16
20
  global-exclude __pycache__/*
17
21
  global-exclude *.py[cod]
18
22
  # Dev-only trees: never ship in the published sdist. They carry no code
19
23
  # the wheel needs (the wheel is only src/rtxclaw_*) and would otherwise
20
- # leak the local virtualenv + test-fixture host paths / LAN topology.
24
+ # leak test-fixture host paths / LAN topology / doc screenshots.
21
25
  prune tests
22
- prune web
23
26
  prune docs
24
27
  prune deploy
25
28
  prune scripts
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rtxclaw
3
- Version: 0.7.2
3
+ Version: 0.7.4
4
4
  Summary: Sovereign-inference TUI chat against an OpenAI-compatible vLLM endpoint.
5
5
  Author: rtxclaw.ai
6
6
  License-Expression: MIT
@@ -35,6 +35,10 @@ Requires-Dist: markitdown-mcp>=0.0.1a3; extra == "full"
35
35
  Requires-Dist: imageio-ffmpeg>=0.5.1; extra == "full"
36
36
  Requires-Dist: yt-dlp>=2024.10.7; extra == "full"
37
37
  Requires-Dist: youtube-transcript-api>=1.0; extra == "full"
38
+ Provides-Extra: web
39
+ Requires-Dist: flask>=3.1.3; extra == "web"
40
+ Requires-Dist: requests>=2.32; extra == "web"
41
+ Requires-Dist: gunicorn>=23.0; extra == "web"
38
42
  Provides-Extra: dev
39
43
  Requires-Dist: pytest>=8.0; extra == "dev"
40
44
  Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
@@ -24,7 +24,7 @@ build-backend = "setuptools.build_meta"
24
24
 
25
25
  [project]
26
26
  name = "rtxclaw"
27
- version = "0.7.2"
27
+ version = "0.7.4"
28
28
  description = "Sovereign-inference TUI chat against an OpenAI-compatible vLLM endpoint."
29
29
  readme = "README.md"
30
30
  requires-python = ">=3.10"
@@ -95,6 +95,16 @@ full = [
95
95
  "yt-dlp>=2024.10.7",
96
96
  "youtube-transcript-api>=1.0",
97
97
  ]
98
+ # Browser chat frontend (rtxclaw_web). The package code + its templates/
99
+ # static asset trees ALWAYS ship in the wheel (see package-data below);
100
+ # this extra only adds the runtime deps needed to actually SERVE it, so a
101
+ # lean `pip install rtxclaw` stays small while `pip install rtxclaw[web]`
102
+ # (or `rtxclaw web start`) can launch the UI with no separate checkout.
103
+ web = [
104
+ "flask>=3.1.3",
105
+ "requests>=2.32",
106
+ "gunicorn>=23.0",
107
+ ]
98
108
  # Test + lint toolchain — mirrors tests/requirements.txt (minus the
99
109
  # `-r ../src/requirements.txt` include, already covered above).
100
110
  dev = [
@@ -117,6 +127,9 @@ dev = [
117
127
  # via `python -m rtxclaw_tui`.
118
128
  [project.scripts]
119
129
  rtxclaw = "rtxclaw_tui.app:main"
130
+ # Browser chat frontend (needs the `[web]` extra installed to run). Also
131
+ # reachable as `python -m rtxclaw_web` and `rtxclaw web start`.
132
+ rtxclaw-web = "rtxclaw_web.server:main"
120
133
 
121
134
  [tool.setuptools]
122
135
  package-dir = { "" = "src" }
@@ -140,3 +153,9 @@ include = ["rtxclaw_*"]
140
153
  "rtxclaw_core.builtin_skills" = ["**/*"]
141
154
  "rtxclaw_core.builtin_commands" = ["**/*"]
142
155
  "rtxclaw_core" = ["profile_agents/**/*.md"]
156
+ # - rtxclaw_web/{templates,static} — Flask resolves them relative to the
157
+ # package dir (server.py builds absolute paths from __file__), so the
158
+ # full asset tree (HTML/CSS/JS + onnxruntime wasm + wakeword models)
159
+ # must ride in the wheel. Screenshots were moved out to docs/ to keep
160
+ # the wheel lean.
161
+ "rtxclaw_web" = ["templates/**/*", "static/**/*", "README.md"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rtxclaw
3
- Version: 0.7.2
3
+ Version: 0.7.4
4
4
  Summary: Sovereign-inference TUI chat against an OpenAI-compatible vLLM endpoint.
5
5
  Author: rtxclaw.ai
6
6
  License-Expression: MIT
@@ -35,6 +35,10 @@ Requires-Dist: markitdown-mcp>=0.0.1a3; extra == "full"
35
35
  Requires-Dist: imageio-ffmpeg>=0.5.1; extra == "full"
36
36
  Requires-Dist: yt-dlp>=2024.10.7; extra == "full"
37
37
  Requires-Dist: youtube-transcript-api>=1.0; extra == "full"
38
+ Provides-Extra: web
39
+ Requires-Dist: flask>=3.1.3; extra == "web"
40
+ Requires-Dist: requests>=2.32; extra == "web"
41
+ Requires-Dist: gunicorn>=23.0; extra == "web"
38
42
  Provides-Extra: dev
39
43
  Requires-Dist: pytest>=8.0; extra == "dev"
40
44
  Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
@@ -152,6 +152,7 @@ src/rtxclaw_core/builtin_skills/nodriver-browser/browser
152
152
  src/rtxclaw_core/builtin_skills/nodriver-browser/scripts/browser.py
153
153
  src/rtxclaw_core/builtin_skills/nodriver-browser/scripts/requirements.txt
154
154
  src/rtxclaw_core/builtin_skills/sglang-install/SKILL.md
155
+ src/rtxclaw_core/builtin_skills/skill-builder/SKILL.md
155
156
  src/rtxclaw_core/builtin_skills/telegram-render-verify/SKILL.md
156
157
  src/rtxclaw_core/builtin_skills/telegram-render-verify/drive.py
157
158
  src/rtxclaw_core/builtin_skills/telegram-render-verify/spawn_test_bot.sh
@@ -228,4 +229,39 @@ src/rtxclaw_tui/commands.py
228
229
  src/rtxclaw_tui/input_hardening.py
229
230
  src/rtxclaw_tui/kanban_panel.py
230
231
  src/rtxclaw_tui/monitor_view.py
231
- src/rtxclaw_tui/py.typed
232
+ src/rtxclaw_tui/py.typed
233
+ src/rtxclaw_web/README.md
234
+ src/rtxclaw_web/__init__.py
235
+ src/rtxclaw_web/__main__.py
236
+ src/rtxclaw_web/server.py
237
+ src/rtxclaw_web/static/agent_mon_mini.js
238
+ src/rtxclaw_web/static/agents.css
239
+ src/rtxclaw_web/static/agents.js
240
+ src/rtxclaw_web/static/app.js
241
+ src/rtxclaw_web/static/favicon.svg
242
+ src/rtxclaw_web/static/goals.css
243
+ src/rtxclaw_web/static/goals.js
244
+ src/rtxclaw_web/static/nav.js
245
+ src/rtxclaw_web/static/realtime.html
246
+ src/rtxclaw_web/static/realtime.js
247
+ src/rtxclaw_web/static/style.css
248
+ src/rtxclaw_web/static/topics.css
249
+ src/rtxclaw_web/static/topics.js
250
+ src/rtxclaw_web/static/wakeword.js
251
+ src/rtxclaw_web/static/models/embedding_model.onnx
252
+ src/rtxclaw_web/static/models/hey_jarvis_v0.1.onnx
253
+ src/rtxclaw_web/static/models/melspectrogram.onnx
254
+ src/rtxclaw_web/static/models/silero_vad.onnx
255
+ src/rtxclaw_web/static/vendor/github-dark.min.css
256
+ src/rtxclaw_web/static/vendor/highlight.min.js
257
+ src/rtxclaw_web/static/vendor/marked.min.js
258
+ src/rtxclaw_web/static/vendor/purify.min.js
259
+ src/rtxclaw_web/static/vendor/onnxruntime/ort-wasm-simd-threaded.mjs
260
+ src/rtxclaw_web/static/vendor/onnxruntime/ort-wasm-simd-threaded.wasm
261
+ src/rtxclaw_web/static/vendor/onnxruntime/ort.wasm.min.js
262
+ src/rtxclaw_web/templates/_nav.html
263
+ src/rtxclaw_web/templates/_nav_items.html
264
+ src/rtxclaw_web/templates/agents.html
265
+ src/rtxclaw_web/templates/goals.html
266
+ src/rtxclaw_web/templates/index.html
267
+ src/rtxclaw_web/templates/topics.html
@@ -1,2 +1,3 @@
1
1
  [console_scripts]
2
2
  rtxclaw = rtxclaw_tui.app:main
3
+ rtxclaw-web = rtxclaw_web.server:main
@@ -27,3 +27,8 @@ markitdown-mcp>=0.0.1a3
27
27
  imageio-ffmpeg>=0.5.1
28
28
  yt-dlp>=2024.10.7
29
29
  youtube-transcript-api>=1.0
30
+
31
+ [web]
32
+ flask>=3.1.3
33
+ requests>=2.32
34
+ gunicorn>=23.0
@@ -6,3 +6,4 @@ rtxclaw_memory
6
6
  rtxclaw_realtime
7
7
  rtxclaw_telegram
8
8
  rtxclaw_tui
9
+ rtxclaw_web
@@ -1085,6 +1085,19 @@ async def _default_run_tool(
1085
1085
  ok, content = await _ask_user_outbound(backend, session_id, call)
1086
1086
  return ok, content, False, False
1087
1087
 
1088
+ # goal_budget runs on the LIVE in-process agent (resume needs the live
1089
+ # supervisor), so it short-circuits the subprocess runner like AskUserQuestion.
1090
+ if call.get("name") == "goal_budget":
1091
+ a = dict(call.get("arguments") or {})
1092
+ try:
1093
+ usd = float(a.get("usd") or 0)
1094
+ except (TypeError, ValueError):
1095
+ return False, "goal_budget: usd must be a number", False, False
1096
+ out = backend.goal_budget(
1097
+ session_id, str(a.get("action") or ""), usd, str(a.get("goal_id") or ""),
1098
+ )
1099
+ return bool(out.get("ok")), str(out.get("message") or ""), False, False
1100
+
1088
1101
  package_parent = str(Path(__file__).resolve().parent.parent)
1089
1102
  env = dict(os.environ)
1090
1103
  existing = env.get("PYTHONPATH", "")
@@ -1227,10 +1240,20 @@ async def _default_run_tool(
1227
1240
  if final is None:
1228
1241
  final = obj
1229
1242
  except asyncio.CancelledError:
1243
+ # SIGKILL the runner's ENTIRE descendant tree, not just the launcher.
1244
+ # A bare ``proc.kill()`` signals only this ``tool_runner`` process; any
1245
+ # subagent / shell it spawned in its OWN session (``start_new_session``
1246
+ # → a different pgid) is left orphaned to init and keeps running. This
1247
+ # is the in-process-cancel twin of ``TurnState.stop(force)`` and
1248
+ # ``_spawn_subagent_runner``'s cancel path — both already whole-tree.
1230
1249
  try:
1231
- proc.kill()
1232
- except ProcessLookupError:
1233
- pass
1250
+ from rtxclaw_core.tools.runners import _kill_tree
1251
+ _kill_tree(proc, signal.SIGKILL)
1252
+ except Exception: # noqa: BLE001
1253
+ try:
1254
+ proc.kill()
1255
+ except ProcessLookupError:
1256
+ pass
1234
1257
  try:
1235
1258
  await proc.wait()
1236
1259
  except Exception: # noqa: BLE001
@@ -2230,6 +2253,39 @@ class CoreBackend:
2230
2253
  return {"ok": False, "message": f"agent unavailable: {exc}"}
2231
2254
  return run_goal_action(agent, goal_id, action)
2232
2255
 
2256
+ def goal_budget(self, session_id: str, action: str, usd: float,
2257
+ goal_id: str = "") -> dict[str, Any]:
2258
+ """Raise or set a goal's cost budget on the LIVE agent.
2259
+
2260
+ Called when the user explicitly authorizes more spend in chat. Uses the
2261
+ in-process agent so ``topup`` → ``resume_goal`` → ``ensure_started``
2262
+ reaches the live supervisor and the paused goal actually resumes.
2263
+ ``action=set`` sets the absolute budget (0 = unbounded); ``action=topup``
2264
+ adds ``usd`` and resumes a goal paused for ``cost_budget_exhausted``.
2265
+ Defaults to the session's active (or ancestor) goal.
2266
+ """
2267
+ from rtxclaw_core.goal_service import set_goal_budget, topup_goal
2268
+ try:
2269
+ agent = self._get_new_agent()
2270
+ except Exception as exc: # noqa: BLE001
2271
+ return {"ok": False, "message": f"agent unavailable: {exc}"}
2272
+ session = self._session_for(session_id)
2273
+ gid = str(goal_id
2274
+ or getattr(session, "cost_ancestor_goal_id", "")
2275
+ or getattr(session, "goal_id", "") or "")
2276
+ if not gid:
2277
+ return {"ok": False, "message": "no active goal to budget"}
2278
+ try:
2279
+ if action == "set":
2280
+ res = set_goal_budget(agent, gid, float(usd))
2281
+ elif action == "topup":
2282
+ res = topup_goal(agent, gid, float(usd), session)
2283
+ else:
2284
+ return {"ok": False, "message": "action must be 'set' or 'topup'"}
2285
+ except Exception as exc: # noqa: BLE001
2286
+ return {"ok": False, "message": f"goal_budget failed: {exc}"}
2287
+ return {"ok": bool(res.ok), "message": res.message}
2288
+
2233
2289
  async def run_command(
2234
2290
  self, session_id: str, text: str, *, frontend: str = "api",
2235
2291
  ) -> Mapping[str, Any]:
@@ -2940,6 +2996,27 @@ class CoreBackend:
2940
2996
  )
2941
2997
  except Exception: # noqa: BLE001
2942
2998
  pass
2999
+ # 1b. SIGKILL the child's engine process subtree from the
3000
+ # DURABLE registry. A subagent (local_llm) turn runs in a
3001
+ # ``tool_runner`` SUBPROCESS that is NOT in this gateway's
3002
+ # in-memory ``_new_backend_active_turns`` map, so step 1 is a
3003
+ # no-op for it — the only thing that reaped its OS process was
3004
+ # the top-level ``_kill_tree`` /proc walk on the aborted turn's
3005
+ # runner. That walk MISSES a grandchild whose own launcher
3006
+ # already died (reparented to init), which is exactly how a
3007
+ # nested ``BatchAgent`` subtree kept running after ``/abort``.
3008
+ # Each subagent records its pid in ``<sid>.engine_pid.json``;
3009
+ # kill that pid + its whole ``/proc`` subtree here so recursive
3010
+ # cancellation walks the parent→child registry instead of
3011
+ # depending on live process ancestry. Downward-only (we only
3012
+ # reached this child via ``parent_session_id``), so the
3013
+ # gateway / orchestrator is never in the kill set. Best-effort.
3014
+ if force_kill:
3015
+ try:
3016
+ from rtxclaw_core.agents import engine_pidfile
3017
+ engine_pidfile.kill_session_engine(sd, str(child_hash))
3018
+ except Exception: # noqa: BLE001
3019
+ pass
2943
3020
  # 2. Close the child's session log (folds it out of live).
2944
3021
  if child_ti is not None:
2945
3022
  try:
@@ -214,7 +214,13 @@ async def _handle_session_history(request: Request) -> Response:
214
214
  jl = sessions_root() / f"{sid}.jsonl"
215
215
  if not jl.exists():
216
216
  return None
217
- d = load_session_dict(sessions_root(), sid)
217
+ # ``fold=False``: the header (sessions.db row) is all we need from
218
+ # load_session_dict — ``scan_history_with_offsets`` below already folds
219
+ # the log ONCE for the history + tail offset, and yields the turns we
220
+ # read the last-turn model from. Folding the whole file a second time
221
+ # here (the old default) doubled the O(file) cost of opening a large
222
+ # conversation from the sidebar / agent monitor.
223
+ d = load_session_dict(sessions_root(), sid, fold=False)
218
224
  turns, tail_offset, active = scan_history_with_offsets(jl)
219
225
  return d, turns, tail_offset, active
220
226
 
@@ -225,7 +231,11 @@ async def _handle_session_history(request: Request) -> Response:
225
231
  if loaded is None:
226
232
  return _error(f"session not found: {sid}", "not_found", 404)
227
233
  d, turns, tail_offset, active = loaded
228
- all_turns = d.get("turns") or []
234
+ # The engine-model badge: prefer the most recent COMPLETED turn's model
235
+ # (from the single scan-fold). An in-flight turn is excluded from ``turns``
236
+ # by design, so fall back to the session header's model when no completed
237
+ # turn carries one yet (the live stream then refines the badge anyway).
238
+ engine_model = _last_turn_model(turns) or (d.get("model") or "")
229
239
  return JSONResponse({
230
240
  "ok": True,
231
241
  "hash": d.get("hash") or sid,
@@ -233,7 +243,7 @@ async def _handle_session_history(request: Request) -> Response:
233
243
  "title": d.get("title") or "",
234
244
  "engine": d.get("engine") or "",
235
245
  "model": d.get("model") or "",
236
- "engine_model": _last_turn_model(all_turns),
246
+ "engine_model": engine_model,
237
247
  "updated_at": d.get("last_turn_ts") or d.get("updated_at") or "",
238
248
  "messages": _fold_turns_to_messages(turns),
239
249
  "tail_offset": tail_offset,
@@ -1,10 +1,10 @@
1
1
  """``rtxclaw web`` — lifecycle for the localhost web frontend.
2
2
 
3
3
  Mirrors ``rtxclaw gateway`` / ``rtxclaw telegram``: a daemon-control CLI for
4
- the Flask web server at ``<repo>/web/server.py`` (the browser frontend that
5
- renders the shared command runtime — see ``web/README.md``). Subcommands:
4
+ the Flask web server bundled as ``rtxclaw_web`` (the browser frontend that
5
+ renders the shared command runtime — see ``rtxclaw_web/README.md``). Subcommands:
6
6
 
7
- rtxclaw web start # daemonize web/server.py (pidfile + log)
7
+ rtxclaw web start # daemonize rtxclaw_web.server (pidfile + log)
8
8
  rtxclaw web stop # SIGTERM the daemon
9
9
  rtxclaw web restart # stop + start
10
10
  rtxclaw web status # pid / uptime / url
@@ -46,17 +46,22 @@ def _rtxclaw_home() -> Path:
46
46
 
47
47
 
48
48
  def _web_dir() -> Path:
49
- """Locate the repo's ``web/`` directory (holds ``server.py``).
49
+ """Locate the packaged web dir (holds ``server.py`` + assets).
50
50
 
51
- ``$RTXCLAW_WEB_DIR`` overrides; otherwise resolve relative to this
52
- module (editable install: ``<repo>/src/rtxclaw_agent/web_cli.py``
53
- ``<repo>/web``). Raising here with a clear message beats a cryptic
54
- FileNotFound deep in Popen.
51
+ ``$RTXCLAW_WEB_DIR`` overrides; otherwise resolve the installed
52
+ ``rtxclaw_web`` package location. Works identically for an installed
53
+ wheel (site-packages/rtxclaw_web) and an editable checkout
54
+ (``<repo>/src/rtxclaw_web``). Raising here with a clear message beats
55
+ a cryptic FileNotFound deep in Popen.
55
56
  """
56
57
  env = os.environ.get("RTXCLAW_WEB_DIR")
57
58
  if env:
58
59
  return Path(env).expanduser()
59
- return Path(__file__).resolve().parents[2] / "web"
60
+ try:
61
+ import rtxclaw_web
62
+ return Path(rtxclaw_web.__file__).resolve().parent
63
+ except Exception: # noqa: BLE001 — fall back to the source-tree layout
64
+ return Path(__file__).resolve().parents[1] / "rtxclaw_web"
60
65
 
61
66
 
62
67
  def _server_py() -> Path:
@@ -124,25 +129,31 @@ def _ensure_web_secret() -> str:
124
129
 
125
130
 
126
131
  def _web_python() -> Path:
127
- """Interpreter that can run the Flask server (flask + requests).
132
+ """Interpreter that can run the Flask server (flask + requests + gunicorn).
133
+
134
+ Now that ``rtxclaw_web`` ships inside the wheel, the web deps live in
135
+ the ``[web]`` extra (``pip install rtxclaw[web]``) and run under the
136
+ SAME interpreter as the gateway — no separate ``web/venv``. Prefer the
137
+ current interpreter when the web deps import; otherwise fall back to a
138
+ legacy ``web/venv`` if one exists (older source checkouts), and finally
139
+ to ``sys.executable`` so the caller sees a clear ImportError rather than
140
+ a silent misconfiguration.
128
141
 
129
- Prefers the web's own venv (``web/venv`` the README pattern); if
130
- missing, bootstraps it once (``python -m venv`` + ``pip install -r
131
- web/requirements.txt``). Keeps the web deps isolated from the
132
- gateway venv exactly as the standalone server intends.
142
+ ``$RTXCLAW_WEB_PYTHON`` overrides everything.
133
143
  """
134
- web_dir = _web_dir()
135
- venv_py = web_dir / "venv" / "bin" / "python"
136
- if venv_py.exists():
137
- return venv_py
138
- # Bootstrap the isolated web venv (first run only).
139
- subprocess.run([sys.executable, "-m", "venv", str(web_dir / "venv")],
140
- check=True, capture_output=True)
141
- req = web_dir / "requirements.txt"
142
- if req.exists():
143
- subprocess.run([str(venv_py), "-m", "pip", "install", "-q", "-r", str(req)],
144
- check=True)
145
- return venv_py
144
+ override = os.environ.get("RTXCLAW_WEB_PYTHON")
145
+ if override:
146
+ return Path(override).expanduser()
147
+ try:
148
+ import flask # noqa: F401
149
+ import requests # noqa: F401
150
+ import gunicorn # noqa: F401
151
+ return Path(sys.executable)
152
+ except Exception: # noqa: BLE001 — deps not in the current interpreter
153
+ legacy_venv = _web_dir() / "venv" / "bin" / "python"
154
+ if legacy_venv.exists():
155
+ return legacy_venv
156
+ return Path(sys.executable)
146
157
 
147
158
 
148
159
  def _web_env(*, debug: bool = False) -> dict:
@@ -218,7 +229,7 @@ def _wait_for_listener(host: str, port: int, *, timeout: float = 15.0) -> bool:
218
229
  # ---- start / stop -----------------------------------------------------
219
230
 
220
231
  def start_web_background(*, debug: bool = False) -> dict:
221
- """Daemonize ``web/server.py``. Returns a result dict (no stdout).
232
+ """Daemonize the packaged ``rtxclaw_web`` server. Returns a result dict (no stdout).
222
233
 
223
234
  ``debug=True`` runs the server with ``RTXCLAW_WEB_DEBUG=1`` (auth
224
235
  skipped)."""
@@ -388,6 +388,23 @@ def _prune_global_config_backups(p: Path, *, keep: int) -> None:
388
388
  pass
389
389
 
390
390
 
391
+ def _env_float(name: str, default: float) -> float:
392
+ """Float from env ``name``, falling back to ``default`` when unset/blank/bad.
393
+
394
+ Lets operators override cost-budget defaults without editing a config:
395
+ e.g. ``RTXCLAW_MAX_GOAL_COST_USD=100 RTXCLAW_MAX_PROMPT_COST_USD=25``.
396
+ A per-agent ``config.json`` value still wins (it's an explicit field);
397
+ this only changes the DEFAULT applied when the field is unset.
398
+ """
399
+ raw = os.environ.get(name, "")
400
+ if raw is None or str(raw).strip() == "":
401
+ return default
402
+ try:
403
+ return float(raw)
404
+ except (TypeError, ValueError):
405
+ return default
406
+
407
+
391
408
  @dataclass
392
409
  class AgentConfig:
393
410
  """Settings for one rtxclaw agent.
@@ -458,14 +475,21 @@ class AgentConfig:
458
475
  # Outer /goal turn budget surfaced on /status (global config may override).
459
476
  # Retained for display/back-compat; the loop terminator is now the goal
460
477
  # COST budget below, not this turn cap.
461
- max_goal_turns: int = 100
478
+ max_goal_turns: int = 0 # 0 == unbounded; cost is the only limit on goal work
462
479
  # Outer /goal COST budget (USD). The loop re-drives until the goal's
463
480
  # accumulated spend (usage-ledger SUM) reaches this, or the goal is
464
- # met/blocked. 0 == unbounded. Default $5.00.
465
- max_goal_cost_usd: float = 5.0
481
+ # met/blocked. 0 == unbounded. Default $50.00 (override:
482
+ # $RTXCLAW_MAX_GOAL_COST_USD).
483
+ max_goal_cost_usd: float = field(
484
+ default_factory=lambda: _env_float("RTXCLAW_MAX_GOAL_COST_USD", 50.0))
466
485
  # Per-session COST cap (USD). 0 == unbounded. New auto-turns are refused
467
486
  # once the session's accumulated spend crosses this.
468
487
  max_session_cost_usd: float = 0.0
488
+ # Per-PROMPT COST cap (USD) for non-goal interactive turns. 0 == unbounded.
489
+ # A single user prompt's spend is bounded here; goal turns use the goal
490
+ # budget, never this. Default $10.00 (override: $RTXCLAW_MAX_PROMPT_COST_USD).
491
+ max_prompt_cost_usd: float = field(
492
+ default_factory=lambda: _env_float("RTXCLAW_MAX_PROMPT_COST_USD", 10.0))
469
493
  # Override path for the per-model pricing table; "" == ~/.rtxclaw/pricing.json.
470
494
  pricing_path: str = ""
471
495
  goal_outer_loop_enabled: bool = True
@@ -373,10 +373,16 @@ def compose_tool_allowlist(cfg: object) -> set[str] | None:
373
373
  if strict:
374
374
  allowed = set(wl or [])
375
375
  else:
376
- from rtxclaw_core.tools.registry import BUILTIN_TOOLS, ToolRegistry
376
+ from rtxclaw_core.tools.registry import (
377
+ BUILTIN_TOOLS,
378
+ ToolRegistry,
379
+ discovered_mcp_tools_sync,
380
+ )
377
381
 
378
382
  registry = ToolRegistry(BUILTIN_TOOLS)
379
383
  allowed = {t.name for t in registry.core_tools()}
384
+ for mcp_tool in discovered_mcp_tools_sync():
385
+ allowed.add(mcp_tool.name)
380
386
  if wl:
381
387
  allowed |= set(wl)
382
388
  disabled = getattr(cfg, "disabled_tools", None) or []
@@ -688,6 +688,11 @@ class AcpEngine(Engine):
688
688
  "prompt_tokens": used,
689
689
  "completion_tokens": ct,
690
690
  "tokens_estimated": estimated,
691
+ # Tag the provider (the ACP agent label, e.g. "cursor") so the
692
+ # pricing table resolves this delegate's cost to that provider's
693
+ # rate instead of the generic default. ``used`` is the real
694
+ # PromptResponse.usage count when the server reported it.
695
+ "provider": (self._name or "").lower(),
691
696
  }
692
697
  if window:
693
698
  raw["context_window"] = window