/** * The chat↔agent bridge: inbound Lark messages drive per-chat DSH agents, * committed assistant output returns as chat messages, and host approval * questions become interactive cards answered by button clicks. * @module dsh-lark-channel/bridge */ import type { Context } from '@deepseek-ai/cordis'; import type { CardActionEvent, CardActionResponse, LarkChannelError, NormalizedMessage, RejectEvent } from '@larksuite/channel'; import type { ResolvedConfig } from './config.ts'; import type { HostUserMessage } from './host.ts'; import type { CotPort } from './cot.ts'; import type { OutboundPort } from './outbound.ts'; import type { Authorization } from './authorization.ts'; import type { CollectedImages, ImagePort } from './images.ts'; import type { CollectedFiles, InboundFilePort } from './files.ts'; import type { SlashPanelPort } from './slash-panel.ts'; /** * The transport surface the bridge drives. `LarkChannel` from * `@larksuite/channel` satisfies it structurally; tests substitute a fake. */ export interface ChannelPort extends OutboundPort, SlashPanelPort, ImagePort, InboundFilePort, CotPort { /** Open the transport (WebSocket long connection by default). */ connect(): Promise; /** Close the transport and release its resources. */ disconnect(): Promise; /** * The transport's own account of its connection, when it offers one. The * SDK reports `failed` for its terminal give-up state, which is exactly the * state the reconnect watchdog exists to catch. */ getConnectionStatus?(): { readonly state?: string; } | undefined; /** Subscribe one normalized inbound event; returns the unsubscriber. */ on(name: 'message', handler: (msg: NormalizedMessage) => void | Promise): () => void; on(name: 'cardAction', handler: (evt: CardActionEvent) => void | CardActionResponse | Promise): () => void; /** * A message the transport's own policy layer refused. Subscribing is the only * way to tell "the bot ignored me" apart from "the bot is broken": a refusal * never reaches the `message` handler and is reported nowhere else. */ on(name: 'reject', handler: (evt: RejectEvent) => void): () => void; /** * A transport failure, including one thrown by an inbound handler: those do * NOT reject the awaited dispatch, so an unsubscribed channel loses them. */ on(name: 'error', handler: (err: LarkChannelError) => void): () => void; /** The long connection dropped; events arriving in the gap are not replayed. */ on(name: 'reconnecting', handler: () => void): () => void; /** The long connection is live again. */ on(name: 'reconnected', handler: () => void): () => void; /** * This bot's own identity, resolved during connect. Optional here so a fake * port need not implement it; it throws before connect, which callers treat * as "not known yet". */ getBotIdentity?(): { readonly openId: string; readonly name?: string; }; /** * List a chat's human roster when the transport exposes it. This is optional * because older channel implementations can still settle approvals using the * callback's open id alone. */ getChatMembers?(chatId: string): Promise; /** Replace a sent card's content in place. */ updateCard(messageId: string, card: object): Promise; } /** * Create an identified user message from one chat input. Group messages carry * the sender so the model can tell voices apart; direct messages stay verbatim. * @param msg - normalized inbound chat message. * @param images - what this message's images became. * @param inbound - what this message's files became on disk. * @returns a frozen user message for `agent.followup()`. */ export declare function chatUserMessage(msg: NormalizedMessage, images: CollectedImages, inbound: CollectedFiles): HostUserMessage; /** * Install the bridge on a scoped plugin context. Every registration is owned * by the context's fiber: disposal disconnects the transport, disposes every * agent this channel owns, and settles pending approvals as `'cancelled'`. * @param ctx - scoped plugin context carrying the `agents` service. * @param config - resolved plugin configuration. * @param port - the transport to drive; production passes the real Lark channel. */ export declare function installBridge(ctx: Context, config: ResolvedConfig, port: ChannelPort, notify: (line: string) => void, authorization: Authorization, persistState?: (patch: object) => Promise, liveness?: { readonly deadlineMs?: number; readonly backoffMs?: readonly number[]; readonly quotaWindowMs?: number; readonly quotaLimit?: number; }): void; //# sourceMappingURL=bridge.d.ts.map