feat(scheduler+dashboard): 5s 心跳统一调度引擎与 Dashboard 子页面 - #555
Merged
ThreeFish-AI merged 12 commits intoMay 17, 2026
Conversation
新增统一调度框架:scheduled_tasks + task_executions 双表 + ScheduledTaskRegistry
单例 + 6 个 handler(skill_invoke / pipeline_watchdog / session_title_inspect /
cache_warm / pgvector_check / agent_inspection)。AsyncScheduler 升级为 5s 心跳
+ interval/cron/oneshot 三类触发判定,保留旧 register() API 兼容性。bootstrap.py
6 个 startup hook 合并为单一 ensure_registry_started() 入口;migration 0034 把
现存 skill_schedules 行回填为 scheduled_tasks 记录(保留旧表与 FK 兼容现有
/skills/{id}/schedules/* API)。Feature flag NEGENTROPY_UNIFIED_SCHEDULER_ENABLED
与 NEGENTROPY_SCHEDULER_HEARTBEAT_SECONDS 支持灰度回退。
参考业界经典心跳模式:MindStudio Heartbeat Pattern(调度层 + 共享状态层 + 持久化
层三层架构)、Scheduling Agent Supervisor Pattern(监督 + 心跳健康检测);
PostgreSQL FOR UPDATE SKIP LOCKED 保证多 worker 并发安全。
🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
提供 Dashboard 所需的 8 个端点:
- GET /scheduler/kpis 顶部 KPI 卡片(runs/success_rate/avg_latency)
- GET /scheduler/tasks 任务清单(5 维筛选 + 最近 3 次状态)
- GET /scheduler/tasks/{id} 单任务详情 + 最近 50 次执行
- GET /scheduler/executions 执行历史(分页 + 多维筛选)
- GET /scheduler/stats 按 role/scenario/agent/owner/handler_kind 分组聚合
- POST /scheduler/tasks/{id}/run 手动触发
- POST /scheduler/tasks/{id}/toggle 启停开关
- GET /scheduler/stream SSE 实时执行事件 + 5s 心跳保活
性能:stats / kpis 加 10s in-memory TTL cache 防高频请求;executions 端点
联表 ScheduledTask 一次完成 5 维筛选避免 N+1。SSE 通道由 ExecutionBus
asyncio.Queue fan-out 总线驱动,每个 SSE 连接独立队列、满则丢最旧消息。
🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
路由结构变更(Plan §3 方案 A):
- 根 / → server-side redirect('/studio'),无 hydration mismatch;
- app/(home)/layout.tsx 承载共享 Suspense + HomeNav;
- app/(home)/studio/page.tsx 平移自原 app/page.tsx(聊天界面零行为变化,
sessionId / CopilotKit Provider / NdjsonHttpAgent 完整保留);
- app/(home)/dashboard/ 路由占位,下个 commit 填充内容。
HomeNav 仿 MemoryNav 风格的 rounded-full 胶囊 Tab。设计取舍:sessionId 仅
Studio 携带,Dashboard URL 干净;在 Tab 之间切换时若有 sessionId 自动保留在
Studio 链接上,避免会话状态丢失。
🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
Dashboard 主页面与 6 个子组件: - KpiRow:6 卡片 KPI(tasks/runs/success_rate/running/failed/avg_latency) - FilterBar:role/scenario/agent/owner/category/window 多维筛选 + SSE 状态徽章 - DimensionCharts:recharts 三图(Role × Success/Failed 堆叠 + Scenario × Runs 水平条 + Owner × Runs 甜甜圈),暗色模式与 Tailwind 主题适配 - TaskTable:sticky header + 最近 3 次 ◐◐◐ 状态点 + 点击行打开 Drawer - ExecutionTimeline:执行历史时间线 + SSE 新增条目 800ms 高亮 - TaskDetailDrawer:Run Now / Toggle Enabled + 最近 50 次执行 + payload JSON Hooks: - useSchedulerData:并行 fetch 6 端点 + 30s 兜底定时刷新 + pushExecution 增量更新 - useSchedulerStream:EventSource + exponential backoff 重连 + ref 防 stale 闭包 反向代理:app/api/scheduler/[...path]/route.ts catch-all 复用 interface/_proxy 鉴权透传;stream/route.ts 用 ReadableStream 直通 SSE 不走 .text() 缓冲,确保 心跳逐条到达浏览器。 E2E 测试覆盖:根 / 跳到 /studio、Dashboard 显示 KPI/表/时间线/图表、HomeNav Tab 切换、点击行打开 Drawer + Run Now 操作链路。新增 recharts 3.8.1 依赖。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
实跑 Playwright Dashboard E2E 暴露两处问题:
1. getByRole('button', {name: 'Close'}) 同时命中 backdrop 的 aria-label='Close drawer'
和真实"Close"按钮 → strict mode violation。改用 exact: true 精确匹配。
2. recharts ResponsiveContainer 在 SSR prerender 阶段(无浏览器视口)测得
width(-1)/height(-1) 输出告警。给 ChartCard 加 min-h-[14rem] + style.minWidth=1
保底非负尺寸,浏览器加载后 ResponsiveContainer 会自然重新测量到 100% 宽高。
E2E 现 4/4 通过:根重定向 / Dashboard 展示 / Tab 切换 / Drawer + Run Now。
🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
引入通用 hook ``useHeartbeatPoll``,承担四项职责(替代散落的裸 setInterval): 1. 默认 5000ms 节拍,与后端 NEGENTROPY_SCHEDULER_HEARTBEAT_SECONDS=5 对齐,让 前端"自然刷新节奏"与后端"调度心跳节奏"在用户感知层面同步; 2. enabled gate 解耦状态机,避免父组件 useEffect 重复创建/销毁; 3. document.hidden 时自动暂停,回前台 / online 恢复立即触发一次(消除"后台 标签持续打 API"的旧问题); 4. callback 错误隔离,单次 throw 不停掉节拍。 统一收口四处轮询: - app/knowledge/pipelines/page.tsx running-state polling(5s) - features/knowledge/components/DocumentViewDialog.tsx 文档摄取进度 - app/knowledge/documents/[id]/page.tsx markdown 处理进度 - app/(home)/dashboard/_hooks/useSchedulerData.ts SSE 兜底刷新 保留 pipelines 页面的 bootstrap polling(1s 探测窗口,与心跳节奏正交,强行 5s 会拖慢检测窗口)。新增 5 个 hook 单测覆盖 fireImmediately / enabled / 错误 隔离 / unmount 清理。前端 vitest 88 文件 649 测试全过。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
把 Phase 4 最小骨架 agent_inspection handler 升级为生产可用: 1. **ContextPack**:每次 tick 从 task_executions 取最近 10 条 status + 24h tokens 累计 + payload + consecutive_failures,构造 dataclass 喂给具体巡检逻辑; 2. **Token 预算门控**:调用任何耗 token 的 Faculty 前预检 ``task.token_budget``, 超额返回 status=ok + skipped 标识,不消耗预算也不报错;token_budget=None 视为无限制,=0 永不放行; 3. **退避策略**:consecutive_failures >= 3 时按指数退避(60s/120s/240s.../1h ceiling + ±10% jitter)写 backoff_until,让 Registry 心跳跳过本任务直到 窗口结束(AWS Builder's Library 经典做法)。 新增两种 inspection_type: - ``faculty_deep_check``:扫描每个 Faculty 模块的 LlmAgent/Agent 实例(不构造 新的、不触发 LLM),暴露 tools 缺失 / 配置漂移等隐性故障; - ``scheduled_tasks_summary``:巡检调度框架自身的 last_status 分布,failed 占比 > 50% 时返回系统级告警。 Registry 默认任务追加 scheduled_tasks_summary_demo(每 10min,token_budget=10K) + 给 faculty_health demo 任务加 100K token 预算,让 Dashboard 默认即可见生产 特性的运作。 新增 11 个单测(ContextPack / token gate / backoff 单调性 / 上限截断 / faculty_health pass),engine 套件 560 个测试全过。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
… 冗余注释); - scheduler_api.py: list_tasks 的 recent_executions 改用 ROW_NUMBER OVER PARTITION BY task_id,避免高频任务挤占低频任务的状态点配额; - async_scheduler.py: _tick_once 同步置位 job.running,消除短 poll_interval 下下一轮 tick 抢先派发同一 job 的竞态; - handlers/pipeline_watchdog.py: KG 异常不再被 status=ok 吞掉,KB 成功 + KG 失败时返回 partial failed + 描述性 error,让退避与告警可见; - registry.py: 清理 _upsert_default_task 冗余三元 + 修正 dispatch 的并发保护注释(lease 仅覆盖 tick,manual 路径不限并发)。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
- app/page.tsx: 根路径重定向接收 searchParams,命中 sessionId 时拼接到 /studio?sessionId=,避免旧书签 /?sessionId=xxx 静默丢失会话; - (home)/dashboard/_hooks/useSchedulerData.ts: 新增 seenExecRef 去重集合,loadAll 后种入当前已落地执行 id,pushExecution 仅在 execution.id 首次以非 running 状态消费时累加 total_runs / recent,杜绝 SSE 重连重发或冷启动 + SSE 二次计数。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
- app/page.tsx 由仅白名单透传 sessionId 改为透传全部 query - 用 URLSearchParams 原生编码替代手写 encodeURIComponent,原生支持多值 key - 修复 E2E `home-chat.spec.ts:725` 第 3 个守卫(外部直达 /?view=archived) - 根路径不再充当 query 白名单网关,新增 query 维度零修改即可工作 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
…/dashboard-heartbeat-scheduler
- 将 0034_unified_scheduler.py 重命名为 0035_unified_scheduler.py - revision "0034" → "0035",down_revision "0033" → "0034" - 链入 origin/feature/1.x.x 已合入的 0034_kg_federated_canonical(PR #554) - 修复 Backend Unit Tests CI 中 alembic 单 head 自检失败 (Expected a single Alembic head, got: ['0034', '0034']) 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
This was referenced Sep 5, 2026
ThreeFish-AI
added a commit
that referenced
this pull request
Sep 6, 2026
…正 torch 阻断根因; 存量 4 条 Dependabot alert 逐条重新定性,不照单 dismiss——先问「能不能修」。 结论:setuptools 可修(本提交),torch/transformers 三条经实测确认不可修,已在 GitHub 侧 dismiss 为 tolerable_risk。 setuptools #555:由 ignore 改为升级 - 抬 setuptools>=82.0.1 → >=83.0.0(实解 84.0.0),删除 CI 中 PYSEC-2026-3447 的 ignore 及其 7 行注释(ignore 28→27) - 依据:① 上一轮隔离验证已证 82↔83 对本项目零功能差异;② negentropy / cognizes 两 app 早已跑 84.0.0,perceives 停在 82 属不对称;③ pip-audit 实跑对照——保留与 剔除该 ignore 两种配置匹配数同为 8、均 exit 0,证明它在 84.0.0 下已是死配置 - 修正上一提交「不为不可达低危变更 build 后端版本」的判断:存在零成本修复路径时, 消因优于记账 torch CVE-2025-3000:注释根因订正(不改依赖) - 原记「受 marker-pdf/surya/docling-ibm-models/torchvision 四方联动约束」经实测 不成立——以 constraint-dependencies 解析 torch>=2.13.0 时前三者版本纹丝不动 - 实测真实阻断:torch>=2.13 强制 torchvision 0.25.0→0.29.0(其 0.25.0 硬钉 torch==2.10.0),而 transformers 受 pillow 冲突钉死 4.57.6,二者在 docling engine worker 导入链上不兼容。同一条 parse-pdf:torch 2.10 → Success(757B), torch 2.14 → Failed(cannot import name AutoProcessor),连续两次确定性复现 - 据此回退 torch 升级、维持 2.10.0,注释改写为已验证的因果链 验证:uv lock --check 三 app 通过;真实 PDF 走 docling 全链路抽取 Success,与升级前 输出逐字节一致(仅 conversion_time 抖动);pip-audit exit 0(8 ignored); pytest -m "not slow" 2130 passed,3 个 test_config 失败经基线复跑确认为既存的本机 配置覆盖问题,与本变更无关。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
ThreeFish-AI
added a commit
that referenced
this pull request
Sep 6, 2026
沉淀存量 alert 清零过程中的四项实测结论,其中两项推翻既有记载: - setuptools #555 由 dismiss 改判为升级:记录 pip-audit 双配置对照(保留/剔除 ignore 匹配数同为 8)作为「该 ignore 已死」的判据,以及「有零成本修复路径时 消因优于记账」这一对上一轮最小干预判断的修正 - torch #507:旧记「四方联动约束」证伪(constraint 解析下三个 PDF 引擎零位移), 真实阻断是 torchvision 0.29 与 transformers 4.57.6 在 docling worker 的不兼容 - transformers #678/#499:pillow<11 冲突经 uv lock exit 1 与上游 METADATA 双重证实 - 附带订正:marker-pdf 1.10.2(当前锁定版)本身也声明 Pillow<11,现状已由 override 压过;准确表述应为「已验证组合换未验证组合」,而非「升 marker 会把 pillow 降级」 两条方法论增补(本轮踩坑所得): - override-dependencies 会静默压过上游声明,故不能用它验证「某约束是否可行」, 必须用 constraint-dependencies(冲突即报错)——本轮曾因此得到 transformers 5.x 「能解析」的假象 - 验证必须走本项目真实调用路径:DocumentConverter 直调在 torch 2.14 下成功, 只有经 perceives engine worker 才失败,只测上游库会得出完全相反的结论 另记 GitHub 侧收口:dismiss #678/#499/#507,并刷新 #492/#343 两条历史 dismiss 的 陈旧 comment(原载已证伪的 transformers.onnx 口径)。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
核心变更
AsyncScheduler升级到 5s 心跳,新增ScheduledTaskRegistry单例 +scheduled_tasks/task_executions双表 + Alembic0034。6 个旧任务(skill_invoke / pipeline_watchdog / session_title_inspect / cache_warm / pgvector_check / agent_inspection)改写为统一 handler,支持 interval / cron / oneshot 三类触发判定。Feature flagNEGENTROPY_UNIFIED_SCHEDULER_ENABLED支持灰度回退。/scheduler/*8 个端点(kpis / tasks / executions / stats / run / toggle / stream),SSE 流通过ExecutionBusasyncio fan-out 推送实时执行事件,stats / kpis 加 10s in-memory TTL cache。app/(home)/{studio,dashboard}嵌套段路由 + 根/自动 redirect 到/studio;Dashboard 含 KpiRow + FilterBar + DimensionCharts(recharts 3.8.1)+ TaskTable + ExecutionTimeline + TaskDetailDrawer 六大组件,支持按角色 / 场景 / 参与人 / Agent / 作用多维筛选与统计。useHeartbeatPoll通用 hook,统一 4 处散落 setInterval 节拍(5s 与后端心跳对齐),自动 visibility 暂停 + online 恢复触发 + callback 错误隔离。agent_inspectionhandler 升级三件套 — ContextPack 上下文包构建器 + Token 预算门控(24h 累计 vstoken_budget)+ 指数退避策略(连续失败 ≥ 3 进入 60s→1h 退避窗口);新增faculty_deep_check/scheduled_tasks_summary两种巡检类型。风险与回滚
scheduled_tasks表索引依赖加重;(3) Dashboard 引入 recharts +60KB gzip 依赖;(4) 前端轮询统一改造改变了 visibility 暂停语义,后台标签页停止轮询。NEGENTROPY_UNIFIED_SCHEDULER_ENABLED=false跳过 Registry 启动,旧调度路径保留;(2)NEGENTROPY_SCHEDULER_HEARTBEAT_SECONDS可改回 60;(3)scheduled_tasks/task_executions表通过alembic downgrade 0033回滚;(4) 旧/skills/{id}/schedules/*API 与skill_schedules表零行为变更,前端 Dashboard 段独立 chunk 不影响 Studio 首屏。验证证据
/scheduler/*API 序列化与缓存。useHeartbeatPoll新增)。覆盖 fireImmediately / enabled / 错误隔离 / unmount 清理 / hidden 暂停。/dashboard、/studio、/api/scheduler/*全部正确注册);TypeScript + ESLint 0 错误;ruff + ruff-format 全过。影响范围
app/(home)/{studio,dashboard}/、app/api/scheduler/*、hooks/useHeartbeatPoll.ts、components/ui/HomeNav.tsx;改造app/page.tsx(→ redirect)、app/knowledge/pipelines/page.tsx、features/knowledge/components/DocumentViewDialog.tsx、app/knowledge/documents/[id]/[id]/page.tsx;新增 recharts 3.8.1 依赖。engine/schedulers/{registry.py,handlers/}、models/scheduled_task.py、interface/scheduler_api.py、db/migrations/versions/0034_unified_scheduler.py;改造engine/bootstrap.py(6 个 startup hook 合并为单一ensure_registry_started())、engine/schedulers/async_scheduler.py(5s 心跳 + cron 触发器)。Next Best Action
scheduled_tasks_summary巡检的 failed_ratio 指标),确认无回归后再切 prod;agent_inspection调用真实 Faculties 完成多 Agent 协作巡检(需开通 LLM 凭证 + 预算管控);Dashboard 增加 cross-tenant 视图、SLA 告警、Anomaly Detection。🤖 Generated with Claude Code