steerable-agent-runtime 0.6.60__tar.gz → 0.6.62__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.60 → steerable_agent_runtime-0.6.62}/PKG-INFO +1 -1
  2. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/pyproject.toml +1 -1
  3. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/approval.py +41 -10
  4. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime.egg-info/PKG-INFO +1 -1
  5. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_approval.py +53 -0
  6. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/README.md +0 -0
  7. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/setup.cfg +0 -0
  8. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/__init__.py +0 -0
  9. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/antihallucination.py +0 -0
  10. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/approval_policy.py +0 -0
  11. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/ask_user.py +0 -0
  12. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/branch.py +0 -0
  13. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/cache_control.py +0 -0
  14. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/calibration.py +0 -0
  15. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/compaction.py +0 -0
  16. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/compaction_policy.py +0 -0
  17. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/config.py +0 -0
  18. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/default.harness.json +0 -0
  19. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/default.harness.yaml +0 -0
  20. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/delegation_gate.py +0 -0
  21. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/errors.py +0 -0
  22. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/gateway_catalog.py +0 -0
  23. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/handoff.py +0 -0
  24. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/harness.py +0 -0
  25. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/harness_spec.py +0 -0
  26. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/history.py +0 -0
  27. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/hooks.py +0 -0
  28. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/llm/__init__.py +0 -0
  29. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/llm/anthropic_native.py +0 -0
  30. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/llm/compat.py +0 -0
  31. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/llm/errors.py +0 -0
  32. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/llm/google_genai.py +0 -0
  33. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/llm/openai_compat.py +0 -0
  34. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/llm/openai_responses.py +0 -0
  35. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/llm/parts.py +0 -0
  36. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/llm/presets.py +0 -0
  37. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/llm/system_proxy.py +0 -0
  38. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/loop.py +0 -0
  39. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/maintenance.py +0 -0
  40. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/mcp.py +0 -0
  41. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/mcp_server.py +0 -0
  42. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/model_catalog.py +0 -0
  43. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/model_info.py +0 -0
  44. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/model_resolve.py +0 -0
  45. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/native_bridge.py +0 -0
  46. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/observation_aging.py +0 -0
  47. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/orchestration.py +0 -0
  48. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/otel.py +0 -0
  49. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/plugins.py +0 -0
  50. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/pool.py +0 -0
  51. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/pricing.py +0 -0
  52. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/pseudo.py +0 -0
  53. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/recording.py +0 -0
  54. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/reminders.py +0 -0
  55. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/replay.py +0 -0
  56. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/resume.py +0 -0
  57. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/retry.py +0 -0
  58. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/sandboxed.py +0 -0
  59. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/skills.py +0 -0
  60. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/spill.py +0 -0
  61. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/storage/__init__.py +0 -0
  62. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/storage/in_memory.py +0 -0
  63. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/storage/sqlalchemy_store.py +0 -0
  64. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/storage/sqlite_store.py +0 -0
  65. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/storage/write_lease.py +0 -0
  66. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/subagent.py +0 -0
  67. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/todo.py +0 -0
  68. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/tokens.py +0 -0
  69. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/tool_presentation.py +0 -0
  70. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/tool_schema.py +0 -0
  71. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/tool_search.py +0 -0
  72. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/tools.py +0 -0
  73. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/tracing.py +0 -0
  74. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/transport/__init__.py +0 -0
  75. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/transport/fastapi_sse.py +0 -0
  76. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/transport/stdio_jsonrpc.py +0 -0
  77. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime/world_state.py +0 -0
  78. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime.egg-info/SOURCES.txt +0 -0
  79. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime.egg-info/dependency_links.txt +0 -0
  80. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime.egg-info/requires.txt +0 -0
  81. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/src/steerable_agent_runtime.egg-info/top_level.txt +0 -0
  82. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_antihallucination.py +0 -0
  83. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_approval_policy.py +0 -0
  84. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_ask_user.py +0 -0
  85. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_branch.py +0 -0
  86. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_cache_control.py +0 -0
  87. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_cache_instrumentation.py +0 -0
  88. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_calibration.py +0 -0
  89. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_compaction.py +0 -0
  90. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_compaction_policy.py +0 -0
  91. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_compaction_strategy.py +0 -0
  92. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_config.py +0 -0
  93. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_content_parts.py +0 -0
  94. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_delegation_gate.py +0 -0
  95. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_error_taxonomy.py +0 -0
  96. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_fragment_bounds.py +0 -0
  97. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_gateway_catalog.py +0 -0
  98. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_golden.py +0 -0
  99. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_handoff.py +0 -0
  100. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_harness.py +0 -0
  101. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_harness_spec.py +0 -0
  102. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_history.py +0 -0
  103. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_history_persistence.py +0 -0
  104. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_hooks.py +0 -0
  105. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_in_memory_storage.py +0 -0
  106. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_llm_gemini_wire.py +0 -0
  107. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_llm_responses_wire.py +0 -0
  108. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_llm_stream_e2e.py +0 -0
  109. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_llm_wire_helpers.py +0 -0
  110. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_long_session.py +0 -0
  111. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_loop.py +0 -0
  112. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_loop_cancellation.py +0 -0
  113. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_loop_replay.py +0 -0
  114. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_loop_sandbox_event.py +0 -0
  115. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_loop_terminal.py +0 -0
  116. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_maintenance.py +0 -0
  117. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_mcp.py +0 -0
  118. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_mcp_server.py +0 -0
  119. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_model_catalog.py +0 -0
  120. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_model_equivalence.py +0 -0
  121. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_model_info.py +0 -0
  122. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_model_resolve.py +0 -0
  123. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_native_default.py +0 -0
  124. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_observation_aging.py +0 -0
  125. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_orchestration.py +0 -0
  126. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_otel.py +0 -0
  127. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_parallel_tools.py +0 -0
  128. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_plugins.py +0 -0
  129. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_provider_compat.py +0 -0
  130. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_provider_presets.py +0 -0
  131. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_pseudo.py +0 -0
  132. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_pyo3_api_surface.py +0 -0
  133. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_recording.py +0 -0
  134. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_reminders.py +0 -0
  135. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_replay_crosslang.py +0 -0
  136. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_resume.py +0 -0
  137. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_retry_hooks.py +0 -0
  138. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_safety_gate.py +0 -0
  139. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_sandboxed.py +0 -0
  140. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_skills.py +0 -0
  141. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_soft_timeout.py +0 -0
  142. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_spill.py +0 -0
  143. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_sqlite_storage.py +0 -0
  144. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_steer.py +0 -0
  145. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_storage_contract.py +0 -0
  146. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_stream_strip.py +0 -0
  147. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_subagent.py +0 -0
  148. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_system_proxy.py +0 -0
  149. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_todo.py +0 -0
  150. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_todo_gate.py +0 -0
  151. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_tokens.py +0 -0
  152. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_tool_exposure.py +0 -0
  153. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_tool_hygiene.py +0 -0
  154. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_tool_presentation.py +0 -0
  155. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_tool_router.py +0 -0
  156. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_tool_schema.py +0 -0
  157. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_tool_timeout.py +0 -0
  158. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_trace_recorder.py +0 -0
  159. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_transport_jsonrpc.py +0 -0
  160. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_transport_sse.py +0 -0
  161. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_usage_attribution.py +0 -0
  162. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/tests/test_world_state.py +0 -0
  163. {steerable_agent_runtime-0.6.60 → steerable_agent_runtime-0.6.62}/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.60
3
+ Version: 0.6.62
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.60"
3
+ version = "0.6.62"
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,18 +193,46 @@ 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
+ Path-scoped tools (``local_write_file``, ``local_edit_file``, reads,
218
+ ``present_files``) skip when every declared path is inside a writable
219
+ root. Shell tools skip only when the OS exec sandbox is on and the
220
+ working directory is inside those roots — the same split Codex uses
221
+ between ``workspace-write`` and ``on-request``. The allow is
222
+ request-scoped. The next call is judged again. Anything else falls
223
+ through to the inner approver.
202
224
  """
203
225
 
204
- def __init__(self, inner: Approver, writable_roots: list[str]) -> None:
226
+ def __init__(
227
+ self,
228
+ inner: Approver,
229
+ writable_roots: list[str],
230
+ *,
231
+ sandbox_enforced: bool = False,
232
+ ) -> None:
205
233
  self._inner = inner
206
234
  self._roots = [root for root in writable_roots if isinstance(root, str) and root.strip()]
235
+ self._sandbox_enforced = sandbox_enforced
207
236
 
208
237
  async def approve(self, request: ApprovalRequest) -> ApprovalDecision:
209
238
  paths = declared_target_paths(request)
@@ -213,6 +242,8 @@ class WorkspaceAutoApprover:
213
242
  and all(path_inside_writable_roots(path, self._roots) for path in paths)
214
243
  ):
215
244
  return ApprovalDecision("allow_once", "path is inside a writable project root")
245
+ if self._sandbox_enforced and shell_stays_in_workspace(request, self._roots):
246
+ return ApprovalDecision("allow_once", "command stays inside the workspace sandbox")
216
247
  return await self._inner.approve(request)
217
248
 
218
249
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: steerable-agent-runtime
3
- Version: 0.6.60
3
+ Version: 0.6.62
4
4
  Summary: Steerable agent runtime: LLM, tool, storage, and transport adapters.
5
5
  License: Apache-2.0
6
6
  Requires-Python: >=3.10
@@ -569,3 +569,56 @@ async def test_workspace_auto_approver_does_not_cache_the_tool_name(tmp_path) ->
569
569
  assert inside.kind == "allow_once"
570
570
  assert outside.kind == "deny_once"
571
571
  assert len(inner.requests) == 1
572
+
573
+
574
+ @pytest.mark.asyncio
575
+ async def test_workspace_auto_approver_allows_sandboxed_shell_inside_writable_roots(tmp_path) -> None:
576
+ from steerable_agent_runtime.approval import WorkspaceAutoApprover
577
+
578
+ project = tmp_path / "111-2"
579
+ project.mkdir()
580
+ source = tmp_path / "sources"
581
+ source.mkdir()
582
+ inner = _ScriptedApprover([ApprovalDecision("deny_once", "should not ask")])
583
+ approver = WorkspaceAutoApprover(inner, [str(project), str(source)], sandbox_enforced=True)
584
+
585
+ omitted = await approver.approve(_request("local_exec_shell", {"command": "mkdir notes"}))
586
+ nested = await approver.approve(
587
+ _request("local_exec_shell", {"command": "touch a.md", "cwd": str(project / "notes")})
588
+ )
589
+ linked = await approver.approve(
590
+ _request("bash", {"command": "ls", "cwd": str(source / "raw")})
591
+ )
592
+ relative = await approver.approve(
593
+ _request("shell", {"command": "pwd", "cwd": "subdir"})
594
+ )
595
+
596
+ assert omitted.kind == "allow_once"
597
+ assert nested.kind == "allow_once"
598
+ assert linked.kind == "allow_once"
599
+ assert relative.kind == "allow_once"
600
+ assert inner.requests == []
601
+
602
+
603
+ @pytest.mark.asyncio
604
+ async def test_workspace_auto_approver_asks_for_shell_that_leaves_the_sandbox(tmp_path) -> None:
605
+ from steerable_agent_runtime.approval import WorkspaceAutoApprover
606
+
607
+ project = tmp_path / "111-2"
608
+ project.mkdir()
609
+ inner = _ScriptedApprover([ApprovalDecision("allow_once", "user allowed")] * 3)
610
+ confined = WorkspaceAutoApprover(inner, [str(project)], sandbox_enforced=True)
611
+ open_sandbox = WorkspaceAutoApprover(inner, [str(project)], sandbox_enforced=False)
612
+
613
+ outside = await confined.approve(
614
+ _request("local_exec_shell", {"command": "ls", "cwd": str(tmp_path / "other")})
615
+ )
616
+ climbed = await confined.approve(
617
+ _request("local_exec_shell", {"command": "ls", "cwd": "../outside"})
618
+ )
619
+ unsandboxed = await open_sandbox.approve(
620
+ _request("local_exec_shell", {"command": "ls", "cwd": str(project)})
621
+ )
622
+
623
+ assert [item.kind for item in (outside, climbed, unsandboxed)] == ["allow_once"] * 3
624
+ assert [item.tool_name for item in inner.requests] == ["local_exec_shell"] * 3