Refine travel reimbursement steward flow
Align planner, runtime rules, and policy assets so travel guidance matches the updated reimbursement workflow.
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
# 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**
|
||||
|
||||
```python
|
||||
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"
|
||||
```
|
||||
|
||||
```python
|
||||
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:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
docker exec -w /app/web x-financial-main npm run build
|
||||
```
|
||||
|
||||
Expected: build succeeds.
|
||||
|
||||
### Task 5: Final Verification
|
||||
|
||||
- [ ] **Step 1: Run backend steward tests**
|
||||
|
||||
```bash
|
||||
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**
|
||||
|
||||
```bash
|
||||
docker exec -w /app/web x-financial-main npm run build
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Report workspace status**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
git status --short
|
||||
```
|
||||
Reference in New Issue
Block a user