feat(runtime): add planner reflection history with rationale and thinking
Tests / Test failed: 2, passed: 849
Tests / Test failed: 2, passed: 849
- ToolCallDecision captures thinking blocks and pre-tool text output
- AnthropicToolCallingClient supports optional extended thinking (budget_tokens + beta header)
- PlannedStep carries rationale and thinking from each LLM decision
- WorldEvent replaces scene_summary with rationale/thinking/page fields (backward-compatible)
- AI planner system prompt instructs reflection before each tool call
- _history_summary() emits compact {page, rationale, action, success} dicts
- Cloud DB migration 0011 adds nullable rationale/thinking columns to planner_decision_log
- OpenAI client extracts reasoning_content into thinking field
This commit is contained in:
@@ -1751,3 +1751,62 @@ def test_prune_planner_decision_log_deletes_only_old_terminal_tasks(
|
||||
)
|
||||
finally:
|
||||
database.close()
|
||||
|
||||
|
||||
def test_record_planner_decision_stores_rationale_and_thinking(
|
||||
database_url: str,
|
||||
) -> None:
|
||||
database = CloudDatabase(database_url)
|
||||
task_id = _unique_id("reflect-task")
|
||||
host_id = _unique_id("reflect-host")
|
||||
now = datetime(2026, 7, 15, 0, 0, tzinfo=UTC)
|
||||
|
||||
try:
|
||||
database.repository.record_planner_decision(
|
||||
host_id=host_id,
|
||||
task_id=task_id,
|
||||
attempt=1,
|
||||
system_prompt="system",
|
||||
user_prompt="user",
|
||||
tool_name="tap",
|
||||
arguments_json='{"x": 1}',
|
||||
now=now,
|
||||
rationale="Previous step opened settings. Now tapping account.",
|
||||
thinking="I need to navigate to account settings.",
|
||||
)
|
||||
|
||||
decisions = database.repository.list_planner_decisions(task_id=task_id, attempt=1)
|
||||
assert len(decisions) == 1
|
||||
assert decisions[0].rationale == "Previous step opened settings. Now tapping account."
|
||||
assert decisions[0].thinking == "I need to navigate to account settings."
|
||||
finally:
|
||||
database.close()
|
||||
|
||||
|
||||
def test_record_planner_decision_stores_null_rationale_and_thinking(
|
||||
database_url: str,
|
||||
) -> None:
|
||||
database = CloudDatabase(database_url)
|
||||
task_id = _unique_id("reflect-null-task")
|
||||
host_id = _unique_id("reflect-null-host")
|
||||
now = datetime(2026, 7, 15, 0, 0, tzinfo=UTC)
|
||||
|
||||
try:
|
||||
database.repository.record_planner_decision(
|
||||
host_id=host_id,
|
||||
task_id=task_id,
|
||||
attempt=1,
|
||||
system_prompt="system",
|
||||
user_prompt="user",
|
||||
tool_name="tap",
|
||||
arguments_json="{}",
|
||||
now=now,
|
||||
# rationale and thinking omitted (default None)
|
||||
)
|
||||
|
||||
decisions = database.repository.list_planner_decisions(task_id=task_id, attempt=1)
|
||||
assert len(decisions) == 1
|
||||
assert decisions[0].rationale is None
|
||||
assert decisions[0].thinking is None
|
||||
finally:
|
||||
database.close()
|
||||
|
||||
Reference in New Issue
Block a user