fix: delegate analysis planning from main agent

This commit is contained in:
wtx
2026-08-08 10:40:01 +08:00
parent bfbddb544c
commit 5f240d1eec
3 changed files with 324 additions and 40 deletions
@@ -0,0 +1,204 @@
# Main Agent Analysis Handoff Boundary 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:** Ensure every `new_analysis` request is passed to the existing IntentAgent without Main Agent workflow, mode, or stage selection.
**Architecture:** Keep the existing RouterRuntime and proposal confirmation flow. Add one deterministic normalization boundary for `RouteDecision(goal="new_analysis")`, apply it after all route/confirmation branches, and remove the RNA-specific workflow override. The downstream IntentAgent, planner, frontend, contracts, and execution stages remain untouched.
**Tech Stack:** Python 3.11, Pydantic v2, pytest/pytest-asyncio, FastAPI backend API.
## Global Constraints
- Modify production code only in `gfa_core/mas/agents/router_runtime.py`.
- Do not modify frontend, IntentAgent, PlanningAgentV2, stage dependencies, RNA-seq YAML, CLI, or backend stage execution.
- Preserve the generic proposal confirmation mechanism.
- Preserve the exact user analysis request passed into the proposal and downstream recognizer.
- Main Agent must not set `workflow_id`, `clarification_question`, or stages for a `new_analysis` decision.
---
### Task 1: Lock the Main Agent handoff boundary with regression tests
**Files:**
- Create: `tests/unit/test_router_analysis_handoff_boundary.py`
- Test: `tests/unit/test_router_analysis_handoff_boundary.py`
**Interfaces:**
- Consumes: `RouterRuntime.run(...)`, `RouteDecision`, and `GoalLedger`.
- Produces: regression coverage proving that route-model workflow/mode clarification is discarded for new analyses.
- [ ] **Step 1: Write a failing generic RNA-seq handoff test**
Create a small fake tool registry whose `resolve_analysis_handoff_request()` returns its input unchanged. Monkeypatch `runtime._decide_route()` to return:
```python
RouteDecision(
goal="new_analysis",
needs=["analysis_intent"],
subject="执行rnaseq",
clarification_question="请选择全基因组还是基因家族成员RNA-seq",
workflow_id="rnaseq_whole_genome",
analysis_request_kind="execution",
)
```
Call `RouterRuntime.run(query="执行rnaseq", ..., goal_ledger=GoalLedger(...))` and assert:
```python
assert outcome.action == "clarify"
assert outcome.proposal is not None
assert outcome.proposal["request"] == "执行rnaseq"
assert "workflow_id" not in outcome.proposal
assert "全基因组还是" not in outcome.message
```
- [ ] **Step 2: Run the generic test and verify RED**
Run:
```bash
pytest -q tests/unit/test_router_analysis_handoff_boundary.py
```
Expected: FAIL because current `RouterRuntime.run()` returns the route model's mode clarification before creating a proposal.
- [ ] **Step 3: Add parameterized explicit-mode and non-RNA analysis cases**
Use the same runtime-level test for:
```python
(
("执行全基因组rnaseq", "rnaseq_whole_genome"),
("对已确认家族成员执行rnaseq", "rnaseq_family_member"),
("执行motif分析", "gene_family"),
)
```
For every case assert that the proposal request equals the original query and has no `workflow_id`.
- [ ] **Step 4: Run all boundary tests and confirm the expected failures**
Run:
```bash
pytest -q tests/unit/test_router_analysis_handoff_boundary.py
```
Expected: the new-analysis cases fail only because the Main Agent still retains clarification/workflow selection.
### Task 2: Implement the deterministic pass-through boundary
**Files:**
- Modify: `gfa_core/mas/agents/router_runtime.py:218-230`
- Modify: `gfa_core/mas/agents/router_runtime.py:630-820`
- Test: `tests/unit/test_router_analysis_handoff_boundary.py`
**Interfaces:**
- Consumes: `RouteDecision` produced by the route model or pending-proposal confirmation branch.
- Produces: `_analysis_handoff_decision(decision: RouteDecision) -> RouteDecision`.
- [ ] **Step 1: Add the minimal normalization helper**
Add one static method on `RouterRuntime`:
```python
@staticmethod
def _analysis_handoff_decision(decision: RouteDecision) -> RouteDecision:
if decision.goal != "new_analysis":
return decision
return RouteDecision(
goal="new_analysis",
needs=["analysis_intent"],
subject=decision.subject,
referent=decision.referent,
interaction_kind=decision.interaction_kind,
analysis_request_kind=decision.analysis_request_kind,
confirms_pending_proposal=decision.confirms_pending_proposal,
)
```
Apply it once after route decision, pending-proposal confirmation, and next-analysis normalization have converged, before any `clarification_question` early return or proposal construction.
- [ ] **Step 2: Remove RNA-specific Main Agent workflow selection**
Delete the `has_rnaseq_marker`, `explicit_family_member`, `explicit_whole_genome`, and replacement `RouteDecision` block in `RouterRuntime.run()`. Explicit mode words remain in `query` and therefore continue downstream unchanged.
- [ ] **Step 3: Tighten the route prompt without adding new behavior**
Replace the unspecified-RNA mode instruction with the general boundary:
```text
For goal=new_analysis, do not ask for an analysis mode, select a workflow, or select stages.
Leave workflow_id and clarification_question null and request analysis_intent; the existing
IntentAgent and PlanningAgent own missing analysis choices and executable stage planning.
```
- [ ] **Step 4: Run boundary tests and verify GREEN**
Run:
```bash
pytest -q tests/unit/test_router_analysis_handoff_boundary.py
```
Expected: all tests pass.
- [ ] **Step 5: Run focused existing conversation tests**
Run:
```bash
pytest -q tests/unit/test_agent_chat_actions.py tests/unit/test_autofill_entrypoints.py
```
Expected: all tests pass; generic proposal persistence, config dialog routing, and existing chat actions remain unchanged.
### Task 3: Verify syntax, diff scope, and live backend behavior
**Files:**
- Verify: `gfa_core/mas/agents/router_runtime.py`
- Verify: `tests/unit/test_router_analysis_handoff_boundary.py`
- Verify: `docs/superpowers/specs/2026-08-07-main-agent-analysis-handoff-boundary-design.md`
- Verify: `docs/superpowers/plans/2026-08-07-main-agent-analysis-handoff-boundary.md`
**Interfaces:**
- Consumes: local implementation and the running `/api/agent/chat` and `/api/agent/plan` endpoints.
- Produces: fresh evidence for regression safety and end-to-end handoff behavior.
- [ ] **Step 1: Compile the modified module**
Run:
```bash
/home/xia-lab/miniconda3/envs/test4py311/bin/python -m py_compile gfa_core/mas/agents/router_runtime.py
```
Expected: exit code 0 and no output.
- [ ] **Step 2: Audit changed-file scope**
Run:
```bash
git diff --name-only
git diff --cached --name-only
```
Expected production change: only `gfa_core/mas/agents/router_runtime.py`. No frontend or downstream analysis file appears.
- [ ] **Step 3: Exercise the real chat API with a fresh session**
POST `执行rnaseq` to `/api/agent/chat` for the existing RNA-seq test job. Assert that the response does not ask whole-genome versus family-member mode and that its proposal request preserves `执行rnaseq`.
- [ ] **Step 4: Confirm the proposal and inspect the recognizer trace**
POST `是` in the same session. Assert that `recognize_analysis_intent` receives a query beginning with `执行rnaseq`, and that returned intent stages come from the downstream IntentAgent.
- [ ] **Step 5: Verify plan fidelity**
POST the returned intent to `/api/agent/plan`. Assert the plan stages equal the dependency expansion of the downstream intent rather than a Main Agent-authored list.
- [ ] **Step 6: Report service state honestly**
If the live service still runs old code, report that API verification is pending restart; do not claim the runtime behavior is fixed based only on unit tests.