deepstrike 0.2.35__tar.gz → 0.2.37__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 (194) hide show
  1. {deepstrike-0.2.35 → deepstrike-0.2.37}/Cargo.lock +5 -5
  2. {deepstrike-0.2.35 → deepstrike-0.2.37}/Cargo.toml +2 -2
  3. {deepstrike-0.2.35 → deepstrike-0.2.37}/PKG-INFO +4 -4
  4. {deepstrike-0.2.35 → deepstrike-0.2.37}/README.md +3 -3
  5. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/context/compression.rs +29 -126
  6. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/context/config.rs +9 -16
  7. deepstrike-0.2.37/crates/deepstrike-core/src/context/fault.rs +23 -0
  8. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/context/manager.rs +264 -206
  9. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/context/mod.rs +1 -3
  10. deepstrike-0.2.37/crates/deepstrike-core/src/context/partitions.rs +331 -0
  11. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/context/renderer.rs +16 -9
  12. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/context/renewal.rs +10 -51
  13. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/context/summarizer.rs +5 -8
  14. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/governance/constraint.rs +1 -5
  15. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/governance/mod.rs +1 -3
  16. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/governance/permission.rs +5 -17
  17. deepstrike-0.2.37/crates/deepstrike-core/src/governance/pipeline.rs +236 -0
  18. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/governance/quota.rs +0 -27
  19. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/governance/rate_limit.rs +0 -4
  20. deepstrike-0.2.37/crates/deepstrike-core/src/governance/repeat_fuse.rs +48 -0
  21. deepstrike-0.2.37/crates/deepstrike-core/src/governance/veto.rs +71 -0
  22. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/lib.rs +5 -14
  23. deepstrike-0.2.37/crates/deepstrike-core/src/memory/durable.rs +15 -0
  24. deepstrike-0.2.37/crates/deepstrike-core/src/memory/mod.rs +13 -0
  25. deepstrike-0.2.37/crates/deepstrike-core/src/memory/semantic.rs +10 -0
  26. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/mm/memory.rs +12 -100
  27. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/mm/mod.rs +6 -57
  28. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/orchestration/task_graph.rs +53 -7
  29. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/orchestration/tournament.rs +0 -4
  30. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/orchestration/workflow/mod.rs +43 -73
  31. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/orchestration/workflow/run.rs +491 -56
  32. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/proc/mod.rs +11 -21
  33. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/runtime/event_log.rs +2 -39
  34. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/runtime/kernel.rs +478 -154
  35. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/runtime/mod.rs +2 -4
  36. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/runtime/repair.rs +2 -6
  37. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/runtime/replay.rs +4 -46
  38. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/runtime/session.rs +1 -124
  39. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/scheduler/milestone.rs +33 -24
  40. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/scheduler/mod.rs +1 -1
  41. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/scheduler/policy.rs +0 -4
  42. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/scheduler/state_machine/eviction.rs +37 -27
  43. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/scheduler/state_machine/gate.rs +136 -61
  44. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/scheduler/state_machine/milestone_exec.rs +30 -44
  45. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/scheduler/state_machine/mod.rs +317 -163
  46. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/scheduler/state_machine/process.rs +4 -4
  47. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/scheduler/state_machine/signal.rs +17 -27
  48. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/scheduler/state_machine/tests.rs +507 -189
  49. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/scheduler/state_machine/workflow.rs +96 -38
  50. deepstrike-0.2.37/crates/deepstrike-core/src/scheduler/tcb.rs +311 -0
  51. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/signals/attention.rs +5 -5
  52. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/signals/queue.rs +0 -33
  53. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/signals/router.rs +4 -57
  54. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/syscall/mod.rs +1 -42
  55. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/types/agent.rs +25 -0
  56. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/types/mod.rs +0 -1
  57. deepstrike-0.2.37/crates/deepstrike-core/src/types/policy.rs +45 -0
  58. deepstrike-0.2.37/crates/deepstrike-core/src/types/result.rs +145 -0
  59. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/types/task.rs +5 -11
  60. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-py/src/lib.rs +2 -20
  61. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/__init__.py +15 -0
  62. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/providers/stream.py +3 -0
  63. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/__init__.py +17 -0
  64. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/facade.py +8 -5
  65. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/kernel_event_log.py +34 -60
  66. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/kernel_step.py +13 -0
  67. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/large_result_spool.py +20 -0
  68. deepstrike-0.2.37/deepstrike/runtime/loop_driver.py +292 -0
  69. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/os_snapshot.py +0 -16
  70. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/reactive_session.py +12 -3
  71. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/run_group.py +30 -12
  72. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/runner.py +662 -151
  73. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/session_log.py +8 -56
  74. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/session_repair.py +75 -22
  75. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/sub_agent_orchestrator.py +73 -32
  76. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/workflow_control_flow.py +30 -6
  77. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/signals/gateway.py +14 -1
  78. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/types/agent.py +62 -2
  79. {deepstrike-0.2.35 → deepstrike-0.2.37}/pyproject.toml +1 -1
  80. deepstrike-0.2.35/crates/deepstrike-core/src/context/dashboard.rs +0 -149
  81. deepstrike-0.2.35/crates/deepstrike-core/src/context/partitions.rs +0 -127
  82. deepstrike-0.2.35/crates/deepstrike-core/src/context/sections.rs +0 -366
  83. deepstrike-0.2.35/crates/deepstrike-core/src/context/snapshot.rs +0 -166
  84. deepstrike-0.2.35/crates/deepstrike-core/src/governance/audit.rs +0 -87
  85. deepstrike-0.2.35/crates/deepstrike-core/src/governance/pipeline.rs +0 -357
  86. deepstrike-0.2.35/crates/deepstrike-core/src/governance/sandbox.rs +0 -137
  87. deepstrike-0.2.35/crates/deepstrike-core/src/governance/tool_decision.rs +0 -145
  88. deepstrike-0.2.35/crates/deepstrike-core/src/governance/veto.rs +0 -151
  89. deepstrike-0.2.35/crates/deepstrike-core/src/memory/durable.rs +0 -95
  90. deepstrike-0.2.35/crates/deepstrike-core/src/memory/extractor.rs +0 -103
  91. deepstrike-0.2.35/crates/deepstrike-core/src/memory/mod.rs +0 -10
  92. deepstrike-0.2.35/crates/deepstrike-core/src/memory/runtime.rs +0 -123
  93. deepstrike-0.2.35/crates/deepstrike-core/src/memory/semantic.rs +0 -102
  94. deepstrike-0.2.35/crates/deepstrike-core/src/memory/session.rs +0 -152
  95. deepstrike-0.2.35/crates/deepstrike-core/src/memory/working.rs +0 -44
  96. deepstrike-0.2.35/crates/deepstrike-core/src/runtime/snapshot.rs +0 -507
  97. deepstrike-0.2.35/crates/deepstrike-core/src/scheduler/tcb.rs +0 -1018
  98. deepstrike-0.2.35/crates/deepstrike-core/src/types/model.rs +0 -34
  99. deepstrike-0.2.35/crates/deepstrike-core/src/types/policy.rs +0 -60
  100. deepstrike-0.2.35/crates/deepstrike-core/src/types/result.rs +0 -58
  101. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/Cargo.toml +0 -0
  102. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/context/pressure.rs +0 -0
  103. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/context/skill_catalog.rs +0 -0
  104. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/context/task_state.rs +0 -0
  105. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/context/text.rs +0 -0
  106. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/context/token_engine.rs +0 -0
  107. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/harness/eval.rs +0 -0
  108. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/harness/mod.rs +0 -0
  109. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/memory/curator.rs +0 -0
  110. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/memory/idle_pipeline.rs +0 -0
  111. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/memory/synthesis.rs +0 -0
  112. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/memory/trace_analyzer.rs +0 -0
  113. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/mm/handle.rs +0 -0
  114. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/orchestration/mod.rs +0 -0
  115. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/scheduler/rollback.rs +0 -0
  116. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/scheduler/state_machine/capability.rs +0 -0
  117. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/signals/mod.rs +0 -0
  118. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/types/capability.rs +0 -0
  119. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/types/contract.rs +0 -0
  120. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/types/error.rs +0 -0
  121. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/types/message.rs +0 -0
  122. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/types/milestone.rs +0 -0
  123. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/types/signal.rs +0 -0
  124. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-core/src/types/skill.rs +0 -0
  125. {deepstrike-0.2.35 → deepstrike-0.2.37}/crates/deepstrike-py/Cargo.toml +0 -0
  126. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/collaboration/__init__.py +0 -0
  127. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/collaboration/contract.py +0 -0
  128. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/collaboration/handoff.py +0 -0
  129. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/collaboration/harness.py +0 -0
  130. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/collaboration/modes.py +0 -0
  131. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/collaboration/pool.py +0 -0
  132. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/governance.py +0 -0
  133. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/harness/__init__.py +0 -0
  134. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/harness/harness.py +0 -0
  135. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/harness/judge.py +0 -0
  136. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/kernel/__init__.py +0 -0
  137. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/knowledge/__init__.py +0 -0
  138. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/knowledge/source.py +0 -0
  139. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/memory/__init__.py +0 -0
  140. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/memory/agent.py +0 -0
  141. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/memory/in_memory_store.py +0 -0
  142. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/memory/protocols.py +0 -0
  143. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/memory/working.py +0 -0
  144. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/providers/__init__.py +0 -0
  145. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/providers/anthropic.py +0 -0
  146. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/providers/anthropic_compatible.py +0 -0
  147. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/providers/base.py +0 -0
  148. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/providers/deepseek.py +0 -0
  149. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/providers/factories.py +0 -0
  150. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/providers/gemini.py +0 -0
  151. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/providers/glm.py +0 -0
  152. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/providers/kimi.py +0 -0
  153. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/providers/minimax.py +0 -0
  154. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/providers/ollama.py +0 -0
  155. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/providers/openai.py +0 -0
  156. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/providers/openai_responses.py +0 -0
  157. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/providers/qwen.py +0 -0
  158. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/providers/replay.py +0 -0
  159. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/providers/replay_validator.py +0 -0
  160. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/providers/vendor_profiles.py +0 -0
  161. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/archive.py +0 -0
  162. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/credential_vault.py +0 -0
  163. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/eval.py +0 -0
  164. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/event_stream.py +0 -0
  165. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/execution_plane.py +0 -0
  166. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/filtered_plane.py +0 -0
  167. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/mcp_proxy_plane.py +0 -0
  168. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/os_profile.py +0 -0
  169. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/output_schema.py +0 -0
  170. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/process_sandbox_plane.py +0 -0
  171. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/provider_replay.py +0 -0
  172. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/reducers.py +0 -0
  173. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/remote_vpc_plane.py +0 -0
  174. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/replay_fixture.py +0 -0
  175. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/replay_provider.py +0 -0
  176. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/replay_sanitize.py +0 -0
  177. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/turn_policy.py +0 -0
  178. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/workflow_store.py +0 -0
  179. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/runtime/worktree_plane.py +0 -0
  180. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/safety/__init__.py +0 -0
  181. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/safety/permissions.py +0 -0
  182. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/signals/__init__.py +0 -0
  183. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/signals/scheduled.py +0 -0
  184. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/signals/types.py +0 -0
  185. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/skills/__init__.py +0 -0
  186. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/skills/registry.py +0 -0
  187. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/skills/watcher.py +0 -0
  188. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/tools/__init__.py +0 -0
  189. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/tools/builtin/__init__.py +0 -0
  190. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/tools/builtin/read_file.py +0 -0
  191. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/tools/errors.py +0 -0
  192. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/tools/execution.py +0 -0
  193. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/tools/registry.py +0 -0
  194. {deepstrike-0.2.35 → deepstrike-0.2.37}/deepstrike/types/__init__.py +0 -0
@@ -194,7 +194,7 @@ dependencies = [
194
194
 
195
195
  [[package]]
196
196
  name = "deepstrike-core"
197
- version = "0.2.35"
197
+ version = "0.2.37"
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.35"
209
+ version = "0.2.37"
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.35"
221
+ version = "0.2.37"
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.35"
232
+ version = "0.2.37"
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.35"
266
+ version = "0.2.37"
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.35"
6
+ version = "0.2.37"
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.35" }
12
+ deepstrike-core = { path = "crates/deepstrike-core", version = "0.2.37" }
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.35
3
+ Version: 0.2.37
4
4
  Requires-Dist: httpx>=0.27
5
5
  Requires-Dist: pyyaml>=6.0
6
6
  Requires-Dist: anyio>=4.0
@@ -149,7 +149,7 @@ The mechanisms above are not internal refactors — they change what you can bui
149
149
  Tool calls, spawns, compression, and signals pass through one kernel gate with an explicit lifecycle (Ready / Running / Blocked / Suspended). You implement I/O; the kernel decides *when* and *whether*. Node, Python, and Rust share the same decision path, so `wake(session_id)` and cross-language tooling see consistent behavior.
150
150
 
151
151
  **Longer, sturdier sessions (Layer-1 spool + semantic page-out)**
152
- Oversized tool results (> 50 KB) stay in context as a preview plus a `.spool/` reference — the model reads the full payload on demand via ordinary file tools. When pressure triggers semantic eviction, the SDK summarizes archived content into `DreamStore` and satisfies `page_in_requested` on the way back in. Long tasks survive token pressure instead of failing mid-run.
152
+ Oversized tool results (> 50 KB) stay in context as a preview plus a `.spool/` reference — the model reads the full payload on demand via ordinary file tools. When pressure triggers semantic eviction, the SDK summarizes archived content into `DreamStore`. Long tasks survive token pressure instead of failing mid-run.
153
153
 
154
154
  **Safety and governance by default (OS native profile)**
155
155
  Every run loads declarative `governance_policy` (deny / ask_user / rate-limit / param rules) and in-kernel signal routing (`attention_policy`, default queue 64). Dangerous tools, external interrupts, and approval flows are policy — not ad-hoc checks in your handlers.
@@ -443,9 +443,9 @@ effort: 1
443
443
 
444
444
  ## Knowledge
445
445
 
446
- Implement `KnowledgeSource` — the kernel injects a `knowledge` meta-tool. Runtime retrieval results land in **history** as tool results. Use `initial_memory` for durable preload into Slot 2.
446
+ Implement `KnowledgeSource` — the kernel injects a `knowledge` meta-tool. Runtime retrieval results land in **history** as tool results (single-use fact content that decays with compaction), not in the durable `knowledge` partition. Use `initial_memory` for durable preload into Slot 2.
447
447
 
448
- Before tool execution the kernel may emit `page_in_requested`; the SDK satisfies it from `DreamStore`, `KnowledgeSource`, and a local semantic page-out cache, then feeds `page_in` back to the kernel.
448
+ For durable content at runtime use `runner.push_knowledge(content, key=..., pinned=...)` a **keyed** entry upserts on a repeated key and `runner.remove_knowledge(key)` removes it, both applied at the next compaction/renewal boundary. `knowledge_budget_ratio` (default 0.25, 0 disables) caps the partition: over budget, the oldest unpinned, non-skill entries are evicted at boundaries while `pinned=True` entries survive. A loaded skill's body is pinned here as `skill:<name>` and unpinned by `runner.deactivate_skill(name)` or a `skill_lease_turns` expiry.
449
449
 
450
450
  ```python
451
451
  from deepstrike import KnowledgeSource
@@ -136,7 +136,7 @@ The mechanisms above are not internal refactors — they change what you can bui
136
136
  Tool calls, spawns, compression, and signals pass through one kernel gate with an explicit lifecycle (Ready / Running / Blocked / Suspended). You implement I/O; the kernel decides *when* and *whether*. Node, Python, and Rust share the same decision path, so `wake(session_id)` and cross-language tooling see consistent behavior.
137
137
 
138
138
  **Longer, sturdier sessions (Layer-1 spool + semantic page-out)**
139
- Oversized tool results (> 50 KB) stay in context as a preview plus a `.spool/` reference — the model reads the full payload on demand via ordinary file tools. When pressure triggers semantic eviction, the SDK summarizes archived content into `DreamStore` and satisfies `page_in_requested` on the way back in. Long tasks survive token pressure instead of failing mid-run.
139
+ Oversized tool results (> 50 KB) stay in context as a preview plus a `.spool/` reference — the model reads the full payload on demand via ordinary file tools. When pressure triggers semantic eviction, the SDK summarizes archived content into `DreamStore`. Long tasks survive token pressure instead of failing mid-run.
140
140
 
141
141
  **Safety and governance by default (OS native profile)**
142
142
  Every run loads declarative `governance_policy` (deny / ask_user / rate-limit / param rules) and in-kernel signal routing (`attention_policy`, default queue 64). Dangerous tools, external interrupts, and approval flows are policy — not ad-hoc checks in your handlers.
@@ -430,9 +430,9 @@ effort: 1
430
430
 
431
431
  ## Knowledge
432
432
 
433
- Implement `KnowledgeSource` — the kernel injects a `knowledge` meta-tool. Runtime retrieval results land in **history** as tool results. Use `initial_memory` for durable preload into Slot 2.
433
+ Implement `KnowledgeSource` — the kernel injects a `knowledge` meta-tool. Runtime retrieval results land in **history** as tool results (single-use fact content that decays with compaction), not in the durable `knowledge` partition. Use `initial_memory` for durable preload into Slot 2.
434
434
 
435
- Before tool execution the kernel may emit `page_in_requested`; the SDK satisfies it from `DreamStore`, `KnowledgeSource`, and a local semantic page-out cache, then feeds `page_in` back to the kernel.
435
+ For durable content at runtime use `runner.push_knowledge(content, key=..., pinned=...)` a **keyed** entry upserts on a repeated key and `runner.remove_knowledge(key)` removes it, both applied at the next compaction/renewal boundary. `knowledge_budget_ratio` (default 0.25, 0 disables) caps the partition: over budget, the oldest unpinned, non-skill entries are evicted at boundaries while `pinned=True` entries survive. A loaded skill's body is pinned here as `skill:<name>` and unpinned by `runner.deactivate_skill(name)` or a `skill_lease_turns` expiry.
436
436
 
437
437
  ```python
438
438
  from deepstrike import KnowledgeSource
@@ -1,7 +1,6 @@
1
1
  use super::config::ContextConfig;
2
2
  use super::partitions::ContextPartitions;
3
3
  use super::pressure::PressureAction;
4
- use super::summarizer::Summarizer;
5
4
  use super::token_engine::ContextTokenEngine;
6
5
  use crate::types::message::{Content, ContentPart, Message};
7
6
 
@@ -28,7 +27,6 @@ pub trait Compressor: Send + Sync {
28
27
  target_tokens: u32,
29
28
  max_tokens: u32,
30
29
  preserve_k: usize,
31
- summarizer: &dyn Summarizer,
32
30
  engine: &ContextTokenEngine,
33
31
  ) -> CompressResult;
34
32
  }
@@ -45,7 +43,6 @@ impl Compressor for SnipCompactor {
45
43
  _target_tokens: u32,
46
44
  max_tokens: u32,
47
45
  preserve_k: usize,
48
- _summarizer: &dyn Summarizer,
49
46
  engine: &ContextTokenEngine,
50
47
  ) -> CompressResult {
51
48
  let per_msg_limit = ((max_tokens as f64 * self.per_msg_ratio) as u32).max(50);
@@ -63,40 +60,17 @@ impl Compressor for SnipCompactor {
63
60
  for &i in &indices {
64
61
  let msg = &mut partition.messages[i];
65
62
  let original_tokens = msg.token_count.unwrap_or_else(|| engine.count_message(msg));
66
- if let Content::Text(ref t) = msg.content {
67
- let head_limit = per_msg_limit / 2;
68
- let tail_limit = per_msg_limit.saturating_sub(head_limit);
69
- let head_text = engine.truncate(t, head_limit);
70
-
71
- let chars: Vec<char> = t.chars().collect();
72
- let mut low = head_text.chars().count();
73
- let mut high = chars.len();
74
- let mut suffix_start = chars.len();
75
- while low <= high {
76
- let mid = (low + high) / 2;
77
- if mid >= chars.len() {
78
- break;
79
- }
80
- let candidate: String = chars[mid..].iter().collect();
81
- let tokens = engine.count(&candidate);
82
- if tokens <= tail_limit {
83
- suffix_start = mid;
84
- if mid == 0 {
85
- break;
86
- }
87
- high = mid - 1;
88
- } else {
89
- low = mid + 1;
90
- }
91
- }
92
- let tail_text: String = chars[suffix_start..].iter().collect();
93
- let omitted = original_tokens
94
- .saturating_sub(head_limit)
95
- .saturating_sub(tail_limit);
96
- msg.content = Content::Text(format!(
97
- "{}… [… {} tokens omitted …] …{}",
98
- head_text, omitted, tail_text
99
- ));
63
+ let head_limit = per_msg_limit / 2;
64
+ let tail_limit = per_msg_limit.saturating_sub(head_limit);
65
+ // Same head/tail elision as excerpt_text; the omitted count comes from the recorded
66
+ // token metadata (not a recount) so the elision marker matches the saved accounting.
67
+ let snipped = if let Content::Text(ref t) = msg.content {
68
+ Some(excerpt_text_with_total(t, head_limit, tail_limit, engine, original_tokens))
69
+ } else {
70
+ None
71
+ };
72
+ if let Some(text) = snipped {
73
+ msg.content = Content::Text(text);
100
74
  msg.token_count = Some(per_msg_limit);
101
75
  saved += original_tokens.saturating_sub(per_msg_limit);
102
76
  }
@@ -157,13 +131,6 @@ fn oversized_text_message_indices(
157
131
  .collect()
158
132
  }
159
133
 
160
- /// 获取当前UTC时间戳
161
- fn utc_now() -> String {
162
- // 在实际使用中,这应该从ProviderResult.now_ms获取
163
- // 这里简化为占位符
164
- format!("{:?}", std::time::SystemTime::now())
165
- }
166
-
167
134
  /// Helper to extract key fields and info from JSON strings.
168
135
  fn extract_json_excerpt(output: &str) -> Option<String> {
169
136
  let val: serde_json::Value = serde_json::from_str(output).ok()?;
@@ -215,7 +182,18 @@ fn excerpt_text(
215
182
  tail_tokens: u32,
216
183
  engine: &ContextTokenEngine,
217
184
  ) -> String {
218
- let total_tokens = engine.count(text);
185
+ excerpt_text_with_total(text, head_tokens, tail_tokens, engine, engine.count(text))
186
+ }
187
+
188
+ /// [`excerpt_text`] with the total token count supplied by the caller (e.g. from recorded
189
+ /// message metadata) instead of recounted — the count only feeds the elision marker.
190
+ fn excerpt_text_with_total(
191
+ text: &str,
192
+ head_tokens: u32,
193
+ tail_tokens: u32,
194
+ engine: &ContextTokenEngine,
195
+ total_tokens: u32,
196
+ ) -> String {
219
197
  if total_tokens <= head_tokens + tail_tokens {
220
198
  return text.to_string();
221
199
  }
@@ -295,7 +273,6 @@ impl Compressor for MicroCompactor {
295
273
  _target_tokens: u32,
296
274
  _max_tokens: u32,
297
275
  preserve_k: usize,
298
- _summarizer: &dyn Summarizer,
299
276
  engine: &ContextTokenEngine,
300
277
  ) -> CompressResult {
301
278
  let find_tool_name = |call_id: &str, msgs: &[Message]| -> Option<String> {
@@ -416,7 +393,6 @@ impl Compressor for CollapseCompactor {
416
393
  target_tokens: u32,
417
394
  _max_tokens: u32,
418
395
  preserve_k: usize,
419
- _summarizer: &dyn Summarizer,
420
396
  engine: &ContextTokenEngine,
421
397
  ) -> CompressResult {
422
398
  let partition = &mut partitions.history;
@@ -452,7 +428,6 @@ impl Compressor for AutoCompactor {
452
428
  _target_tokens: u32,
453
429
  _max_tokens: u32,
454
430
  preserve_k: usize,
455
- _summarizer: &dyn Summarizer,
456
431
  engine: &ContextTokenEngine,
457
432
  ) -> CompressResult {
458
433
  let partition = &mut partitions.history;
@@ -496,47 +471,6 @@ impl Compressor for AutoCompactor {
496
471
  }
497
472
  }
498
473
 
499
- // ─── Cache-aware compaction (W1-1 step 2) ───────────────────────────────────────────────────────
500
- // Additive cost model: introduced + tested before it drives the cascade, so the behavior-changing
501
- // wiring (prefix-safe-first selection + batching, with golden updates) is a separate, reviewable step.
502
-
503
- /// A fully-specified compaction step the cache-aware planner emits; the executor applies it
504
- /// mechanically (all *selection* already done by the planner via the pure helpers above).
505
- #[derive(Debug, Clone, PartialEq)]
506
- pub enum CompactionStep {
507
- /// Excerpt the tool results at these history-message indices. Prefix-safe in practice: tool
508
- /// results are interleaved mid/late, so the earliest touched index is rarely the cache prefix.
509
- Excerpt { msg_idx: Vec<usize> },
510
- /// Cap the oversized text messages at these indices to `per_msg_limit`.
511
- Snip { msg_idx: Vec<usize>, per_msg_limit: u32 },
512
- /// Drop the `count` oldest messages (the pipeline summarizes them). Prefix-breaking at index 0.
513
- DropOldest { count: usize },
514
- }
515
-
516
- impl CompactionStep {
517
- /// The earliest history-message index this step rewrites or removes — i.e. where it invalidates
518
- /// the prompt-cache prefix. `None` = prefix-safe (touches nothing). A lower index is a higher
519
- /// cache cost (Anthropic keys the cache off the first N messages), so the planner prefers `None`
520
- /// or a later index, and escalates to a prefix-breaking drop only when the safe steps can't free
521
- /// enough.
522
- pub fn invalidates_prefix_at(&self) -> Option<usize> {
523
- match self {
524
- CompactionStep::Excerpt { msg_idx } | CompactionStep::Snip { msg_idx, .. } => {
525
- msg_idx.iter().min().copied()
526
- }
527
- CompactionStep::DropOldest { count } => (*count > 0).then_some(0),
528
- }
529
- }
530
- }
531
-
532
- /// The prompt-cache-invalidation index of a whole plan = the earliest break across its steps (an
533
- /// earlier break invalidates everything after it, so the minimum dominates the cost). `None` means
534
- /// the plan is entirely prefix-safe and preserves the prompt cache — the cache-aware planner's goal
535
- /// whenever the safe steps can free enough.
536
- pub fn plan_cache_cost(steps: &[CompactionStep]) -> Option<usize> {
537
- steps.iter().filter_map(|s| s.invalidates_prefix_at()).min()
538
- }
539
-
540
474
  /// Compression pipeline — operates on history partition but can reference full partitions.
541
475
  pub struct CompressionPipeline {
542
476
  stages: Vec<(PressureAction, Box<dyn Compressor>)>,
@@ -590,7 +524,6 @@ impl CompressionPipeline {
590
524
  target_tokens,
591
525
  max_tokens,
592
526
  self.preserve_recent_turns,
593
- &summarizer,
594
527
  engine,
595
528
  );
596
529
  total_saved += res.tokens_saved;
@@ -647,7 +580,7 @@ mod tests {
647
580
  let mut ctx = ContextPartitions::new(&cfg);
648
581
  ctx.history.push(Message::user("a".repeat(800)), 200);
649
582
  // preserve_k=0: exercise the truncation transform directly (no cache-prefix protection).
650
- let result = compactor.compress(&mut ctx, 0, MAX, 0, &summarizer(), &engine());
583
+ let result = compactor.compress(&mut ctx, 0, MAX, 0, &engine());
651
584
  assert!(result.tokens_saved > 0);
652
585
  if let Content::Text(ref t) = ctx.history.messages[0].content {
653
586
  assert!(t.contains("… [… 100 tokens omitted …] …"), "got: {t}");
@@ -665,7 +598,7 @@ mod tests {
665
598
  };
666
599
  let mut ctx = ContextPartitions::new(&cfg);
667
600
  ctx.history.push(Message::user("short"), 5);
668
- let result = compactor.compress(&mut ctx, 0, MAX, 2, &summarizer(), &engine());
601
+ let result = compactor.compress(&mut ctx, 0, MAX, 2, &engine());
669
602
  assert_eq!(result.tokens_saved, 0);
670
603
  }
671
604
 
@@ -691,7 +624,7 @@ mod tests {
691
624
  ctx.history.token_count = 300;
692
625
 
693
626
  // preserve_k=0: exercise the excerpt transform directly (no cache-prefix protection).
694
- let result = compactor.compress(&mut ctx, 0, MAX, 0, &summarizer(), &engine());
627
+ let result = compactor.compress(&mut ctx, 0, MAX, 0, &engine());
695
628
  assert!(result.tokens_saved > 0);
696
629
  let text = ctx.history.messages[0].content.as_text().unwrap();
697
630
  assert!(
@@ -707,7 +640,7 @@ mod tests {
707
640
  for _ in 0..8 {
708
641
  ctx.history.push(Message::user("msg"), 50);
709
642
  }
710
- let result = compactor.compress(&mut ctx, 250, MAX, 2, &summarizer(), &engine());
643
+ let result = compactor.compress(&mut ctx, 250, MAX, 2, &engine());
711
644
  assert!(result.tokens_saved > 0);
712
645
  assert!(ctx.history.messages.len() < 8);
713
646
  // Pure executor: returns the drained messages; summary + log attribution is the pipeline's
@@ -764,7 +697,7 @@ mod tests {
764
697
  ctx.history.messages.push(msg);
765
698
  ctx.history.token_count = 300;
766
699
 
767
- let result = compactor.compress(&mut ctx, 0, MAX, 2, &summarizer(), &engine());
700
+ let result = compactor.compress(&mut ctx, 0, MAX, 2, &engine());
768
701
  // Since call_id "keep_me" is in preserved_refs, it should not be replaced!
769
702
  assert_eq!(result.tokens_saved, 0);
770
703
  let text_opt = ctx.history.messages[0].content.as_text();
@@ -781,7 +714,7 @@ mod tests {
781
714
  for i in 0..10 {
782
715
  ctx.history.push(Message::user(format!("msg {i}")), 10);
783
716
  }
784
- let result = compactor.compress(&mut ctx, 0, MAX, 2, &summarizer(), &engine());
717
+ let result = compactor.compress(&mut ctx, 0, MAX, 2, &engine());
785
718
  assert!(result.tokens_saved > 0);
786
719
  assert_eq!(ctx.history.messages.len(), 4); // kept last 2 turns = 4 messages
787
720
  // Pure executor: returns the drained messages; the pipeline summarizes + logs under the
@@ -820,36 +753,6 @@ mod tests {
820
753
  assert_eq!(prefix_keep_for(0, 2), 0);
821
754
  }
822
755
 
823
- #[test]
824
- fn compaction_step_prefix_cost() {
825
- // Excerpt/Snip cost = the earliest touched message index; DropOldest breaks the prefix at 0.
826
- assert_eq!(CompactionStep::Excerpt { msg_idx: vec![5, 8] }.invalidates_prefix_at(), Some(5));
827
- assert_eq!(
828
- CompactionStep::Snip { msg_idx: vec![3, 9], per_msg_limit: 50 }.invalidates_prefix_at(),
829
- Some(3)
830
- );
831
- assert_eq!(CompactionStep::DropOldest { count: 4 }.invalidates_prefix_at(), Some(0));
832
- assert_eq!(CompactionStep::DropOldest { count: 0 }.invalidates_prefix_at(), None);
833
- // An empty selection touches nothing → prefix-safe.
834
- assert_eq!(CompactionStep::Excerpt { msg_idx: vec![] }.invalidates_prefix_at(), None);
835
- }
836
-
837
- #[test]
838
- fn plan_cache_cost_is_the_earliest_break() {
839
- // Cost of a plan = the earliest message any step touches (an earlier break dominates).
840
- let late = vec![
841
- CompactionStep::Excerpt { msg_idx: vec![6] },
842
- CompactionStep::Snip { msg_idx: vec![7], per_msg_limit: 50 },
843
- ];
844
- assert_eq!(plan_cache_cost(&late), Some(6));
845
- // Escalating to a DropOldest breaks the prefix at 0 — the whole plan's cost collapses to 0.
846
- let mut with_drop = late.clone();
847
- with_drop.push(CompactionStep::DropOldest { count: 3 });
848
- assert_eq!(plan_cache_cost(&with_drop), Some(0));
849
- // An empty plan preserves the cache entirely.
850
- assert_eq!(plan_cache_cost(&[]), None);
851
- }
852
-
853
756
  #[test]
854
757
  fn pipeline_reports_accurate_prefix_invalidation() {
855
758
  // (a) DoD #4: the pipeline surfaces the earliest message any stage actually touched. On the
@@ -41,10 +41,6 @@ pub struct ContextConfig {
41
41
  pub preserve_recent_turns: usize,
42
42
 
43
43
  // ── Noise reduction ──────────────────────────────────────────────────────
44
- /// Include the dashboard block in the rendered system context.
45
- /// Defaults to false; enable only in explicit agent-os mode.
46
- pub render_dashboard: bool,
47
-
48
44
  /// Use verbose internal control notes (e.g. "[SYSTEM] Transaction rollback: …").
49
45
  /// Defaults to false; uses concise natural-language notes instead.
50
46
  pub verbose_control_notes: bool,
@@ -83,18 +79,16 @@ pub struct ContextConfig {
83
79
 
84
80
  /// Preview byte budget kept in context when a tool result is spooled. Default: 2 KiB.
85
81
  pub spool_preview_bytes: u32,
86
- }
87
82
 
88
- fn default_micro_compact_idle_minutes() -> u32 {
89
- 60
90
- }
91
-
92
- fn default_preserved_tool_results() -> usize {
93
- 5
94
- }
83
+ // ── K2: knowledge budget ─────────────────────────────────────────────
95
84
 
96
- fn default_autocompact_buffer() -> u32 {
97
- 13_000
85
+ /// Max share of `max_tokens` the knowledge partition may occupy. Exceeding it emits a
86
+ /// `KnowledgeBudgetExceeded` observation (once per cache generation) and marks the OLDEST
87
+ /// unpinned, non-skill entries for eviction at the next compaction/renewal boundary until the
88
+ /// projected usage fits. Pinned entries and `skill:`-keyed pins are never budget-evicted
89
+ /// (skills are governed by deactivation/lease, not the budget). `0.0` disables (no cap).
90
+ /// Default: 0.25.
91
+ pub knowledge_budget_ratio: f64,
98
92
  }
99
93
 
100
94
  impl Default for ContextConfig {
@@ -111,7 +105,6 @@ impl Default for ContextConfig {
111
105
  recovery_content_ratio: 0.25,
112
106
  preserve_recent_msgs: 4,
113
107
  preserve_recent_turns: 2,
114
- render_dashboard: false,
115
108
  verbose_control_notes: false,
116
109
  collapse_assistant_narration: true,
117
110
  micro_compact_idle_minutes: 60,
@@ -119,6 +112,7 @@ impl Default for ContextConfig {
119
112
  autocompact_buffer: 13_000,
120
113
  spool_threshold_bytes: 50 * 1024,
121
114
  spool_preview_bytes: 2 * 1024,
115
+ knowledge_budget_ratio: 0.25,
122
116
  }
123
117
  }
124
118
  }
@@ -159,7 +153,6 @@ mod tests {
159
153
  #[test]
160
154
  fn noise_reduction_defaults_to_quiet() {
161
155
  let c = ContextConfig::default();
162
- assert!(!c.render_dashboard, "dashboard should be off by default");
163
156
  assert!(!c.verbose_control_notes, "verbose notes should be off by default");
164
157
  }
165
158
 
@@ -0,0 +1,23 @@
1
+ use serde::{Deserialize, Serialize};
2
+
3
+ /// Errors/Faults that can occur during Context VM execution or replay.
4
+ #[derive(Debug, Clone, thiserror::Error, Serialize, Deserialize)]
5
+ pub enum ContextFault {
6
+ #[error("Prompt exceeds maximum token limit: budget={budget}, actual={actual}")]
7
+ PromptTooLong { budget: u32, actual: u32 },
8
+ #[error("Missing archive chunk {seq} for session {session_id}")]
9
+ MissingArchive { session_id: String, seq: u64 },
10
+ #[error("Invalid replay at turn {turn}: {reason}")]
11
+ InvalidReplay { turn: u32, reason: String },
12
+ }
13
+
14
+ /// FNV-1a 64-bit — the render layer's cache-stability test fingerprint dialect.
15
+ #[cfg(test)]
16
+ pub(crate) fn stable_hash(bytes: &[u8]) -> u64 {
17
+ let mut hash = 0xcbf29ce484222325u64;
18
+ for byte in bytes {
19
+ hash ^= u64::from(*byte);
20
+ hash = hash.wrapping_mul(0x100000001b3);
21
+ }
22
+ hash
23
+ }