drydock-cli 3.0.127__tar.gz → 3.0.128__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 (140) hide show
  1. {drydock_cli-3.0.127/drydock_cli.egg-info → drydock_cli-3.0.128}/PKG-INFO +1 -1
  2. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/events.py +51 -0
  3. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/tui/app.py +23 -0
  4. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/tui/widgets.py +1 -1
  5. {drydock_cli-3.0.127 → drydock_cli-3.0.128/drydock_cli.egg-info}/PKG-INFO +1 -1
  6. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/pyproject.toml +1 -1
  7. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_events.py +33 -0
  8. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/LICENSE +0 -0
  9. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/NOTICE +0 -0
  10. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/README.md +0 -0
  11. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/__init__.py +0 -0
  12. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/__main__.py +0 -0
  13. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/advisor.py +0 -0
  14. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/agent.py +0 -0
  15. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/bash_safety.py +0 -0
  16. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/builtin_skills/__init__.py +0 -0
  17. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/builtin_skills/ml-data.md +0 -0
  18. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/builtin_skills/ml-debug.md +0 -0
  19. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/builtin_skills/ml-finetune.md +0 -0
  20. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/builtin_skills/ml-metrics.md +0 -0
  21. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/builtin_skills/ml-rl.md +0 -0
  22. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/builtin_skills/ml-train.md +0 -0
  23. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/builtin_skills/rmf-categorize.md +0 -0
  24. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/builtin_skills/rmf-control.md +0 -0
  25. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/builtin_skills/rmf-poam.md +0 -0
  26. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/builtin_skills/rmf-review.md +0 -0
  27. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/builtin_skills/stig-assess.md +0 -0
  28. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/builtin_skills/stig-remediate.md +0 -0
  29. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/cci.py +0 -0
  30. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/cli.py +0 -0
  31. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/compaction.py +0 -0
  32. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/config.py +0 -0
  33. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/detect.py +0 -0
  34. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/extract.py +0 -0
  35. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/gittools.py +0 -0
  36. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/graphrag.py +0 -0
  37. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/guards.py +0 -0
  38. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/loop_detect.py +0 -0
  39. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/mcp.py +0 -0
  40. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/poam.py +0 -0
  41. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/providers.py +0 -0
  42. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/recipes.py +0 -0
  43. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/rmf.py +0 -0
  44. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/rmf_graph.py +0 -0
  45. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/skills.py +0 -0
  46. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/stig.py +0 -0
  47. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/suggest.py +0 -0
  48. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/task_state.py +0 -0
  49. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/tool_registry.py +0 -0
  50. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/tools/__init__.py +0 -0
  51. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/tui/__init__.py +0 -0
  52. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/tui/approval.py +0 -0
  53. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/tui/messages.py +0 -0
  54. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/tuning.py +0 -0
  55. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/verification.py +0 -0
  56. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock/web.py +0 -0
  57. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock_cli.egg-info/SOURCES.txt +0 -0
  58. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock_cli.egg-info/dependency_links.txt +0 -0
  59. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock_cli.egg-info/entry_points.txt +0 -0
  60. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock_cli.egg-info/requires.txt +0 -0
  61. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/drydock_cli.egg-info/top_level.txt +0 -0
  62. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/setup.cfg +0 -0
  63. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_advisor.py +0 -0
  64. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_approval.py +0 -0
  65. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_back_command.py +0 -0
  66. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_bash_background.py +0 -0
  67. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_bash_binary_output.py +0 -0
  68. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_bash_crossplatform.py +0 -0
  69. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_bash_output_bounding.py +0 -0
  70. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_bash_process_group.py +0 -0
  71. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_bash_safety.py +0 -0
  72. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_bash_sanitize.py +0 -0
  73. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_bash_shell.py +0 -0
  74. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_bash_stdin.py +0 -0
  75. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_bash_stop_partial.py +0 -0
  76. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_bash_timeout_network.py +0 -0
  77. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_bash_timeout_param.py +0 -0
  78. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_cci.py +0 -0
  79. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_cli_agents.py +0 -0
  80. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_compact_command.py +0 -0
  81. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_compaction.py +0 -0
  82. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_config.py +0 -0
  83. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_config_migration.py +0 -0
  84. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_context_limit_config.py +0 -0
  85. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_detect.py +0 -0
  86. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_dispatch.py +0 -0
  87. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_e2e_connected.py +0 -0
  88. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_edit_replace_all.py +0 -0
  89. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_empty_response.py +0 -0
  90. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_extract.py +0 -0
  91. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_failure_loop.py +0 -0
  92. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_first_run_setup.py +0 -0
  93. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_gittools.py +0 -0
  94. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_glob_edit_edges.py +0 -0
  95. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_graphify_example.py +0 -0
  96. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_graphrag.py +0 -0
  97. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_graphrag_quoted_path.py +0 -0
  98. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_grep_and_read_robust.py +0 -0
  99. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_guards_and_tools.py +0 -0
  100. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_hallucinated_tools.py +0 -0
  101. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_leaked_tool_call.py +0 -0
  102. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_loop_detect.py +0 -0
  103. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_mcp.py +0 -0
  104. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_oneshot_unreachable.py +0 -0
  105. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_overthink_interrupt.py +0 -0
  106. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_plan_autocontinue.py +0 -0
  107. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_poam.py +0 -0
  108. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_providers_unreachable.py +0 -0
  109. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_read_index.py +0 -0
  110. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_recipes.py +0 -0
  111. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_repetition_interrupt.py +0 -0
  112. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_rmf.py +0 -0
  113. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_rmf_graph.py +0 -0
  114. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_rmf_stig_graph.py +0 -0
  115. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_runaway_repetition.py +0 -0
  116. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_screenshot.py +0 -0
  117. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_server_probe.py +0 -0
  118. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_skills.py +0 -0
  119. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_stall_retry.py +0 -0
  120. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_stig.py +0 -0
  121. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_stop.py +0 -0
  122. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_streaming_newlines.py +0 -0
  123. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_subagent.py +0 -0
  124. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_suggest.py +0 -0
  125. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_system_prompt_help.py +0 -0
  126. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_task_state.py +0 -0
  127. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_todo.py +0 -0
  128. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_tool_arg_coercion.py +0 -0
  129. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_tool_arg_coercion_more.py +0 -0
  130. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_tool_arg_parsing.py +0 -0
  131. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_tools_undo.py +0 -0
  132. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_tui.py +0 -0
  133. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_tuning.py +0 -0
  134. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_verification_gate.py +0 -0
  135. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_viewimage.py +0 -0
  136. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_vision_input.py +0 -0
  137. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_web_tools.py +0 -0
  138. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_windows_shell.py +0 -0
  139. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_write_content_coerce.py +0 -0
  140. {drydock_cli-3.0.127 → drydock_cli-3.0.128}/tests/test_xccdf.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drydock-cli
3
- Version: 3.0.127
3
+ Version: 3.0.128
4
4
  Summary: Drydock — a local, provider-agnostic terminal coding agent for local LLMs
5
5
  Author: Frank Bobe III
6
6
  License-Expression: Apache-2.0
@@ -66,3 +66,54 @@ def default_event_log_path():
66
66
  import time
67
67
  from pathlib import Path
68
68
  return Path.home() / ".drydock" / "events" / f"session-{int(time.time())}.jsonl"
69
+
70
+
71
+ def _events(events_or_path):
72
+ return events_or_path if isinstance(events_or_path, list) else EventLog.read(events_or_path)
73
+
74
+
75
+ def reconstruct_task_state(events_or_path):
76
+ """Rebuild a TaskState (objective, acceptance criteria, phase) from an event
77
+ trace — the PRD "a task can be reconstructed from serialized state" / resume.
78
+ Returns a fresh TaskState (empty if the trace has no task_start)."""
79
+ from drydock.task_state import TaskState
80
+ ts = TaskState()
81
+ for e in _events(events_or_path):
82
+ t = e.get("type")
83
+ if t == "task_start":
84
+ ts.objective = e.get("objective", "") or ts.objective
85
+ ts.acceptance_criteria = list(e.get("acceptance_criteria", []) or ts.acceptance_criteria)
86
+ elif t in ("verify_gate", "verification", "done") and e.get("phase"):
87
+ ts.phase = e.get("phase", ts.phase)
88
+ elif t == "verify_gate":
89
+ ts.phase = "repair" if e.get("kind") == "failed" else "verify"
90
+ elif t == "done":
91
+ ts.phase = e.get("phase", ts.phase)
92
+ return ts
93
+
94
+
95
+ def summarize(events_or_path) -> dict:
96
+ """A compact digest of a task's execution trace for inspection/diagnosis."""
97
+ evs = _events(events_or_path)
98
+ tools: dict[str, int] = {}
99
+ turns = in_tok = out_tok = verify_pass = verify_fail = 0
100
+ phase = "understand"
101
+ for e in evs:
102
+ t = e.get("type")
103
+ if t == "turn":
104
+ turns += 1; in_tok += e.get("in_tok", 0) or 0; out_tok += e.get("out_tok", 0) or 0
105
+ elif t == "tool":
106
+ tools[e.get("name", "?")] = tools.get(e.get("name", "?"), 0) + 1
107
+ elif t == "verification":
108
+ if e.get("status") == "pass": verify_pass += 1
109
+ elif e.get("status") == "fail": verify_fail += 1
110
+ elif t == "done":
111
+ phase = e.get("phase", phase)
112
+ ts = reconstruct_task_state(evs)
113
+ return {
114
+ "objective": ts.objective, "acceptance_criteria": ts.acceptance_criteria,
115
+ "final_phase": phase, "turns": turns, "tools": tools,
116
+ "in_tok": in_tok, "out_tok": out_tok,
117
+ "verifications": {"pass": verify_pass, "fail": verify_fail},
118
+ "event_count": len(evs),
119
+ }
@@ -531,6 +531,8 @@ class DrydockApp(App):
531
531
  self._cmd_context(arg)
532
532
  elif cmd == "/shell":
533
533
  self._cmd_shell()
534
+ elif cmd == "/events":
535
+ self._cmd_events()
534
536
  elif cmd == "/advisor":
535
537
  self._cmd_advisor(arg)
536
538
  elif cmd == "/ask":
@@ -837,6 +839,27 @@ class DrydockApp(App):
837
839
  else:
838
840
  self._begin(prompt)
839
841
 
842
+ def _cmd_events(self) -> None:
843
+ """Show a digest of this session's durable execution trace (event log)."""
844
+ log = self.state.events
845
+ if log is None:
846
+ self._info("Event log is off (config event_log = false).")
847
+ return
848
+ from drydock.events import summarize
849
+ s = summarize(str(log.path))
850
+ tools = ", ".join(f"{k}×{v}" for k, v in sorted(s["tools"].items())) or "none"
851
+ v = s["verifications"]
852
+ lines = [
853
+ f"Task trace — {log.path}",
854
+ f" objective : {(s['objective'] or '(none yet)')[:80]}",
855
+ f" criteria : {len(s['acceptance_criteria'])}",
856
+ f" phase : {s['final_phase']}",
857
+ f" turns : {s['turns']} tools: {tools}",
858
+ f" verifications: {v['pass']} passed, {v['fail']} failed",
859
+ f" tokens : {s['in_tok']:,} in / {s['out_tok']:,} out ({s['event_count']} events)",
860
+ ]
861
+ self._info("\n".join(lines))
862
+
840
863
  def _cmd_shell(self) -> None:
841
864
  """Show exactly which shell the Bash tool runs commands through, plus the
842
865
  platform signals — so a 'still using bash on Windows' report is instantly
@@ -153,7 +153,7 @@ class PromptHistory:
153
153
  # completes the prefix.
154
154
  SLASH_COMMANDS = [
155
155
  "/help", "/model", "/cwd", "/undo", "/back", "/stop", "/status",
156
- "/compact", "/context", "/shell", "/advisor", "/ask", "/ask!", "/graphrag", "/skills",
156
+ "/compact", "/context", "/shell", "/events", "/advisor", "/ask", "/ask!", "/graphrag", "/skills",
157
157
  "/loop", "/mcp", "/rmf", "/stig",
158
158
  "/clear", "/quit",
159
159
  ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drydock-cli
3
- Version: 3.0.127
3
+ Version: 3.0.128
4
4
  Summary: Drydock — a local, provider-agnostic terminal coding agent for local LLMs
5
5
  Author: Frank Bobe III
6
6
  License-Expression: Apache-2.0
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
7
7
  # PyPI distribution name is drydock-cli (the established install name, continued
8
8
  # from the retired v2 fork); the import package + CLI command stay `drydock`.
9
9
  name = "drydock-cli"
10
- version = "3.0.127"
10
+ version = "3.0.128"
11
11
  description = "Drydock — a local, provider-agnostic terminal coding agent for local LLMs"
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.11"
@@ -56,3 +56,36 @@ def test_run_writes_full_trace():
56
56
  def test_disabled_no_events_attr():
57
57
  st = agent.AgentState()
58
58
  assert st.events is None # off by default on a bare AgentState
59
+
60
+
61
+ def test_reconstruct_task_state_from_trace():
62
+ from drydock.events import EventLog, reconstruct_task_state
63
+ p = os.path.join(tempfile.mkdtemp(), "r.jsonl")
64
+ log = EventLog(p)
65
+ log.emit("task_start", objective="Recover the password", acceptance_criteria=["23 chars", "write out.txt"])
66
+ log.emit("tool", name="Write")
67
+ log.emit("done", phase="complete")
68
+ ts = reconstruct_task_state(p)
69
+ assert ts.objective == "Recover the password"
70
+ assert ts.acceptance_criteria == ["23 chars", "write out.txt"]
71
+ assert ts.phase == "complete"
72
+
73
+
74
+ def test_summarize_digest():
75
+ from drydock.events import EventLog, summarize
76
+ p = os.path.join(tempfile.mkdtemp(), "s.jsonl")
77
+ log = EventLog(p)
78
+ log.emit("task_start", objective="do X", acceptance_criteria=["a"])
79
+ log.emit("turn", in_tok=100, out_tok=50)
80
+ log.emit("tool", name="Bash"); log.emit("tool", name="Bash")
81
+ log.emit("verification", status="fail"); log.emit("verification", status="pass")
82
+ log.emit("done", phase="complete")
83
+ s = summarize(p)
84
+ assert s["turns"] == 1 and s["tools"] == {"Bash": 2}
85
+ assert s["verifications"] == {"pass": 1, "fail": 1} and s["final_phase"] == "complete"
86
+ assert s["in_tok"] == 100 and s["out_tok"] == 50
87
+
88
+
89
+ def test_reconstruct_empty_trace():
90
+ from drydock.events import reconstruct_task_state
91
+ assert reconstruct_task_state([]).objective == ""
File without changes
File without changes
File without changes
File without changes