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:
caoxiaozhu
2026-06-15 22:55:18 +08:00
parent 792741709a
commit 9f7b8b46a3
85 changed files with 9496 additions and 2555 deletions

View File

@@ -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
```