Align planner, runtime rules, and policy assets so travel guidance matches the updated reimbursement workflow.
5.9 KiB
Steward Application Reimbursement State Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Build a persistent ontology-bound steward state for travel application and travel reimbursement flows.
Architecture: Keep the existing steward planning UI and assistant delegation flow. Add a backend state layer that stores steward_state in AgentConversation.state_json, merges LLM/rule output as patches, and rejects fields outside the ontology registry before downstream services consume them.
Tech Stack: FastAPI, SQLAlchemy JSON state, Pydantic schemas, pytest in Docker x-financial-main:/app, Vue/Vite frontend.
Task 1: Backend State Contract
Files:
-
Modify:
server/src/app/schemas/steward.py -
Create:
server/src/app/services/steward_flow_state.py -
Test:
server/tests/test_steward_flow_state.py -
Step 1: Write failing tests
def test_state_merge_keeps_application_and_reimbursement_flows():
service = StewardFlowStateService()
state = service.merge_state(
{},
StewardFlowStatePatch(
active_flow="travel_application",
flow_id="travel_application",
intent="travel_application_create",
fields={"expense_type": "travel", "location": "上海"},
),
)
state = service.merge_state(
state,
StewardFlowStatePatch(
active_flow="travel_reimbursement",
flow_id="travel_reimbursement",
intent="travel_reimbursement_draft",
fields={"amount": "708", "invoice_no": "NO-1"},
),
)
assert state["flows"]["travel_application"]["fields"]["location"] == "上海"
assert state["flows"]["travel_reimbursement"]["fields"]["amount"] == "708"
def test_state_merge_filters_non_ontology_fields():
service = StewardFlowStateService()
state = service.merge_state(
{},
StewardFlowStatePatch(
active_flow="travel_application",
flow_id="travel_application",
intent="travel_application_create",
fields={"location": "上海", "invented_field": "x"},
),
)
assert state["flows"]["travel_application"]["fields"] == {"location": "上海"}
- Step 2: Run red tests
Run:
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main /tmp/x-financial-server-venv/bin/pytest -q server/tests/test_steward_flow_state.py
Expected: fail because steward_flow_state.py does not exist.
- Step 3: Implement minimal state service
Create StewardFlowStatePatch, StewardFlowStateService.merge_state, ontology field filtering, and event append logic.
- Step 4: Run green tests
Run the same pytest command and expect pass.
Task 2: Steward Plan Persistence
Files:
-
Modify:
server/src/app/schemas/steward.py -
Modify:
server/src/app/api/v1/endpoints/steward.py -
Modify:
server/src/app/services/agent_conversations.py -
Test:
server/tests/test_steward_planner.py -
Step 1: Write failing API/service test
Add a test proving /steward/plans response contains conversation_id and steward_state when context_json.session_type = steward, and the state contains two flows when the input contains one application and one reimbursement task.
- Step 2: Run red test
Run:
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main /tmp/x-financial-server-venv/bin/pytest -q server/tests/test_steward_planner.py
- Step 3: Implement conversation state persistence
Add conversation_id and steward_state fields to response schemas, persist state through AgentConversationService, and merge planner tasks into steward_state.
- Step 4: Run green test
Run the same pytest command and expect pass.
Task 3: Runtime Decision Reads Persistent State
Files:
-
Modify:
server/src/app/services/steward_runtime_decision_agent.py -
Test:
server/tests/test_steward_runtime_decision_agent.py -
Step 1: Write failing test
Add a test proving runtime decision uses context_json.conversation_state.steward_state when runtime_state is empty.
- Step 2: Implement minimal fallback hydration
Normalize runtime state by merging request runtime state with persisted steward state.
- Step 3: Run green test
Run:
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main /tmp/x-financial-server-venv/bin/pytest -q server/tests/test_steward_runtime_decision_agent.py
Task 4: Frontend State Carry
Files:
-
Modify:
web/src/views/scripts/stewardPlanModel.js -
Modify:
web/src/views/scripts/TravelReimbursementCreateView.js -
Modify:
web/src/views/scripts/useTravelReimbursementSessionState.js -
Step 1: Preserve steward state from backend responses
Normalize conversation_id and steward_state from plan/runtime responses into the local session model.
- Step 2: Send steward state in later requests
Include the current steward_state under context_json for plan and runtime decision calls.
- Step 3: Build frontend
Run:
docker exec -w /app/web x-financial-main npm run build
Expected: build succeeds.
Task 5: Final Verification
- Step 1: Run backend steward tests
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main /tmp/x-financial-server-venv/bin/pytest -q server/tests/test_steward_flow_state.py server/tests/test_steward_planner.py server/tests/test_steward_runtime_decision_agent.py server/tests/test_steward_slot_decision_agent.py
- Step 2: Run frontend build
docker exec -w /app/web x-financial-main npm run build
- Step 3: Report workspace status
Run:
git status --short