From ccbe6ca565b03b138fa50d7951636198e75b4b34 Mon Sep 17 00:00:00 2001 From: kris Date: Sun, 29 Mar 2026 18:05:30 +0800 Subject: [PATCH] docs: add main agent runtime flow spec --- .../2026-03-29-main-agent-runtime-flow.md | 480 ++++++++++++++++++ ...26-03-29-main-agent-runtime-flow-design.md | 354 +++++++++++++ 2 files changed, 834 insertions(+) create mode 100644 docs/superpowers/plans/2026-03-29-main-agent-runtime-flow.md create mode 100644 docs/superpowers/specs/2026-03-29-main-agent-runtime-flow-design.md diff --git a/docs/superpowers/plans/2026-03-29-main-agent-runtime-flow.md b/docs/superpowers/plans/2026-03-29-main-agent-runtime-flow.md new file mode 100644 index 0000000..da58883 --- /dev/null +++ b/docs/superpowers/plans/2026-03-29-main-agent-runtime-flow.md @@ -0,0 +1,480 @@ +# Main Agent Runtime Flow 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:** Add the first production-ready main-agent run layer so StoryForge can create confirmable runs, display runtime progress in the floating OneLiner window, and unify “handoff to main agent” actions. + +**Architecture:** Keep existing `OneLiner session/message` as the conversation layer, add `agent_runs` plus `agent_run_events` inside `oneliner_features.py` as a separate runtime layer, then extend the existing floating OneLiner UI to render a run header area above the chat stream and wire selected page actions into run creation. + +**Tech Stack:** FastAPI, SQLite, existing StoryForge Web V4 vanilla JS, Node test runner, Python unittest + +--- + +### Task 1: Save docs for the runtime flow + +**Files:** +- Create: `docs/superpowers/specs/2026-03-29-main-agent-runtime-flow-design.md` +- Create: `docs/superpowers/plans/2026-03-29-main-agent-runtime-flow.md` + +- [ ] **Step 1: Save the approved design** + +Write the runtime flow design into the spec file above. + +- [ ] **Step 2: Save this implementation plan** + +Write this plan file and keep it committed with the implementation. + +- [ ] **Step 3: Commit docs checkpoint** + +```bash +git add docs/superpowers/specs/2026-03-29-main-agent-runtime-flow-design.md docs/superpowers/plans/2026-03-29-main-agent-runtime-flow.md +git commit -m "docs: add main agent runtime flow spec" +``` + +### Task 2: Add failing backend tests for the run layer + +**Files:** +- Modify: `tests/test_main_agent_governance.py` + +- [ ] **Step 1: Write the failing test for run creation** + +Add a test that creates a run through `POST /v2/oneliner/runs` and asserts: + +```python +response = self.client.post( + "/v2/oneliner/runs", + headers=self.ctx["member_headers"], + json={ + "project_id": self.ctx["project_id"], + "source_screen": "dashboard", + "source_action_key": "homepage-primary-action", + "title": "跟进重点账号", + "summary": "先由主 Agent 评估优先级", + "intent_key": "track_account", + "platform": "douyin", + "platform_scope": "single_platform", + "plan_request": { + "goal": "跟进重点账号", + "steps": ["读取当前项目上下文", "检查重点账号变化", "决定下一步"] + }, + }, +) +payload = response.json() +self.assertEqual(response.status_code, 200, response.text) +self.assertEqual(payload["run_status"], "needs_confirmation") +self.assertEqual(payload["source_screen"], "dashboard") +self.assertEqual(payload["platform"], "douyin") +self.assertTrue(payload["plan"]["steps"]) +``` + +- [ ] **Step 2: Write the failing test for confirm flow** + +Add a test that confirms a run and asserts: + +```python +confirm = self.client.post( + f"/v2/oneliner/runs/{run_id}/confirm", + headers=self.ctx["member_headers"], + json={"reason": "user confirmed"}, +) +payload = confirm.json() +self.assertEqual(confirm.status_code, 200, confirm.text) +self.assertIn(payload["run_status"], {"queued", "running"}) +``` + +- [ ] **Step 3: Write the failing test for projectless governance snapshot** + +Add a test that creates a run for an approved user with no project id and verifies no default project is auto-created while the run still stores a blank governance snapshot. + +- [ ] **Step 4: Run the backend tests and confirm they fail** + +Run: + +```bash +python3 -m unittest tests.test_main_agent_governance -v +``` + +Expected: FAIL because the run tables and endpoints do not exist yet. + +### Task 3: Add backend run schema and payload helpers + +**Files:** +- Modify: `collector-service/app/oneliner_features.py` + +- [ ] **Step 1: Add the new tables** + +Add schema creation for: + +```sql +CREATE TABLE IF NOT EXISTS agent_runs ( + id TEXT PRIMARY KEY, + session_id TEXT NOT NULL, + user_id TEXT NOT NULL, + project_id TEXT NOT NULL DEFAULT '', + source_type TEXT NOT NULL, + source_screen TEXT NOT NULL, + source_action_key TEXT NOT NULL, + title TEXT NOT NULL, + summary TEXT NOT NULL DEFAULT '', + intent_key TEXT NOT NULL DEFAULT '', + platform TEXT NOT NULL DEFAULT '', + platform_scope TEXT NOT NULL DEFAULT 'single_platform', + delivery_mode TEXT NOT NULL DEFAULT 'hybrid', + run_status TEXT NOT NULL, + scheduling_mode TEXT NOT NULL DEFAULT 'queued', + active_executor_key TEXT NOT NULL DEFAULT '', + plan_json TEXT NOT NULL DEFAULT '{}', + result_json TEXT NOT NULL DEFAULT '{}', + status_summary TEXT NOT NULL DEFAULT '', + needs_user_input INTEGER NOT NULL DEFAULT 0, + blocked_reason TEXT NOT NULL DEFAULT '', + active_admin_override_notice_json TEXT NOT NULL DEFAULT '{}', + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + started_at TEXT NOT NULL DEFAULT '', + finished_at TEXT NOT NULL DEFAULT '' +); + +CREATE TABLE IF NOT EXISTS agent_run_events ( + id TEXT PRIMARY KEY, + run_id TEXT NOT NULL, + event_type TEXT NOT NULL, + summary TEXT NOT NULL DEFAULT '', + details_json TEXT NOT NULL DEFAULT '{}', + created_at TEXT NOT NULL +); +``` + +- [ ] **Step 2: Add helper payload builders** + +Implement focused helpers for: + +```python +def _agent_run_payload(row: dict[str, Any]) -> dict[str, Any]: + ... + +def _agent_run_event_payload(row: dict[str, Any]) -> dict[str, Any]: + ... + +def _list_agent_run_events(run_id: str) -> list[dict[str, Any]]: + ... +``` + +- [ ] **Step 3: Add governance snapshot helper** + +Add a helper that returns: + +```python +{ + "project_id": project_id, + "platform": platform, + "effective_policy": ..., + "layers": ..., + "active_admin_override_notice": ..., +} +``` + +for use at run creation time. + +- [ ] **Step 4: Run backend tests** + +Run: + +```bash +python3 -m unittest tests.test_main_agent_governance -v +``` + +Expected: tests still fail, but schema-related failures move forward. + +### Task 4: Add backend run endpoints and state transitions + +**Files:** +- Modify: `collector-service/app/oneliner_features.py` +- Test: `tests/test_main_agent_governance.py` + +- [ ] **Step 1: Add request models** + +Add minimal request models for: + +```python +class AgentRunCreateRequest(BaseModel): + project_id: str = "" + source_screen: str + source_action_key: str + title: str + summary: str = "" + intent_key: str = "" + platform: str = "" + platform_scope: str = "single_platform" + plan_request: dict[str, Any] = Field(default_factory=dict) + +class AgentRunConfirmRequest(BaseModel): + reason: str = "" + +class AgentRunCancelRequest(BaseModel): + reason: str = "" +``` + +- [ ] **Step 2: Add `POST /v2/oneliner/runs`** + +Create a run that: +- resolves or creates the current session via the existing OneLiner session helper +- stores `run_status = "needs_confirmation"` +- snapshots current governance +- logs `run.created` + +- [ ] **Step 3: Add read endpoints** + +Implement: + +```python +@app.get("/v2/oneliner/runs") +@app.get("/v2/oneliner/runs/{run_id}") +@app.get("/v2/oneliner/runs/{run_id}/events") +``` + +The list endpoint should return the latest 20 runs for the current user and project, newest first. + +- [ ] **Step 4: Add confirm and cancel endpoints** + +Implement: + +```python +@app.post("/v2/oneliner/runs/{run_id}/confirm") +@app.post("/v2/oneliner/runs/{run_id}/cancel") +``` + +Confirm should: +- move `needs_confirmation -> queued` +- set `status_summary = "等待主 Agent 执行"` or `"主 Agent 正在执行"` +- create `run.confirmed` +- for the first version, immediately promote to `running` when no other active run exists for that user/project + +Cancel should: +- move `needs_confirmation -> cancelled` or `queued -> cancelled` +- create `run.cancelled` + +- [ ] **Step 5: Add one backend test for event sequencing** + +Assert that creation + confirm writes at least: +- `run.created` +- `run.confirmed` +- one of `run.queued` / `run.started` + +- [ ] **Step 6: Re-run backend tests** + +Run: + +```bash +python3 -m unittest tests.test_main_agent_governance -v +``` + +Expected: PASS. + +### Task 5: Add failing frontend tests for the floating runtime header + +**Files:** +- Modify: `web/storyforge-web-v4/tests/workbench-pages.test.mjs` + +- [ ] **Step 1: Add a failing test for the run header** + +Assert the OneLiner UI now includes a dedicated runtime header zone: + +```javascript +const source = extractBetween(APP, "function ensureOneLinerUi()", "function renderOneLinerSessionTabs()"); +assert.match(source, /data-role="oneliner-runs"/); +``` + +- [ ] **Step 2: Add a failing test for the run list loader** + +Assert the app state loader hits the new endpoints: + +```javascript +const source = extractBetween(APP, "async function loadAgentControlSurfaces(projectId = \"\")", "async function loadOneLinerMessages(sessionId)"); +assert.match(source, /\/v2\/oneliner\/runs/); +``` + +- [ ] **Step 3: Add a failing test for the handoff entrypoint** + +Assert the click handler routes a main-agent handoff to a dedicated action instead of only opening the chat: + +```javascript +const actions = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {"); +assert.match(actions, /handoff-to-main-agent/); +``` + +- [ ] **Step 4: Run the frontend tests and confirm failure** + +Run: + +```bash +node --test web/storyforge-web-v4/tests/workbench-pages.test.mjs +``` + +Expected: FAIL on missing run UI and handoff actions. + +### Task 6: Extend app state and OneLiner UI with the runtime header + +**Files:** +- Modify: `web/storyforge-web-v4/assets/app.js` +- Modify: `web/storyforge-web-v4/assets/styles.css` +- Test: `web/storyforge-web-v4/tests/workbench-pages.test.mjs` + +- [ ] **Step 1: Extend app state** + +Add state fields: + +```javascript +onelinerRuns: [], +selectedOnelinerRunId: "", +onelinerRunEvents: [], +``` + +- [ ] **Step 2: Render the runtime header area** + +Inside `ensureOneLinerUi()`, add a dedicated block: + +```html +
+``` + +above the message list. + +- [ ] **Step 3: Add render helpers** + +Implement focused helpers: + +```javascript +function pickPrimaryRun(runs) { ... } +function renderOneLinerRunSummary(primaryRun, runs) { ... } +function renderOneLinerRunEventChips(primaryRunEvents) { ... } +``` + +Behavior: +- prefer `needs_confirmation` +- then `blocked` +- then `running` +- then latest `done` + +- [ ] **Step 4: Add CSS for the runtime header** + +Add styles for: +- `.oneliner-runs` +- `.oneliner-run-card` +- `.oneliner-run-title` +- `.oneliner-run-summary` + +Keep the current OneLiner visual language. Do not redesign the shell. + +- [ ] **Step 5: Re-run frontend tests** + +Run: + +```bash +node --test web/storyforge-web-v4/tests/workbench-pages.test.mjs +node --check web/storyforge-web-v4/assets/app.js +``` + +Expected: PASS. + +### Task 7: Wire run loading, confirmation, and page handoff + +**Files:** +- Modify: `web/storyforge-web-v4/assets/app.js` +- Test: `web/storyforge-web-v4/tests/workbench-pages.test.mjs` + +- [ ] **Step 1: Load runs into app state** + +Extend `loadAgentControlSurfaces(projectId)` to fetch: + +```javascript +storyforgeFetch(`/v2/oneliner/runs?project_id=${encodeURIComponent(normalizedProjectId)}`) +``` + +and store it in `appState.onelinerRuns`. + +- [ ] **Step 2: Add API helpers** + +Implement: + +```javascript +async function createMainAgentRun(input) { ... } +async function confirmMainAgentRun(runId, reason = "") { ... } +async function cancelMainAgentRun(runId, reason = "") { ... } +``` + +- [ ] **Step 3: Add the dedicated handoff action** + +In the click handler, add: + +```javascript +if (name === "handoff-to-main-agent") { + ... +} +``` + +This action should: +- create a `needs_confirmation` run +- refresh run state +- open the OneLiner panel + +- [ ] **Step 4: Replace the first batch of entrypoints** + +Update these buttons to use `handoff-to-main-agent`: +- homepage primary action handoff +- homepage secondary action handoff +- strategy page `交给 OneLiner 调整` +- agent governance handoff tags + +- [ ] **Step 5: Add confirmation controls in the run header** + +For `needs_confirmation` runs, show: +- `确认执行` +- `取消` + +For `running/queued/blocked/done`, show compact status only. + +- [ ] **Step 6: Re-run frontend tests** + +Run: + +```bash +node --test web/storyforge-web-v4/tests/workbench-pages.test.mjs +``` + +Expected: PASS. + +### Task 8: Full verification, deploy, and publish + +**Files:** +- Modify only files already touched above + +- [ ] **Step 1: Run full verification** + +```bash +python3 -m unittest tests.test_main_agent_governance tests.test_platform_contracts tests.test_production_baseline -v +node --test web/storyforge-web-v4/tests/dashboard-home.test.mjs web/storyforge-web-v4/tests/workbench-pages.test.mjs +python3 -m compileall collector-service/app tests +git diff --check +bash scripts/check_repo_baseline.sh +``` + +Expected: all pass. + +- [ ] **Step 2: Deploy to NAS** + +```bash +STORYFORGE_FNOS_COLLECTOR_DEPLOY_MODE=remote_build bash /Users/kris/code/StoryForge-gitea/scripts/deploy_fnos_storyforge_collector.sh +bash /Users/kris/code/StoryForge-gitea/scripts/deploy_fnos_storyforge_web.sh +bash /Users/kris/code/StoryForge-gitea/scripts/smoke_fnos_storyforge_lan.sh +``` + +Expected: web, collector, cutvideo tunnel, compat smoke all pass. + +- [ ] **Step 3: Commit and push** + +```bash +git add collector-service/app/oneliner_features.py tests/test_main_agent_governance.py web/storyforge-web-v4/assets/app.js web/storyforge-web-v4/assets/styles.css web/storyforge-web-v4/tests/workbench-pages.test.mjs docs/superpowers/specs/2026-03-29-main-agent-runtime-flow-design.md docs/superpowers/plans/2026-03-29-main-agent-runtime-flow.md +git commit -m "feat: add main agent runtime flow" +git push gitea codex/storyforge-live-orchestrator-sync-20260323 +``` diff --git a/docs/superpowers/specs/2026-03-29-main-agent-runtime-flow-design.md b/docs/superpowers/specs/2026-03-29-main-agent-runtime-flow-design.md new file mode 100644 index 0000000..09caa0b --- /dev/null +++ b/docs/superpowers/specs/2026-03-29-main-agent-runtime-flow-design.md @@ -0,0 +1,354 @@ +# StoryForge 主 Agent 运行层与悬浮工作流设计 + +- 日期:2026-03-29 +- 状态:已确认,直接进入实现 +- 范围:`collector-service`、`web/storyforge-web-v4` + +## 1. 背景 + +当前仓库已经有两类能力: + +- `OneLiner session/message` + - 承担用户与主 Agent 的对话历史 +- `execution_card` + - 能在单条消息里附带执行建议、下一步、证据和管理员覆盖提示 + +但这些能力还不足以支撑“主 Agent 是全站统一工作入口”的产品目标。当前缺口主要有: + +- 页面里的“交给主 Agent”还没有统一承接链路。 +- 用户确认执行、后台运行、阻塞等待、近期进度都还没有独立的运行单元。 +- 右下角悬浮主 Agent 目前还是“聊天面板”,还不是“聊天 + 任务运行中心”。 +- 多任务并行/排队、最小化后状态感知、最近待确认任务都没有统一模型。 + +如果继续把执行请求直接塞进聊天消息,会导致: + +- 聊天和任务状态纠缠 +- 运行中/待确认/阻塞/完成难以跟踪 +- 页面动作无法统一接入 +- 后续审计、商业化和管理员治理会越来越难做 + +## 2. 目标 + +- 在现有 `OneLiner session/message` 之外,新增独立的 `agent run` 运行层。 +- 所有页面里的“交给主 Agent”统一先创建一个 `needs_confirmation` 的 run。 +- 右下角悬浮主 Agent 继续作为唯一入口,但内部升级为: + - 顶部执行区 + - 下方聊天流 +- 用户确认后,run 才进入真正执行。 +- 主 Agent 自己判断 run 是并行还是排队。 +- 悬浮按钮最小化后仍可看到: + - 状态点 + - 当前任务数 + - 一行极短状态摘要 +- 当存在管理员覆盖时,确认卡和运行卡需要显式提示。 + +## 3. 非目标 + +- 本轮不重做整套视觉风格。 +- 本轮不把所有前端按钮都改成真正自动化执行。 +- 本轮不实现复杂图形化编排器。 +- 本轮不引入新的任务基础设施或消息队列。 +- 本轮不替换现有 `OneLiner session/message`。 + +## 4. 总体方案 + +采用“双层结构”: + +1. `OneLiner session/message` +- 保留现有聊天历史与自然语言上下文 + +2. `agent run` +- 新增专门的运行单元 +- 用于承接: + - 页面动作升级为主 Agent 执行 + - 需要用户确认的执行计划 + - 后台运行状态 + - 阻塞等待和恢复 + - 最近一次执行结果 + +这两层通过 `session_id` 关联,但职责不同: + +- `session/message` 负责“说了什么” +- `agent run` 负责“当前在做什么” + +## 5. 数据模型 + +### 5.1 新表 + +新增表:`agent_runs` + +核心字段: + +- `id` +- `session_id` +- `user_id` +- `project_id` +- `source_type` + - `homepage_action` + - `page_action` + - `chat_request` + - `system_followup` +- `source_screen` +- `source_action_key` +- `title` +- `summary` +- `intent_key` +- `platform` +- `platform_scope` + - `single_platform` + - `all_platforms` +- `delivery_mode` + - `ui` + - `oneliner` + - `hybrid` +- `run_status` + - `needs_confirmation` + - `queued` + - `running` + - `blocked` + - `done` + - `failed` + - `cancelled` +- `scheduling_mode` + - `parallel` + - `queued` +- `active_executor_key` +- `plan_json` +- `result_json` +- `status_summary` +- `needs_user_input` +- `blocked_reason` +- `active_admin_override_notice_json` +- `created_at` +- `updated_at` +- `started_at` +- `finished_at` + +### 5.2 事件表 + +新增表:`agent_run_events` + +核心字段: + +- `id` +- `run_id` +- `event_type` + - `run.created` + - `run.confirmed` + - `run.queued` + - `run.started` + - `run.progress` + - `run.blocked` + - `run.done` + - `run.failed` + - `run.cancelled` +- `summary` +- `details_json` +- `created_at` + +### 5.3 运行状态机 + +默认状态流转: + +- `needs_confirmation -> queued -> running -> done` + +异常流转: + +- `needs_confirmation -> cancelled` +- `running -> blocked` +- `blocked -> running` +- `running -> failed` +- `queued -> cancelled` + +## 6. 运行规则 + +### 6.1 页面动作进入主 Agent + +所有页面中的“交给主 Agent”统一调用新入口: + +- `POST /v2/oneliner/runs` + +提交内容至少包含: + +- `project_id` +- `source_screen` +- `source_action_key` +- `title` +- `summary` +- `platform` +- `platform_scope` +- `intent_key` +- `plan_request` + +后端创建: + +- 一个 `agent run` +- 默认 `run_status = needs_confirmation` +- 并把当时的: + - 有效策略 + - 执行步骤 + - 平台 Agent 目标 + - 管理员覆盖提示 + 写成 `plan_json` + +### 6.2 确认卡 + +点击“交给主 Agent”后: + +- 自动打开右下角悬浮窗口 +- 顶部优先展示最近一次 `needs_confirmation` 的 run + +确认卡默认展示标准信息: + +- 目标 +- 影响对象 +- 执行步骤 +- 会调用哪些平台 Agent +- 可能影响什么 + +如果存在管理员覆盖,再额外展示一段简短提示: + +- `当前存在管理员覆盖:xxx` + +### 6.3 确认后执行 + +确认执行后: + +- run 进入 `queued` +- 主 Agent 根据当前运行情况决定: + - 并行执行 + - 还是排队等待 + +如果可以直接执行: + +- `queued -> running` + +如果要等其他 run: + +- 保持 `queued` +- 更新 `status_summary` + +### 6.4 最小化后的状态 + +悬浮按钮最小化时显示: + +- 状态点 + - 空闲 + - 需确认 + - 运行中 + - 阻塞 +- 当前任务数 +- 一行极短状态摘要 + +摘要优先级: + +1. 最近待确认任务 +2. 最近阻塞任务 +3. 当前运行中的任务 +4. 最近完成任务 + +## 7. 前端交互设计 + +### 7.1 悬浮窗口布局 + +保留现有 `OneLiner` 右下角入口,不新增第二入口。 + +窗口内部改成: + +1. 顶部 `run` 区 +- 待确认卡 / 运行中卡 / 阻塞卡 / 完成卡 + +2. 中部聊天流 +- 保留现有 `session/message` + +3. 底部输入区 +- 继续支持自然语言对话 + +### 7.2 顶部 run 区优先级 + +打开窗口后,顶部默认显示: + +1. 最近一次需要用户确认的 run +2. 若没有待确认,则显示最近一次阻塞 run +3. 若没有阻塞,则显示当前运行中的 run +4. 若都没有,则显示最近完成的 run + +### 7.3 页面动作接入 + +第一版先接以下入口: + +- 首页主动作中的 `交给主 Agent` +- 首页次动作中的 `交给主 Agent` +- `我的策略` 页的 `交给 OneLiner 调整` +- `Agent` 页与策略治理相关的 `交给主 Agent` + +其他页面先保留现有 `open-oneliner`,后续再逐步切到 run 创建入口。 + +## 8. 后端接口 + +### 8.1 运行层 + +- `POST /v2/oneliner/runs` + - 创建一个待确认 run +- `GET /v2/oneliner/runs` + - 读取当前用户最近 run 列表 +- `GET /v2/oneliner/runs/{run_id}` + - 读取单个 run 详情 +- `POST /v2/oneliner/runs/{run_id}/confirm` + - 用户确认执行 +- `POST /v2/oneliner/runs/{run_id}/cancel` + - 用户取消 +- `GET /v2/oneliner/runs/{run_id}/events` + - 读取运行事件 + +### 8.2 会话层保持不变 + +保留现有: + +- `POST /v2/oneliner/sessions/{session_id}/messages` +- `POST /v2/oneliner/actions/execute` + +第一版由 run 层在确认执行后,内部复用现有 `actions/execute` 或对话处理逻辑。 + +## 9. 与治理底座的关系 + +`agent run` 创建时会固化: + +- 当前有效策略摘要 +- 当前叠加层 +- 当前管理员覆盖提示 + +这样可以确保: + +- 用户看到的确认卡可解释 +- 运行中状态与当时策略一致 +- 后续审计可以回答“为什么这样执行” + +## 10. 测试 + +### 10.1 后端 + +- run 创建测试 +- run 确认流转测试 +- run 阻塞/完成事件测试 +- run 创建时固化治理快照测试 +- run 列表优先级测试 + +### 10.2 前端 + +- 悬浮窗口包含 run 顶部区 +- 页面动作会创建待确认 run +- 待确认 run 会优先展示 +- 最小化按钮显示状态点、数量、摘要 +- 管理员覆盖提示可见 + +## 11. 第一版验收标准 + +- 用户从首页点“交给主 Agent”,会打开悬浮窗口并看到标准确认卡。 +- 确认后,顶部 run 区能看到: + - 运行状态 + - 极短状态摘要 + - 最新进度 +- 下方聊天流仍然正常工作。 +- 最小化后,右下角能看到当前任务状态。 +- 有管理员覆盖时,确认卡和运行卡都会明确提示。