deepstrike 0.2.23__tar.gz → 0.2.24__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 (174) hide show
  1. {deepstrike-0.2.23 → deepstrike-0.2.24}/Cargo.lock +5 -5
  2. {deepstrike-0.2.23 → deepstrike-0.2.24}/Cargo.toml +2 -2
  3. {deepstrike-0.2.23 → deepstrike-0.2.24}/PKG-INFO +1 -1
  4. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/__init__.py +6 -1
  5. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/providers/stream.py +13 -0
  6. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/execution_plane.py +78 -3
  7. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/mcp_proxy_plane.py +2 -1
  8. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/process_sandbox_plane.py +2 -1
  9. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/remote_vpc_plane.py +2 -1
  10. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/runner.py +4 -3
  11. deepstrike-0.2.24/deepstrike/tools/__init__.py +9 -0
  12. deepstrike-0.2.24/deepstrike/tools/errors.py +135 -0
  13. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/tools/execution.py +2 -1
  14. {deepstrike-0.2.23 → deepstrike-0.2.24}/pyproject.toml +1 -1
  15. deepstrike-0.2.23/deepstrike/tools/__init__.py +0 -5
  16. {deepstrike-0.2.23 → deepstrike-0.2.24}/README.md +0 -0
  17. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/Cargo.toml +0 -0
  18. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/context/compression.rs +0 -0
  19. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/context/config.rs +0 -0
  20. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/context/dashboard.rs +0 -0
  21. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/context/manager.rs +0 -0
  22. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/context/mod.rs +0 -0
  23. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/context/partitions.rs +0 -0
  24. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/context/pressure.rs +0 -0
  25. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/context/renderer.rs +0 -0
  26. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/context/renewal.rs +0 -0
  27. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/context/sections.rs +0 -0
  28. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/context/skill_catalog.rs +0 -0
  29. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/context/snapshot.rs +0 -0
  30. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/context/summarizer.rs +0 -0
  31. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/context/task_state.rs +0 -0
  32. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/context/text.rs +0 -0
  33. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/context/token_engine.rs +0 -0
  34. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/governance/audit.rs +0 -0
  35. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/governance/constraint.rs +0 -0
  36. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/governance/mod.rs +0 -0
  37. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/governance/permission.rs +0 -0
  38. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/governance/pipeline.rs +0 -0
  39. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/governance/quota.rs +0 -0
  40. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/governance/rate_limit.rs +0 -0
  41. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/governance/sandbox.rs +0 -0
  42. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/governance/tool_decision.rs +0 -0
  43. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/governance/veto.rs +0 -0
  44. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/harness/eval.rs +0 -0
  45. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/harness/mod.rs +0 -0
  46. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/lib.rs +0 -0
  47. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/memory/curator.rs +0 -0
  48. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/memory/durable.rs +0 -0
  49. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/memory/extractor.rs +0 -0
  50. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/memory/idle_pipeline.rs +0 -0
  51. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/memory/mod.rs +0 -0
  52. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/memory/runtime.rs +0 -0
  53. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/memory/semantic.rs +0 -0
  54. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/memory/session.rs +0 -0
  55. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/memory/synthesis.rs +0 -0
  56. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/memory/trace_analyzer.rs +0 -0
  57. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/memory/working.rs +0 -0
  58. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/mm/handle.rs +0 -0
  59. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/mm/memory.rs +0 -0
  60. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/mm/mod.rs +0 -0
  61. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/orchestration/mod.rs +0 -0
  62. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/orchestration/task_graph.rs +0 -0
  63. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/orchestration/tournament.rs +0 -0
  64. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/orchestration/workflow/mod.rs +0 -0
  65. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/orchestration/workflow/run.rs +0 -0
  66. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/proc/mod.rs +0 -0
  67. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/runtime/event_log.rs +0 -0
  68. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/runtime/kernel.rs +0 -0
  69. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/runtime/mod.rs +0 -0
  70. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/runtime/repair.rs +0 -0
  71. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/runtime/replay.rs +0 -0
  72. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/runtime/session.rs +0 -0
  73. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/runtime/snapshot.rs +0 -0
  74. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/scheduler/milestone.rs +0 -0
  75. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/scheduler/mod.rs +0 -0
  76. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/scheduler/policy.rs +0 -0
  77. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/scheduler/rollback.rs +0 -0
  78. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/scheduler/state_machine/capability.rs +0 -0
  79. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/scheduler/state_machine/eviction.rs +0 -0
  80. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/scheduler/state_machine/gate.rs +0 -0
  81. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/scheduler/state_machine/milestone_exec.rs +0 -0
  82. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/scheduler/state_machine/mod.rs +0 -0
  83. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/scheduler/state_machine/process.rs +0 -0
  84. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/scheduler/state_machine/signal.rs +0 -0
  85. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/scheduler/state_machine/tests.rs +0 -0
  86. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/scheduler/state_machine/workflow.rs +0 -0
  87. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/scheduler/tcb.rs +0 -0
  88. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/signals/attention.rs +0 -0
  89. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/signals/mod.rs +0 -0
  90. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/signals/queue.rs +0 -0
  91. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/signals/router.rs +0 -0
  92. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/syscall/mod.rs +0 -0
  93. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/types/agent.rs +0 -0
  94. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/types/capability.rs +0 -0
  95. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/types/contract.rs +0 -0
  96. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/types/error.rs +0 -0
  97. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/types/message.rs +0 -0
  98. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/types/milestone.rs +0 -0
  99. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/types/mod.rs +0 -0
  100. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/types/model.rs +0 -0
  101. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/types/policy.rs +0 -0
  102. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/types/result.rs +0 -0
  103. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/types/signal.rs +0 -0
  104. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/types/skill.rs +0 -0
  105. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-core/src/types/task.rs +0 -0
  106. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-py/Cargo.toml +0 -0
  107. {deepstrike-0.2.23 → deepstrike-0.2.24}/crates/deepstrike-py/src/lib.rs +0 -0
  108. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/collaboration/__init__.py +0 -0
  109. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/collaboration/contract.py +0 -0
  110. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/collaboration/handoff.py +0 -0
  111. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/collaboration/harness.py +0 -0
  112. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/collaboration/modes.py +0 -0
  113. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/collaboration/pool.py +0 -0
  114. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/governance.py +0 -0
  115. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/harness/__init__.py +0 -0
  116. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/harness/harness.py +0 -0
  117. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/kernel/__init__.py +0 -0
  118. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/knowledge/__init__.py +0 -0
  119. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/knowledge/source.py +0 -0
  120. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/memory/__init__.py +0 -0
  121. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/memory/agent.py +0 -0
  122. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/memory/in_memory_store.py +0 -0
  123. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/memory/protocols.py +0 -0
  124. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/memory/working.py +0 -0
  125. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/providers/__init__.py +0 -0
  126. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/providers/anthropic.py +0 -0
  127. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/providers/base.py +0 -0
  128. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/providers/deepseek.py +0 -0
  129. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/providers/gemini.py +0 -0
  130. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/providers/glm.py +0 -0
  131. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/providers/kimi.py +0 -0
  132. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/providers/minimax.py +0 -0
  133. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/providers/ollama.py +0 -0
  134. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/providers/openai.py +0 -0
  135. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/providers/openai_responses.py +0 -0
  136. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/providers/qwen.py +0 -0
  137. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/providers/replay.py +0 -0
  138. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/providers/replay_validator.py +0 -0
  139. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/__init__.py +0 -0
  140. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/archive.py +0 -0
  141. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/credential_vault.py +0 -0
  142. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/eval.py +0 -0
  143. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/filtered_plane.py +0 -0
  144. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/kernel_event_log.py +0 -0
  145. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/kernel_step.py +0 -0
  146. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/large_result_spool.py +0 -0
  147. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/os_profile.py +0 -0
  148. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/os_snapshot.py +0 -0
  149. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/output_schema.py +0 -0
  150. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/provider_replay.py +0 -0
  151. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/reducers.py +0 -0
  152. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/replay_fixture.py +0 -0
  153. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/replay_provider.py +0 -0
  154. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/replay_sanitize.py +0 -0
  155. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/session_log.py +0 -0
  156. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/session_repair.py +0 -0
  157. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/sub_agent_orchestrator.py +0 -0
  158. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/workflow_control_flow.py +0 -0
  159. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/workflow_store.py +0 -0
  160. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/runtime/worktree_plane.py +0 -0
  161. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/safety/__init__.py +0 -0
  162. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/safety/permissions.py +0 -0
  163. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/signals/__init__.py +0 -0
  164. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/signals/gateway.py +0 -0
  165. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/signals/scheduled.py +0 -0
  166. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/signals/types.py +0 -0
  167. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/skills/__init__.py +0 -0
  168. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/skills/registry.py +0 -0
  169. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/skills/watcher.py +0 -0
  170. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/tools/builtin/__init__.py +0 -0
  171. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/tools/builtin/read_file.py +0 -0
  172. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/tools/registry.py +0 -0
  173. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/types/__init__.py +0 -0
  174. {deepstrike-0.2.23 → deepstrike-0.2.24}/deepstrike/types/agent.py +0 -0
@@ -194,7 +194,7 @@ dependencies = [
194
194
 
195
195
  [[package]]
196
196
  name = "deepstrike-core"
197
- version = "0.2.23"
197
+ version = "0.2.24"
198
198
  dependencies = [
199
199
  "compact_str",
200
200
  "pretty_assertions",
@@ -206,7 +206,7 @@ dependencies = [
206
206
 
207
207
  [[package]]
208
208
  name = "deepstrike-node"
209
- version = "0.2.23"
209
+ version = "0.2.24"
210
210
  dependencies = [
211
211
  "compact_str",
212
212
  "deepstrike-core",
@@ -218,7 +218,7 @@ dependencies = [
218
218
 
219
219
  [[package]]
220
220
  name = "deepstrike-py"
221
- version = "0.2.23"
221
+ version = "0.2.24"
222
222
  dependencies = [
223
223
  "compact_str",
224
224
  "deepstrike-core",
@@ -229,7 +229,7 @@ dependencies = [
229
229
 
230
230
  [[package]]
231
231
  name = "deepstrike-sdk"
232
- version = "0.2.23"
232
+ version = "0.2.24"
233
233
  dependencies = [
234
234
  "async-stream",
235
235
  "async-trait",
@@ -263,7 +263,7 @@ dependencies = [
263
263
 
264
264
  [[package]]
265
265
  name = "deepstrike-wasm"
266
- version = "0.2.23"
266
+ version = "0.2.24"
267
267
  dependencies = [
268
268
  "compact_str",
269
269
  "deepstrike-core",
@@ -3,13 +3,13 @@ resolver = "2"
3
3
  members = ["crates/deepstrike-core", "crates/deepstrike-py"]
4
4
 
5
5
  [workspace.package]
6
- version = "0.2.23"
6
+ version = "0.2.24"
7
7
  edition = "2024"
8
8
  license = "MIT"
9
9
  repository = "https://github.com/kongusen/deepstrike"
10
10
 
11
11
  [workspace.dependencies]
12
- deepstrike-core = { path = "crates/deepstrike-core", version = "0.2.23" }
12
+ deepstrike-core = { path = "crates/deepstrike-core", version = "0.2.24" }
13
13
  notify = "6"
14
14
  serde = { version = "1", features = ["derive"] }
15
15
  serde_json = "1"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deepstrike
3
- Version: 0.2.23
3
+ Version: 0.2.24
4
4
  Requires-Dist: httpx>=0.27
5
5
  Requires-Dist: pyyaml>=6.0
6
6
  Requires-Dist: anyio>=4.0
@@ -64,7 +64,11 @@ from deepstrike.providers import (
64
64
  PermissionRequestEvent, PermissionResolvedEvent, PermissionResponse, ToolArgumentRepairedEvent,
65
65
  RetryConfig, CircuitBreaker, TokenUsage, ProviderToolSpec,
66
66
  )
67
- from deepstrike.tools import RegisteredTool, tool, streaming_tool, validate_tool_arguments, execute_tools, read_file
67
+ from deepstrike.tools import (
68
+ RegisteredTool, tool, streaming_tool, validate_tool_arguments, execute_tools, read_file,
69
+ ToolError, safe_tool, ok, fail, format_tool_error,
70
+ )
71
+ from deepstrike.providers.stream import ToolAuditFailedEvent
68
72
  from deepstrike.memory import (
69
73
  WorkingMemory,
70
74
  DreamStore, DreamResult, SessionData, MemoryEntry, CurationResult, CurationStats,
@@ -139,6 +143,7 @@ __all__ = [
139
143
  "PermissionRequestEvent", "PermissionResolvedEvent", "PermissionResponse", "ToolArgumentRepairedEvent",
140
144
  "RetryConfig", "CircuitBreaker", "TokenUsage", "ProviderToolSpec",
141
145
  "RegisteredTool", "tool", "streaming_tool", "validate_tool_arguments", "execute_tools", "read_file",
146
+ "ToolError", "safe_tool", "ok", "fail", "format_tool_error", "ToolAuditFailedEvent",
142
147
  "WorkingMemory",
143
148
  "DreamStore", "DreamResult", "SessionData", "MemoryEntry", "CurationResult", "CurationStats",
144
149
  "PermissionManager", "PermissionMode", "Permission", "PermissionDecision",
@@ -126,6 +126,18 @@ class ToolDeniedEvent:
126
126
  reason: str = ""
127
127
 
128
128
 
129
+ @dataclass
130
+ class ToolAuditFailedEvent:
131
+ """A tool's ``ctx.audit(label, fn)`` best-effort side-effect threw. The tool itself completed
132
+ successfully (no ``is_error`` flip, no retry); this event lets the host log / monitor that an
133
+ audit-store / metrics-emit / non-essential persistence step failed."""
134
+ type: str = "tool_audit_failed"
135
+ call_id: str = ""
136
+ name: str = ""
137
+ label: str = ""
138
+ error: str = ""
139
+
140
+
129
141
  @dataclass
130
142
  class WorkflowNodesSubmittedEvent:
131
143
  """R3-1: a workflow node's agent called the ``submit_workflow_nodes`` tool. The runner surfaces
@@ -149,5 +161,6 @@ StreamEvent = Union[
149
161
  PermissionResolvedEvent,
150
162
  ToolArgumentRepairedEvent,
151
163
  ToolDeniedEvent,
164
+ ToolAuditFailedEvent,
152
165
  WorkflowNodesSubmittedEvent,
153
166
  ]
@@ -1,7 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import asyncio
4
+ import inspect
4
5
  import json
6
+ import warnings
5
7
  from collections.abc import AsyncIterable, AsyncIterator
6
8
  from dataclasses import dataclass
7
9
  from pathlib import Path
@@ -13,12 +15,14 @@ from deepstrike.providers.stream import (
13
15
  PermissionResolvedEvent,
14
16
  PermissionResponse,
15
17
  StreamEvent,
18
+ ToolAuditFailedEvent,
16
19
  ToolDeltaEvent,
17
20
  ToolDeniedEvent,
18
21
  ToolResultEvent,
19
22
  ToolSuspendEvent,
20
23
  ToolArgumentRepairedEvent,
21
24
  )
25
+ from deepstrike.tools.errors import format_tool_error
22
26
  from deepstrike.tools.registry import RegisteredTool, normalize_tool_chunk, tool_chunk_text, validate_tool_arguments
23
27
 
24
28
  if TYPE_CHECKING:
@@ -33,6 +37,39 @@ def _strip_frontmatter(content: str) -> str:
33
37
  return re.sub(r"^---\n.*?\n---\n?", "", content, count=1, flags=re.DOTALL)
34
38
 
35
39
 
40
+ _WARNED_FAILURE_SHAPES: set[str] = set()
41
+
42
+
43
+ def _maybe_warn_failure_shaped_chunk(tool_name: str, delta_text: str) -> None:
44
+ """One-shot heuristic: detect when a streaming tool yielded text that *looks* like a failure
45
+ envelope. The runtime cannot block the tool from doing it, but we warn (once per tool) so
46
+ the author migrates to raising — the canonical "streaming tool fails" path. Aligns with the
47
+ non-streaming ``tool()`` / ``safe_tool`` contract: failures raise, successes return data."""
48
+ if not delta_text or tool_name in _WARNED_FAILURE_SHAPES:
49
+ return
50
+ trimmed = delta_text.strip()
51
+ if len(trimmed) < 2 or trimmed[0] != "{":
52
+ return
53
+ try:
54
+ parsed = json.loads(trimmed)
55
+ except Exception:
56
+ return
57
+ if not isinstance(parsed, dict):
58
+ return
59
+ looks_like_failure = parsed.get("success") is False or parsed.get("isError") is True or parsed.get("is_error") is True
60
+ if not looks_like_failure:
61
+ return
62
+ _WARNED_FAILURE_SHAPES.add(tool_name)
63
+ warnings.warn(
64
+ f'streaming tool "{tool_name}" yielded a failure-shaped chunk '
65
+ "(success:false / isError:true). Streaming tools should fail by raising; the runtime will "
66
+ "catch and surface the error consistently. Returning a failure-shaped chunk is a foot-gun: "
67
+ "the kernel still sees is_error=False.",
68
+ RuntimeWarning,
69
+ stacklevel=2,
70
+ )
71
+
72
+
36
73
  @dataclass
37
74
  class RunContext:
38
75
  agent_id: str | None = None
@@ -45,6 +82,12 @@ class RunContext:
45
82
  # M3/G4: the working directory a sub-agent's tools should run in (the git worktree created for an
46
83
  # ``isolation: "worktree"`` node). Injected by ``WorktreeExecutionPlane``; a cwd-aware tool reads it.
47
84
  cwd: str | None = None
85
+ # Per-call best-effort side-effect helper (injected by the execution plane). Wrap audit-log
86
+ # writes, metrics emits, or any non-essential persistence in ``await ctx.audit(label, fn)``;
87
+ # if ``fn`` raises, the failure is surfaced as a ``ToolAuditFailedEvent`` and the tool still
88
+ # completes successfully — avoiding the foot-gun where a transient audit-store outage flips
89
+ # an already-committed write into ``is_error=True`` and triggers a duplicate retry.
90
+ audit: Callable[[str, Callable[[], Awaitable[None] | None]], Awaitable[None]] | None = None
48
91
 
49
92
 
50
93
  class ExecutionPlane:
@@ -174,6 +217,29 @@ class LocalExecutionPlane:
174
217
  error_kind="recoverable",
175
218
  )
176
219
  return
220
+ # Per-call ``audit`` helper: failures collected here are surfaced as
221
+ # ``ToolAuditFailedEvent`` rather than flipping the main tool result to ``is_error=True``.
222
+ audit_failures: list[tuple[str, str]] = []
223
+
224
+ async def _audit(label: str, fn: Callable[[], Awaitable[None] | None]) -> None:
225
+ try:
226
+ result = fn()
227
+ if inspect.isawaitable(result):
228
+ await result
229
+ except Exception as ae:
230
+ audit_failures.append((label, format_tool_error(ae)))
231
+
232
+ call_ctx = RunContext(
233
+ agent_id=ctx.agent_id,
234
+ skill_dir=ctx.skill_dir,
235
+ dream_store=ctx.dream_store,
236
+ knowledge_source=ctx.knowledge_source,
237
+ on_tool_suspend=ctx.on_tool_suspend,
238
+ on_permission_request=ctx.on_permission_request,
239
+ result_spool=ctx.result_spool,
240
+ cwd=ctx.cwd,
241
+ audit=_audit,
242
+ )
177
243
  try:
178
244
  kwargs = json.loads(call.arguments or "{}")
179
245
  original_args_str = json.dumps(kwargs)
@@ -195,8 +261,9 @@ class LocalExecutionPlane:
195
261
  original_arguments=original_args_str,
196
262
  repaired_arguments=json.dumps(kwargs),
197
263
  )
198
- # M3/G4: pass the run context (incl. ``cwd``) so cwd-aware tools scope work to the worktree.
199
- output = await registered(_ctx=ctx, **kwargs)
264
+ # M3/G4: pass the run context (incl. ``cwd``, ``audit``) so cwd-aware / audit-aware tools
265
+ # scope work to the worktree and route best-effort side-effects through the plane.
266
+ output = await registered(_ctx=call_ctx, **kwargs)
200
267
  if isinstance(output, AsyncIterable):
201
268
  combined = ""
202
269
  iterator = output.__aiter__()
@@ -234,22 +301,30 @@ class LocalExecutionPlane:
234
301
  continue
235
302
  delta = tool_chunk_text(raw)
236
303
  combined += delta
304
+ if delta:
305
+ _maybe_warn_failure_shaped_chunk(call.name, delta)
237
306
  yield ToolDeltaEvent(
238
307
  call_id=call.id, name=call.name, delta=delta,
239
308
  chunk=None if isinstance(raw, str) else chunk,
240
309
  )
310
+ for label, error in audit_failures:
311
+ yield ToolAuditFailedEvent(call_id=call.id, name=call.name, label=label, error=error)
241
312
  yield ToolResultEvent(call_id=call.id, name=call.name, content=combined, is_error=False)
242
313
  return
314
+ for label, error in audit_failures:
315
+ yield ToolAuditFailedEvent(call_id=call.id, name=call.name, label=label, error=error)
243
316
  yield ToolResultEvent(call_id=call.id, name=call.name, content=str(output), is_error=False)
244
317
  except Exception as exc:
245
318
  is_fatal = getattr(exc, "is_fatal", False)
246
319
  error_kind = getattr(exc, "error_kind", None)
247
320
  if error_kind is None:
248
321
  error_kind = "fatal" if is_fatal else "recoverable"
322
+ for label, error in audit_failures:
323
+ yield ToolAuditFailedEvent(call_id=call.id, name=call.name, label=label, error=error)
249
324
  yield ToolResultEvent(
250
325
  call_id=call.id,
251
326
  name=call.name,
252
- content=str(exc),
327
+ content=format_tool_error(exc),
253
328
  is_error=True,
254
329
  is_fatal=is_fatal,
255
330
  error_kind=error_kind,
@@ -10,6 +10,7 @@ from typing import TYPE_CHECKING, Any
10
10
 
11
11
  from deepstrike._kernel import ToolCall, ToolSchema
12
12
  from deepstrike.providers.stream import StreamEvent, ToolResultEvent
13
+ from deepstrike.tools.errors import format_tool_error
13
14
  from deepstrike.tools.registry import RegisteredTool
14
15
  from deepstrike.runtime.execution_plane import ExecutionPlane, LocalExecutionPlane, RunContext
15
16
  from deepstrike.runtime.credential_vault import CredentialVault
@@ -126,7 +127,7 @@ class _McpConnection:
126
127
  )
127
128
  return (text or json.dumps(result)), result.get("isError", False)
128
129
  except Exception as exc:
129
- return str(exc), True
130
+ return format_tool_error(exc), True
130
131
 
131
132
  async def stop(self) -> None:
132
133
  if self._reader_task:
@@ -6,6 +6,7 @@ import os
6
6
  from pathlib import Path
7
7
 
8
8
  from deepstrike._kernel import ToolSchema
9
+ from deepstrike.tools.errors import format_tool_error
9
10
  from deepstrike.tools.registry import RegisteredTool
10
11
  from deepstrike.runtime.execution_plane import LocalExecutionPlane
11
12
 
@@ -72,7 +73,7 @@ class ProcessSandboxPlane(LocalExecutionPlane):
72
73
  combined = combined[: self._max_output_bytes] + b"\n[output truncated]"
73
74
  return combined.decode("utf-8", errors="replace"), proc.returncode != 0
74
75
  except Exception as exc:
75
- return str(exc), True
76
+ return format_tool_error(exc), True
76
77
 
77
78
  def _make_bash_tool(self) -> RegisteredTool:
78
79
  sandbox = self
@@ -9,6 +9,7 @@ import aiohttp
9
9
 
10
10
  from deepstrike._kernel import ToolCall, ToolSchema
11
11
  from deepstrike.providers.stream import StreamEvent, ToolResultEvent
12
+ from deepstrike.tools.errors import format_tool_error
12
13
  from deepstrike.tools.registry import RegisteredTool
13
14
  from deepstrike.runtime.execution_plane import LocalExecutionPlane, RunContext
14
15
  from deepstrike.runtime.credential_vault import CredentialVault
@@ -97,4 +98,4 @@ class RemoteVpcPlane:
97
98
  result: dict = await resp.json()
98
99
  return result.get("output", ""), bool(result.get("isError", False))
99
100
  except Exception as exc:
100
- return str(exc), True
101
+ return format_tool_error(exc), True
@@ -37,6 +37,7 @@ from deepstrike.providers.stream import (
37
37
  WorkflowNodesSubmittedEvent,
38
38
  )
39
39
  from deepstrike.runtime.execution_plane import ExecutionPlane, LocalExecutionPlane, RunContext
40
+ from deepstrike.tools.errors import format_tool_error
40
41
  from deepstrike.governance import governance_policy_to_kernel_event
41
42
  from deepstrike.runtime.kernel_event_log import kernel_observation_to_session_event, with_category
42
43
  from deepstrike.runtime.kernel_step import (
@@ -1449,7 +1450,7 @@ class RuntimeRunner:
1449
1450
  id=evt.id, name=evt.name, arguments=json.dumps(evt.arguments),
1450
1451
  ))
1451
1452
  except Exception as exc:
1452
- err_msg = str(exc).lower()
1453
+ err_msg = format_tool_error(exc).lower()
1453
1454
  if (
1454
1455
  ("413" in err_msg or "too long" in err_msg or "context length exceeded" in err_msg or "context_length_exceeded" in err_msg)
1455
1456
  and not has_attempted_reactive_compact
@@ -1462,7 +1463,7 @@ class RuntimeRunner:
1462
1463
  should_retry = True
1463
1464
 
1464
1465
  if not should_retry:
1465
- yield ErrorEvent(message=str(exc))
1466
+ yield ErrorEvent(message=format_tool_error(exc))
1466
1467
  action = kernel_action(runtime, self._pending_observations, {"kind": "timeout"})
1467
1468
  break
1468
1469
 
@@ -1716,7 +1717,7 @@ class RuntimeRunner:
1716
1717
  except Exception as err:
1717
1718
  # I0b: kernel rejection (or any other thrown error inside the loop) is observable here — emit
1718
1719
  # run_terminal so downstream code sees a clean end rather than mid-loop EOF.
1719
- err_msg = str(err)
1720
+ err_msg = format_tool_error(err)
1720
1721
  is_invalid_arg = "invalidarg" in err_msg.lower() or "invalid argument" in err_msg.lower()
1721
1722
  reason = "invalid_arg" if is_invalid_arg else "error"
1722
1723
  yield ErrorEvent(message=err_msg)
@@ -0,0 +1,9 @@
1
+ from .registry import RegisteredTool, tool, streaming_tool, validate_tool_arguments
2
+ from .execution import execute_tools
3
+ from .builtin import read_file
4
+ from .errors import ToolError, safe_tool, ok, fail, format_tool_error
5
+
6
+ __all__ = [
7
+ "RegisteredTool", "tool", "streaming_tool", "validate_tool_arguments", "execute_tools", "read_file",
8
+ "ToolError", "safe_tool", "ok", "fail", "format_tool_error",
9
+ ]
@@ -0,0 +1,135 @@
1
+ """Tool error envelope + ``safe_tool`` decorator (Python parity for the Node ``tools/errors.ts``).
2
+
3
+ Three pieces:
4
+
5
+ - ``format_tool_error`` replaces the old ``str(exc)`` at SDK error sites: an ``Exception`` with
6
+ no extra fields gives ``str(exc)`` (the message); an exception carrying ``code`` / ``hint`` /
7
+ ``__cause__`` gives JSON; a non-exception value falls back to ``str(...)``.
8
+ - ``ToolError`` is the canonical "the tool wants to fail with a code+hint" exception. Throwing it
9
+ from a ``safe_tool``-wrapped body produces ``{success:false, code, error, hint?}``.
10
+ - ``safe_tool`` wraps a function so plain-data returns become ``{success:true, data}`` and any
11
+ raise becomes a fail envelope — opt-in equivalent of ``tool()`` for tools that want the
12
+ stable structured shape on the wire instead of free-form strings.
13
+
14
+ The classic ``tool()`` factory is untouched; ``safe_tool`` is the migration path."""
15
+ from __future__ import annotations
16
+
17
+ import inspect
18
+ import json
19
+ from collections.abc import AsyncIterable
20
+ from typing import Any, Callable
21
+
22
+ from .registry import RegisteredTool, _schema_for
23
+
24
+
25
+ class ToolError(Exception):
26
+ """Carries machine-readable ``code`` + optional ``hint`` alongside the message. ``safe_tool``
27
+ converts a raised ``ToolError`` into ``{success:false, code, error, hint?}``. Code defaults
28
+ to ``"internal"`` so a bare ``raise ToolError("...")`` still produces a usable envelope."""
29
+
30
+ def __init__(self, message: str, *, code: str = "internal", hint: str | None = None,
31
+ cause: BaseException | None = None) -> None:
32
+ super().__init__(message)
33
+ self.code = code
34
+ self.hint = hint
35
+ if cause is not None:
36
+ self.__cause__ = cause
37
+
38
+
39
+ def ok(data: Any = None) -> dict[str, Any]:
40
+ return {"success": True} if data is None else {"success": True, "data": data}
41
+
42
+
43
+ def fail(code: str, error: str, hint: str | None = None) -> dict[str, Any]:
44
+ env: dict[str, Any] = {"success": False, "code": code, "error": error}
45
+ if hint is not None:
46
+ env["hint"] = hint
47
+ return env
48
+
49
+
50
+ def _is_envelope(v: Any) -> bool:
51
+ return isinstance(v, dict) and isinstance(v.get("success"), bool)
52
+
53
+
54
+ def format_tool_error(err: Any) -> str:
55
+ """Error-aware replacement for ``str(exc)`` / ``String(err)``.
56
+
57
+ - ``Exception`` with no extra fields → ``str(exc)`` (the message).
58
+ - ``Exception`` carrying ``code`` / ``hint`` / ``__cause__`` → JSON ``{message, name?, code?,
59
+ hint?, cause?}`` — agents can branch on ``code``.
60
+ - ``None`` / primitives / strings → ``str(...)`` unchanged.
61
+ - Other objects → ``json.dumps(...)`` if possible (replaces the old ``"<X object at 0x...>"``)."""
62
+ if err is None:
63
+ return "None"
64
+ if isinstance(err, str):
65
+ return err
66
+ if isinstance(err, BaseException):
67
+ code = getattr(err, "code", None)
68
+ hint = getattr(err, "hint", None)
69
+ cause = getattr(err, "__cause__", None)
70
+ if code is None and hint is None and cause is None:
71
+ return str(err) or type(err).__name__
72
+ payload: dict[str, Any] = {"message": str(err)}
73
+ name = type(err).__name__
74
+ if name not in ("Exception", "ToolError"):
75
+ payload["name"] = name
76
+ if code is not None:
77
+ payload["code"] = code
78
+ if hint is not None:
79
+ payload["hint"] = hint
80
+ if cause is not None:
81
+ payload["cause"] = str(cause) if isinstance(cause, BaseException) else cause
82
+ try:
83
+ return json.dumps(payload, default=str)
84
+ except Exception:
85
+ return str(err) or type(err).__name__
86
+ try:
87
+ return json.dumps(err, default=str)
88
+ except Exception:
89
+ return str(err)
90
+
91
+
92
+ class _SafeRegisteredTool(RegisteredTool):
93
+ """``RegisteredTool`` subclass with the safe-envelope try/except baked into ``__call__``.
94
+
95
+ We can't reuse ``RegisteredTool``'s wrapper because that one stringifies the result; here we
96
+ serialize via ``json.dumps`` so the model receives a proper envelope, not ``str({...})``."""
97
+
98
+ async def __call__(self, _ctx: Any = None, **kwargs: Any) -> str:
99
+ if self._wants_ctx:
100
+ kwargs["ctx"] = _ctx
101
+ try:
102
+ result = self.fn(**kwargs)
103
+ if inspect.isawaitable(result):
104
+ result = await result
105
+ if isinstance(result, AsyncIterable):
106
+ # Streaming safe_tool: collect chunks, then envelope. Authors who want streaming
107
+ # output should use the classic ``streaming_tool`` + raise convention; ``safe_tool``
108
+ # is for the structured envelope path.
109
+ chunks: list[str] = []
110
+ async for chunk in result:
111
+ chunks.append(chunk if isinstance(chunk, str) else str(chunk))
112
+ result = "".join(chunks)
113
+ if _is_envelope(result):
114
+ return json.dumps(result)
115
+ return json.dumps(ok(result))
116
+ except ToolError as e:
117
+ return json.dumps(fail(e.code, str(e) or type(e).__name__, e.hint))
118
+ except Exception as e:
119
+ code = getattr(e, "code", None)
120
+ hint = getattr(e, "hint", None)
121
+ code_str = code if isinstance(code, str) else "internal"
122
+ hint_str = hint if isinstance(hint, str) else None
123
+ return json.dumps(fail(code_str, str(e) or type(e).__name__, hint_str))
124
+
125
+
126
+ def safe_tool(fn: Callable) -> RegisteredTool:
127
+ """``tool()`` equivalent that wraps the body in a try/except and returns a stable
128
+ ``{success, code, error, hint?}`` JSON envelope to the model. Drop-in: ``@safe_tool``
129
+ instead of ``@tool``.
130
+
131
+ The body may return plain data (auto-wrapped as ``ok(data)``), an envelope produced by
132
+ ``ok()`` / ``fail()`` (passed through), or raise — ``ToolError`` becomes a fail envelope
133
+ with the ``code`` and ``hint``; any other ``Exception`` becomes ``{success:false, code:
134
+ err.code if str else "internal", error: str(err)}``."""
135
+ return _SafeRegisteredTool(fn, _schema_for(fn))
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
  import json
3
3
  from deepstrike._kernel import ToolCall, ToolResult
4
4
  from collections.abc import AsyncIterable
5
+ from .errors import format_tool_error
5
6
  from .registry import RegisteredTool, tool_chunk_text, validate_tool_arguments
6
7
 
7
8
 
@@ -29,5 +30,5 @@ async def execute_tools(
29
30
  output = "".join(chunks)
30
31
  results.append(ToolResult(call_id=call.id, output=str(output)))
31
32
  except Exception as exc:
32
- results.append(ToolResult(call_id=call.id, output=str(exc), is_error=True))
33
+ results.append(ToolResult(call_id=call.id, output=format_tool_error(exc), is_error=True))
33
34
  return results
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "deepstrike"
7
- version = "0.2.23"
7
+ version = "0.2.24"
8
8
  requires-python = ">=3.10"
9
9
  readme = "README.md"
10
10
  dependencies = [
@@ -1,5 +0,0 @@
1
- from .registry import RegisteredTool, tool, streaming_tool, validate_tool_arguments
2
- from .execution import execute_tools
3
- from .builtin import read_file
4
-
5
- __all__ = ["RegisteredTool", "tool", "streaming_tool", "validate_tool_arguments", "execute_tools", "read_file"]
File without changes