steerable-agent-runtime 0.6.48__tar.gz → 0.6.49__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 (161) hide show
  1. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/PKG-INFO +2 -2
  2. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/pyproject.toml +2 -2
  3. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/__init__.py +2 -0
  4. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/reminders.py +28 -0
  5. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/todo.py +69 -1
  6. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime.egg-info/PKG-INFO +2 -2
  7. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime.egg-info/requires.txt +1 -1
  8. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_todo_gate.py +60 -2
  9. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/README.md +0 -0
  10. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/setup.cfg +0 -0
  11. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/antihallucination.py +0 -0
  12. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/approval.py +0 -0
  13. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/approval_policy.py +0 -0
  14. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/ask_user.py +0 -0
  15. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/branch.py +0 -0
  16. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/cache_control.py +0 -0
  17. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/calibration.py +0 -0
  18. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/compaction.py +0 -0
  19. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/compaction_policy.py +0 -0
  20. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/config.py +0 -0
  21. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/default.harness.json +0 -0
  22. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/default.harness.yaml +0 -0
  23. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/delegation_gate.py +0 -0
  24. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/errors.py +0 -0
  25. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/gateway_catalog.py +0 -0
  26. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/handoff.py +0 -0
  27. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/harness.py +0 -0
  28. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/harness_spec.py +0 -0
  29. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/history.py +0 -0
  30. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/hooks.py +0 -0
  31. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/llm/__init__.py +0 -0
  32. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/llm/anthropic_native.py +0 -0
  33. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/llm/compat.py +0 -0
  34. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/llm/errors.py +0 -0
  35. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/llm/google_genai.py +0 -0
  36. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/llm/openai_compat.py +0 -0
  37. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/llm/openai_responses.py +0 -0
  38. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/llm/parts.py +0 -0
  39. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/llm/presets.py +0 -0
  40. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/llm/system_proxy.py +0 -0
  41. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/loop.py +0 -0
  42. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/maintenance.py +0 -0
  43. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/mcp.py +0 -0
  44. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/mcp_server.py +0 -0
  45. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/model_catalog.py +0 -0
  46. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/model_info.py +0 -0
  47. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/model_resolve.py +0 -0
  48. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/native_bridge.py +0 -0
  49. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/observation_aging.py +0 -0
  50. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/orchestration.py +0 -0
  51. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/otel.py +0 -0
  52. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/plugins.py +0 -0
  53. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/pool.py +0 -0
  54. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/pricing.py +0 -0
  55. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/pseudo.py +0 -0
  56. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/recording.py +0 -0
  57. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/replay.py +0 -0
  58. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/resume.py +0 -0
  59. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/retry.py +0 -0
  60. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/sandboxed.py +0 -0
  61. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/skills.py +0 -0
  62. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/spill.py +0 -0
  63. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/storage/__init__.py +0 -0
  64. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/storage/in_memory.py +0 -0
  65. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/storage/sqlalchemy_store.py +0 -0
  66. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/storage/sqlite_store.py +0 -0
  67. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/storage/write_lease.py +0 -0
  68. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/subagent.py +0 -0
  69. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/tokens.py +0 -0
  70. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/tool_schema.py +0 -0
  71. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/tool_search.py +0 -0
  72. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/tools.py +0 -0
  73. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/tracing.py +0 -0
  74. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/transport/__init__.py +0 -0
  75. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/transport/fastapi_sse.py +0 -0
  76. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/transport/stdio_jsonrpc.py +0 -0
  77. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime/world_state.py +0 -0
  78. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime.egg-info/SOURCES.txt +0 -0
  79. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime.egg-info/dependency_links.txt +0 -0
  80. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/src/steerable_agent_runtime.egg-info/top_level.txt +0 -0
  81. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_antihallucination.py +0 -0
  82. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_approval.py +0 -0
  83. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_approval_policy.py +0 -0
  84. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_ask_user.py +0 -0
  85. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_branch.py +0 -0
  86. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_cache_control.py +0 -0
  87. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_cache_instrumentation.py +0 -0
  88. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_calibration.py +0 -0
  89. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_compaction.py +0 -0
  90. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_compaction_policy.py +0 -0
  91. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_compaction_strategy.py +0 -0
  92. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_config.py +0 -0
  93. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_content_parts.py +0 -0
  94. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_delegation_gate.py +0 -0
  95. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_error_taxonomy.py +0 -0
  96. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_fragment_bounds.py +0 -0
  97. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_gateway_catalog.py +0 -0
  98. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_golden.py +0 -0
  99. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_handoff.py +0 -0
  100. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_harness.py +0 -0
  101. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_harness_spec.py +0 -0
  102. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_history.py +0 -0
  103. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_history_persistence.py +0 -0
  104. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_hooks.py +0 -0
  105. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_in_memory_storage.py +0 -0
  106. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_llm_gemini_wire.py +0 -0
  107. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_llm_responses_wire.py +0 -0
  108. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_llm_stream_e2e.py +0 -0
  109. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_llm_wire_helpers.py +0 -0
  110. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_long_session.py +0 -0
  111. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_loop.py +0 -0
  112. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_loop_cancellation.py +0 -0
  113. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_loop_replay.py +0 -0
  114. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_loop_sandbox_event.py +0 -0
  115. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_loop_terminal.py +0 -0
  116. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_maintenance.py +0 -0
  117. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_mcp.py +0 -0
  118. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_mcp_server.py +0 -0
  119. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_model_catalog.py +0 -0
  120. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_model_equivalence.py +0 -0
  121. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_model_info.py +0 -0
  122. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_model_resolve.py +0 -0
  123. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_native_default.py +0 -0
  124. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_observation_aging.py +0 -0
  125. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_orchestration.py +0 -0
  126. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_otel.py +0 -0
  127. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_parallel_tools.py +0 -0
  128. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_plugins.py +0 -0
  129. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_provider_compat.py +0 -0
  130. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_provider_presets.py +0 -0
  131. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_pseudo.py +0 -0
  132. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_pyo3_api_surface.py +0 -0
  133. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_recording.py +0 -0
  134. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_reminders.py +0 -0
  135. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_replay_crosslang.py +0 -0
  136. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_resume.py +0 -0
  137. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_retry_hooks.py +0 -0
  138. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_safety_gate.py +0 -0
  139. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_sandboxed.py +0 -0
  140. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_skills.py +0 -0
  141. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_soft_timeout.py +0 -0
  142. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_spill.py +0 -0
  143. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_sqlite_storage.py +0 -0
  144. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_steer.py +0 -0
  145. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_storage_contract.py +0 -0
  146. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_stream_strip.py +0 -0
  147. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_subagent.py +0 -0
  148. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_system_proxy.py +0 -0
  149. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_todo.py +0 -0
  150. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_tokens.py +0 -0
  151. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_tool_exposure.py +0 -0
  152. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_tool_hygiene.py +0 -0
  153. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_tool_router.py +0 -0
  154. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_tool_schema.py +0 -0
  155. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_tool_timeout.py +0 -0
  156. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_trace_recorder.py +0 -0
  157. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_transport_jsonrpc.py +0 -0
  158. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_transport_sse.py +0 -0
  159. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_usage_attribution.py +0 -0
  160. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/tests/test_world_state.py +0 -0
  161. {steerable_agent_runtime-0.6.48 → steerable_agent_runtime-0.6.49}/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.48
3
+ Version: 0.6.49
4
4
  Summary: Steerable agent runtime: LLM, tool, storage, and transport adapters.
5
5
  License: Apache-2.0
6
6
  Requires-Python: >=3.10
@@ -8,7 +8,7 @@ Description-Content-Type: text/markdown
8
8
  Requires-Dist: pydantic>=2.10.0
9
9
  Requires-Dist: steerable-agent-protocol<1.0.0,>=0.1.0
10
10
  Requires-Dist: steerable-agent-harness<1.0.0,>=0.1.0
11
- Requires-Dist: steerable-agent-runtime-native==1.0.2
11
+ Requires-Dist: steerable-agent-runtime-native==1.0.3
12
12
  Provides-Extra: sqlalchemy
13
13
  Requires-Dist: sqlalchemy>=2.0; extra == "sqlalchemy"
14
14
  Provides-Extra: fastapi
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "steerable-agent-runtime"
3
- version = "0.6.48"
3
+ version = "0.6.49"
4
4
  description = "Steerable agent runtime: LLM, tool, storage, and transport adapters."
5
5
  license = { text = "Apache-2.0" }
6
6
  readme = "README.md"
@@ -16,7 +16,7 @@ dependencies = [
16
16
  "pydantic>=2.10.0",
17
17
  "steerable-agent-protocol>=0.1.0,<1.0.0",
18
18
  "steerable-agent-harness>=0.1.0,<1.0.0",
19
- "steerable-agent-runtime-native==1.0.2",
19
+ "steerable-agent-runtime-native==1.0.3",
20
20
  ]
21
21
 
22
22
  [project.optional-dependencies]
@@ -47,6 +47,7 @@ from .todo import (
47
47
  TODO_SCHEMA,
48
48
  TODO_TOOL_NAME,
49
49
  TodoCompletionGate,
50
+ TodoPlanningNudge,
50
51
  TodoStore,
51
52
  make_todo_write_tool,
52
53
  todo_write_tool_descriptor,
@@ -424,6 +425,7 @@ __all__ = [
424
425
  "ToolExposure",
425
426
  "ToolRouter",
426
427
  "TodoCompletionGate",
428
+ "TodoPlanningNudge",
427
429
  "TodoStore",
428
430
  "TraceRecorder",
429
431
  "TranscriptAppend",
@@ -119,6 +119,29 @@ class CompactionThrashingReminder(ContextFragment):
119
119
  return ("[system notice] Context thrashing:", "")
120
120
 
121
121
 
122
+ class TodoPlanningReminder(ContextFragment):
123
+ """A turn has run many tool calls without ever writing a task list."""
124
+
125
+ content_kind = "reminder.todo_planning"
126
+ max_tokens = 200
127
+
128
+ def __init__(self, calls: int) -> None:
129
+ self._calls = calls
130
+
131
+ def body(self) -> str:
132
+ return (
133
+ f"[system notice] {self._calls} tool calls into this turn and no "
134
+ "task list yet. If several steps remain, call todo_write now "
135
+ "with the remaining steps (the current one in_progress) and keep "
136
+ "it updated as you go. If the work is a single step or nearly "
137
+ "done, ignore this notice and continue."
138
+ )
139
+
140
+ @classmethod
141
+ def type_markers(cls) -> tuple[str, str]:
142
+ return ("[system notice]", "ignore this notice and continue.")
143
+
144
+
122
145
  # ---------------------------------------------------------------------------
123
146
  # Catalog
124
147
  # ---------------------------------------------------------------------------
@@ -192,6 +215,11 @@ REMINDER_CATALOG: tuple[ReminderEntry, ...] = (
192
215
  failure_mode="压缩后 3 轮内又填满、连续 3 次(rapid refill)——继续压只毁缓存",
193
216
  fragment=CompactionThrashingReminder,
194
217
  ),
218
+ ReminderEntry(
219
+ id="planning.todo_missing",
220
+ failure_mode="多步长任务全程不建 todo 清单,进度只存在于模型的注意力里",
221
+ fragment=TodoPlanningReminder,
222
+ ),
195
223
  )
196
224
 
197
225
 
@@ -16,7 +16,15 @@ from __future__ import annotations
16
16
  from typing import Any
17
17
 
18
18
  from .errors import ToolDispatchError
19
- from .hooks import CompletionAction, CompletionDraft, NoopHooks
19
+ from .hooks import (
20
+ CompletionAction,
21
+ CompletionDraft,
22
+ NoopHooks,
23
+ PreStepAction,
24
+ TranscriptAppend,
25
+ )
26
+ from .llm import LLMMessage
27
+ from .reminders import TodoPlanningReminder, reminder_entry
20
28
 
21
29
  #: The tool name the model calls.
22
30
  TODO_TOOL_NAME = "todo_write"
@@ -278,3 +286,63 @@ class TodoCompletionGate(NoopHooks):
278
286
  "update the list with todo_write first, then finish."
279
287
  ),
280
288
  )
289
+
290
+
291
+ #: Non-todo tool calls in one turn before the planning reminder fires. Low
292
+ #: enough to catch a long task early, high enough that ordinary 2-4 call
293
+ #: lookups never see it.
294
+ DEFAULT_TODO_NUDGE_AFTER_CALLS = 5
295
+
296
+
297
+ class TodoPlanningNudge(NoopHooks):
298
+ """``pre_step`` hook: remind a long-running turn to start a task list.
299
+
300
+ The prompt alone leaves ``todo_write`` to the model's judgement, and a
301
+ follow-up message deep in a long chat reads as "continue", so a 40-round
302
+ task can run without a list — and without a list the completion gate has
303
+ nothing to hold the turn to. After ``after_calls`` non-todo tool calls in
304
+ one turn, with no ``todo_write`` call yet and no unfinished list carried
305
+ over for the chat, this appends one ``planning.todo_missing`` reminder at
306
+ the highest-recency position. It fires at most once per turn.
307
+
308
+ Per-turn state: construct one instance per run.
309
+ """
310
+
311
+ def __init__(
312
+ self, store: TodoStore, *, after_calls: int = DEFAULT_TODO_NUDGE_AFTER_CALLS
313
+ ) -> None:
314
+ self._store = store
315
+ self._after_calls = after_calls
316
+ self._calls = 0
317
+ self._planned = False
318
+ self._fired = False
319
+
320
+ async def post_tool_result(self, result: Any, call: Any, ctx: Any) -> Any:
321
+ if call.name == TODO_TOOL_NAME:
322
+ self._planned = True
323
+ else:
324
+ self._calls += 1
325
+ return result
326
+
327
+ async def pre_step(self, transcript: Any, ctx: Any) -> PreStepAction:
328
+ if self._fired or self._planned or self._calls < self._after_calls:
329
+ return PreStepAction(kind="proceed")
330
+ chat_id = str(getattr(ctx, "chat_id", None) or "")
331
+ if any(
332
+ item["status"] in _UNFINISHED_STATUSES for item in self._store.get(chat_id)
333
+ ):
334
+ return PreStepAction(kind="proceed")
335
+ self._fired = True
336
+ entry = reminder_entry("planning.todo_missing")
337
+ fragment = TodoPlanningReminder(self._calls)
338
+ return PreStepAction(
339
+ kind="proceed",
340
+ appends=[
341
+ TranscriptAppend(
342
+ message=LLMMessage.text_of(fragment.role, fragment.render()),
343
+ kind=entry.fragment.content_kind,
344
+ fragment=fragment,
345
+ )
346
+ ],
347
+ append_action="reminder",
348
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: steerable-agent-runtime
3
- Version: 0.6.48
3
+ Version: 0.6.49
4
4
  Summary: Steerable agent runtime: LLM, tool, storage, and transport adapters.
5
5
  License: Apache-2.0
6
6
  Requires-Python: >=3.10
@@ -8,7 +8,7 @@ Description-Content-Type: text/markdown
8
8
  Requires-Dist: pydantic>=2.10.0
9
9
  Requires-Dist: steerable-agent-protocol<1.0.0,>=0.1.0
10
10
  Requires-Dist: steerable-agent-harness<1.0.0,>=0.1.0
11
- Requires-Dist: steerable-agent-runtime-native==1.0.2
11
+ Requires-Dist: steerable-agent-runtime-native==1.0.3
12
12
  Provides-Extra: sqlalchemy
13
13
  Requires-Dist: sqlalchemy>=2.0; extra == "sqlalchemy"
14
14
  Provides-Extra: fastapi
@@ -1,7 +1,7 @@
1
1
  pydantic>=2.10.0
2
2
  steerable-agent-protocol<1.0.0,>=0.1.0
3
3
  steerable-agent-harness<1.0.0,>=0.1.0
4
- steerable-agent-runtime-native==1.0.2
4
+ steerable-agent-runtime-native==1.0.3
5
5
 
6
6
  [all]
7
7
  sqlalchemy>=2.0
@@ -5,9 +5,10 @@ from __future__ import annotations
5
5
  from types import SimpleNamespace
6
6
 
7
7
  import pytest
8
-
9
- from steerable_agent_runtime import TodoCompletionGate, TodoStore
8
+ from steerable_agent_protocol.generated import ToolCall, ToolResult
9
+ from steerable_agent_runtime import TodoCompletionGate, TodoPlanningNudge, TodoStore
10
10
  from steerable_agent_runtime.hooks import CompletionDraft
11
+ from steerable_agent_runtime.reminders import TodoPlanningReminder
11
12
 
12
13
 
13
14
  def _draft(status: str = "completed") -> CompletionDraft:
@@ -92,3 +93,60 @@ class TestTodoCompletionGate:
92
93
  assert "15 unfinished" in action.message
93
94
  assert "task 9" in action.message
94
95
  assert "task 10" not in action.message # listing capped at 10
96
+
97
+
98
+ async def _call(nudge: TodoPlanningNudge, name: str, ctx: SimpleNamespace) -> None:
99
+ await nudge.post_tool_result(
100
+ ToolResult(success=True, data={}),
101
+ ToolCall(id=name, name=name, arguments={}),
102
+ ctx,
103
+ )
104
+
105
+
106
+ class TestTodoPlanningNudge:
107
+ @pytest.mark.asyncio
108
+ async def test_fires_once_after_threshold(self) -> None:
109
+ nudge = TodoPlanningNudge(TodoStore(), after_calls=3)
110
+ ctx = _ctx()
111
+ for _ in range(2):
112
+ await _call(nudge, "local_read_file", ctx)
113
+ assert not (await nudge.pre_step([], ctx)).appends
114
+ await _call(nudge, "local_exec_shell", ctx)
115
+ action = await nudge.pre_step([], ctx)
116
+ assert action.appends is not None
117
+ assert action.append_action == "reminder"
118
+ fragment = action.appends[0].fragment
119
+ assert isinstance(fragment, TodoPlanningReminder)
120
+ assert "3 tool calls into this turn" in fragment.render()
121
+ assert fragment.matches_text(fragment.render())
122
+ await _call(nudge, "local_exec_shell", ctx)
123
+ assert not (await nudge.pre_step([], ctx)).appends
124
+
125
+ @pytest.mark.asyncio
126
+ async def test_todo_write_this_turn_silences(self) -> None:
127
+ nudge = TodoPlanningNudge(TodoStore(), after_calls=2)
128
+ ctx = _ctx()
129
+ await _call(nudge, "todo_write", ctx)
130
+ for _ in range(5):
131
+ await _call(nudge, "local_exec_shell", ctx)
132
+ assert not (await nudge.pre_step([], ctx)).appends
133
+
134
+ @pytest.mark.asyncio
135
+ async def test_unfinished_list_carried_over_silences(self) -> None:
136
+ store = TodoStore()
137
+ _seed(store, "c1", ["completed", "pending"])
138
+ nudge = TodoPlanningNudge(store, after_calls=2)
139
+ ctx = _ctx()
140
+ for _ in range(3):
141
+ await _call(nudge, "local_exec_shell", ctx)
142
+ assert not (await nudge.pre_step([], ctx)).appends
143
+
144
+ @pytest.mark.asyncio
145
+ async def test_finished_list_carried_over_still_nudges(self) -> None:
146
+ store = TodoStore()
147
+ _seed(store, "c1", ["completed", "completed"])
148
+ nudge = TodoPlanningNudge(store, after_calls=2)
149
+ ctx = _ctx()
150
+ for _ in range(2):
151
+ await _call(nudge, "local_exec_shell", ctx)
152
+ assert (await nudge.pre_step([], ctx)).appends