Documentation
¶
Overview ¶
* ChatCLI - MCP channel reactive triggers * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 * * The trigger engine turns inbound MCP channel messages into actionable * events for the CLI. Three modes are supported: * * notify — show a discreet banner above the next prompt and bump * the unread counter. Default mode. Zero side effects. * confirm — same banner, plus a one-line yes/no prompt the user * resolves manually (via /channel confirm <id> [yes|no]). * auto — when the session is idle, schedule the configured prompt * to run as a synthetic agent turn, rendered inside a * clearly-marked auto-run envelope. Tool whitelist and * rate-limit per rule enforce guard-rails. * * This package is intentionally agnostic of the CLI UI: the engine * emits a stream of Action values; the CLI subscribes and decides * how/where to render and how to gate on session state. * * Concurrency: the engine is safe for concurrent rule reloads and * concurrent Dispatch calls. Per-rule rate-limit state lives in * sync.Map so adding/removing rules at runtime never invalidates * other rules' state.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Action ¶
type Action struct {
ID uint64
Rule Rule
Event ChannelEvent
Mode Mode
Prompt string // already-rendered template, ready to feed the agent
IssuedAt time.Time
ExpiresAt time.Time // for confirm actions; zero means no expiration
ToolFilter []string // copy of Rule.Tools so consumers do not race
}
Action is what the engine emits when a rule fires. The CLI listens on Engine.Actions() and decides UI behavior per mode.
ID is unique per emitted Action (not per Rule) — the CLI uses it to address pending confirm actions when the user responds with /channel confirm <id>.
type ChannelEvent ¶
type ChannelEvent struct {
ServerName string
Channel string
Content string
Metadata map[string]string
Timestamp time.Time
Seq uint64
}
ChannelEvent is the trigger engine's view of an incoming MCP message. Decoupled from cli/mcp.ChannelMessage so the engine has no import dependency back into the manager — keeps the package boundary clean.
type Engine ¶
type Engine struct {
// contains filtered or unexported fields
}
Engine evaluates rules against incoming events and dispatches actions on a buffered channel for downstream UI/agent consumers.
Lifecycle:
e := triggers.NewEngine(logger)
e.SetRules(initial) // safe to call again on /config reload
e.Dispatch(event) // wired to ChannelManager.OnMessage
for a := range e.Actions() { ... }
e.Close() // drains and closes the actions chan
func NewEngineWithOptions ¶
func NewEngineWithOptions(logger *zap.Logger, opts EngineOptions) *Engine
NewEngineWithOptions constructs an engine with explicit options.
func (*Engine) Actions ¶
Actions exposes the read end of the action stream. Consumers MUST keep up — when the channel fills, the engine logs a warning and drops the newest action. (Confirm/Auto actions are not retried; the next matching event will produce a fresh Action.)
func (*Engine) Close ¶
func (e *Engine) Close()
Close drains and closes the actions channel. Idempotent — safe to call from the CLI shutdown path even if the engine was never started.
func (*Engine) Dispatch ¶
func (e *Engine) Dispatch(event ChannelEvent)
Dispatch runs each rule against the event and emits an Action for every match (subject to rate-limit and dedup). Safe to call from multiple goroutines — typically wired directly to ChannelManager.OnMessage.
func (*Engine) Pause ¶
func (e *Engine) Pause()
Pause suspends all trigger evaluation until Resume is called. Dispatch keeps draining events so the channel never blocks, but no Actions are emitted while paused.
func (*Engine) Rules ¶
Rules returns a snapshot of the active rule set. Useful for /channel rules introspection.
func (*Engine) SetRules ¶
SetRules replaces the active rule set atomically. Returns the first validation error encountered, with no partial application — either every rule is accepted or none are.
Safe to call concurrently with Dispatch. The next Dispatch picks up the new rules; in-flight ones continue with the snapshot they captured at entry.
type EngineOptions ¶
type EngineOptions struct {
// ActionBuffer caps how many pending actions can be queued before
// Dispatch starts dropping the oldest. Zero → 64, which is more
// than enough for the bursty CI/Prometheus use case.
ActionBuffer int
}
EngineOptions configures the engine. All fields optional.
type Rule ¶
type Rule struct {
Name string `json:"name"`
Server string `json:"server,omitempty"`
Channel string `json:"channel,omitempty"`
ContentRegex string `json:"contentRegex,omitempty"`
Mode Mode `json:"mode,omitempty"`
Prompt string `json:"prompt,omitempty"`
Tools []string `json:"tools,omitempty"`
RateLimit time.Duration `json:"-"` // populated from RateLimitText
RateLimitTxt string `json:"rateLimit,omitempty"`
DedupWindow time.Duration `json:"-"`
DedupTxt string `json:"dedupWindow,omitempty"`
// contains filtered or unexported fields
}
Rule declares how a single trigger reacts to incoming events.
Match semantics: an empty Server / Channel / ContentRegex matches everything. When multiple fields are specified, all must match (AND). When a Rule produces a fire, its Prompt template is rendered against the matched ChannelEvent.
Tools is the optional whitelist of MCP/native tool names the auto-run session may invoke. Empty list means "no restriction" for backward-compatible behavior in notify/confirm modes; in auto mode an empty list is rejected by Validate because running the agent without a tool floor is a foot-gun.