steerable-agent-runtime 0.6.61__tar.gz → 0.6.63__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 (163) hide show
  1. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/PKG-INFO +1 -1
  2. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/pyproject.toml +1 -1
  3. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/approval.py +47 -10
  4. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/history.py +1 -2
  5. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/llm/parts.py +1 -1
  6. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/mcp.py +1 -1
  7. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/recording.py +3 -4
  8. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/tool_search.py +2 -2
  9. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime.egg-info/PKG-INFO +1 -1
  10. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_approval.py +72 -0
  11. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/README.md +0 -0
  12. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/setup.cfg +0 -0
  13. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/__init__.py +0 -0
  14. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/antihallucination.py +0 -0
  15. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/approval_policy.py +0 -0
  16. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/ask_user.py +0 -0
  17. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/branch.py +0 -0
  18. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/cache_control.py +0 -0
  19. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/calibration.py +0 -0
  20. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/compaction.py +0 -0
  21. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/compaction_policy.py +0 -0
  22. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/config.py +0 -0
  23. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/default.harness.json +0 -0
  24. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/default.harness.yaml +0 -0
  25. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/delegation_gate.py +0 -0
  26. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/errors.py +0 -0
  27. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/gateway_catalog.py +0 -0
  28. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/handoff.py +0 -0
  29. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/harness.py +0 -0
  30. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/harness_spec.py +0 -0
  31. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/hooks.py +0 -0
  32. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/llm/__init__.py +0 -0
  33. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/llm/anthropic_native.py +0 -0
  34. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/llm/compat.py +0 -0
  35. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/llm/errors.py +0 -0
  36. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/llm/google_genai.py +0 -0
  37. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/llm/openai_compat.py +0 -0
  38. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/llm/openai_responses.py +0 -0
  39. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/llm/presets.py +0 -0
  40. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/llm/system_proxy.py +0 -0
  41. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/loop.py +0 -0
  42. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/maintenance.py +0 -0
  43. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/mcp_server.py +0 -0
  44. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/model_catalog.py +0 -0
  45. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/model_info.py +0 -0
  46. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/model_resolve.py +0 -0
  47. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/native_bridge.py +0 -0
  48. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/observation_aging.py +0 -0
  49. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/orchestration.py +0 -0
  50. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/otel.py +0 -0
  51. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/plugins.py +0 -0
  52. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/pool.py +0 -0
  53. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/pricing.py +0 -0
  54. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/pseudo.py +0 -0
  55. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/reminders.py +0 -0
  56. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/replay.py +0 -0
  57. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/resume.py +0 -0
  58. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/retry.py +0 -0
  59. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/sandboxed.py +0 -0
  60. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/skills.py +0 -0
  61. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/spill.py +0 -0
  62. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/storage/__init__.py +0 -0
  63. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/storage/in_memory.py +0 -0
  64. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/storage/sqlalchemy_store.py +0 -0
  65. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/storage/sqlite_store.py +0 -0
  66. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/storage/write_lease.py +0 -0
  67. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/subagent.py +0 -0
  68. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/todo.py +0 -0
  69. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/tokens.py +0 -0
  70. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/tool_presentation.py +0 -0
  71. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/tool_schema.py +0 -0
  72. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/tools.py +0 -0
  73. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/tracing.py +0 -0
  74. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/transport/__init__.py +0 -0
  75. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/transport/fastapi_sse.py +0 -0
  76. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/transport/stdio_jsonrpc.py +0 -0
  77. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime/world_state.py +0 -0
  78. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime.egg-info/SOURCES.txt +0 -0
  79. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime.egg-info/dependency_links.txt +0 -0
  80. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime.egg-info/requires.txt +0 -0
  81. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/src/steerable_agent_runtime.egg-info/top_level.txt +0 -0
  82. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_antihallucination.py +0 -0
  83. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_approval_policy.py +0 -0
  84. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_ask_user.py +0 -0
  85. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_branch.py +0 -0
  86. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_cache_control.py +0 -0
  87. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_cache_instrumentation.py +0 -0
  88. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_calibration.py +0 -0
  89. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_compaction.py +0 -0
  90. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_compaction_policy.py +0 -0
  91. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_compaction_strategy.py +0 -0
  92. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_config.py +0 -0
  93. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_content_parts.py +0 -0
  94. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_delegation_gate.py +0 -0
  95. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_error_taxonomy.py +0 -0
  96. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_fragment_bounds.py +0 -0
  97. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_gateway_catalog.py +0 -0
  98. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_golden.py +0 -0
  99. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_handoff.py +0 -0
  100. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_harness.py +0 -0
  101. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_harness_spec.py +0 -0
  102. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_history.py +0 -0
  103. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_history_persistence.py +0 -0
  104. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_hooks.py +0 -0
  105. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_in_memory_storage.py +0 -0
  106. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_llm_gemini_wire.py +0 -0
  107. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_llm_responses_wire.py +0 -0
  108. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_llm_stream_e2e.py +0 -0
  109. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_llm_wire_helpers.py +0 -0
  110. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_long_session.py +0 -0
  111. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_loop.py +0 -0
  112. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_loop_cancellation.py +0 -0
  113. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_loop_replay.py +0 -0
  114. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_loop_sandbox_event.py +0 -0
  115. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_loop_terminal.py +0 -0
  116. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_maintenance.py +0 -0
  117. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_mcp.py +0 -0
  118. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_mcp_server.py +0 -0
  119. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_model_catalog.py +0 -0
  120. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_model_equivalence.py +0 -0
  121. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_model_info.py +0 -0
  122. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_model_resolve.py +0 -0
  123. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_native_default.py +0 -0
  124. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_observation_aging.py +0 -0
  125. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_orchestration.py +0 -0
  126. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_otel.py +0 -0
  127. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_parallel_tools.py +0 -0
  128. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_plugins.py +0 -0
  129. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_provider_compat.py +0 -0
  130. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_provider_presets.py +0 -0
  131. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_pseudo.py +0 -0
  132. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_pyo3_api_surface.py +0 -0
  133. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_recording.py +0 -0
  134. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_reminders.py +0 -0
  135. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_replay_crosslang.py +0 -0
  136. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_resume.py +0 -0
  137. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_retry_hooks.py +0 -0
  138. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_safety_gate.py +0 -0
  139. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_sandboxed.py +0 -0
  140. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_skills.py +0 -0
  141. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_soft_timeout.py +0 -0
  142. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_spill.py +0 -0
  143. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_sqlite_storage.py +0 -0
  144. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_steer.py +0 -0
  145. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_storage_contract.py +0 -0
  146. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_stream_strip.py +0 -0
  147. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_subagent.py +0 -0
  148. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_system_proxy.py +0 -0
  149. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_todo.py +0 -0
  150. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_todo_gate.py +0 -0
  151. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_tokens.py +0 -0
  152. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_tool_exposure.py +0 -0
  153. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_tool_hygiene.py +0 -0
  154. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_tool_presentation.py +0 -0
  155. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_tool_router.py +0 -0
  156. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_tool_schema.py +0 -0
  157. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_tool_timeout.py +0 -0
  158. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_trace_recorder.py +0 -0
  159. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_transport_jsonrpc.py +0 -0
  160. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_transport_sse.py +0 -0
  161. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_usage_attribution.py +0 -0
  162. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_world_state.py +0 -0
  163. {steerable_agent_runtime-0.6.61 → steerable_agent_runtime-0.6.63}/tests/test_write_lease.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: steerable-agent-runtime
3
- Version: 0.6.61
3
+ Version: 0.6.63
4
4
  Summary: Steerable agent runtime: LLM, tool, storage, and transport adapters.
5
5
  License: Apache-2.0
6
6
  Requires-Python: >=3.10
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "steerable-agent-runtime"
3
- version = "0.6.61"
3
+ version = "0.6.63"
4
4
  description = "Steerable agent runtime: LLM, tool, storage, and transport adapters."
5
5
  license = { text = "Apache-2.0" }
6
6
  readme = "README.md"
@@ -38,6 +38,7 @@ from steerable_agent_harness.policy import ToolMode, decide_tool_mode
38
38
  from steerable_agent_protocol.generated import ToolCall, ToolResult
39
39
 
40
40
  from .errors import ApprovalAborted
41
+ from .sandboxed import DEFAULT_SHELL_TOOLS
41
42
 
42
43
  if TYPE_CHECKING:
43
44
  from .loop import LoopContext, ToolExecutor
@@ -142,9 +143,9 @@ _PATH_ARG_TOOLS = {
142
143
  def declared_target_paths(request: ApprovalRequest) -> list[str] | None:
143
144
  """Filesystem targets of a path-scoped tool, or None when the call is not one.
144
145
 
145
- ``None`` means the approver cannot prove the call stays inside the
146
- project, so the interactive prompt still runs. Shell commands stay in
147
- that bucket: the command text can name paths the cwd does not.
146
+ ``None`` means this approver cannot prove the call from its path
147
+ arguments. Shell commands are judged separately, from the sandbox and
148
+ the working directory, not from the command text.
148
149
  """
149
150
  if request.tool_name == "present_files":
150
151
  files = request.arguments.get("files")
@@ -192,20 +193,54 @@ def path_inside_writable_roots(raw: str, roots: list[str]) -> bool:
192
193
  return False
193
194
 
194
195
 
195
- class WorkspaceAutoApprover:
196
- """Skip the host prompt when every declared path is already inside a writable root.
196
+ def shell_stays_in_workspace(request: ApprovalRequest, roots: list[str]) -> bool:
197
+ """True when a shell call's working directory is inside a writable root.
198
+
199
+ The command text is not parsed. Confinement is the OS sandbox's job:
200
+ writes outside the roots fail there. An omitted cwd uses the host's
201
+ project directory. An explicit cwd outside the roots, or one that
202
+ climbs out with ``..``, still needs a prompt.
203
+ """
204
+ if request.tool_name not in DEFAULT_SHELL_TOOLS or not roots:
205
+ return False
206
+ cwd = request.arguments.get("cwd")
207
+ if cwd is None:
208
+ return True
209
+ if not isinstance(cwd, str) or not cwd.strip():
210
+ return True
211
+ return path_inside_writable_roots(cwd, roots)
197
212
 
198
- The allow is request-scoped. The next call is judged again, so an
199
- in-project ``present_files`` does not grant the same tool outside the
200
- project. Calls with no path we can check, or any path outside the roots,
201
- fall through to the inner approver.
213
+
214
+ class WorkspaceAutoApprover:
215
+ """Skip the host prompt for work the workspace sandbox already confines.
216
+
217
+ Embedders may also name host-owned control tools whose effects are limited
218
+ to internal session state and therefore need no interactive consent.
219
+ Path-scoped tools (``local_write_file``, ``local_edit_file``, reads,
220
+ ``present_files``) skip when every declared path is inside a writable
221
+ root. Shell tools skip only when the OS exec sandbox is on and the
222
+ working directory is inside those roots — the same split Codex uses
223
+ between ``workspace-write`` and ``on-request``. The allow is
224
+ request-scoped. The next call is judged again. Anything else falls
225
+ through to the inner approver.
202
226
  """
203
227
 
204
- def __init__(self, inner: Approver, writable_roots: list[str]) -> None:
228
+ def __init__(
229
+ self,
230
+ inner: Approver,
231
+ writable_roots: list[str],
232
+ *,
233
+ sandbox_enforced: bool = False,
234
+ auto_allow_tools: tuple[str, ...] = (),
235
+ ) -> None:
205
236
  self._inner = inner
206
237
  self._roots = [root for root in writable_roots if isinstance(root, str) and root.strip()]
238
+ self._sandbox_enforced = sandbox_enforced
239
+ self._auto_allow_tools = frozenset(auto_allow_tools)
207
240
 
208
241
  async def approve(self, request: ApprovalRequest) -> ApprovalDecision:
242
+ if request.tool_name in self._auto_allow_tools:
243
+ return ApprovalDecision("allow_once", "trusted host control tool")
209
244
  paths = declared_target_paths(request)
210
245
  if (
211
246
  self._roots
@@ -213,6 +248,8 @@ class WorkspaceAutoApprover:
213
248
  and all(path_inside_writable_roots(path, self._roots) for path in paths)
214
249
  ):
215
250
  return ApprovalDecision("allow_once", "path is inside a writable project root")
251
+ if self._sandbox_enforced and shell_stays_in_workspace(request, self._roots):
252
+ return ApprovalDecision("allow_once", "command stays inside the workspace sandbox")
216
253
  return await self._inner.approve(request)
217
254
 
218
255
 
@@ -1,7 +1,6 @@
1
1
  """Typed append-only history — the model-visible record and its projection.
2
2
 
3
- Wave 1 foundation (docs/roadmap.md "Wave 1 — the foundation"): the
4
- model-visible transcript becomes a *projection* of a typed, append-only
3
+ The model-visible transcript is a *projection* of a typed, append-only
5
4
  record instead of a mutable ``list[LLMMessage]`` that hooks rewrite in
6
5
  place.
7
6
 
@@ -1,6 +1,6 @@
1
1
  """Content parts — the structured form of ``LLMMessage.content``.
2
2
 
3
- Wave 1 (docs/roadmap.md "Wave 1 — the foundation"): message content is a
3
+ Message content is a
4
4
  list of typed parts instead of a bare string, unblocking multimodal input,
5
5
  structured output, and (Wave 2) per-block cache annotations.
6
6
 
@@ -19,7 +19,7 @@ caps.
19
19
  finds them through the ``tool_search`` seam instead of paying for every
20
20
  schema in every request. Hosts pin favorites with ``exposure="direct"``.
21
21
 
22
- Architecture (recorded in docs/roadmap.md): in the desktop product, MCP
22
+ In the desktop product, MCP
23
23
  servers are launched host-side (Electron main) and reached through
24
24
  `ToolRouter.register_remote` — a Seatbelt-confined sidecar never spawns
25
25
  them. `McpStdioClient` and `McpStreamableHttpClient` exist for hosts that
@@ -1,10 +1,9 @@
1
1
  """RecordingProvider — capture every outbound LLM request, plus the
2
2
  prompt-invariant assertions built on the recording.
3
3
 
4
- Wave 0 tripwire (docs/roadmap.md "Wave 0 — prerequisites"): Wave 1 rewrites
5
- history into typed append-only envelopes, and without a recording of what the
6
- model actually saw, a correct rewrite can silently regress. This module closes
7
- that gap:
4
+ Wave 1 rewrites history into typed append-only envelopes. Without a
5
+ recording of what the model actually saw, a correct rewrite can silently
6
+ regress. This module closes that gap:
8
7
 
9
8
  - ``RecordingProvider`` wraps any ``LLMProvider`` and snapshots every outbound
10
9
  request (messages + params) into a sink *before* delegating, so a failed
@@ -26,8 +26,8 @@ from .tools import RegisteredTool, ToolRouter
26
26
 
27
27
  TOOL_SEARCH_NAME = "tool_search"
28
28
 
29
- #: Default matches per call. 8 matches codex's tool_discovery cap
30
- #: (docs/roadmap.md's tier comparison); the per-call ceiling below bounds
29
+ #: Default matches per call. 8 matches codex's tool_discovery cap.
30
+ #: The per-call ceiling below bounds
31
31
  #: the schema payload regardless of what a call requests.
32
32
  DEFAULT_MAX_RESULTS = 8
33
33
  #: Hard ceiling per call: every match carries a full schema, so an
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: steerable-agent-runtime
3
- Version: 0.6.61
3
+ Version: 0.6.63
4
4
  Summary: Steerable agent runtime: LLM, tool, storage, and transport adapters.
5
5
  License: Apache-2.0
6
6
  Requires-Python: >=3.10
@@ -512,6 +512,25 @@ async def test_workspace_auto_approver_allows_paths_inside_writable_roots(tmp_pa
512
512
  assert inner.requests == []
513
513
 
514
514
 
515
+ @pytest.mark.asyncio
516
+ async def test_workspace_auto_approver_allows_named_host_control_tools() -> None:
517
+ from steerable_agent_runtime.approval import WorkspaceAutoApprover
518
+
519
+ inner = _ScriptedApprover([ApprovalDecision("deny_once", "should not ask")])
520
+ approver = WorkspaceAutoApprover(
521
+ inner,
522
+ [],
523
+ auto_allow_tools=("update_goal", "loop_stop"),
524
+ )
525
+
526
+ goal = await approver.approve(_request("update_goal", {"action": "complete"}))
527
+ loop = await approver.approve(_request("loop_stop", {"id": "loop-1"}))
528
+
529
+ assert goal.kind == "allow_once"
530
+ assert loop.kind == "allow_once"
531
+ assert inner.requests == []
532
+
533
+
515
534
  @pytest.mark.asyncio
516
535
  async def test_workspace_auto_approver_asks_when_a_path_leaves_the_project(tmp_path) -> None:
517
536
  from steerable_agent_runtime.approval import WorkspaceAutoApprover
@@ -569,3 +588,56 @@ async def test_workspace_auto_approver_does_not_cache_the_tool_name(tmp_path) ->
569
588
  assert inside.kind == "allow_once"
570
589
  assert outside.kind == "deny_once"
571
590
  assert len(inner.requests) == 1
591
+
592
+
593
+ @pytest.mark.asyncio
594
+ async def test_workspace_auto_approver_allows_sandboxed_shell_inside_writable_roots(tmp_path) -> None:
595
+ from steerable_agent_runtime.approval import WorkspaceAutoApprover
596
+
597
+ project = tmp_path / "111-2"
598
+ project.mkdir()
599
+ source = tmp_path / "sources"
600
+ source.mkdir()
601
+ inner = _ScriptedApprover([ApprovalDecision("deny_once", "should not ask")])
602
+ approver = WorkspaceAutoApprover(inner, [str(project), str(source)], sandbox_enforced=True)
603
+
604
+ omitted = await approver.approve(_request("local_exec_shell", {"command": "mkdir notes"}))
605
+ nested = await approver.approve(
606
+ _request("local_exec_shell", {"command": "touch a.md", "cwd": str(project / "notes")})
607
+ )
608
+ linked = await approver.approve(
609
+ _request("bash", {"command": "ls", "cwd": str(source / "raw")})
610
+ )
611
+ relative = await approver.approve(
612
+ _request("shell", {"command": "pwd", "cwd": "subdir"})
613
+ )
614
+
615
+ assert omitted.kind == "allow_once"
616
+ assert nested.kind == "allow_once"
617
+ assert linked.kind == "allow_once"
618
+ assert relative.kind == "allow_once"
619
+ assert inner.requests == []
620
+
621
+
622
+ @pytest.mark.asyncio
623
+ async def test_workspace_auto_approver_asks_for_shell_that_leaves_the_sandbox(tmp_path) -> None:
624
+ from steerable_agent_runtime.approval import WorkspaceAutoApprover
625
+
626
+ project = tmp_path / "111-2"
627
+ project.mkdir()
628
+ inner = _ScriptedApprover([ApprovalDecision("allow_once", "user allowed")] * 3)
629
+ confined = WorkspaceAutoApprover(inner, [str(project)], sandbox_enforced=True)
630
+ open_sandbox = WorkspaceAutoApprover(inner, [str(project)], sandbox_enforced=False)
631
+
632
+ outside = await confined.approve(
633
+ _request("local_exec_shell", {"command": "ls", "cwd": str(tmp_path / "other")})
634
+ )
635
+ climbed = await confined.approve(
636
+ _request("local_exec_shell", {"command": "ls", "cwd": "../outside"})
637
+ )
638
+ unsandboxed = await open_sandbox.approve(
639
+ _request("local_exec_shell", {"command": "ls", "cwd": str(project)})
640
+ )
641
+
642
+ assert [item.kind for item in (outside, climbed, unsandboxed)] == ["allow_once"] * 3
643
+ assert [item.tool_name for item in inner.requests] == ["local_exec_shell"] * 3