Skip to content

Commit b63d563

Browse files
committed
Replay observations and auto-approve pending calls in TUI resume
- Extend TUI resume command to replay tool call observations from the prior run and auto-approve any pending approval request - Report replayed_observations count in the resume result payload
1 parent 29a6529 commit b63d563

2 files changed

Lines changed: 49 additions & 5 deletions

File tree

teaagent/tui.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import json
44
import shlex
55
from pathlib import Path
6-
from typing import Callable, Optional
6+
from typing import Any, Callable, Optional
77

88
from teaagent import __version__
99
from teaagent.chat_agent import ChatAgentConfig, run_chat_agent
@@ -294,13 +294,22 @@ def handle_command(self, raw_command: str) -> bool:
294294
if len(args) != 1:
295295
self.output_fn("error: resume requires a run id")
296296
return True
297+
store = RunStore(self.root)
297298
try:
298-
original_task = RunStore(self.root).task_for_run(args[0])
299+
original_task = store.task_for_run(args[0])
300+
observations = store.observations_for_run(args[0])
301+
pending = store.pending_approval_for_run(args[0])
299302
except (FileNotFoundError, ValueError) as exc:
300303
self.output_fn(f"error: {exc}")
301304
return True
305+
if pending:
306+
self.approved_call_ids.add(pending["call_id"])
307+
self.output_fn(f"auto-approved pending call: {pending['call_id']}")
302308
self.output_fn(f"resume: {args[0]}")
303-
self._run_agent_task(original_task)
309+
self._run_agent_task(
310+
original_task,
311+
initial_observations=observations if observations else None,
312+
)
304313
return True
305314
if action == "use":
306315
if len(args) != 1:
@@ -355,7 +364,7 @@ def _handle_memory(self, args: list[str]) -> None:
355364
return
356365
self.output_fn(f"error: unknown memory command '{action}'")
357366

358-
def _run_agent_task(self, task: str, *, clarify_first: bool = False) -> None:
367+
def _run_agent_task(self, task: str, *, clarify_first: bool = False, initial_observations: Optional[list[dict[str, Any]]] = None) -> None:
359368
task_spec = None
360369
if clarify_first:
361370
clarification = clarify_task(task)
@@ -388,9 +397,13 @@ def _run_agent_task(self, task: str, *, clarify_first: bool = False) -> None:
388397
),
389398
audit=audit,
390399
task_spec=task_spec,
400+
initial_observations=initial_observations,
391401
)
392402
store.logger_for_result(result, audit)
393-
self._print_json(self._run_result_payload(result, routing=routing.to_dict() if routing else None))
403+
payload = self._run_result_payload(result, routing=routing.to_dict() if routing else None)
404+
if initial_observations:
405+
payload["replayed_observations"] = len(initial_observations)
406+
self._print_json(payload)
394407

395408
def _approval_handler(self, request: ApprovalRequest) -> bool:
396409
self._print_json({"status": "approval_required", "approval": request.to_dict()})

tests/test_tui.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,37 @@ def test_tui_resume_replays_persisted_run_task(self) -> None:
250250
self.assertEqual(resume_payload["final_answer"], "second")
251251
self.assertIn(f"resume: {run_id}", output)
252252

253+
def test_tui_resume_replays_observations_for_non_destructive_run(self) -> None:
254+
with tempfile.TemporaryDirectory() as tmp:
255+
root = Path(tmp)
256+
(root / "note.txt").write_text("hello", encoding="utf-8")
257+
output = []
258+
adapter = FakeAdapter(
259+
[
260+
'{"type":"tool","tool_name":"workspace_read_file","arguments":{"path":"note.txt"},"call_id":"read-1"}',
261+
'{"type":"final","content":"first-done"}',
262+
'{"type":"final","content":"second-done"}',
263+
]
264+
)
265+
tui = TeaAgentTUI(
266+
root=tmp,
267+
input_fn=lambda _prompt: "exit",
268+
output_fn=output.append,
269+
adapter_factory=lambda _provider, _model: adapter,
270+
)
271+
272+
self.assertTrue(tui.handle_command("ask read note"))
273+
first_payload = json.loads(output[-1])
274+
run_id = first_payload["run_id"]
275+
276+
self.assertTrue(tui.handle_command(f"resume {run_id}"))
277+
resume_payload = json.loads(output[-1])
278+
279+
self.assertEqual(resume_payload["status"], "completed")
280+
self.assertEqual(resume_payload["final_answer"], "second-done")
281+
self.assertEqual(resume_payload["replayed_observations"], 1)
282+
self.assertIn(f"resume: {run_id}", output)
283+
253284
def test_tui_preflight_command_uses_current_settings(self) -> None:
254285
with tempfile.TemporaryDirectory() as tmp:
255286
output = []

0 commit comments

Comments
 (0)