/** * The response gate (SH2) — the mandatory stage BEFORE `POST /run` that decides * WHETHER and HOW to answer. Learned from the omni/omniagent study: omni ships a * working two-tier gate; omniagent defined a gate but never wired it (every * message hit the LLM). The lesson: the gate is a required stage, not an optional * library. * * It returns a reply DISPOSITION, which the base acts on: * agent_reply run the agent (the normal path) * canned_reply send a fixed message, no LLM (pairing code, out-of-office…) * drop silently ignore (unmentioned group, not on allowlist, spam) * defer_to_human a person takes over this thread (handoff) * * Keyed on the message + the line's policy (personal ↔ business). */ import type { ShuttleMessage, GroupPolicy } from './types.js'; import type { PairingStore } from './pairing.js'; export type Disposition = { readonly kind: 'agent_reply'; } | { readonly kind: 'canned_reply'; readonly text: string; } | { readonly kind: 'drop'; readonly reason: string; } | { readonly kind: 'defer_to_human'; readonly reason: string; }; /** Who may start a DM. `open` = business line; `pairing`/`allowlist` = personal/closed. */ export type DmPolicy = 'open' | 'pairing' | 'allowlist'; export type HandoffPolicy = 'off' | 'on-request' | 'on-signal'; /** The access + response policy for one line (personal vs business). */ export interface LinePolicy { /** DM access. Default `open`. Personal lines set `pairing`. */ readonly dm?: DmPolicy; /** Group/channel answering. Default `mention`. */ readonly group?: GroupPolicy; /** Allowed user ids when `dm: 'allowlist'`. */ readonly allowlist?: readonly string[]; /** Human handoff. Default `off`. */ readonly handoff?: HandoffPolicy; } /** Optional cheap "is this message even for us?" pre-filter (business/group lines). */ export interface LlmGate { shouldRespond(msg: ShuttleMessage): Promise; } export interface ResponseGate { evaluate(msg: ShuttleMessage): Promise; } export interface PolicyGateDeps { /** Required when `dm: 'pairing'`. */ readonly pairing?: PairingStore; /** Optional cheap LLM pre-filter (business/group lines). */ readonly llmGate?: LlmGate; /** Whether this thread is currently handed off to a human. */ readonly isPaused?: (msg: ShuttleMessage) => boolean | Promise; } /** The default gate: deterministic policy checks, then an optional fail-open LLM gate. */ export declare class PolicyGate implements ResponseGate { private readonly channel; private readonly policy; private readonly deps; constructor(channel: string, policy: LinePolicy, deps?: PolicyGateDeps); evaluate(msg: ShuttleMessage): Promise; } //# sourceMappingURL=gate.d.ts.map