deepstrike 0.2.22__tar.gz → 0.2.23__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 (172) hide show
  1. {deepstrike-0.2.22 → deepstrike-0.2.23}/Cargo.lock +5 -5
  2. {deepstrike-0.2.22 → deepstrike-0.2.23}/Cargo.toml +2 -2
  3. {deepstrike-0.2.22 → deepstrike-0.2.23}/PKG-INFO +1 -1
  4. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/__init__.py +4 -0
  5. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/governance.py +32 -0
  6. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/harness/harness.py +45 -22
  7. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/providers/anthropic.py +35 -0
  8. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/providers/stream.py +3 -0
  9. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/runner.py +72 -3
  10. {deepstrike-0.2.22 → deepstrike-0.2.23}/pyproject.toml +1 -1
  11. {deepstrike-0.2.22 → deepstrike-0.2.23}/README.md +0 -0
  12. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/Cargo.toml +0 -0
  13. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/context/compression.rs +0 -0
  14. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/context/config.rs +0 -0
  15. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/context/dashboard.rs +0 -0
  16. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/context/manager.rs +0 -0
  17. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/context/mod.rs +0 -0
  18. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/context/partitions.rs +0 -0
  19. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/context/pressure.rs +0 -0
  20. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/context/renderer.rs +0 -0
  21. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/context/renewal.rs +0 -0
  22. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/context/sections.rs +0 -0
  23. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/context/skill_catalog.rs +0 -0
  24. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/context/snapshot.rs +0 -0
  25. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/context/summarizer.rs +0 -0
  26. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/context/task_state.rs +0 -0
  27. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/context/text.rs +0 -0
  28. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/context/token_engine.rs +0 -0
  29. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/governance/audit.rs +0 -0
  30. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/governance/constraint.rs +0 -0
  31. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/governance/mod.rs +0 -0
  32. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/governance/permission.rs +0 -0
  33. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/governance/pipeline.rs +0 -0
  34. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/governance/quota.rs +0 -0
  35. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/governance/rate_limit.rs +0 -0
  36. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/governance/sandbox.rs +0 -0
  37. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/governance/tool_decision.rs +0 -0
  38. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/governance/veto.rs +0 -0
  39. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/harness/eval.rs +0 -0
  40. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/harness/mod.rs +0 -0
  41. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/lib.rs +0 -0
  42. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/memory/curator.rs +0 -0
  43. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/memory/durable.rs +0 -0
  44. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/memory/extractor.rs +0 -0
  45. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/memory/idle_pipeline.rs +0 -0
  46. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/memory/mod.rs +0 -0
  47. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/memory/runtime.rs +0 -0
  48. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/memory/semantic.rs +0 -0
  49. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/memory/session.rs +0 -0
  50. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/memory/synthesis.rs +0 -0
  51. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/memory/trace_analyzer.rs +0 -0
  52. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/memory/working.rs +0 -0
  53. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/mm/handle.rs +0 -0
  54. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/mm/memory.rs +0 -0
  55. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/mm/mod.rs +0 -0
  56. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/orchestration/mod.rs +0 -0
  57. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/orchestration/task_graph.rs +0 -0
  58. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/orchestration/tournament.rs +0 -0
  59. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/orchestration/workflow/mod.rs +0 -0
  60. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/orchestration/workflow/run.rs +0 -0
  61. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/proc/mod.rs +0 -0
  62. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/runtime/event_log.rs +0 -0
  63. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/runtime/kernel.rs +0 -0
  64. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/runtime/mod.rs +0 -0
  65. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/runtime/repair.rs +0 -0
  66. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/runtime/replay.rs +0 -0
  67. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/runtime/session.rs +0 -0
  68. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/runtime/snapshot.rs +0 -0
  69. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/scheduler/milestone.rs +0 -0
  70. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/scheduler/mod.rs +0 -0
  71. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/scheduler/policy.rs +0 -0
  72. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/scheduler/rollback.rs +0 -0
  73. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/scheduler/state_machine/capability.rs +0 -0
  74. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/scheduler/state_machine/eviction.rs +0 -0
  75. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/scheduler/state_machine/gate.rs +0 -0
  76. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/scheduler/state_machine/milestone_exec.rs +0 -0
  77. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/scheduler/state_machine/mod.rs +0 -0
  78. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/scheduler/state_machine/process.rs +0 -0
  79. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/scheduler/state_machine/signal.rs +0 -0
  80. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/scheduler/state_machine/tests.rs +0 -0
  81. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/scheduler/state_machine/workflow.rs +0 -0
  82. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/scheduler/tcb.rs +0 -0
  83. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/signals/attention.rs +0 -0
  84. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/signals/mod.rs +0 -0
  85. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/signals/queue.rs +0 -0
  86. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/signals/router.rs +0 -0
  87. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/syscall/mod.rs +0 -0
  88. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/types/agent.rs +0 -0
  89. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/types/capability.rs +0 -0
  90. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/types/contract.rs +0 -0
  91. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/types/error.rs +0 -0
  92. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/types/message.rs +0 -0
  93. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/types/milestone.rs +0 -0
  94. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/types/mod.rs +0 -0
  95. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/types/model.rs +0 -0
  96. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/types/policy.rs +0 -0
  97. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/types/result.rs +0 -0
  98. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/types/signal.rs +0 -0
  99. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/types/skill.rs +0 -0
  100. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-core/src/types/task.rs +0 -0
  101. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-py/Cargo.toml +0 -0
  102. {deepstrike-0.2.22 → deepstrike-0.2.23}/crates/deepstrike-py/src/lib.rs +0 -0
  103. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/collaboration/__init__.py +0 -0
  104. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/collaboration/contract.py +0 -0
  105. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/collaboration/handoff.py +0 -0
  106. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/collaboration/harness.py +0 -0
  107. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/collaboration/modes.py +0 -0
  108. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/collaboration/pool.py +0 -0
  109. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/harness/__init__.py +0 -0
  110. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/kernel/__init__.py +0 -0
  111. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/knowledge/__init__.py +0 -0
  112. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/knowledge/source.py +0 -0
  113. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/memory/__init__.py +0 -0
  114. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/memory/agent.py +0 -0
  115. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/memory/in_memory_store.py +0 -0
  116. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/memory/protocols.py +0 -0
  117. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/memory/working.py +0 -0
  118. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/providers/__init__.py +0 -0
  119. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/providers/base.py +0 -0
  120. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/providers/deepseek.py +0 -0
  121. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/providers/gemini.py +0 -0
  122. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/providers/glm.py +0 -0
  123. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/providers/kimi.py +0 -0
  124. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/providers/minimax.py +0 -0
  125. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/providers/ollama.py +0 -0
  126. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/providers/openai.py +0 -0
  127. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/providers/openai_responses.py +0 -0
  128. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/providers/qwen.py +0 -0
  129. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/providers/replay.py +0 -0
  130. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/providers/replay_validator.py +0 -0
  131. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/__init__.py +0 -0
  132. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/archive.py +0 -0
  133. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/credential_vault.py +0 -0
  134. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/eval.py +0 -0
  135. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/execution_plane.py +0 -0
  136. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/filtered_plane.py +0 -0
  137. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/kernel_event_log.py +0 -0
  138. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/kernel_step.py +0 -0
  139. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/large_result_spool.py +0 -0
  140. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/mcp_proxy_plane.py +0 -0
  141. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/os_profile.py +0 -0
  142. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/os_snapshot.py +0 -0
  143. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/output_schema.py +0 -0
  144. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/process_sandbox_plane.py +0 -0
  145. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/provider_replay.py +0 -0
  146. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/reducers.py +0 -0
  147. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/remote_vpc_plane.py +0 -0
  148. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/replay_fixture.py +0 -0
  149. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/replay_provider.py +0 -0
  150. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/replay_sanitize.py +0 -0
  151. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/session_log.py +0 -0
  152. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/session_repair.py +0 -0
  153. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/sub_agent_orchestrator.py +0 -0
  154. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/workflow_control_flow.py +0 -0
  155. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/workflow_store.py +0 -0
  156. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/runtime/worktree_plane.py +0 -0
  157. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/safety/__init__.py +0 -0
  158. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/safety/permissions.py +0 -0
  159. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/signals/__init__.py +0 -0
  160. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/signals/gateway.py +0 -0
  161. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/signals/scheduled.py +0 -0
  162. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/signals/types.py +0 -0
  163. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/skills/__init__.py +0 -0
  164. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/skills/registry.py +0 -0
  165. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/skills/watcher.py +0 -0
  166. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/tools/__init__.py +0 -0
  167. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/tools/builtin/__init__.py +0 -0
  168. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/tools/builtin/read_file.py +0 -0
  169. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/tools/execution.py +0 -0
  170. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/tools/registry.py +0 -0
  171. {deepstrike-0.2.22 → deepstrike-0.2.23}/deepstrike/types/__init__.py +0 -0
  172. {deepstrike-0.2.22 → deepstrike-0.2.23}/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.22"
197
+ version = "0.2.23"
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.22"
209
+ version = "0.2.23"
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.22"
221
+ version = "0.2.23"
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.22"
232
+ version = "0.2.23"
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.22"
266
+ version = "0.2.23"
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.22"
6
+ version = "0.2.23"
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.22" }
12
+ deepstrike-core = { path = "crates/deepstrike-core", version = "0.2.23" }
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.22
3
+ Version: 0.2.23
4
4
  Requires-Dist: httpx>=0.27
5
5
  Requires-Dist: pyyaml>=6.0
6
6
  Requires-Dist: anyio>=4.0
@@ -75,6 +75,9 @@ from deepstrike.harness import (
75
75
  QualityGate,
76
76
  SinglePassHarness, HarnessLoop, EvalLoopHarness,
77
77
  HarnessRequest, HarnessOutcome,
78
+ # I3.1: surface harness types so hosts can construct verdicts and stream-event handlers
79
+ # without importing from deepstrike.harness.harness directly.
80
+ HarnessEvent, CriterionResult,
78
81
  )
79
82
  from deepstrike.skills import SkillRegistry
80
83
  from deepstrike.knowledge import KnowledgeSource
@@ -141,6 +144,7 @@ __all__ = [
141
144
  "PermissionManager", "PermissionMode", "Permission", "PermissionDecision",
142
145
  "QualityGate",
143
146
  "SinglePassHarness", "HarnessLoop", "EvalLoopHarness", "HarnessRequest", "HarnessOutcome",
147
+ "HarnessEvent", "CriterionResult",
144
148
  "SkillRegistry",
145
149
  "KnowledgeSource",
146
150
  "RuntimeSignal", "SignalSource", "ScheduledPrompt", "SignalGateway",
@@ -28,6 +28,38 @@ class GovernancePolicy:
28
28
  vetoes: list[str] = field(default_factory=list)
29
29
  rate_limits: list[GovernanceRateLimit] = field(default_factory=list)
30
30
  constraints: list[dict[str, Any]] = field(default_factory=list)
31
+ # I5: when True (default), the runner pre-filters denied tools out of the schema. Mirrors Node.
32
+ surface_denied_in_system: bool = True
33
+
34
+
35
+ def governance_filter_schema(tools: list, policy: "GovernancePolicy | None") -> tuple[list, list[str]]:
36
+ """I5: bucket tools into (allowed, denied) per the policy. Pure. Mirrors Node ``governanceFilterSchema``."""
37
+ if policy is None:
38
+ return tools, []
39
+ vetoes = set(policy.vetoes or [])
40
+ allowed: list = []
41
+ denied: list[str] = []
42
+ def matches(pat: str, name: str) -> bool:
43
+ return pat == name or (pat.endswith("*") and name.startswith(pat[:-1]))
44
+ for t in tools:
45
+ name = t.name if hasattr(t, "name") else (t.get("name") if isinstance(t, dict) else None)
46
+ if name is None:
47
+ allowed.append(t)
48
+ continue
49
+ if name in vetoes:
50
+ denied.append(name)
51
+ continue
52
+ action = policy.default_action or "allow"
53
+ for r in (policy.rules or []):
54
+ pat = r.pattern if hasattr(r, "pattern") else r.get("pattern")
55
+ act = r.action if hasattr(r, "action") else r.get("action")
56
+ if pat is not None and matches(pat, name):
57
+ action = act
58
+ if action == "deny":
59
+ denied.append(name)
60
+ else:
61
+ allowed.append(t)
62
+ return allowed, denied
31
63
 
32
64
 
33
65
  def governance_policy_to_kernel_event(policy: GovernancePolicy) -> dict[str, Any]:
@@ -16,6 +16,10 @@ class Criterion:
16
16
  text: str
17
17
  required: bool = True
18
18
  weight: float = 1.0
19
+ # I3.3 (A4): optional stable id from the host's contract layer (threaded to verdict_fn).
20
+ id: "str | None" = None
21
+ # I3.3 (A4): host hint — host has a deterministic check for this criterion.
22
+ machine_checkable: "bool | None" = None
19
23
 
20
24
 
21
25
  @dataclass
@@ -160,6 +164,9 @@ class SinglePassHarness:
160
164
 
161
165
 
162
166
  class EvalLoopHarness:
167
+ """I3.4 (A1): deprecated — prefer ``HarnessLoop`` with ``verdict_fn`` for host-defined
168
+ judgment. ``EvalLoopHarness.stream()`` does NOT honor ``gate`` (only ``.run()`` does);
169
+ ``HarnessLoop`` runs the eval loop uniformly across stream and run."""
163
170
  def __init__(self, runner: "RuntimeRunner", gate: "QualityGate", max_attempts: int = 3):
164
171
  self._runner = runner
165
172
  self._gate = gate
@@ -186,11 +193,16 @@ class HarnessLoop:
186
193
  *,
187
194
  max_attempts: int = 3,
188
195
  skill_dir: str | None = None,
196
+ # I3.2 (A2/A3): host-supplied judgment. Receives kwargs (goal, criteria, attempt, result);
197
+ # returns Verdict to short-circuit the LLM eval, or None/Awaitable[None] to defer. Mirrors
198
+ # the Node SDK ``verdictFn``.
199
+ verdict_fn=None,
189
200
  ):
190
201
  self._runner = runner
191
202
  self._eval_provider = eval_provider
192
203
  self._max_attempts = max_attempts
193
204
  self._skill_dir = pathlib.Path(skill_dir) if skill_dir else None
205
+ self._verdict_fn = verdict_fn
194
206
 
195
207
  async def run(self, request: HarnessRequest) -> HarnessOutcome:
196
208
  # R3-1: collect nodes the agent submits while running under the harness (dynamic fan-out in
@@ -251,30 +263,41 @@ class HarnessLoop:
251
263
 
252
264
  yield SupervisingEvent()
253
265
 
254
- # #6 (0.5.0): the eval/verdict compute is the kernel's stateless free functions (was the
255
- # EvalPipeline state machine). Build the eval prompt, call the eval LLM, parse the verdict.
256
- eval_msgs = build_eval_messages(request.goal, criteria, last_result, attempt, True)
257
- eval_text = ""
258
- eval_system = "\n\n".join(m.content for m in eval_msgs if m.role == "system")
259
- eval_turns = [m for m in eval_msgs if m.role != "system"]
260
- eval_context = RenderedContext(system_text=eval_system, turns=eval_turns)
261
- async for evt in self._eval_provider.stream(eval_context, [], extensions=None):
262
- if isinstance(evt, TextDelta):
263
- eval_text += evt.delta
264
-
265
- parsed = parse_verdict(eval_text)
266
- verdict = Verdict(
267
- passed=parsed.passed,
268
- overall_score=parsed.overall_score,
269
- feedback=parsed.feedback,
270
- details=[
271
- CriterionResult(criterion=d.criterion, passed=d.passed, score=d.score, feedback=d.feedback)
272
- for d in (parsed.details or [])
273
- ],
274
- )
266
+ # I3.2 (A2/A3): host-supplied verdict_fn short-circuits the LLM eval. Returning None
267
+ # (or awaitable None) defers to the built-in eval below enables hybrid judgment.
268
+ verdict = None
269
+ skill_candidate = None
270
+ if self._verdict_fn is not None:
271
+ result = self._verdict_fn(goal=request.goal, criteria=criteria, attempt=attempt, result=last_result)
272
+ if hasattr(result, "__await__"):
273
+ result = await result
274
+ verdict = result
275
+ if verdict is None:
276
+ # #6 (0.5.0): the eval/verdict compute is the kernel's stateless free functions (was the
277
+ # EvalPipeline state machine). Build the eval prompt, call the eval LLM, parse the verdict.
278
+ eval_msgs = build_eval_messages(request.goal, criteria, last_result, attempt, True)
279
+ eval_text = ""
280
+ eval_system = "\n\n".join(m.content for m in eval_msgs if m.role == "system")
281
+ eval_turns = [m for m in eval_msgs if m.role != "system"]
282
+ eval_context = RenderedContext(system_text=eval_system, turns=eval_turns)
283
+ async for evt in self._eval_provider.stream(eval_context, [], extensions=None):
284
+ if isinstance(evt, TextDelta):
285
+ eval_text += evt.delta
286
+
287
+ parsed = parse_verdict(eval_text)
288
+ verdict = Verdict(
289
+ passed=parsed.passed,
290
+ overall_score=parsed.overall_score,
291
+ feedback=parsed.feedback,
292
+ details=[
293
+ CriterionResult(criterion=d.criterion, passed=d.passed, score=d.score, feedback=d.feedback)
294
+ for d in (parsed.details or [])
295
+ ],
296
+ )
297
+ skill_candidate = parsed.skill_candidate
275
298
 
276
299
  if verdict.passed:
277
- sc = parsed.skill_candidate
300
+ sc = skill_candidate
278
301
  if sc and self._skill_dir:
279
302
  lines = ["---", f"name: {sc.name}", f"description: {sc.description}"]
280
303
  if sc.when_to_use:
@@ -222,6 +222,8 @@ class AnthropicProvider:
222
222
  system = self._build_system(context, strategy)
223
223
  tool_defs = self._build_tools(tools, anchor_cache=not isinstance(system, list), strategy=strategy)
224
224
  _assert_cache_budget(system, len(tools))
225
+ # I1: capture which slots will carry cache_control for pro-rata attribution at usage time.
226
+ slot_bp = _count_cache_control_slots(system, tool_defs, msgs)
225
227
 
226
228
  native_blocks: dict[int, dict] = {}
227
229
  tool_blocks: dict[int, dict] = {}
@@ -254,12 +256,14 @@ class AnthropicProvider:
254
256
  # input_tokens is the FULL prompt size (uncached + cache
255
257
  # read + cache write) for accurate context accounting.
256
258
  full_input = uncached_input + cache_read + cache_creation
259
+ by_slot = _estimate_cache_read_by_slot(cache_read, slot_bp)
257
260
  yield UsageEvent(
258
261
  total_tokens=full_input + output_tokens,
259
262
  input_tokens=full_input,
260
263
  output_tokens=output_tokens,
261
264
  cache_read_input_tokens=cache_read,
262
265
  cache_creation_input_tokens=cache_creation,
266
+ cache_read_input_tokens_by_slot=by_slot,
263
267
  )
264
268
  elif event.type == "content_block_start":
265
269
  idx = event.index
@@ -341,6 +345,37 @@ def _resolve_cache_breakpoint_strategy(extensions: "dict | None") -> str:
341
345
  return "default"
342
346
 
343
347
 
348
+ def _count_cache_control_slots(system, tool_defs, msgs) -> dict:
349
+ """I1: which slots of the outgoing request carry a ``cache_control`` breakpoint. Mirrors Node."""
350
+ sys_bp = isinstance(system, list) and any((isinstance(b, dict) and b.get("cache_control") is not None) for b in system)
351
+ tool_bp = bool(tool_defs) and any((isinstance(t, dict) and t.get("cache_control") is not None) for t in tool_defs)
352
+ msg_bp = False
353
+ for m in msgs or []:
354
+ content = m.get("content") if isinstance(m, dict) else None
355
+ if isinstance(content, list):
356
+ if any((isinstance(b, dict) and b.get("cache_control") is not None) for b in content):
357
+ msg_bp = True
358
+ break
359
+ return {"system": sys_bp, "tools": tool_bp, "messages": msg_bp}
360
+
361
+
362
+ def _estimate_cache_read_by_slot(cache_read: int, slot_bp: dict) -> "dict | None":
363
+ """I1: split ``cache_read_input_tokens`` evenly across contributing slots. Remainder lands on the
364
+ first contributing slot to keep the sum exact. Returns None when no cache read or no slot
365
+ contributed — consumers see the field absent rather than all zeros. Mirrors Node."""
366
+ if cache_read <= 0:
367
+ return None
368
+ contributors = [s for s in ("system", "tools", "messages") if slot_bp.get(s)]
369
+ if not contributors:
370
+ return None
371
+ share = cache_read // len(contributors)
372
+ remainder = cache_read - share * len(contributors)
373
+ out: dict = {}
374
+ for i, slot in enumerate(contributors):
375
+ out[slot] = share + (remainder if i == 0 else 0)
376
+ return out
377
+
378
+
344
379
  def _apply_message_cache_control(msgs: list[dict], frozen_prefix_len: "int | None" = None, strategy: str = "default") -> None:
345
380
  """Place the (<=2) message-history cache breakpoints. The final message always
346
381
  gets one (writes the current full prefix). The second is placed by one of two
@@ -63,6 +63,9 @@ class UsageEvent:
63
63
  # Cost breakdown (subset of input_tokens): reads bill ~0.1x, writes ~1.25x.
64
64
  cache_read_input_tokens: int = 0
65
65
  cache_creation_input_tokens: int = 0
66
+ # I1: pro-rata per-slot attribution of cache_read_input_tokens (Anthropic only). None when the
67
+ # provider doesn't honor cache_control. Shape: {"system": int?, "tools": int?, "messages": int?}.
68
+ cache_read_input_tokens_by_slot: "dict | None" = None
66
69
 
67
70
 
68
71
  @dataclass
@@ -133,6 +133,8 @@ class TurnMetrics:
133
133
  cache_read_tokens: int
134
134
  cache_creation_tokens: int
135
135
  active_skill: str | None = None
136
+ # I1: pro-rata per-slot attribution of cache_read_tokens (Anthropic only). Mirrors Node.
137
+ cache_read_tokens_by_slot: "dict | None" = None
136
138
 
137
139
 
138
140
  @dataclass
@@ -154,6 +156,10 @@ class RuntimeOptions:
154
156
  max_total_tokens: int | None = None
155
157
  timeout_ms: int | None = None
156
158
  agent_id: str | None = None
159
+ # I4: run-start memory pre-fetch hook. Callable receiving kwarg `goal=`; returns a list of query
160
+ # strings (or None). Each query becomes a dreamStore search; hits page into the knowledge
161
+ # partition before turn 1. Requires dream_store + agent_id. Errs-open. Mirrors Node ``preQueryMemory``.
162
+ pre_query_memory: "Callable[..., Any] | None" = None
157
163
  system_prompt: str | None = None
158
164
  initial_memory: list[str] | None = None
159
165
  skill_dir: str | Path | None = None
@@ -1334,6 +1340,25 @@ class RuntimeRunner:
1334
1340
  "message": {"role": "user", "content": list(attachments)},
1335
1341
  })
1336
1342
 
1343
+ # I4: pre-fetch memory into the knowledge partition before the first LLM turn (mirrors Node).
1344
+ if not resume_mid_run and self._opts.pre_query_memory and self._opts.dream_store and self._opts.agent_id:
1345
+ try:
1346
+ result = self._opts.pre_query_memory(goal=goal)
1347
+ if hasattr(result, "__await__"):
1348
+ result = await result
1349
+ queries = result or []
1350
+ entries = []
1351
+ for q in queries:
1352
+ if not isinstance(q, str) or not q.strip():
1353
+ continue
1354
+ hits = await self._opts.dream_store.search(self._opts.agent_id, q, 5)
1355
+ for hit in hits:
1356
+ entries.append({"content": f"[memory score={hit.score:.3f}] {hit.text}", "source": "memory"})
1357
+ if entries:
1358
+ kernel_apply(runtime, self._pending_observations, {"kind": "page_in", "entries": entries})
1359
+ except Exception:
1360
+ pass # errs-open
1361
+
1337
1362
  action = (
1338
1363
  kernel_action(runtime, self._pending_observations, {"kind": "resume"})
1339
1364
  if resume_mid_run
@@ -1343,7 +1368,9 @@ class RuntimeRunner:
1343
1368
  # P0-C: the skill loaded and in effect going into the current turn → per-turn ``active_skill`` metric.
1344
1369
  active_skill: str | None = None
1345
1370
 
1346
- while not runtime.is_terminal():
1371
+ # I0b: kernel-throw safety net — see Node runner for full rationale.
1372
+ try:
1373
+ while not runtime.is_terminal():
1347
1374
  if action.kind == "execute_tool":
1348
1375
  await self._apply_kernel_page_in(runtime, session_id)
1349
1376
  next_compressed_archive_start = await self._append_observations(
@@ -1360,6 +1387,9 @@ class RuntimeRunner:
1360
1387
  sig_action = kernel_maybe_action(runtime, self._pending_observations, _signal_to_kernel_event(sig))
1361
1388
  if sig_action:
1362
1389
  action = sig_action
1390
+ # I0a: Critical signal carries user_abort intent; see Node runner for full rationale.
1391
+ if getattr(sig, "urgency", None) == "critical":
1392
+ self._interrupted = True
1363
1393
  if runtime.is_terminal():
1364
1394
  break
1365
1395
 
@@ -1372,14 +1402,29 @@ class RuntimeRunner:
1372
1402
  final_tool_calls: list[ToolCall] = []
1373
1403
  final_text = ""
1374
1404
  context = action.context or RenderedContext()
1405
+ # I5: governance schema-level pre-filter — mirrors Node. Tools that the policy denies are
1406
+ # dropped from the schema before the provider sees them; the model never tries them.
1407
+ turn_tools = action.tools or []
1408
+ if self._opts.governance_policy and getattr(self._opts.governance_policy, "surface_denied_in_system", True):
1409
+ from deepstrike.governance import governance_filter_schema as _gov_filter
1410
+ allowed, denied = _gov_filter(turn_tools, self._opts.governance_policy)
1411
+ if denied:
1412
+ turn_tools = allowed
1413
+ note = f"[governance] the following tools are denied for this run and will fail if called: {', '.join(denied)}."
1414
+ existing = getattr(context, "system_knowledge", "") or ""
1415
+ try:
1416
+ context = type(context)(**{**context.__dict__, "system_knowledge": f"{existing}\n\n{note}".strip()})
1417
+ except Exception:
1418
+ pass # don't break the run if the context can't be cloned
1375
1419
  turn_tokens = 0
1376
1420
  turn_input_tokens = 0
1377
1421
  turn_cache_read_tokens = 0
1378
1422
  turn_cache_creation_tokens = 0
1423
+ turn_cache_read_by_slot = None
1379
1424
  should_retry = False
1380
1425
  try:
1381
1426
  async for evt in self._opts.provider.stream(
1382
- context, action.tools or [], extensions=ext if ext else None, state=provider_state,
1427
+ context, turn_tools, extensions=ext if ext else None, state=provider_state,
1383
1428
  ):
1384
1429
  # #2-B-ii: a preempting interrupt() stops consuming the live stream immediately; breaking
1385
1430
  # the `async for` closes the provider's async generator → its httpx context exits → the
@@ -1393,6 +1438,8 @@ class RuntimeRunner:
1393
1438
  turn_input_tokens = getattr(evt, "input_tokens", 0) or 0
1394
1439
  turn_cache_read_tokens = getattr(evt, "cache_read_input_tokens", 0) or 0
1395
1440
  turn_cache_creation_tokens = getattr(evt, "cache_creation_input_tokens", 0) or 0
1441
+ # I1: per-slot attribution forwarded to TurnMetrics; None on non-Anthropic providers.
1442
+ turn_cache_read_by_slot = getattr(evt, "cache_read_input_tokens_by_slot", None)
1396
1443
  continue
1397
1444
  yield evt
1398
1445
  if isinstance(evt, TextDelta):
@@ -1466,6 +1513,7 @@ class RuntimeRunner:
1466
1513
  # INTO this turn; a ``skill`` call here only takes effect next turn — emit first, then advance.
1467
1514
  if self._opts.on_turn_metrics is not None:
1468
1515
  try:
1516
+ _tm_kwargs_by_slot = {"cache_read_tokens_by_slot": turn_cache_read_by_slot} if turn_cache_read_by_slot else {}
1469
1517
  self._opts.on_turn_metrics(TurnMetrics(
1470
1518
  turn=runtime.turn(),
1471
1519
  tools_exposed=len(action.tools or []),
@@ -1474,6 +1522,7 @@ class RuntimeRunner:
1474
1522
  cache_read_tokens=turn_cache_read_tokens,
1475
1523
  cache_creation_tokens=turn_cache_creation_tokens,
1476
1524
  active_skill=active_skill,
1525
+ **_tm_kwargs_by_slot,
1477
1526
  ))
1478
1527
  except Exception:
1479
1528
  pass # metrics must never break the run
@@ -1664,9 +1713,29 @@ class RuntimeRunner:
1664
1713
 
1665
1714
  elif action.kind == "done":
1666
1715
  break
1716
+ except Exception as err:
1717
+ # I0b: kernel rejection (or any other thrown error inside the loop) is observable here — emit
1718
+ # run_terminal so downstream code sees a clean end rather than mid-loop EOF.
1719
+ err_msg = str(err)
1720
+ is_invalid_arg = "invalidarg" in err_msg.lower() or "invalid argument" in err_msg.lower()
1721
+ reason = "invalid_arg" if is_invalid_arg else "error"
1722
+ yield ErrorEvent(message=err_msg)
1723
+ try:
1724
+ await self._opts.session_log.append(session_id, build_run_terminal_event(
1725
+ reason=reason,
1726
+ turns_used=runtime.turn() or 0,
1727
+ total_tokens=0,
1728
+ ))
1729
+ except Exception:
1730
+ pass # session log failure must not mask the original error
1731
+ yield DoneEvent(iterations=runtime.turn() or 0, total_tokens=0, status=reason)
1732
+ self._active_kernel = None
1733
+ self._current_session_id = None
1734
+ return
1667
1735
 
1668
1736
  result = action.result if action.kind == "done" else None
1669
- status = result.termination if result else "error"
1737
+ # I0a: preserve preempt intent when loop exits without clean kernel-done (see Node runner for full rationale).
1738
+ status = result.termination if result else ("user_abort" if self._interrupted else "error")
1670
1739
  turns_used = max(1, result.turns_used) if result else (runtime.turn() or 0)
1671
1740
  total_tokens = result.total_tokens_used if result else 0
1672
1741
 
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "deepstrike"
7
- version = "0.2.22"
7
+ version = "0.2.23"
8
8
  requires-python = ">=3.10"
9
9
  readme = "README.md"
10
10
  dependencies = [
File without changes