@aigne/afs-messaging 1.11.0-beta.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.mjs","names":["m"],"sources":["../src/base.ts"],"sourcesContent":["/**\n * BaseMessageProvider — unified abstract base for all messaging platform AFS providers.\n *\n * Plan 9 model: one mount per platform, bots are instances within (like /net/tcp/0/).\n *\n * Path structure:\n * / → List bots\n * /:botName/ctl → Bot status\n * /:botName/conversations → List conversations\n * /:botName/conversations/:convId → Conversation info\n * /:botName/conversations/:convId/messages → List messages\n * /:botName/conversations/:convId/messages/:msgId → Read message\n *\n * Actions:\n * /.actions/add-bot → Add bot at runtime\n * /.actions/remove-bot → Remove bot\n * /:botName/conversations/:convId/.actions/send → Send message\n *\n * Events (standard):\n * messaging:message → New message received\n * messaging:command → Command message (/prefix)\n * messaging:sent → Outbound message confirmed\n * messaging:callback → Interactive callback (buttons)\n *\n * Subclass implements: providerName, eventPrefix, getMessageCapabilities(),\n * createBotClient(), sendMessage(), normalizeMessage(), normalizeSender().\n */\n\nimport type {\n ActionCatalog,\n AFSEntry,\n AFSExecResult,\n AFSExplainResult,\n AFSListResult,\n CapabilitiesManifest,\n} from \"@aigne/afs\";\nimport { AFSNotFoundError } from \"@aigne/afs\";\nimport {\n Actions,\n AFSBaseProvider,\n Explain,\n List,\n Read,\n type RouteContext,\n} from \"@aigne/afs/provider\";\nimport type {\n BotConfig,\n BufferedMessage,\n MessageCapabilities,\n MessageSender,\n SendOptions,\n} from \"./types.js\";\nimport { MESSAGING_EVENTS } from \"./types.js\";\n\nconst DEFAULT_BUFFER_SIZE = 100;\n\nexport interface BaseMessageProviderOptions {\n bots: BotConfig[];\n bufferSize?: number;\n}\n\n/**\n * Abstract base class for messaging platform providers.\n *\n * Subclass must implement:\n * - providerName: string (e.g., \"telegram\")\n * - eventPrefix: string (e.g., \"telegram\")\n * - getMessageCapabilities(): MessageCapabilities\n * - createBotClient(config: BotConfig): unknown\n * - sendMessage(client, convId, text, opts?): Promise<{ messageId: string }>\n * - normalizeMessage(raw): BufferedMessage\n * - normalizeSender(raw): MessageSender\n */\nexport abstract class BaseMessageProvider extends AFSBaseProvider {\n get name(): string {\n return this.providerName;\n }\n\n readonly accessMode = \"readwrite\" as const;\n\n /** Platform name (e.g., \"telegram\", \"slack\") */\n abstract readonly providerName: string;\n\n /** Event prefix for platform-specific (non-standard) events */\n abstract readonly eventPrefix: string;\n\n /** Return platform capabilities */\n abstract getMessageCapabilities(): MessageCapabilities;\n\n /** Create a platform API client from bot config */\n abstract createBotClient(config: BotConfig): unknown;\n\n /** Send a message via platform API. Returns { messageId } on success. */\n abstract sendMessage(\n client: unknown,\n convId: string,\n text: string,\n opts?: SendOptions,\n ): Promise<{ messageId: string }>;\n\n /** Normalize a raw platform message to standard BufferedMessage */\n abstract normalizeMessage(raw: Record<string, unknown>): BufferedMessage;\n\n /** Normalize a raw platform sender to standard MessageSender */\n abstract normalizeSender(raw: Record<string, unknown>): MessageSender;\n\n /** Send a typing indicator to a conversation. No-op for platforms without typing API. */\n abstract sendTypingIndicator(client: unknown, convId: string): Promise<void>;\n\n // ─── Internal State ──────────────────────────────────\n\n protected readonly _bufferSize: number;\n\n /** botName → platform client */\n protected readonly _botClients = new Map<string, unknown>();\n\n /** botName → BotConfig */\n protected readonly _botConfigs = new Map<string, BotConfig>();\n\n /** botName → Set<conversationId> */\n protected readonly _botConversations = new Map<string, Set<string>>();\n\n /** botName → (conversationId → BufferedMessage[]) */\n protected readonly _botBuffers = new Map<string, Map<string, BufferedMessage[]>>();\n\n /** Ordered list of bot names (for consistent listing) */\n protected readonly _botOrder: string[] = [];\n\n /** Pending bot configs — created in constructor, clients instantiated lazily */\n protected _pendingBots: BotConfig[] | null = null;\n\n constructor(options: BaseMessageProviderOptions) {\n super();\n this._bufferSize = options.bufferSize ?? DEFAULT_BUFFER_SIZE;\n\n // Store configs for deferred initialization.\n // createBotClient() is abstract and subclass fields aren't initialized during super().\n this._pendingBots = options.bots;\n for (const botConfig of options.bots) {\n this._addBotConfig(botConfig);\n }\n }\n\n /** Ensure all pending bot clients are created. Called lazily on first access. */\n private _ensureClients(): void {\n if (!this._pendingBots) return;\n const pending = this._pendingBots;\n this._pendingBots = null;\n for (const config of pending) {\n if (!this._botClients.has(config.name)) {\n const client = this.createBotClient(config);\n this._botClients.set(config.name, client);\n }\n }\n }\n\n /** Get a bot client, creating lazily if needed. */\n protected _getClient(botName: string): unknown | undefined {\n this._ensureClients();\n return this._botClients.get(botName);\n }\n\n // ─── Bot Lifecycle ───────────────────────────────────\n\n /** Register bot config and conversations without creating the client. */\n private _addBotConfig(config: BotConfig): void {\n const name = config.name;\n if (this._botConfigs.has(name)) return;\n\n this._botConfigs.set(name, config);\n\n const conversations = new Set<string>();\n if (Array.isArray(config.conversations)) {\n for (const c of config.conversations) {\n conversations.add(String(c));\n }\n }\n this._botConversations.set(name, conversations);\n\n const buffers = new Map<string, BufferedMessage[]>();\n for (const convId of conversations) {\n buffers.set(convId, []);\n }\n this._botBuffers.set(name, buffers);\n\n this._botOrder.push(name);\n }\n\n private _removeBot(name: string): boolean {\n if (!this._botConfigs.has(name)) return false;\n\n this._botClients.delete(name);\n this._botConfigs.delete(name);\n this._botConversations.delete(name);\n this._botBuffers.delete(name);\n const idx = this._botOrder.indexOf(name);\n if (idx >= 0) this._botOrder.splice(idx, 1);\n\n this.onBotRemoved(name);\n return true;\n }\n\n /** Hook for subclasses to initialize platform-specific state (e.g. polling, gateway) when a bot is added at runtime. */\n protected onBotAdded(_name: string): void {}\n\n /** Hook for subclasses to clean up platform-specific state when a bot is removed. */\n protected onBotRemoved(_name: string): void {}\n\n // ─── Public: emitMessageReceived ─────────────────────\n\n /**\n * Buffer a received message and emit the appropriate event.\n * Called by subclass when a new message arrives from the platform.\n *\n * - Buffers the message in the ring buffer\n * - Auto-adds conversation if not yet tracked\n * - Detects /commands → emits messaging:command\n * - Otherwise → emits messaging:message\n */\n emitMessageReceived(botName: string, msg: BufferedMessage): void {\n const convId = msg.conversationId;\n\n // Auto-add conversation if not tracked\n const conversations = this._botConversations.get(botName);\n if (conversations && !conversations.has(convId)) {\n conversations.add(convId);\n const buffers = this._botBuffers.get(botName);\n if (buffers && !buffers.has(convId)) {\n buffers.set(convId, []);\n }\n }\n\n // Buffer the message\n this._pushToRingBuffer(botName, convId, msg);\n\n // Detect command vs regular message\n const path = `/${botName}/conversations/${convId}/messages/${msg.id}`;\n const text = msg.text.trim();\n\n if (text.startsWith(\"/\")) {\n const spaceIdx = text.indexOf(\" \");\n const command = spaceIdx > 0 ? text.slice(1, spaceIdx) : text.slice(1);\n const args = spaceIdx > 0 ? text.slice(spaceIdx + 1).trim() : \"\";\n\n this.emit({\n type: MESSAGING_EVENTS.COMMAND,\n path,\n data: {\n botName,\n conversationId: convId,\n messageId: msg.id,\n command,\n args,\n text,\n from: msg.from,\n },\n });\n } else {\n this.emit({\n type: MESSAGING_EVENTS.MESSAGE,\n path,\n data: {\n botName,\n conversationId: convId,\n messageId: msg.id,\n text,\n from: msg.from,\n },\n });\n }\n }\n\n private _pushToRingBuffer(botName: string, convId: string, msg: BufferedMessage): void {\n let botBuffers = this._botBuffers.get(botName);\n if (!botBuffers) {\n botBuffers = new Map();\n this._botBuffers.set(botName, botBuffers);\n }\n let buffer = botBuffers.get(convId);\n if (!buffer) {\n buffer = [];\n botBuffers.set(convId, buffer);\n }\n buffer.push(msg);\n while (buffer.length > this._bufferSize) {\n buffer.shift();\n }\n }\n\n // ─── AFS Routes: List ────────────────────────────────\n\n @List(\"/\")\n async listRoot(_ctx: RouteContext): Promise<AFSListResult> {\n return {\n data: this._botOrder.map((name) => {\n return this.buildEntry(`/${name}`, {\n id: name,\n meta: { type: \"directory\", childrenCount: 2 },\n });\n }),\n };\n }\n\n @List(\"/:botName\")\n async listBot(ctx: RouteContext<{ botName: string }>): Promise<AFSListResult> {\n const { botName } = ctx.params;\n if (!this._botConfigs.has(botName)) throw new AFSNotFoundError(`/${botName}`);\n\n const convs = this._botConversations.get(botName)!;\n return {\n data: [\n this.buildEntry(`/${botName}/ctl`, {\n meta: { description: \"Bot control file\" },\n }),\n this.buildEntry(`/${botName}/conversations`, {\n meta: { type: \"directory\", childrenCount: convs.size },\n }),\n ],\n };\n }\n\n @List(\"/:botName/conversations\")\n async listConversations(ctx: RouteContext<{ botName: string }>): Promise<AFSListResult> {\n const { botName } = ctx.params;\n const convs = this._botConversations.get(botName);\n if (!convs) throw new AFSNotFoundError(`/${botName}/conversations`);\n\n return {\n data: [...convs].map((convId) => {\n const buffer = this._botBuffers.get(botName)?.get(convId) ?? [];\n return this.buildEntry(`/${botName}/conversations/${convId}`, {\n id: convId,\n meta: { conversationId: convId, childrenCount: buffer.length },\n });\n }),\n };\n }\n\n @List(\"/:botName/conversations/:convId\")\n async listConversationChildren(\n ctx: RouteContext<{ botName: string; convId: string }>,\n ): Promise<AFSListResult> {\n const { botName, convId } = ctx.params;\n const buffer = this._botBuffers.get(botName)?.get(convId) ?? [];\n return {\n data: [\n this.buildEntry(`/${botName}/conversations/${convId}/messages`, {\n meta: { type: \"directory\", childrenCount: buffer.length },\n }),\n ],\n };\n }\n\n @List(\"/:botName/conversations/:convId/messages\")\n async listMessages(\n ctx: RouteContext<{ botName: string; convId: string }>,\n ): Promise<AFSListResult> {\n const { botName, convId } = ctx.params;\n const buffer = this._botBuffers.get(botName)?.get(convId) ?? [];\n\n return {\n data: buffer.map((msg) =>\n this.buildEntry(`/${botName}/conversations/${convId}/messages/${msg.id}`, {\n id: msg.id,\n content: msg.text,\n meta: {\n kind: \"messaging:message\" as any,\n from: msg.from,\n timestamp: msg.timestamp,\n format: \"text\",\n conversationId: convId,\n ...(msg.replyTo ? { replyTo: msg.replyTo } : {}),\n ...(msg.platform ? { platform: msg.platform } : {}),\n },\n }),\n ),\n };\n }\n\n @List(\"/:botName/conversations/:convId/messages/:msgId\")\n async listMessageChildren(\n _ctx: RouteContext<{ botName: string; convId: string; msgId: string }>,\n ): Promise<AFSListResult> {\n return { data: [] };\n }\n\n // ─── AFS Routes: Read ────────────────────────────────\n\n @Read(\"/\")\n async readRoot(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n return this.buildEntry(\"/\", {\n content: JSON.stringify({\n provider: this.providerName,\n bots: this._botOrder,\n bufferSize: this._bufferSize,\n }),\n meta: { childrenCount: this._botOrder.length },\n });\n }\n\n @Read(\"/:botName\")\n async readBot(ctx: RouteContext<{ botName: string }>): Promise<AFSEntry | undefined> {\n const { botName } = ctx.params;\n const config = this._botConfigs.get(botName);\n if (!config) throw new AFSNotFoundError(`/${botName}`);\n\n const conversations = [...(this._botConversations.get(botName) ?? [])];\n return this.buildEntry(`/${botName}`, {\n id: botName,\n content: JSON.stringify({\n name: botName,\n platform: this.providerName,\n conversations,\n }),\n meta: { type: \"directory\", childrenCount: 2 },\n });\n }\n\n @Read(\"/:botName/ctl\")\n async readCtl(ctx: RouteContext<{ botName: string }>): Promise<AFSEntry | undefined> {\n const { botName } = ctx.params;\n const config = this._botConfigs.get(botName);\n if (!config) throw new AFSNotFoundError(`/${botName}/ctl`);\n\n const conversations = [...(this._botConversations.get(botName) ?? [])];\n return this.buildEntry(`/${botName}/ctl`, {\n content: JSON.stringify({\n name: botName,\n platform: this.providerName,\n conversations,\n }),\n });\n }\n\n @Read(\"/:botName/conversations\")\n async readConversationsDir(\n ctx: RouteContext<{ botName: string }>,\n ): Promise<AFSEntry | undefined> {\n const { botName } = ctx.params;\n const convs = this._botConversations.get(botName);\n if (!convs) throw new AFSNotFoundError(`/${botName}/conversations`);\n\n return this.buildEntry(`/${botName}/conversations`, {\n content: JSON.stringify({ type: \"directory\", count: convs.size }),\n meta: { type: \"directory\", childrenCount: convs.size },\n });\n }\n\n @Read(\"/:botName/conversations/:convId\")\n async readConversation(\n ctx: RouteContext<{ botName: string; convId: string }>,\n ): Promise<AFSEntry | undefined> {\n const { botName, convId } = ctx.params;\n const convs = this._botConversations.get(botName);\n if (!convs || !convs.has(convId))\n throw new AFSNotFoundError(`/${botName}/conversations/${convId}`);\n\n const buffer = this._botBuffers.get(botName)?.get(convId) ?? [];\n return this.buildEntry(`/${botName}/conversations/${convId}`, {\n id: convId,\n content: JSON.stringify({\n conversationId: convId,\n messageCount: buffer.length,\n }),\n meta: { childrenCount: 1 },\n });\n }\n\n @Read(\"/:botName/conversations/:convId/messages\")\n async readMessagesDir(\n ctx: RouteContext<{ botName: string; convId: string }>,\n ): Promise<AFSEntry | undefined> {\n const { botName, convId } = ctx.params;\n const buffer = this._botBuffers.get(botName)?.get(convId) ?? [];\n return this.buildEntry(`/${botName}/conversations/${convId}/messages`, {\n content: JSON.stringify({ type: \"directory\", count: buffer.length }),\n meta: { type: \"directory\", childrenCount: buffer.length },\n });\n }\n\n @Read(\"/:botName/conversations/:convId/messages/:msgId\")\n async readMessage(\n ctx: RouteContext<{ botName: string; convId: string; msgId: string }>,\n ): Promise<AFSEntry | undefined> {\n const { botName, convId, msgId } = ctx.params;\n const buffer = this._botBuffers.get(botName)?.get(convId) ?? [];\n const msg = buffer.find((m) => m.id === msgId);\n if (!msg) throw new AFSNotFoundError(`/${botName}/conversations/${convId}/messages/${msgId}`);\n\n return this.buildEntry(`/${botName}/conversations/${convId}/messages/${msgId}`, {\n id: msgId,\n content: msg.text,\n meta: {\n kind: \"messaging:message\" as any,\n from: msg.from,\n timestamp: msg.timestamp,\n format: \"text\",\n conversationId: convId,\n ...(msg.replyTo ? { replyTo: msg.replyTo } : {}),\n ...(msg.platform ? { platform: msg.platform } : {}),\n },\n });\n }\n\n // ─── Meta ────────────────────────────────────────────\n\n @Read(\"/.meta\")\n async readRootMeta(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n const m = { childrenCount: this._botOrder.length };\n return this.buildEntry(\"/.meta\", { content: m, meta: m });\n }\n\n @Read(\"/.meta/.capabilities\")\n async readCapabilities(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n const messaging = this.getMessageCapabilities();\n\n const actionCatalogs: ActionCatalog[] = [\n {\n description: \"Root-level bot management actions\",\n catalog: [\n {\n name: \"add-bot\",\n description: \"Add a bot instance at runtime\",\n inputSchema: {\n type: \"object\",\n properties: {\n name: { type: \"string\", description: \"Bot instance name\" },\n },\n required: [\"name\"],\n },\n },\n {\n name: \"remove-bot\",\n description: \"Remove a bot instance\",\n inputSchema: {\n type: \"object\",\n properties: {\n name: { type: \"string\", description: \"Bot instance name to remove\" },\n },\n required: [\"name\"],\n },\n },\n ],\n discovery: { pathTemplate: \"/.actions\" },\n },\n {\n kind: \"messaging:conversation\",\n description: \"Conversation-level messaging actions\",\n catalog: [\n {\n name: \"send\",\n description: \"Send a text message to this conversation\",\n inputSchema: {\n type: \"object\",\n properties: {\n text: { type: \"string\", description: \"Message text to send\" },\n },\n required: [\"text\"],\n },\n },\n {\n name: \"typing\",\n description: \"Show typing indicator in this conversation\",\n inputSchema: {\n type: \"object\",\n properties: {},\n required: [],\n },\n },\n ],\n discovery: {\n pathTemplate: \"/:botName/conversations/:convId/.actions\",\n note: \"Replace :botName and :convId with actual values\",\n },\n },\n ];\n\n const manifest: CapabilitiesManifest = {\n schemaVersion: 1,\n provider: this.providerName,\n description: `${this.providerName} messaging provider`,\n tools: [],\n actions: actionCatalogs,\n operations: this.getOperationsDeclaration(),\n };\n\n return this.buildEntry(\"/.meta/.capabilities\", {\n content: { ...manifest, messaging },\n meta: { kind: \"afs:capabilities\" },\n });\n }\n\n @Read(\"/:botName/.meta\")\n async readBotMeta(ctx: RouteContext<{ botName: string }>): Promise<AFSEntry | undefined> {\n const { botName } = ctx.params;\n if (!this._botConfigs.has(botName)) throw new AFSNotFoundError(`/${botName}/.meta`);\n const m = { botName, childrenCount: 2 };\n return this.buildEntry(`/${botName}/.meta`, { content: m, meta: m });\n }\n\n @Read(\"/:botName/conversations/.meta\")\n async readConversationsMeta(\n ctx: RouteContext<{ botName: string }>,\n ): Promise<AFSEntry | undefined> {\n const { botName } = ctx.params;\n const convs = this._botConversations.get(botName);\n if (!convs) throw new AFSNotFoundError(`/${botName}/conversations/.meta`);\n const m = { type: \"directory\" as const, childrenCount: convs.size };\n return this.buildEntry(`/${botName}/conversations/.meta`, { content: m, meta: m });\n }\n\n @Read(\"/:botName/conversations/:convId/.meta\")\n async readConversationMeta(\n ctx: RouteContext<{ botName: string; convId: string }>,\n ): Promise<AFSEntry | undefined> {\n const { botName, convId } = ctx.params;\n const buffer = this._botBuffers.get(botName)?.get(convId) ?? [];\n const m = { conversationId: convId, childrenCount: buffer.length };\n return this.buildEntry(`/${botName}/conversations/${convId}/.meta`, { content: m, meta: m });\n }\n\n @Read(\"/:botName/conversations/:convId/messages/.meta\")\n async readMessagesMeta(\n ctx: RouteContext<{ botName: string; convId: string }>,\n ): Promise<AFSEntry | undefined> {\n const { botName, convId } = ctx.params;\n const buffer = this._botBuffers.get(botName)?.get(convId) ?? [];\n const m = { type: \"directory\" as const, childrenCount: buffer.length };\n return this.buildEntry(`/${botName}/conversations/${convId}/messages/.meta`, {\n content: m,\n meta: m,\n });\n }\n\n @Read(\"/:botName/conversations/:convId/messages/:msgId/.meta\")\n async readMsgMeta(\n ctx: RouteContext<{ botName: string; convId: string; msgId: string }>,\n ): Promise<AFSEntry | undefined> {\n const { botName, convId, msgId } = ctx.params;\n const buffer = this._botBuffers.get(botName)?.get(convId) ?? [];\n const msg = buffer.find((m) => m.id === msgId);\n if (!msg)\n throw new AFSNotFoundError(`/${botName}/conversations/${convId}/messages/${msgId}/.meta`);\n const m = { from: msg.from, timestamp: msg.timestamp };\n return this.buildEntry(`/${botName}/conversations/${convId}/messages/${msgId}/.meta`, {\n content: m,\n meta: m,\n });\n }\n\n // ─── Explain ─────────────────────────────────────────\n\n @Explain(\"/\")\n async explainRoot(_ctx: RouteContext): Promise<AFSExplainResult> {\n return {\n content: `${this.providerName} messaging provider. Lists bots and their conversations. Messages are files you read().`,\n format: \"markdown\",\n };\n }\n\n @Explain(\"/:botName\")\n async explainBot(_ctx: RouteContext<{ botName: string }>): Promise<AFSExplainResult> {\n return {\n content: `A ${this.providerName} bot instance. Read \\`ctl\\` for status. List \\`conversations/\\` for active conversations.`,\n format: \"markdown\",\n };\n }\n\n @Explain(\"/:botName/conversations/:convId\")\n async explainConversation(\n _ctx: RouteContext<{ botName: string; convId: string }>,\n ): Promise<AFSExplainResult> {\n return {\n content:\n \"A conversation. List `messages/` for buffered messages. Use `.actions/send` to send a message.\",\n format: \"markdown\",\n };\n }\n\n @Explain(\"/:botName/conversations/:convId/messages/:msgId\")\n async explainMessage(\n _ctx: RouteContext<{ botName: string; convId: string; msgId: string }>,\n ): Promise<AFSExplainResult> {\n return {\n content: \"A single buffered message.\",\n format: \"markdown\",\n };\n }\n\n // ─── Actions ─────────────────────────────────────────\n\n @Actions(\"/\")\n async listRootActions(_ctx: RouteContext): Promise<AFSListResult> {\n return {\n data: [\n this.buildEntry(\"/.actions/add-bot\", {\n meta: {\n description: \"Add a bot instance at runtime\",\n inputSchema: {\n type: \"object\",\n properties: {\n name: { type: \"string\", description: \"Bot instance name\" },\n },\n required: [\"name\"],\n },\n },\n }),\n this.buildEntry(\"/.actions/remove-bot\", {\n meta: {\n description: \"Remove a bot instance\",\n inputSchema: {\n type: \"object\",\n properties: {\n name: { type: \"string\", description: \"Bot instance name to remove\" },\n },\n required: [\"name\"],\n },\n },\n }),\n ],\n };\n }\n\n @Actions.Exec(\"/\", \"add-bot\")\n async execAddBot(_ctx: RouteContext, args: Record<string, unknown>): Promise<AFSExecResult> {\n const name = String(args.name ?? \"\");\n if (!name) throw new Error(\"add-bot requires a name\");\n\n const config: BotConfig = { name, ...args };\n this._addBotConfig(config);\n this._botClients.set(name, this.createBotClient(config));\n this.onBotAdded(name);\n return { success: true, data: { ok: true, botName: name } };\n }\n\n @Actions.Exec(\"/\", \"remove-bot\")\n async execRemoveBot(_ctx: RouteContext, args: Record<string, unknown>): Promise<AFSExecResult> {\n const name = String(args.name ?? \"\");\n const removed = this._removeBot(name);\n return { success: true, data: { ok: removed, botName: name } };\n }\n\n @Actions(\"/:botName/conversations/:convId\")\n async listConversationActions(\n ctx: RouteContext<{ botName: string; convId: string }>,\n ): Promise<AFSListResult> {\n const { botName, convId } = ctx.params;\n return {\n data: [\n this.buildEntry(`/${botName}/conversations/${convId}/.actions/send`, {\n meta: {\n description: \"Send a text message to this conversation\",\n inputSchema: {\n type: \"object\",\n properties: {\n text: { type: \"string\", description: \"Message text to send\" },\n },\n required: [\"text\"],\n },\n },\n }),\n this.buildEntry(`/${botName}/conversations/${convId}/.actions/typing`, {\n meta: {\n description: \"Show typing indicator in this conversation\",\n inputSchema: {\n type: \"object\",\n properties: {},\n required: [],\n },\n },\n }),\n ],\n };\n }\n\n @Actions.Exec(\"/:botName/conversations/:convId\", \"send\")\n async execSend(\n ctx: RouteContext<{ botName: string; convId: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n const { botName, convId } = ctx.params;\n const client = this._getClient(botName);\n if (!client) throw new Error(`Bot \"${botName}\" not found`);\n\n const text = String(args.text ?? \"\");\n const { text: _t, ...sendOpts } = args;\n const result = await this.sendMessage(client, convId, text, sendOpts as SendOptions);\n\n return { success: true, data: result };\n }\n\n @Actions.Exec(\"/:botName/conversations/:convId\", \"typing\")\n async execTyping(ctx: RouteContext<{ botName: string; convId: string }>): Promise<AFSExecResult> {\n const { botName, convId } = ctx.params;\n const client = this._getClient(botName);\n if (!client) throw new Error(`Bot \"${botName}\" not found`);\n await this.sendTypingIndicator(client, convId);\n return { success: true, data: { ok: true } };\n }\n}\n"],"mappings":"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"}
package/dist/index.cjs ADDED
@@ -0,0 +1,5 @@
1
+ const require_types = require('./types.cjs');
2
+ const require_base = require('./base.cjs');
3
+
4
+ exports.BaseMessageProvider = require_base.BaseMessageProvider;
5
+ exports.MESSAGING_EVENTS = require_types.MESSAGING_EVENTS;
@@ -0,0 +1,3 @@
1
+ import { BotConfig, BufferedMessage, MESSAGING_EVENTS, MessageCapabilities, MessageEventData, MessageFormat, MessageSender, MessagingEventType, SendOptions, StandardMessageMeta } from "./types.cjs";
2
+ import { BaseMessageProvider } from "./base.cjs";
3
+ export { BaseMessageProvider, type BotConfig, type BufferedMessage, MESSAGING_EVENTS, type MessageCapabilities, type MessageEventData, type MessageFormat, type MessageSender, type MessagingEventType, type SendOptions, type StandardMessageMeta };
@@ -0,0 +1,3 @@
1
+ import { BotConfig, BufferedMessage, MESSAGING_EVENTS, MessageCapabilities, MessageEventData, MessageFormat, MessageSender, MessagingEventType, SendOptions, StandardMessageMeta } from "./types.mjs";
2
+ import { BaseMessageProvider } from "./base.mjs";
3
+ export { BaseMessageProvider, type BotConfig, type BufferedMessage, MESSAGING_EVENTS, type MessageCapabilities, type MessageEventData, type MessageFormat, type MessageSender, type MessagingEventType, type SendOptions, type StandardMessageMeta };
package/dist/index.mjs ADDED
@@ -0,0 +1,4 @@
1
+ import { MESSAGING_EVENTS } from "./types.mjs";
2
+ import { BaseMessageProvider } from "./base.mjs";
3
+
4
+ export { BaseMessageProvider, MESSAGING_EVENTS };
package/dist/types.cjs ADDED
@@ -0,0 +1,12 @@
1
+
2
+ //#region src/types.ts
3
+ /** Standard messaging event types emitted by BaseMessageProvider. */
4
+ const MESSAGING_EVENTS = {
5
+ MESSAGE: "messaging:message",
6
+ COMMAND: "messaging:command",
7
+ SENT: "messaging:sent",
8
+ CALLBACK: "messaging:callback"
9
+ };
10
+
11
+ //#endregion
12
+ exports.MESSAGING_EVENTS = MESSAGING_EVENTS;
@@ -0,0 +1,89 @@
1
+ //#region src/types.d.ts
2
+ /**
3
+ * AFS Messaging Types — shared types for all messaging platform providers.
4
+ *
5
+ * Design: Plan 9 model where messaging platforms are devices.
6
+ * Messages are files you read(). Events are notifications that a new file exists.
7
+ */
8
+ type MessageFormat = "text" | "markdown" | "html" | "image" | "video" | "audio" | "file";
9
+ interface MessageSender {
10
+ id: string;
11
+ name: string;
12
+ isBot?: boolean;
13
+ }
14
+ /** Standard message metadata — returned in AFSEntry.meta for every message read(). */
15
+ interface StandardMessageMeta {
16
+ kind: "messaging:message";
17
+ from: MessageSender;
18
+ timestamp: number;
19
+ format: MessageFormat;
20
+ conversationId: string;
21
+ replyTo?: string;
22
+ /** Raw platform-specific data (e.g., { message_id: 67890 } for Telegram) */
23
+ platform?: Record<string, unknown>;
24
+ }
25
+ interface BotConfig {
26
+ /** Bot instance name (appears as path segment, e.g., "aos-bot") */
27
+ name: string;
28
+ /** Platform-specific credentials/config (token, etc.) */
29
+ [key: string]: unknown;
30
+ }
31
+ interface SendOptions {
32
+ /** Message format (default: "text") */
33
+ format?: MessageFormat;
34
+ /** Reply to a specific message ID */
35
+ replyTo?: string;
36
+ /** Platform-specific send options */
37
+ [key: string]: unknown;
38
+ }
39
+ interface MessageCapabilities {
40
+ formats: {
41
+ send: MessageFormat[];
42
+ receive: MessageFormat[];
43
+ };
44
+ maxMessageLength: number;
45
+ maxFileSize?: number;
46
+ features: {
47
+ edit: boolean;
48
+ delete: boolean;
49
+ reply: boolean;
50
+ thread: boolean;
51
+ reaction: boolean;
52
+ inlineKeyboard: boolean;
53
+ };
54
+ limits: {
55
+ messagesPerSecond?: number;
56
+ messagesPerMinute?: number;
57
+ };
58
+ }
59
+ /** Internal ring buffer entry — platform-agnostic after normalization. */
60
+ interface BufferedMessage {
61
+ id: string;
62
+ text: string;
63
+ from: MessageSender;
64
+ timestamp: number;
65
+ conversationId: string;
66
+ replyTo?: string;
67
+ platform?: Record<string, unknown>;
68
+ }
69
+ /** Standard messaging event types emitted by BaseMessageProvider. */
70
+ declare const MESSAGING_EVENTS: {
71
+ readonly MESSAGE: "messaging:message";
72
+ readonly COMMAND: "messaging:command";
73
+ readonly SENT: "messaging:sent";
74
+ readonly CALLBACK: "messaging:callback";
75
+ };
76
+ type MessagingEventType = (typeof MESSAGING_EVENTS)[keyof typeof MESSAGING_EVENTS];
77
+ /** Data payload for messaging:message and messaging:command events. */
78
+ interface MessageEventData {
79
+ botName: string;
80
+ conversationId: string;
81
+ messageId: string;
82
+ /** Only present for messaging:command */
83
+ command?: string;
84
+ /** Only present for messaging:command */
85
+ args?: string;
86
+ }
87
+ //#endregion
88
+ export { BotConfig, BufferedMessage, MESSAGING_EVENTS, MessageCapabilities, MessageEventData, MessageFormat, MessageSender, MessagingEventType, SendOptions, StandardMessageMeta };
89
+ //# sourceMappingURL=types.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.cts","names":[],"sources":["../src/types.ts"],"mappings":";;AASA;;;;;KAAY,aAAA;AAAA,UAIK,aAAA;EACf,EAAA;EACA,IAAA;EACA,KAAA;AAAA;;UAMe,mBAAA;EACf,IAAA;EACA,IAAA,EAAM,aAAA;EACN,SAAA;EACA,MAAA,EAAQ,aAAA;EACR,cAAA;EACA,OAAA;EAEW;EAAX,QAAA,GAAW,MAAA;AAAA;AAAA,UAKI,SAAA;EAXf;EAaA,IAAA;EAZA;EAAA,CAcC,GAAA;AAAA;AAAA,UAKc,WAAA;EAhBf;EAkBA,MAAA,GAAS,aAAA;EAhBE;EAkBX,OAAA;EAlBiB;EAAA,CAoBhB,GAAA;AAAA;AAAA,UAKc,mBAAA;EACf,OAAA;IACE,IAAA,EAAM,aAAA;IACN,OAAA,EAAS,aAAA;EAAA;EAEX,gBAAA;EACA,WAAA;EACA,QAAA;IACE,IAAA;IACA,MAAA;IACA,KAAA;IACA,MAAA;IACA,QAAA;IACA,cAAA;EAAA;EAEF,MAAA;IACE,iBAAA;IACA,iBAAA;EAAA;AAAA;;UAOa,eAAA;EACf,EAAA;EACA,IAAA;EACA,IAAA,EAAM,aAAA;EACN,SAAA;EACA,cAAA;EACA,OAAA;EACA,QAAA,GAAW,MAAA;AAAA;;cAMA,gBAAA;EAAA;;;;;KAOD,kBAAA,WAA6B,gBAAA,eAA+B,gBAAA;;UAGvD,gBAAA;EACf,OAAA;EACA,cAAA;EACA,SAAA;EAvBM;EAyBN,OAAA;EAvBA;EAyBA,IAAA;AAAA"}
@@ -0,0 +1,89 @@
1
+ //#region src/types.d.ts
2
+ /**
3
+ * AFS Messaging Types — shared types for all messaging platform providers.
4
+ *
5
+ * Design: Plan 9 model where messaging platforms are devices.
6
+ * Messages are files you read(). Events are notifications that a new file exists.
7
+ */
8
+ type MessageFormat = "text" | "markdown" | "html" | "image" | "video" | "audio" | "file";
9
+ interface MessageSender {
10
+ id: string;
11
+ name: string;
12
+ isBot?: boolean;
13
+ }
14
+ /** Standard message metadata — returned in AFSEntry.meta for every message read(). */
15
+ interface StandardMessageMeta {
16
+ kind: "messaging:message";
17
+ from: MessageSender;
18
+ timestamp: number;
19
+ format: MessageFormat;
20
+ conversationId: string;
21
+ replyTo?: string;
22
+ /** Raw platform-specific data (e.g., { message_id: 67890 } for Telegram) */
23
+ platform?: Record<string, unknown>;
24
+ }
25
+ interface BotConfig {
26
+ /** Bot instance name (appears as path segment, e.g., "aos-bot") */
27
+ name: string;
28
+ /** Platform-specific credentials/config (token, etc.) */
29
+ [key: string]: unknown;
30
+ }
31
+ interface SendOptions {
32
+ /** Message format (default: "text") */
33
+ format?: MessageFormat;
34
+ /** Reply to a specific message ID */
35
+ replyTo?: string;
36
+ /** Platform-specific send options */
37
+ [key: string]: unknown;
38
+ }
39
+ interface MessageCapabilities {
40
+ formats: {
41
+ send: MessageFormat[];
42
+ receive: MessageFormat[];
43
+ };
44
+ maxMessageLength: number;
45
+ maxFileSize?: number;
46
+ features: {
47
+ edit: boolean;
48
+ delete: boolean;
49
+ reply: boolean;
50
+ thread: boolean;
51
+ reaction: boolean;
52
+ inlineKeyboard: boolean;
53
+ };
54
+ limits: {
55
+ messagesPerSecond?: number;
56
+ messagesPerMinute?: number;
57
+ };
58
+ }
59
+ /** Internal ring buffer entry — platform-agnostic after normalization. */
60
+ interface BufferedMessage {
61
+ id: string;
62
+ text: string;
63
+ from: MessageSender;
64
+ timestamp: number;
65
+ conversationId: string;
66
+ replyTo?: string;
67
+ platform?: Record<string, unknown>;
68
+ }
69
+ /** Standard messaging event types emitted by BaseMessageProvider. */
70
+ declare const MESSAGING_EVENTS: {
71
+ readonly MESSAGE: "messaging:message";
72
+ readonly COMMAND: "messaging:command";
73
+ readonly SENT: "messaging:sent";
74
+ readonly CALLBACK: "messaging:callback";
75
+ };
76
+ type MessagingEventType = (typeof MESSAGING_EVENTS)[keyof typeof MESSAGING_EVENTS];
77
+ /** Data payload for messaging:message and messaging:command events. */
78
+ interface MessageEventData {
79
+ botName: string;
80
+ conversationId: string;
81
+ messageId: string;
82
+ /** Only present for messaging:command */
83
+ command?: string;
84
+ /** Only present for messaging:command */
85
+ args?: string;
86
+ }
87
+ //#endregion
88
+ export { BotConfig, BufferedMessage, MESSAGING_EVENTS, MessageCapabilities, MessageEventData, MessageFormat, MessageSender, MessagingEventType, SendOptions, StandardMessageMeta };
89
+ //# sourceMappingURL=types.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.mts","names":[],"sources":["../src/types.ts"],"mappings":";;AASA;;;;;KAAY,aAAA;AAAA,UAIK,aAAA;EACf,EAAA;EACA,IAAA;EACA,KAAA;AAAA;;UAMe,mBAAA;EACf,IAAA;EACA,IAAA,EAAM,aAAA;EACN,SAAA;EACA,MAAA,EAAQ,aAAA;EACR,cAAA;EACA,OAAA;EAEW;EAAX,QAAA,GAAW,MAAA;AAAA;AAAA,UAKI,SAAA;EAXf;EAaA,IAAA;EAZA;EAAA,CAcC,GAAA;AAAA;AAAA,UAKc,WAAA;EAhBf;EAkBA,MAAA,GAAS,aAAA;EAhBE;EAkBX,OAAA;EAlBiB;EAAA,CAoBhB,GAAA;AAAA;AAAA,UAKc,mBAAA;EACf,OAAA;IACE,IAAA,EAAM,aAAA;IACN,OAAA,EAAS,aAAA;EAAA;EAEX,gBAAA;EACA,WAAA;EACA,QAAA;IACE,IAAA;IACA,MAAA;IACA,KAAA;IACA,MAAA;IACA,QAAA;IACA,cAAA;EAAA;EAEF,MAAA;IACE,iBAAA;IACA,iBAAA;EAAA;AAAA;;UAOa,eAAA;EACf,EAAA;EACA,IAAA;EACA,IAAA,EAAM,aAAA;EACN,SAAA;EACA,cAAA;EACA,OAAA;EACA,QAAA,GAAW,MAAA;AAAA;;cAMA,gBAAA;EAAA;;;;;KAOD,kBAAA,WAA6B,gBAAA,eAA+B,gBAAA;;UAGvD,gBAAA;EACf,OAAA;EACA,cAAA;EACA,SAAA;EAvBM;EAyBN,OAAA;EAvBA;EAyBA,IAAA;AAAA"}
package/dist/types.mjs ADDED
@@ -0,0 +1,12 @@
1
+ //#region src/types.ts
2
+ /** Standard messaging event types emitted by BaseMessageProvider. */
3
+ const MESSAGING_EVENTS = {
4
+ MESSAGE: "messaging:message",
5
+ COMMAND: "messaging:command",
6
+ SENT: "messaging:sent",
7
+ CALLBACK: "messaging:callback"
8
+ };
9
+
10
+ //#endregion
11
+ export { MESSAGING_EVENTS };
12
+ //# sourceMappingURL=types.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.mjs","names":[],"sources":["../src/types.ts"],"sourcesContent":["/**\n * AFS Messaging Types — shared types for all messaging platform providers.\n *\n * Design: Plan 9 model where messaging platforms are devices.\n * Messages are files you read(). Events are notifications that a new file exists.\n */\n\n// ─── Message Format ──────────────────────────────────────────\n\nexport type MessageFormat = \"text\" | \"markdown\" | \"html\" | \"image\" | \"video\" | \"audio\" | \"file\";\n\n// ─── Message Sender ──────────────────────────────────────────\n\nexport interface MessageSender {\n id: string;\n name: string;\n isBot?: boolean;\n}\n\n// ─── Standard Message ────────────────────────────────────────\n\n/** Standard message metadata — returned in AFSEntry.meta for every message read(). */\nexport interface StandardMessageMeta {\n kind: \"messaging:message\";\n from: MessageSender;\n timestamp: number;\n format: MessageFormat;\n conversationId: string;\n replyTo?: string;\n /** Raw platform-specific data (e.g., { message_id: 67890 } for Telegram) */\n platform?: Record<string, unknown>;\n}\n\n// ─── Bot Config ──────────────────────────────────────────────\n\nexport interface BotConfig {\n /** Bot instance name (appears as path segment, e.g., \"aos-bot\") */\n name: string;\n /** Platform-specific credentials/config (token, etc.) */\n [key: string]: unknown;\n}\n\n// ─── Send Options ────────────────────────────────────────────\n\nexport interface SendOptions {\n /** Message format (default: \"text\") */\n format?: MessageFormat;\n /** Reply to a specific message ID */\n replyTo?: string;\n /** Platform-specific send options */\n [key: string]: unknown;\n}\n\n// ─── Message Capabilities ────────────────────────────────────\n\nexport interface MessageCapabilities {\n formats: {\n send: MessageFormat[];\n receive: MessageFormat[];\n };\n maxMessageLength: number;\n maxFileSize?: number;\n features: {\n edit: boolean;\n delete: boolean;\n reply: boolean;\n thread: boolean;\n reaction: boolean;\n inlineKeyboard: boolean;\n };\n limits: {\n messagesPerSecond?: number;\n messagesPerMinute?: number;\n };\n}\n\n// ─── Buffered Message (internal) ─────────────────────────────\n\n/** Internal ring buffer entry — platform-agnostic after normalization. */\nexport interface BufferedMessage {\n id: string;\n text: string;\n from: MessageSender;\n timestamp: number;\n conversationId: string;\n replyTo?: string;\n platform?: Record<string, unknown>;\n}\n\n// ─── Event Types ─────────────────────────────────────────────\n\n/** Standard messaging event types emitted by BaseMessageProvider. */\nexport const MESSAGING_EVENTS = {\n MESSAGE: \"messaging:message\",\n COMMAND: \"messaging:command\",\n SENT: \"messaging:sent\",\n CALLBACK: \"messaging:callback\",\n} as const;\n\nexport type MessagingEventType = (typeof MESSAGING_EVENTS)[keyof typeof MESSAGING_EVENTS];\n\n/** Data payload for messaging:message and messaging:command events. */\nexport interface MessageEventData {\n botName: string;\n conversationId: string;\n messageId: string;\n /** Only present for messaging:command */\n command?: string;\n /** Only present for messaging:command */\n args?: string;\n}\n"],"mappings":";;AA4FA,MAAa,mBAAmB;CAC9B,SAAS;CACT,SAAS;CACT,MAAM;CACN,UAAU;CACX"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@aigne/afs-messaging",
3
+ "version": "1.11.0-beta.12",
4
+ "description": "AIGNE AFS base provider for messaging platforms (Telegram, Slack, etc.)",
5
+ "license": "UNLICENSED",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "author": "Arcblock <blocklet@arcblock.io> https://github.com/arcblock",
10
+ "homepage": "https://github.com/arcblock/afs",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/arcblock/afs"
14
+ },
15
+ "bugs": {
16
+ "url": "https://github.com/arcblock/afs/issues"
17
+ },
18
+ "type": "module",
19
+ "main": "./dist/index.cjs",
20
+ "module": "./dist/index.mjs",
21
+ "types": "./dist/index.d.cts",
22
+ "exports": {
23
+ ".": {
24
+ "require": "./dist/index.cjs",
25
+ "import": "./dist/index.mjs"
26
+ },
27
+ "./*": "./*"
28
+ },
29
+ "files": [
30
+ "dist",
31
+ "LICENSE",
32
+ "README.md",
33
+ "CHANGELOG.md"
34
+ ],
35
+ "dependencies": {
36
+ "@aigne/afs": "^1.11.0-beta.12"
37
+ },
38
+ "devDependencies": {
39
+ "@types/bun": "^1.3.6",
40
+ "npm-run-all": "^4.1.5",
41
+ "rimraf": "^6.1.2",
42
+ "tsdown": "0.20.0-beta.3",
43
+ "typescript": "5.9.2",
44
+ "@aigne/scripts": "0.0.0",
45
+ "@aigne/typescript-config": "0.0.0"
46
+ },
47
+ "scripts": {
48
+ "build": "tsdown",
49
+ "check-types": "tsc --noEmit",
50
+ "clean": "rimraf dist coverage",
51
+ "test": "bun test",
52
+ "test:coverage": "bun test --coverage --coverage-reporter=lcov --coverage-reporter=text"
53
+ }
54
+ }