Skip to content

Commit db60bd9

Browse files
authored
Merge pull request #258 from Integration-Automation/feat/notify-channels-batch
Add multi-channel webhook notifications (Slack/Discord/Teams/raw)
2 parents 265b6d8 + 4031a6f commit db60bd9

15 files changed

Lines changed: 355 additions & 1 deletion

File tree

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
## Table of Contents
1515

16+
- [What's new (2026-06-20) — Multi-Channel Webhook Notifications](#whats-new-2026-06-20--multi-channel-webhook-notifications)
1617
- [What's new (2026-06-20) — Outbound CloudEvents Emitter](#whats-new-2026-06-20--outbound-cloudevents-emitter)
1718
- [What's new (2026-06-20) — Environment-Scoped Typed Asset Store](#whats-new-2026-06-20--environment-scoped-typed-asset-store)
1819
- [What's new (2026-06-20) — Task / Process Mining (Automation-Candidate Discovery)](#whats-new-2026-06-20--task--process-mining-automation-candidate-discovery)
@@ -102,6 +103,12 @@
102103

103104
---
104105

106+
## What's new (2026-06-20) — Multi-Channel Webhook Notifications
107+
108+
Alert Teams/Discord/Slack/webhook. Full reference: [`docs/source/Eng/doc/new_features/v50_features_doc.rst`](docs/source/Eng/doc/new_features/v50_features_doc.rst).
109+
110+
- **`notify_webhook` / `WebhookChannel`** (`AC_notify_webhook`, `ac_notify_webhook`): `notify` was desktop-toast only and ChatOps shipped Slack only — this sends to **Slack / Discord / Microsoft Teams / raw** webhooks, building the transport-shaped payload (Slack & Teams MessageCard use `text`, Discord uses `content`) and POSTing via the egress-guarded HTTP client. The `poster` transport is injectable (or `set_default_poster`), so sending is unit-tested with no network.
111+
105112
## What's new (2026-06-20) — Outbound CloudEvents Emitter
106113

107114
Emit run/automation events as CloudEvents. Full reference: [`docs/source/Eng/doc/new_features/v49_features_doc.rst`](docs/source/Eng/doc/new_features/v49_features_doc.rst).

README/README_zh-CN.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
## 目录
1414

15+
- [本次更新 (2026-06-20) — 多通道 Webhook 通知](#本次更新-2026-06-20--多通道-webhook-通知)
1516
- [本次更新 (2026-06-20) — 对外 CloudEvents 发送器](#本次更新-2026-06-20--对外-cloudevents-发送器)
1617
- [本次更新 (2026-06-20) — 环境范围的带类型资产存储](#本次更新-2026-06-20--环境范围的带类型资产存储)
1718
- [本次更新 (2026-06-20) — 任务 / 流程挖掘(自动化候选发现)](#本次更新-2026-06-20--任务--流程挖掘自动化候选发现)
@@ -101,6 +102,12 @@
101102

102103
---
103104

105+
## 本次更新 (2026-06-20) — 多通道 Webhook 通知
106+
107+
通知 Teams/Discord/Slack/webhook。完整参考:[`docs/source/Zh/doc/new_features/v50_features_doc.rst`](../docs/source/Zh/doc/new_features/v50_features_doc.rst)
108+
109+
- **`notify_webhook` / `WebhookChannel`**(`AC_notify_webhook``ac_notify_webhook`):`notify` 仅限桌面弹窗、ChatOps 只内建 Slack —— 本功能可发送到 **Slack / Discord / Microsoft Teams / raw** webhook,组出对应传输的载荷(Slack 与 Teams MessageCard 用 `text`,Discord 用 `content`)并通过受出口守卫保护的 HTTP 客户端 POST。`poster` 传输可注入(或 `set_default_poster`),因此发送在无网络下即可单元测试。
110+
104111
## 本次更新 (2026-06-20) — 对外 CloudEvents 发送器
105112

106113
将运行/自动化事件以 CloudEvents 发送。完整参考:[`docs/source/Zh/doc/new_features/v49_features_doc.rst`](../docs/source/Zh/doc/new_features/v49_features_doc.rst)

README/README_zh-TW.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
## 目錄
1414

15+
- [本次更新 (2026-06-20) — 多通道 Webhook 通知](#本次更新-2026-06-20--多通道-webhook-通知)
1516
- [本次更新 (2026-06-20) — 對外 CloudEvents 發送器](#本次更新-2026-06-20--對外-cloudevents-發送器)
1617
- [本次更新 (2026-06-20) — 環境範圍的具型別資產儲存](#本次更新-2026-06-20--環境範圍的具型別資產儲存)
1718
- [本次更新 (2026-06-20) — 任務 / 流程探勘(自動化候選發現)](#本次更新-2026-06-20--任務--流程探勘自動化候選發現)
@@ -101,6 +102,12 @@
101102

102103
---
103104

105+
## 本次更新 (2026-06-20) — 多通道 Webhook 通知
106+
107+
通知 Teams/Discord/Slack/webhook。完整參考:[`docs/source/Zh/doc/new_features/v50_features_doc.rst`](../docs/source/Zh/doc/new_features/v50_features_doc.rst)
108+
109+
- **`notify_webhook` / `WebhookChannel`**(`AC_notify_webhook``ac_notify_webhook`):`notify` 僅限桌面快顯、ChatOps 只內建 Slack —— 本功能可發送到 **Slack / Discord / Microsoft Teams / raw** webhook,組出對應傳輸的酬載(Slack 與 Teams MessageCard 用 `text`,Discord 用 `content`)並透過受出口守衛保護的 HTTP 用戶端 POST。`poster` 傳輸可注入(或 `set_default_poster`),因此發送在無網路下即可單元測試。
110+
104111
## 本次更新 (2026-06-20) — 對外 CloudEvents 發送器
105112

106113
將執行/自動化事件以 CloudEvents 發送。完整參考:[`docs/source/Zh/doc/new_features/v49_features_doc.rst`](../docs/source/Zh/doc/new_features/v49_features_doc.rst)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
Multi-Channel Webhook Notifications
2+
===================================
3+
4+
The built-in ``notify`` is desktop-toast only, and ChatOps shipped Slack as the
5+
only transport — but unattended runs want to alert Microsoft Teams, Discord, or a
6+
generic incoming webhook too. Each is a simple JSON POST with a transport-shaped
7+
payload (Slack and a Teams MessageCard use ``text``, Discord uses ``content``);
8+
``notify_webhook`` builds the right body and POSTs it through the egress-guarded
9+
HTTP client.
10+
11+
The transport is injectable (a ``poster`` callable or a module-level default),
12+
so sending is unit-testable with no network. Pure standard library; imports no
13+
``PySide6``.
14+
15+
Headless API
16+
------------
17+
18+
.. code-block:: python
19+
20+
from je_auto_control import notify_webhook, WebhookChannel
21+
22+
notify_webhook("https://hooks.slack.com/...", "Run finished", transport="slack")
23+
notify_webhook("https://discord.com/api/webhooks/...", "Build broke",
24+
transport="discord", title="CI")
25+
notify_webhook("https://prod.webhook.office.com/...", "Deploy done",
26+
transport="teams", title="Release")
27+
28+
chan = WebhookChannel("https://hooks.example.com/x", transport="raw")
29+
result = chan.send("hello") # -> WebhookResult(ok, status, transport)
30+
31+
``transport`` is ``slack`` / ``discord`` / ``teams`` / ``raw``; the result's
32+
``ok`` reflects a 2xx status. Pass a ``poster(url, payload) -> status`` to
33+
``WebhookChannel`` / ``notify_webhook`` (or install one with
34+
``set_default_poster``) to route through a custom transport or a test fake.
35+
36+
Executor command
37+
----------------
38+
39+
``AC_notify_webhook`` takes ``url``, ``text`` (+ optional ``transport`` /
40+
``title``) and returns ``{ok, status, transport}``. The same operation is exposed
41+
as the MCP tool ``ac_notify_webhook`` and as a Script Builder command under
42+
**Tools**.

docs/source/Eng/eng_index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ Comprehensive guides for all AutoControl features.
7272
doc/new_features/v47_features_doc
7373
doc/new_features/v48_features_doc
7474
doc/new_features/v49_features_doc
75+
doc/new_features/v50_features_doc
7576
doc/ocr_backends/ocr_backends_doc
7677
doc/observability/observability_doc
7778
doc/operations_layer/operations_layer_doc
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
多通道 Webhook 通知
2+
===================
3+
4+
內建的 ``notify`` 僅限桌面快顯,而 ChatOps 只內建 Slack 一種傳輸 —— 但無人值守的執行也
5+
想通知 Microsoft Teams、Discord 或一般的 incoming webhook。每一種都是簡單的 JSON POST,
6+
搭配對應傳輸的酬載結構(Slack 與 Teams MessageCard 用 ``text``,Discord 用
7+
``content``);``notify_webhook`` 會組出正確的本文,並透過受出口守衛保護的 HTTP 用戶端
8+
POST 出去。
9+
10+
傳輸可注入(``poster`` 可呼叫物件或模組層級預設),因此發送在無網路下即可單元測試。純標
11+
準函式庫;不匯入 ``PySide6``。
12+
13+
無頭 API
14+
--------
15+
16+
.. code-block:: python
17+
18+
from je_auto_control import notify_webhook, WebhookChannel
19+
20+
notify_webhook("https://hooks.slack.com/...", "Run finished", transport="slack")
21+
notify_webhook("https://discord.com/api/webhooks/...", "Build broke",
22+
transport="discord", title="CI")
23+
notify_webhook("https://prod.webhook.office.com/...", "Deploy done",
24+
transport="teams", title="Release")
25+
26+
chan = WebhookChannel("https://hooks.example.com/x", transport="raw")
27+
result = chan.send("hello") # -> WebhookResult(ok, status, transport)
28+
29+
``transport`` 為 ``slack`` / ``discord`` / ``teams`` / ``raw``;結果的 ``ok`` 反映 2xx 狀
30+
態。可傳入 ``poster(url, payload) -> status`` 給 ``WebhookChannel`` / ``notify_webhook``
31+
(或以 ``set_default_poster`` 安裝一個)以走自訂傳輸或測試假物件。
32+
33+
執行器指令
34+
----------
35+
36+
``AC_notify_webhook`` 接受 ``url``、``text``(以及選用的 ``transport`` / ``title``),回傳
37+
``{ok, status, transport}``。相同操作亦提供為 MCP 工具 ``ac_notify_webhook``,以及 Script
38+
Builder 中 **Tools** 分類下的指令。

docs/source/Zh/zh_index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ AutoControl 所有功能的完整使用指南。
7272
doc/new_features/v47_features_doc
7373
doc/new_features/v48_features_doc
7474
doc/new_features/v49_features_doc
75+
doc/new_features/v50_features_doc
7576
doc/ocr_backends/ocr_backends_doc
7677
doc/observability/observability_doc
7778
doc/operations_layer/operations_layer_doc

je_auto_control/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,10 @@
272272
from je_auto_control.utils.events import (
273273
EventEmitter, post_cloudevent, to_cloudevent,
274274
)
275+
# Outbound chat/webhook notifications (Slack/Discord/Teams/raw)
276+
from je_auto_control.utils.notify_channels import (
277+
WebhookChannel, WebhookResult, notify_webhook, set_default_poster,
278+
)
275279
# Background popup/interrupt watchdog (unattended automation)
276280
from je_auto_control.utils.watchdog import (
277281
PopupWatchdog, WatchdogRule, default_popup_watchdog,
@@ -733,6 +737,7 @@ def start_autocontrol_gui(*args, **kwargs):
733737
"rank_automation_candidates",
734738
"Asset", "AssetStore", "AssetValue", "active_environment",
735739
"EventEmitter", "post_cloudevent", "to_cloudevent",
740+
"WebhookChannel", "WebhookResult", "notify_webhook", "set_default_poster",
736741
# MCP server
737742
"AuditLogger", "HttpMCPServer", "MCPContent", "MCPPrompt",
738743
"MCPPromptArgument", "MCPResource", "MCPServer", "MCPTool",

je_auto_control/gui/script_builder/command_schema.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,19 @@ def _add_misc_specs(specs: List[CommandSpec]) -> None:
11141114
),
11151115
description="Wrap data in a CloudEvents envelope; optionally POST it.",
11161116
))
1117+
specs.append(CommandSpec(
1118+
"AC_notify_webhook", "Tools", "Notify: Webhook/Chat",
1119+
fields=(
1120+
FieldSpec("url", FieldType.STRING,
1121+
placeholder="https://hooks.example.com/..."),
1122+
FieldSpec("text", FieldType.STRING),
1123+
FieldSpec("transport", FieldType.ENUM, optional=True,
1124+
default="raw",
1125+
choices=("raw", "slack", "discord", "teams")),
1126+
FieldSpec("title", FieldType.STRING, optional=True),
1127+
),
1128+
description="Send a Slack/Discord/Teams/raw webhook notification.",
1129+
))
11171130
specs.append(CommandSpec(
11181131
"AC_generate_sop", "Report", "Generate SOP Document",
11191132
fields=(

je_auto_control/utils/executor/action_executor.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3287,6 +3287,15 @@ def _emit_event(event_type: str, data: Any = None,
32873287
return result
32883288

32893289

3290+
def _notify_webhook(url: str, text: str, transport: str = "raw",
3291+
title: Optional[str] = None) -> Dict[str, Any]:
3292+
"""Adapter: send a chat/webhook notification (slack/discord/teams/raw)."""
3293+
from je_auto_control.utils.notify_channels import notify_webhook
3294+
outcome = notify_webhook(url, text, transport=transport, title=title)
3295+
return {"ok": outcome.ok, "status": outcome.status,
3296+
"transport": outcome.transport}
3297+
3298+
32903299
class Executor:
32913300
"""
32923301
Executor
@@ -3566,6 +3575,7 @@ def __init__(self):
35663575
"AC_get_asset": _get_asset,
35673576
"AC_list_assets": _list_assets,
35683577
"AC_emit_event": _emit_event,
3578+
"AC_notify_webhook": _notify_webhook,
35693579
"AC_a11y_record_start": _a11y_record_start,
35703580
"AC_a11y_record_stop": _a11y_record_stop,
35713581
"AC_a11y_record_events": _a11y_record_events,

0 commit comments

Comments
 (0)