Skip to content

feat(automations): 条件驱动的自动化工作流 - #94

Merged
69gg merged 23 commits into
mainfrom
feat/automations
Aug 23, 2026
Merged

feat(automations): 条件驱动的自动化工作流#94
69gg merged 23 commits into
mainfrom
feat/automations

Conversation

@69gg

@69gg 69gg commented Aug 23, 2026

Copy link
Copy Markdown
Owner

本版本将「定时任务」整体升级为条件驱动的「自动化 / Automations」工作流:消息与时间事件命中后按 DAG 执行工具、模板与 LLM 节点,可选择接管本轮 AI;WebUI 配套 Dify 式画布编辑器,旧定时任务数据在启动时自动迁移。

  • 新的工作流引擎 src/Undefined/automations/:支持场景多选与 @ 专项消费,节点覆盖 tool / template / 三种 LLM,可自动派生 if-else 与 LLM 分支(分支选项即工具调用),循环最多 25 次。运行时只写 data/automations.json;启动时若发现旧 scheduled_tasks.json 则自动转为新格式写入新文件,旧文件保留、不双写。
  • 运行时由 AutomationService 取代原调度服务,时间 job 只携带 task_id/api/v1/schedulesscheduler.* 随之下线,对外只剩 /api/v1/automationsautomation.* 的增删改查加启停共六个工具。
  • 工作流接入群聊、QQ 私聊、微信、拍一拍、入退群五类消息入口,都在 pipeline 之后、对应 AI loop 之前触发;consume_ai_loop=true 时等工作流完成并拦截该入口的 AI 回复,否则后台执行、立刻放行主 AI。
  • 执行模型面向实时对话优化:无相互依赖的分支依赖就绪即并行,不再整波等齐(多上游仍 AND join);消息触发的工具与 LLM 直接使用当前会话上下文,send_message 只填 message 即发往当前会话;工具节点自动注入认知记忆、知识库、表情包与附件注册表,避免已启用能力被误报未启用。
  • 统一的变量系统:节点输出可存成命名变量供下游以 {{名称}} 引用;三种 LLM 还支持 extract_vars,把待抽取变量变成 extract_<名称> 工具由模型调用后写入;入退群事件会解析群名片 / QQ 昵称写入 {{trigger.nickname}},入群欢迎预设直接可用。
  • 管理能力完整开放:新增 catalog 端点与 CRUD,POST /api/v1/automations/validate 一次性返回全部问题;配置节 [automations] 支持热更新。
  • WebUI 自动化页重做为 Dify 式画布编辑器:节点盘添加节点,先点出点再点目标即可连线,类型化检查器编辑参数;列表与画布上下两屏滚动切换,布局随任务保存;空白 LLM 白名单改为搜索点选。
  • 运行默认放宽且全程可观测:事件类工作流默认不再冷却(default_cooldown_seconds = 0),并发与节点 / 工作流超时上限提高,空白 LLM 迭代上限放宽到 100;新建自动化默认不拦截主 AI、不自动发送终值;事件匹配、时间触发、节点执行、出站发送与超时均有详细日志。

69gg and others added 18 commits August 16, 2026 12:36
Keep one-way startup migration from scheduled_tasks.json, and drop the old
/schedules API plus scheduler.* tools so only automations remain as the entry.

Co-authored-by: Cursor <cursoragent@cursor.com>
Move crontab add/update and ScheduledTask storage out of the runtime so time jobs only carry task_id and workflows run through the new service.

Co-authored-by: Cursor <cursoragent@cursor.com>
Log event matching, clock fires, DAG node execution, outbound sends and timeouts so automation runs are easier to trace.

Co-authored-by: Cursor <cursoragent@cursor.com>
Give the automations page a Dify-style palette, drag-and-connect canvas, and typed inspector, and persist layout plus catalog/validate APIs for the editor.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep stats and selection on one viewport and the graph editor on the next, snapping by scroll instead of replacing the list.

Co-authored-by: Cursor <cursoragent@cursor.com>
Replace the blank-LLM multi-selects with searchable toggles, and connect edges by clicking an outlet then a valid target.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep the 自动化 header outside the list/canvas scroll so it stays visible like other sticky page headers.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…on context

Ready nodes now start as soon as their deps complete instead of waiting on a gather wave, and message-triggered tools inherit the current session so send_message can omit the target.

Co-authored-by: Cursor <cursoragent@cursor.com>
…runtime

Tool nodes were reading an empty context and reporting cognitive memory as disabled even when the bot had it enabled.

Co-authored-by: Cursor <cursoragent@cursor.com>
Saving stayed on the canvas and skipped the list refresh while busy, so cards kept stale server state.

Co-authored-by: Cursor <cursoragent@cursor.com>
Event automations no longer cool down by default, and concurrency, node/workflow timeouts, and blank LLM iterations are large enough for longer graphs.

Co-authored-by: Cursor <cursoragent@cursor.com>
Event workflows with consume_ai_loop disabled no longer wait before the main AI, and new WebUI drafts default intercept and auto-send off.

Co-authored-by: Cursor <cursoragent@cursor.com>
Let blank/agent/main LLM nodes declare extract_vars so the model writes named {{values}} through injected extract_* tools; WebUI inspector and canvas expose the same setting.

Co-authored-by: Cursor <cursoragent@cursor.com>
Use {{trigger.nickname}} instead of the QQ number, and resolve group card or QQ nickname on join/leave events so the greeting is not empty.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: GPT-5 <noreply@openai.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Too many files!

This PR contains 131 files, which is 31 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3b33d77f-d8c4-48fb-a284-56ed676a429e

📥 Commits

Reviewing files that changed from the base of the PR and between 9591dc2 and 210970c.

⛔ Files ignored due to path filters (5)
  • apps/undefined-chat/package-lock.json is excluded by !**/package-lock.json
  • apps/undefined-chat/src-tauri/Cargo.lock is excluded by !**/*.lock
  • apps/undefined-console/package-lock.json is excluded by !**/package-lock.json
  • apps/undefined-console/src-tauri/Cargo.lock is excluded by !**/*.lock
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (131)
  • AGENTS.md
  • ARCHITECTURE.md
  • CHANGELOG.md
  • CLAUDE.md
  • README.md
  • apps/undefined-chat/package.json
  • apps/undefined-chat/src-tauri/Cargo.toml
  • apps/undefined-chat/src-tauri/tauri.conf.json
  • apps/undefined-console/package.json
  • apps/undefined-console/src-tauri/Cargo.toml
  • apps/undefined-console/src-tauri/tauri.conf.json
  • config.toml.example
  • docs/access-control.md
  • docs/automations.md
  • docs/cognitive-memory.md
  • docs/configuration.md
  • docs/management-api.md
  • docs/message-batching.md
  • docs/openapi.md
  • docs/usage.md
  • docs/webui-guide.md
  • docs/wechat-ilink.md
  • pyproject.toml
  • res/IMPORTANT/each.md
  • res/prompts/undefined.xml
  • res/prompts/undefined_nagaagent.xml
  • src/Undefined/__init__.py
  • src/Undefined/ai/client/ask_loop.py
  • src/Undefined/ai/prompts/builder.py
  • src/Undefined/ai/tooling.py
  • src/Undefined/api/_openapi.py
  • src/Undefined/api/app.py
  • src/Undefined/api/routes/automations.py
  • src/Undefined/api/routes/schedules.py
  • src/Undefined/api/routes/system.py
  • src/Undefined/api/routes/tools.py
  • src/Undefined/automations/__init__.py
  • src/Undefined/automations/address.py
  • src/Undefined/automations/catalog.py
  • src/Undefined/automations/clock.py
  • src/Undefined/automations/constants.py
  • src/Undefined/automations/engine.py
  • src/Undefined/automations/extract.py
  • src/Undefined/automations/logutil.py
  • src/Undefined/automations/match.py
  • src/Undefined/automations/mentions.py
  • src/Undefined/automations/migrate.py
  • src/Undefined/automations/runner.py
  • src/Undefined/automations/service.py
  • src/Undefined/automations/short.py
  • src/Undefined/automations/storage.py
  • src/Undefined/automations/template.py
  • src/Undefined/automations/triggers.py
  • src/Undefined/automations/validate.py
  • src/Undefined/config/__init__.py
  • src/Undefined/config/config_class.py
  • src/Undefined/config/domain_parsers.py
  • src/Undefined/config/hot_reload.py
  • src/Undefined/config/load_sections/domains.py
  • src/Undefined/config/models.py
  • src/Undefined/handlers/message_flow.py
  • src/Undefined/handlers/poke.py
  • src/Undefined/main.py
  • src/Undefined/onebot/client.py
  • src/Undefined/scheduled_task_storage.py
  • src/Undefined/services/coordinator/__init__.py
  • src/Undefined/services/coordinator/group.py
  • src/Undefined/services/coordinator/private.py
  • src/Undefined/skills/README.md
  • src/Undefined/skills/agents/__init__.py
  • src/Undefined/skills/agents/agent_tool_registry.py
  • src/Undefined/skills/agents/runner/context.py
  • src/Undefined/skills/registry.py
  • src/Undefined/skills/tools/__init__.py
  • src/Undefined/skills/toolsets/README.md
  • src/Undefined/skills/toolsets/automation/README.md
  • src/Undefined/skills/toolsets/automation/_runtime.py
  • src/Undefined/skills/toolsets/automation/create/config.json
  • src/Undefined/skills/toolsets/automation/create/handler.py
  • src/Undefined/skills/toolsets/automation/delete/config.json
  • src/Undefined/skills/toolsets/automation/delete/handler.py
  • src/Undefined/skills/toolsets/automation/get/config.json
  • src/Undefined/skills/toolsets/automation/get/handler.py
  • src/Undefined/skills/toolsets/automation/list/config.json
  • src/Undefined/skills/toolsets/automation/list/handler.py
  • src/Undefined/skills/toolsets/automation/set_enabled/config.json
  • src/Undefined/skills/toolsets/automation/set_enabled/handler.py
  • src/Undefined/skills/toolsets/automation/update/config.json
  • src/Undefined/skills/toolsets/automation/update/handler.py
  • src/Undefined/skills/toolsets/scheduler/README.md
  • src/Undefined/skills/toolsets/scheduler/create_schedule_task/config.json
  • src/Undefined/skills/toolsets/scheduler/create_schedule_task/handler.py
  • src/Undefined/skills/toolsets/scheduler/delete_schedule_task/config.json
  • src/Undefined/skills/toolsets/scheduler/delete_schedule_task/handler.py
  • src/Undefined/skills/toolsets/scheduler/list_schedule_tasks/config.json
  • src/Undefined/skills/toolsets/scheduler/list_schedule_tasks/handler.py
  • src/Undefined/skills/toolsets/scheduler/update_schedule_task/config.json
  • src/Undefined/skills/toolsets/scheduler/update_schedule_task/handler.py
  • src/Undefined/utils/io.py
  • src/Undefined/utils/scheduler.py
  • src/Undefined/webui/routes/_index.py
  • src/Undefined/webui/routes/_runtime.py
  • src/Undefined/webui/static/css/components.css
  • src/Undefined/webui/static/css/responsive.css
  • src/Undefined/webui/static/css/style.css
  • src/Undefined/webui/static/css/workflow.css
  • src/Undefined/webui/static/js/i18n.js
  • src/Undefined/webui/static/js/main.js
  • src/Undefined/webui/static/js/schedules.js
  • src/Undefined/webui/static/js/state.js
  • src/Undefined/webui/static/js/ui.js
  • src/Undefined/webui/static/js/workflow-canvas.js
  • src/Undefined/webui/static/js/workflow-graph.js
  • src/Undefined/webui/static/js/workflow-inspector.js
  • src/Undefined/webui/templates/index.html
  • tests/test_ai_tooling_context.py
  • tests/test_automations.py
  • tests/test_config_api.py
  • tests/test_config_hot_reload.py
  • tests/test_handlers_poke_history.py
  • tests/test_prompt_builder_message_order.py
  • tests/test_runtime_api_probes.py
  • tests/test_runtime_api_schedules.py
  • tests/test_runtime_api_tool_invoke.py
  • tests/test_scheduled_task_unit.py
  • tests/test_scheduler_self_instruction.py
  • tests/test_skills_registry_stats.py
  • tests/test_system_prompt_constraints.py
  • tests/test_webui_management_api.py
  • tests/test_webui_runtime_chat_frontend.py
  • tests/test_webui_schedules_frontend.py

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

69gg and others added 5 commits August 23, 2026 19:20
…-blocking

- poke: honor the core process_poke_message toggle at entry, skipping
  history writes, automation matching, and AI replies when disabled
- group/private/wechat entries: stop matching automations when the
  corresponding should_process_* gate is off
- consume_ai_loop now defaults to false across service, migration,
  short commands, and API serialization so matched messages reach the
  main AI unless a workflow explicitly opts in
- document gate semantics and the new default; cover them with tests
- loop_max_iterations is now purely config-driven with a floor of 1 and
  no ceiling; the previous 25 clamp is gone from config parsing, service
  settings, runner execution, and validation
- validate_automation/collect_automation_issues accept the configured
  cap so save-time checks match runtime; node max_iterations must be
  1..configured
- catalog endpoint exposes the configured value instead of a fixed 25;
  WebUI loop inputs drop the max=25 attribute
- docs, changelog and config example updated; tests cover parsing,
  validation and runner behavior under larger caps
Co-authored-by: GPT-5 Codex <noreply@openai.com>
@69gg
69gg merged commit 355fad9 into main Aug 23, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant