Govern · 第一則 Reply
協作式 Website 整合
Website path 是 assisted integration reference,不是 Govern self-service 或 SDK quickstart。LINE 是架構已定義的 path,不是目前已有端到端 Govern 驗證的 supported product mode。兩者都保留相同的 Govern effect 契約。
Govern + Relay
一則回覆,兩個系統各自負責
Website path
-
Host UI
向 Govern 取得 session material。
-
Relay
加入 channel,並使用固定 nonce 傳送訊息。
-
Govern
重新驗證 context,產生有界的
reply。 -
Relay
指派 sequence,並送出 bot message。
| 模式 | 使用者介面 | Transport Path | 目前驗證 |
|---|---|---|---|
| Website | 產品自有 Web UI | Govern session → Relay SDK | 協作式參考整合;Govern 到 Relay 的 reply path 已測試 |
| LINE Bot | LINE Official Account | LINE webhook → Relay LINE adapter | 架構已定義;Relay ingress 與 egress 已測試,但尚無端到端 Govern captured proof |
模式一:Website Reply
Website path 從產品自有的 conversation UI 開始。Tonetify 為指定的 bot profile 建立 Relay session;Relay 傳送 user message;Govern 解析 runtime context 並產生 reply effect;Relay 再把 bot message 傳回同一個 channel。
Browser
→ POST /session to Govern
→ connect and send through Relay
→ signed message.created webhook to Govern
→ Govern reply effect
→ bot message through Relay 這個組合讓每個系統問題只有一位 owner。Govern 不會另外實作一套 chat transport,Relay 也不會決定 bot 應該說什麼。
成熟度與前置條件
這是協作式 Website integration reference,不是 Govern self-service 或 SDK quickstart。你需要:
- 已設定的 Govern bot profile;
- 已設定的 Relay provider credential 與 provider channel;
- 建置完成的
@tonetify/relayartifact,或自行實作的 Relay client; - 從 Relay
message.createdevent 回到 Govern 的 callback path。
Relay SDK 已公開發布為 @tonetify/relay@0.1.0-beta.1。在 Relay 提供 server compatibility matrix 與 upgrade policy 前,請固定使用這個完整的 beta version。
1. 建立 Website Session
使用這個 bot 的 provider-channel installation ID 呼叫 Govern:
const response = await fetch("https://govern.example.com/session", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
provider_channel_id: "govern-provider-channel-id",
subject: { type: "visitor", id: "visitor-123" },
actor: { type: "anonymous" }
})
});
if (!response.ok) throw new Error(`session failed: ${response.status}`);
const { data: session } = await response.json(); Response 會包含 Govern 選定的 Relay connection material:
{
"data": {
"token": "host-signed-relay-jwt",
"tenantId": "relay-tenant-id",
"channelId": "relay-channel-id",
"userId": "session-user-id",
"socketUrl": "wss://relay.example.com/socket",
"apiUrl": "https://relay.example.com",
"botName": "Operations Assistant",
"providerChannelId": "govern-provider-channel-id",
"organizationName": "Example Organization",
"botProfileId": "govern-profile-id"
}
} POST /session 只建立 transport state,不會直接回傳 model response,也不會執行 Govern turn。
2. 連接 Relay 並傳送訊息
import { ChatClient } from "@tonetify/relay";
const client = new ChatClient({
url: session.socketUrl,
apiUrl: session.apiUrl,
token: session.token,
userId: session.userId
});
client.connect();
const channel = client.channel(session.channelId, session.tenantId);
channel.on("msg:new", (message) => {
console.log(message.seq, message.body);
});
await channel.join();
await channel.send("What can you help me with?", {
nonce: crypto.randomUUID()
}); User message 與 bot reply 都會成為 Relay msg:new event。畫面排序應使用 Relay 由 server 指派的 seq。
3. 理解 Govern Turn
Relay 會簽署 message.created 並傳給 Govern,接著 Govern 會:
- 驗證 webhook,並取得其 idempotency identity;
- 透過 provider channel 解析 organization、bot profile 與 runtime mode;
- 把 input 寫入 conversation state;
- 執行
InputEnvelope → TurnOrchestrator; - 透過 provider adapter dispatch
reply; - 記錄 runtime trace metadata。
Static-profile bot 可以依照設定好的 rules 與 knowledge 回答。Tool-agent bot 則能先呼叫固定版本的 Host Tool,再決定回傳 reply、proposal 或 noop。
模式二:LINE Bot Reply
LINE 使用 Relay 內建的 LINE adapter。Govern 仍然接收 Relay 簽署的 message.created event,並透過同一條 Relay message write path 送出 effect。
LINE user message
→ POST /adapters/line/webhook to Relay
→ X-Line-Signature verification
→ tenant route and per-user LINE channel
→ Relay message.created webhook to Govern
→ Govern reply effect through Relay
→ LINE reply_token when fresh, otherwise push Provider-specific work 由 Relay 負責:
- 使用
X-Line-Signature驗證 LINE 簽署的 exact raw body; - 透過 LINE
destination找到對應 tenant; - 為每位 external user 建立或重用一個 LINE channel;
- 保存 inbound
reply_token與有限的有效時間; - 透過標準 Relay message path 送出 reply;
- 一次性使用仍有效的 reply token;沒有可用 token 時,改用 LINE push。
Govern 維持 provider-neutral。它收到 provider: "relay"、Relay tenant ID、channel ID、message ID 與 body,先把這些欄位解析到指定 bot profile,再執行與 website chat 相同的 InputEnvelope → TurnOrchestrator → EffectDispatcher path。
目前的 Integration Boundary
LINE transport 已在 Relay repository 具有 end-to-end test。尚未產品化的是 cross-repo dynamic mapping:Relay 會依需求建立 LINE user channel,但 Govern 目前採 fail-closed;只有完全相符的 Relay tenant 與 channel 已存在 ProviderChannel mapping 時,才會執行 runtime。
因此 LINE Bot Reply 是架構已定義的 path,不是目前已有端到端 Govern 驗證的 supported product mode。尚缺的 close 是自動或 deterministic provider-channel registration,以及一筆 captured LINE → Govern → LINE bot-reply proof。
失敗行為
| 狀況 | 結果 |
|---|---|
| 找不到 provider channel、organization、profile 或 credential | 404 RFC 9457 problem detail |
Provider 不是目前識別為 relay 的 Relay adapter | 422 unsupported_provider |
| Relay configuration 不完整 | 422 missing_relay_config |
| Relay session creation 發生 upstream failure | 502 upstream_session_failed |
| Message retry 使用新的 nonce | Relay 會視為新的 logical message |
| LINE signature 或 destination 無效 | Relay 會在 Govern 執行前拒絕或忽略 provider webhook |
| LINE channel 沒有 Govern provider mapping | Govern 以 runtime_context_not_found fail closed,不會產生 bot reply |
| LINE reply token 已過期或使用過 | Relay 不會重用 token,會改用 LINE push |
| Runtime 無法產生 reply | Turn 會記錄 error;Govern 不能自行創造 host truth |
權責邊界
- Browser 負責 presentation 與 session lifecycle。
- LINE 負責 user identity、webhook event、reply token 與 Messaging API contract。
- Relay 負責 provider ingress、channel、membership、message order、retry-safe send 與 delivery。
- Govern 負責 runtime context resolution,以及有界的
reply、proposal或noopresult。 - Host 負責 identity、business truth、policy 與 execution。