Govern · First reply
Assisted website integration
The website path is an assisted integration reference, not a Govern self-service or SDK quickstart. LINE is an architecturally defined path, not a currently supported product mode with end-to-end Govern verification. Both preserve the same Govern effect contract.
Govern + Relay
One reply, two system owners
Website path
-
Host UI
Requests session material from Govern.
-
Relay
Joins the channel and sends with a stable nonce.
-
Govern
Revalidates context and produces a bounded
reply. -
Relay
Assigns sequence and delivers the bot message.
| Mode | User surface | Transport path | Current proof |
|---|---|---|---|
| Website | Product-owned web UI | Govern session → Relay SDK | Assisted reference integration; Govern-to-Relay reply path is tested |
| LINE Bot | LINE Official Account | LINE webhook → Relay LINE adapter | Architecturally defined; Relay ingress and egress are tested, but end-to-end Govern verification is not captured |
Mode 1: Website reply
The website path starts with a product-owned conversation UI. Tonetify creates a Relay session for a configured bot profile; Relay transports the user message; Govern resolves the runtime context and produces a reply effect; Relay delivers the bot message back to the same channel.
Browser
→ POST /session to Govern
→ connect and send through Relay
→ signed message.created webhook to Govern
→ Govern reply effect
→ bot message through Relay This composition keeps one owner per problem. Govern does not implement a second chat transport, and Relay does not decide what the bot should say.
Maturity and prerequisites
This is an assisted website integration reference, not a Govern self-service or SDK quickstart. You need:
- a configured Govern bot profile;
- a configured Relay provider credential and provider channel;
- the built
@tonetify/relayartifact or your own Relay client; - a deployed callback path from Relay
message.createdevents to Govern.
The Relay SDK is published as @tonetify/relay@0.1.0-beta.1. Pin that exact beta version until Relay publishes a server compatibility matrix and upgrade policy.
1. Create a website session
Call Govern with the provider-channel installation ID created for this bot:
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(); The response contains the Relay connection material selected by Govern:
{
"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 creates transport state. It does not return a model response or execute a Govern turn.
2. Connect to Relay and send
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()
}); The user message and the bot reply both arrive as Relay msg:new events. Use Relay’s server-assigned seq to render them in order.
3. Understand the Govern turn
Relay signs and delivers message.created to Govern. Govern then:
- verifies the webhook and claims its idempotency identity;
- resolves the organization, bot profile, and runtime mode from the provider channel;
- appends the input to its conversation state;
- runs
InputEnvelope → TurnOrchestrator; - dispatches the resulting
replythrough the provider adapter; - records runtime trace metadata.
A static-profile bot can answer from configured rules and knowledge. A tool-agent bot may call a pinned Host Tool before deciding whether to return reply, proposal, or noop.
Mode 2: LINE Bot reply
LINE uses Relay’s in-tree LINE adapter. Govern still sees a signed Relay message.created event and returns its effect through the same Relay message write path.
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 Relay owns the provider-specific work:
- verifies the exact raw body with
X-Line-Signature; - routes LINE
destinationto one tenant; - creates or reuses one LINE channel per external user;
- stores the inbound
reply_tokenwith a bounded validity window; - sends the reply through the normal Relay message path;
- consumes a fresh reply token once, then falls back to LINE push when no usable token remains.
Govern remains provider-neutral. It receives provider: "relay", the Relay tenant ID, channel ID, message ID, and body. It resolves those fields to a configured bot profile before running the same InputEnvelope → TurnOrchestrator → EffectDispatcher path used by website chat.
Current integration boundary
The LINE transport itself has repository-level end-to-end coverage in Relay. The cross-repo dynamic mapping is not yet productized: Relay creates LINE user channels on demand, while Govern currently fails closed unless the exact Relay tenant and channel already have a ProviderChannel mapping.
Therefore LINE Bot reply is an architecturally defined path, not a currently supported product mode with end-to-end Govern verification. The missing close is automatic or deterministic provider-channel registration plus one captured LINE → Govern → LINE bot-reply proof.
Failure behavior
| Condition | Result |
|---|---|
| Provider channel, organization, profile, or credential is unknown | 404 RFC 9457 problem detail |
Provider is not the current Relay adapter, identified as relay | 422 unsupported_provider |
| Relay configuration is incomplete | 422 missing_relay_config |
| Relay session creation fails upstream | 502 upstream_session_failed |
| Message retry uses a new nonce | Relay treats it as a new logical message |
| LINE signature or destination is invalid | Relay rejects or ignores the provider webhook before Govern runs |
| LINE channel has no Govern provider mapping | Govern fails closed with runtime_context_not_found; no bot reply is produced |
| LINE reply token is expired or consumed | Relay attempts LINE push instead of reusing the token |
| Runtime cannot produce a reply | The turn records an error; Govern must not invent host truth |
Ownership boundary
- The browser owns presentation and session lifecycle.
- LINE owns its user identity, webhook event, reply token, and Messaging API contract.
- Relay owns provider ingress, channel, membership, message order, retry-safe send, and delivery.
- Govern owns runtime context resolution and the bounded
reply,proposal, ornoopresult. - The host owns identity, business truth, policy, and execution.