Full Matrix channel integration for LettaBot: - E2EE via rust crypto (ephemeral mode, cross-signing bootstrap) - Proactive SAS verification with Element clients - TTS (VibeVoice) and STT (Faster-Whisper) voice pipeline - Streaming message edits with 800ms throttle - Collapsible reasoning blocks via <details> htmlPrefix - Per-tool emoji reactions (brain, eyes, tool-specific, max 6) - Heartbeat room conversation routing (heartbeatTargetChatId) - Custom heartbeat prompt with first-person voice - Per-room conversation isolation (per-chat mode) - !pause, !resume, !status, !new, !timeout, !turns commands - Audio/image/file upload handlers with E2EE media - SDK 0.1.11 (approval recovery), CLI 0.18.2 Tested against Synapse homeserver with E2EE enabled for 2+ weeks, handles key backup/restore and device verification.
93 lines
3.3 KiB
TypeScript
93 lines
3.3 KiB
TypeScript
/**
|
|
* AgentSession interface - the contract for agent communication.
|
|
*
|
|
* Consumers (cron, heartbeat, polling, API server) depend on this interface,
|
|
* not the concrete LettaBot class. This enables multi-agent orchestration
|
|
* via LettaGateway without changing consumer code.
|
|
*/
|
|
|
|
import type { ChannelAdapter } from '../channels/types.js';
|
|
import type { InboundMessage, TriggerContext } from './types.js';
|
|
import type { GroupBatcher } from './group-batcher.js';
|
|
import type { StreamMsg } from './types.js';
|
|
|
|
export interface AgentSession {
|
|
/** Register a channel adapter */
|
|
registerChannel(adapter: ChannelAdapter): void;
|
|
|
|
/** Configure group message batching */
|
|
setGroupBatcher(batcher: GroupBatcher, intervals: Map<string, number>, instantGroupIds?: Set<string>, listeningGroupIds?: Set<string>): void;
|
|
|
|
/** Process a batched group message */
|
|
processGroupBatch(msg: InboundMessage, adapter: ChannelAdapter): void;
|
|
|
|
/** Start all registered channels */
|
|
start(): Promise<void>;
|
|
|
|
/** Stop all channels */
|
|
stop(): Promise<void>;
|
|
|
|
/** Send a message to the agent (used by cron, heartbeat, polling) */
|
|
sendToAgent(text: string, context?: TriggerContext): Promise<string>;
|
|
|
|
/** Stream a message to the agent, yielding chunks as they arrive */
|
|
streamToAgent(text: string, context?: TriggerContext): AsyncGenerator<StreamMsg>;
|
|
|
|
/** Deliver a message/file to a specific channel */
|
|
deliverToChannel(channelId: string, chatId: string, options: {
|
|
text?: string;
|
|
filePath?: string;
|
|
kind?: 'image' | 'file' | 'audio';
|
|
}): Promise<string | undefined>;
|
|
|
|
/** Get agent status */
|
|
getStatus(): { agentId: string | null; conversationId: string | null; channels: string[] };
|
|
|
|
/** Set agent ID (for container deploys) */
|
|
setAgentId(agentId: string): void;
|
|
|
|
/** Reset agent state */
|
|
reset(): void;
|
|
|
|
/** Get the last message target (for heartbeat delivery) */
|
|
getLastMessageTarget(): { channel: string; chatId: string } | null;
|
|
|
|
/** Get the time of the last user message (for heartbeat skip logic) */
|
|
getLastUserMessageTime(): Date | null;
|
|
|
|
/** Callback to trigger heartbeat */
|
|
onTriggerHeartbeat?: () => Promise<void>;
|
|
|
|
/** Invalidate a cached session, forcing fresh session on next message */
|
|
invalidateSession(key?: string): void;
|
|
|
|
/** Callback for session invalidation requests (e.g., from !new command) */
|
|
onInvalidateSession?: (key?: string) => void;
|
|
}
|
|
|
|
/**
|
|
* Minimal interface for message delivery.
|
|
* Satisfied by both AgentSession and LettaGateway.
|
|
*/
|
|
export interface MessageDeliverer {
|
|
deliverToChannel(channelId: string, chatId: string, options: {
|
|
text?: string;
|
|
filePath?: string;
|
|
kind?: 'image' | 'file' | 'audio';
|
|
}): Promise<string | undefined>;
|
|
}
|
|
|
|
/**
|
|
* Extended interface for the API server.
|
|
* Supports both outbound delivery (to channels) and inbound chat (to agents).
|
|
* Satisfied by LettaGateway.
|
|
*/
|
|
export interface AgentRouter extends MessageDeliverer {
|
|
/** Send a message to a named agent and return the response text */
|
|
sendToAgent(agentName: string | undefined, text: string, context?: TriggerContext): Promise<string>;
|
|
/** Stream a message to a named agent, yielding chunks as they arrive */
|
|
streamToAgent(agentName: string | undefined, text: string, context?: TriggerContext): AsyncGenerator<StreamMsg>;
|
|
/** Get all registered agent names */
|
|
getAgentNames(): string[];
|
|
}
|