import type { ChatType } from "../channels/chat-type.js"; import type { RemoteClawConfig } from "../config/config.js"; /** @deprecated Use ChatType from channels/chat-type.js */ export type RoutePeerKind = ChatType; export type RoutePeer = { kind: ChatType; id: string; }; export type ResolveAgentRouteInput = { cfg: RemoteClawConfig; channel: string; accountId?: string | null; peer?: RoutePeer | null; /** Parent peer for threads — used for binding inheritance when peer doesn't match directly. */ parentPeer?: RoutePeer | null; guildId?: string | null; teamId?: string | null; /** Discord member role IDs — used for role-based agent routing. */ memberRoleIds?: string[]; }; export type MatchedByTier = "binding.peer" | "binding.peer.parent" | "binding.guild+roles" | "binding.guild" | "binding.team" | "binding.account" | "binding.channel" | "fallback.soleAgent" | "fallback.legacyRoute" | "unmatched.catchAll"; /** * Backward-compatible shape used by downstream consumers (channel adapters, * session builders, tests) that hold a successfully resolved route. This is * the shape emitted by {@link resolveAgentRoute} on the `matched: true` branch * and by {@link buildMatchedRoute}. Consumers that only read the route fields * (`agentId`, `sessionKey`, ...) should type their variables as * `ResolvedAgentRoute`. Code that invokes {@link resolveAgentRoute} directly * and must handle unmatched results should use {@link AgentRouteOutcome}. */ export type ResolvedAgentRoute = { agentId: string; channel: string; accountId: string; /** Internal session key used for persistence + concurrency. */ sessionKey: string; /** Convenience alias for direct-chat collapse. */ mainSessionKey: string; /** Which session should receive inbound last-route updates. */ lastRoutePolicy: "main" | "session"; /** Match description for debugging/logging. */ matchedBy: MatchedByTier; }; export type MatchedAgentRoute = ResolvedAgentRoute & { matched: true; }; /** * Normalized routing scope passed to unmatched handler / telemetry. * Strings are post-normalization forms emitted by {@link resolveAgentRoute}. */ export type RouteScope = { channel: string; accountId: string; peer: RoutePeer | null; guildId: string | null; teamId: string | null; }; export type UnmatchedAgentRoute = { matched: false; reason: "unmatched"; scope: RouteScope; }; /** Full discriminated return type of {@link resolveAgentRoute}. */ export type AgentRouteOutcome = MatchedAgentRoute | UnmatchedAgentRoute; export { DEFAULT_ACCOUNT_ID } from "./session-key.js"; export declare function deriveLastRoutePolicy(params: { sessionKey: string; mainSessionKey: string; }): MatchedAgentRoute["lastRoutePolicy"]; export declare function resolveInboundLastRouteSessionKey(params: { route: Pick; sessionKey: string; }): string; export declare function buildAgentSessionKey(params: { agentId: string; channel: string; accountId?: string | null; peer?: RoutePeer | null; /** DM session scope. */ dmScope?: "main" | "per-peer" | "per-channel-peer" | "per-account-channel-peer"; identityLinks?: Record; }): string; /** * Resolve an agent id against `cfg.agents.list`, returning the sanitized canonical * form when the id exists, or a sanitized passthrough when the list is empty or the * id is not configured. Schema-level validation in `zod-schema.ts` ensures binding * agent ids must exist in `agents.list`; this function is a runtime safety net for * topic overrides and other operator-supplied ids that bypass the binding path. */ export declare function pickFirstExistingAgentId(cfg: RemoteClawConfig, agentId: string): string; /** * Build a {@link MatchedAgentRoute} for a given agent/scope without going through * binding resolution. Used by the catch-all unmatched path to produce a route for * the operator-designated fallback agent. */ export declare function buildMatchedRoute(params: { cfg: RemoteClawConfig; agentId: string; scope: RouteScope; matchedBy: MatchedByTier; }): MatchedAgentRoute; /** * Low-level route resolution returning the full discriminated outcome. Callers * that want explicit control over unmatched handling (e.g. tests, the policy * wrapper, telemetry) use this form. For the backward-compatible, always-matched * variant, use {@link resolveAgentRoute}. */ export declare function resolveAgentRouteExplicit(input: ResolveAgentRouteInput): AgentRouteOutcome; /** * Resolve an agent route, applying the operator `routing.unmatched` policy when * no binding matches and no sole agent is configured. Returns `null` when the * policy drops the message (silent drop + telemetry). Otherwise returns a * {@link ResolvedAgentRoute}. * * This is the preferred entry point for channel adapters. Adapters migrate from * `resolveAgentRoute` to this wrapper with a one-line change: add * `if (!route) return;` after the call. */ export declare function resolveAgentRouteWithPolicy(input: ResolveAgentRouteInput): MatchedAgentRoute | null; /** * Backward-compatible entry point for code paths that type their variable as * {@link ResolvedAgentRoute} and can not tolerate a `null` return. Applies the * operator `routing.unmatched` policy through {@link resolveAgentRouteWithPolicy} * first — this fires the full operator telemetry stack (structured log, OTel * counter, Control UI event, `/remoteclaw status` accrual) when the policy * says drop. * * When the policy says "drop" and the caller is on the legacy path, there is * no safe way to halt processing from inside this function. The wrapper falls * back to the first configured agent and tags the route with * `matchedBy = "fallback.legacyRoute"` so downstream consumers, operators, and * telemetry can distinguish it from sole-agent promotion (a legitimate single- * agent config) or catch-all routing (an explicit operator choice). A * structured warn log fires on every fallback occurrence so the migration * gap is visible in production. * * New adapters SHOULD prefer {@link resolveAgentRouteWithPolicy} for explicit * silent-drop semantics — that form returns `null` instead of a fallback route, * allowing adapters to halt message processing cleanly and honoring the drop * telemetry as the sole outcome. */ export declare function resolveAgentRoute(input: ResolveAgentRouteInput): ResolvedAgentRoute;