fix: delegate analysis planning from main agent
This commit is contained in:
@@ -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.
|
||||
Reference in New Issue
Block a user