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:
@@ -155,6 +155,8 @@ class PlannerDecisionLogRow(Base):
|
||||
tool_name: Mapped[str] = mapped_column(String, nullable=False)
|
||||
arguments_json: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
created_at: Mapped[str] = mapped_column(String, nullable=False)
|
||||
rationale: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
thinking: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
|
||||
|
||||
class PluginRow(Base):
|
||||
|
||||
@@ -504,6 +504,8 @@ def create_internal_router(
|
||||
tool_name=decision.tool_name,
|
||||
arguments_json=json.dumps(decision.arguments),
|
||||
now=utc_now(),
|
||||
rationale=getattr(decision, "text_output", None),
|
||||
thinking=getattr(decision, "thinking", None),
|
||||
)
|
||||
logger.info(
|
||||
"planner-decision request resolved",
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
"""Add rationale and thinking columns to planner_decision_log."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
revision = "0011_planner_decision_log_reflection"
|
||||
down_revision = "0010_skill_management"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.add_column(
|
||||
"planner_decision_log",
|
||||
sa.Column("rationale", sa.Text(), nullable=True),
|
||||
)
|
||||
op.add_column(
|
||||
"planner_decision_log",
|
||||
sa.Column("thinking", sa.Text(), nullable=True),
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column("planner_decision_log", "thinking")
|
||||
op.drop_column("planner_decision_log", "rationale")
|
||||
@@ -134,6 +134,8 @@ class PlannerDecisionRecord:
|
||||
tool_name: str
|
||||
arguments_json: str
|
||||
created_at: datetime
|
||||
rationale: str | None = None
|
||||
thinking: str | None = None
|
||||
|
||||
|
||||
class CloudRepository(Protocol):
|
||||
@@ -518,6 +520,8 @@ class CloudRepository(Protocol):
|
||||
tool_name: str,
|
||||
arguments_json: str,
|
||||
now: datetime,
|
||||
rationale: str | None = None,
|
||||
thinking: str | None = None,
|
||||
) -> int:
|
||||
"""Insert one planner-decision log row, returning the assigned step_index.
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ from alembic.runtime.migration import MigrationContext
|
||||
from cloud.database import create_database_engine, normalize_database_url
|
||||
|
||||
|
||||
HEAD_REVISION = "0010_skill_management"
|
||||
HEAD_REVISION = "0011_planner_decision_log_reflection"
|
||||
|
||||
|
||||
class SchemaVersionError(RuntimeError):
|
||||
|
||||
@@ -1694,6 +1694,8 @@ class SQLAlchemyCloudRepository:
|
||||
tool_name: str,
|
||||
arguments_json: str,
|
||||
now: datetime,
|
||||
rationale: str | None = None,
|
||||
thinking: str | None = None,
|
||||
) -> int:
|
||||
with self._sessions.begin() as session:
|
||||
current_max = session.scalars(
|
||||
@@ -1714,6 +1716,8 @@ class SQLAlchemyCloudRepository:
|
||||
tool_name=tool_name,
|
||||
arguments_json=arguments_json,
|
||||
created_at=_iso(now),
|
||||
rationale=rationale,
|
||||
thinking=thinking,
|
||||
)
|
||||
)
|
||||
session.flush()
|
||||
@@ -1766,6 +1770,8 @@ class SQLAlchemyCloudRepository:
|
||||
tool_name=row.tool_name,
|
||||
arguments_json=row.arguments_json,
|
||||
created_at=_parse_dt(row.created_at), # type: ignore[arg-type]
|
||||
rationale=row.rationale,
|
||||
thinking=row.thinking,
|
||||
)
|
||||
for row in rows
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user