@memberjunction/messaging-adapters 0.0.1 → 5.18.0
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.
- package/README.md +231 -43
- package/dist/base/BaseMessagingAdapter.d.ts +428 -0
- package/dist/base/BaseMessagingAdapter.d.ts.map +1 -0
- package/dist/base/BaseMessagingAdapter.js +934 -0
- package/dist/base/BaseMessagingAdapter.js.map +1 -0
- package/dist/base/message-formatter.d.ts +70 -0
- package/dist/base/message-formatter.d.ts.map +1 -0
- package/dist/base/message-formatter.js +201 -0
- package/dist/base/message-formatter.js.map +1 -0
- package/dist/base/types.d.ts +211 -0
- package/dist/base/types.d.ts.map +1 -0
- package/dist/base/types.js +6 -0
- package/dist/base/types.js.map +1 -0
- package/dist/index.d.ts +72 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +76 -0
- package/dist/index.js.map +1 -0
- package/dist/slack/SlackAdapter.d.ts +141 -0
- package/dist/slack/SlackAdapter.d.ts.map +1 -0
- package/dist/slack/SlackAdapter.js +291 -0
- package/dist/slack/SlackAdapter.js.map +1 -0
- package/dist/slack/SlackMessagingExtension.d.ts +148 -0
- package/dist/slack/SlackMessagingExtension.d.ts.map +1 -0
- package/dist/slack/SlackMessagingExtension.js +433 -0
- package/dist/slack/SlackMessagingExtension.js.map +1 -0
- package/dist/slack/slack-block-builder.d.ts +133 -0
- package/dist/slack/slack-block-builder.d.ts.map +1 -0
- package/dist/slack/slack-block-builder.js +748 -0
- package/dist/slack/slack-block-builder.js.map +1 -0
- package/dist/slack/slack-formatter.d.ts +37 -0
- package/dist/slack/slack-formatter.d.ts.map +1 -0
- package/dist/slack/slack-formatter.js +116 -0
- package/dist/slack/slack-formatter.js.map +1 -0
- package/dist/slack/slack-interactivity.d.ts +38 -0
- package/dist/slack/slack-interactivity.d.ts.map +1 -0
- package/dist/slack/slack-interactivity.js +414 -0
- package/dist/slack/slack-interactivity.js.map +1 -0
- package/dist/slack/slack-routes.d.ts +35 -0
- package/dist/slack/slack-routes.d.ts.map +1 -0
- package/dist/slack/slack-routes.js +98 -0
- package/dist/slack/slack-routes.js.map +1 -0
- package/dist/teams/TeamsAdapter.d.ts +155 -0
- package/dist/teams/TeamsAdapter.d.ts.map +1 -0
- package/dist/teams/TeamsAdapter.js +383 -0
- package/dist/teams/TeamsAdapter.js.map +1 -0
- package/dist/teams/TeamsMessagingExtension.d.ts +75 -0
- package/dist/teams/TeamsMessagingExtension.d.ts.map +1 -0
- package/dist/teams/TeamsMessagingExtension.js +176 -0
- package/dist/teams/TeamsMessagingExtension.js.map +1 -0
- package/dist/teams/teams-card-builder.d.ts +94 -0
- package/dist/teams/teams-card-builder.d.ts.map +1 -0
- package/dist/teams/teams-card-builder.js +648 -0
- package/dist/teams/teams-card-builder.js.map +1 -0
- package/dist/teams/teams-formatter.d.ts +39 -0
- package/dist/teams/teams-formatter.d.ts.map +1 -0
- package/dist/teams/teams-formatter.js +107 -0
- package/dist/teams/teams-formatter.js.map +1 -0
- package/package.json +40 -7
package/dist/index.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @memberjunction/messaging-adapters
|
|
3
|
+
*
|
|
4
|
+
* Messaging platform adapters for MemberJunction AI agents.
|
|
5
|
+
*
|
|
6
|
+
* This package provides Slack and Microsoft Teams integrations that allow
|
|
7
|
+
* MJ AI agents to be invoked directly from messaging platforms. Messages
|
|
8
|
+
* are received via webhooks, routed to the appropriate agent via
|
|
9
|
+
* `AgentRunner.RunAgent()`, and responses are streamed back as rich
|
|
10
|
+
* formatted messages (Slack Block Kit / Teams Adaptive Cards).
|
|
11
|
+
*
|
|
12
|
+
* ## Architecture
|
|
13
|
+
*
|
|
14
|
+
* Built on the MJServer Extension framework (`@memberjunction/server-extensions-core`):
|
|
15
|
+
* - `SlackMessagingExtension` and `TeamsMessagingExtension` extend `BaseServerExtension`
|
|
16
|
+
* - Auto-discovered via `@RegisterClass` and configured in `mj.config.cjs`
|
|
17
|
+
* - Zero MJServer source code changes needed per adapter
|
|
18
|
+
*
|
|
19
|
+
* ## Quick Start
|
|
20
|
+
*
|
|
21
|
+
* ```javascript
|
|
22
|
+
* // mj.config.cjs
|
|
23
|
+
* serverExtensions: [
|
|
24
|
+
* {
|
|
25
|
+
* Enabled: true,
|
|
26
|
+
* DriverClass: 'SlackMessagingExtension',
|
|
27
|
+
* RootPath: '/webhook/slack',
|
|
28
|
+
* Settings: {
|
|
29
|
+
* DefaultAgentName: 'Sage',
|
|
30
|
+
* ContextUserEmail: 'bot@company.com',
|
|
31
|
+
* BotToken: process.env.SLACK_BOT_TOKEN,
|
|
32
|
+
* SigningSecret: process.env.SLACK_SIGNING_SECRET,
|
|
33
|
+
* }
|
|
34
|
+
* }
|
|
35
|
+
* ]
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @see {@link BaseMessagingAdapter} for the shared adapter base class
|
|
39
|
+
* @see {@link SlackMessagingExtension} for Slack integration
|
|
40
|
+
* @see {@link TeamsMessagingExtension} for Teams integration
|
|
41
|
+
*/
|
|
42
|
+
// Base adapter and types
|
|
43
|
+
export { BaseMessagingAdapter } from './base/BaseMessagingAdapter.js';
|
|
44
|
+
export { splitMarkdownIntoSections, convertToSlackMrkdwn, convertBoldToSlackFormat, convertLinksToSlackFormat, truncateText, splitTextIntoChunks, } from './base/message-formatter.js';
|
|
45
|
+
// Slack adapter
|
|
46
|
+
export { SlackMessagingExtension } from './slack/SlackMessagingExtension.js';
|
|
47
|
+
export { SlackAdapter } from './slack/SlackAdapter.js';
|
|
48
|
+
export { markdownToBlocks } from './slack/slack-formatter.js';
|
|
49
|
+
export { verifySlackSignature } from './slack/slack-routes.js';
|
|
50
|
+
export { handleSlackInteraction, registerActiveForm } from './slack/slack-interactivity.js';
|
|
51
|
+
export { buildRichResponse, buildAgentContextBlock, buildTextBlocks, buildArtifactCard, buildActionButtons, buildMediaBlocks, buildErrorBlocks, buildMetadataFooter, buildDivider, buildResponseForm, buildFormModal, buildNotificationBlocks, getFullResponseText, } from './slack/slack-block-builder.js';
|
|
52
|
+
// Teams adapter
|
|
53
|
+
export { TeamsMessagingExtension } from './teams/TeamsMessagingExtension.js';
|
|
54
|
+
export { TeamsAdapter } from './teams/TeamsAdapter.js';
|
|
55
|
+
export { markdownToAdaptiveCard } from './teams/teams-formatter.js';
|
|
56
|
+
export { buildRichAdaptiveCard, buildAgentHeader as buildTeamsAgentHeader, buildTextBody as buildTeamsTextBody, buildArtifactCard as buildTeamsArtifactCard, buildActionButtons as buildTeamsActionButtons, buildExplorerLink as buildTeamsExplorerLink, buildMetadataFooter as buildTeamsMetadataFooter, buildErrorCard as buildTeamsErrorCard, buildResponseFormElements as buildTeamsResponseFormElements, } from './teams/teams-card-builder.js';
|
|
57
|
+
/**
|
|
58
|
+
* Tree-shaking prevention function.
|
|
59
|
+
*
|
|
60
|
+
* Import and call this function from your application's entry point
|
|
61
|
+
* (or include it in the class manifest) to ensure the `@RegisterClass`
|
|
62
|
+
* decorators on `SlackMessagingExtension` and `TeamsMessagingExtension`
|
|
63
|
+
* fire at module load time.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* import { LoadMessagingAdapters } from '@memberjunction/messaging-adapters';
|
|
68
|
+
* LoadMessagingAdapters();
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export function LoadMessagingAdapters() {
|
|
72
|
+
// This function exists solely to create a static reference that
|
|
73
|
+
// prevents bundlers from tree-shaking the @RegisterClass decorators.
|
|
74
|
+
// The decorators fire as a side effect of importing the module.
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,yBAAyB;AACzB,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAUtE,OAAO,EACH,yBAAyB,EACzB,oBAAoB,EACpB,wBAAwB,EACxB,yBAAyB,EACzB,YAAY,EACZ,mBAAmB,GACtB,MAAM,6BAA6B,CAAC;AAErC,gBAAgB;AAChB,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAC5F,OAAO,EACH,iBAAiB,EACjB,sBAAsB,EACtB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,uBAAuB,EACvB,mBAAmB,GACtB,MAAM,gCAAgC,CAAC;AAGxC,gBAAgB;AAChB,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EACH,qBAAqB,EACrB,gBAAgB,IAAI,qBAAqB,EACzC,aAAa,IAAI,kBAAkB,EACnC,iBAAiB,IAAI,sBAAsB,EAC3C,kBAAkB,IAAI,uBAAuB,EAC7C,iBAAiB,IAAI,sBAAsB,EAC3C,mBAAmB,IAAI,wBAAwB,EAC/C,cAAc,IAAI,mBAAmB,EACrC,yBAAyB,IAAI,8BAA8B,GAC9D,MAAM,+BAA+B,CAAC;AAGvC;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,qBAAqB;IACjC,gEAAgE;IAChE,qEAAqE;IACrE,gEAAgE;AACpE,CAAC"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @memberjunction/messaging-adapters
|
|
3
|
+
* @description Slack-specific messaging adapter implementation.
|
|
4
|
+
*
|
|
5
|
+
* Extends `BaseMessagingAdapter` with Slack API calls for:
|
|
6
|
+
* - Posting and updating messages via the Web API with per-agent identity
|
|
7
|
+
* - Fetching thread history via `conversations.replies`
|
|
8
|
+
* - Rich Block Kit formatting with agent context, artifact cards, and metadata
|
|
9
|
+
* - Multi-word agent name matching via known-name lookup
|
|
10
|
+
* - Looking up user email addresses
|
|
11
|
+
* - Stripping bot @mentions from message text
|
|
12
|
+
*/
|
|
13
|
+
import { ExecuteAgentResult, MJAIAgentEntityExtended } from '@memberjunction/ai-core-plus';
|
|
14
|
+
import { BaseMessagingAdapter } from '../base/BaseMessagingAdapter.js';
|
|
15
|
+
import { IncomingMessage, FormattedResponse, MessagingAdapterSettings, AgentResponseMetadata } from '../base/types.js';
|
|
16
|
+
/**
|
|
17
|
+
* Slack-specific adapter that implements all platform operations
|
|
18
|
+
* using the Slack Web API (`@slack/web-api`).
|
|
19
|
+
*
|
|
20
|
+
* ## Features
|
|
21
|
+
* - Per-agent identity: each agent's name and avatar appear on their messages
|
|
22
|
+
* - Thread-based conversation context via `conversations.replies`
|
|
23
|
+
* - Progressive streaming updates via `chat.postMessage` / `chat.update`
|
|
24
|
+
* - Rich Block Kit formatting with agent headers, artifact cards, and metadata
|
|
25
|
+
* - Multi-word agent name matching (e.g., `@Research Agent`)
|
|
26
|
+
* - User email lookup via `users.info` for MJ user mapping
|
|
27
|
+
* - Bot mention stripping for clean agent input
|
|
28
|
+
*
|
|
29
|
+
* ## Authentication
|
|
30
|
+
* Requires a Bot User OAuth Token (`xoxb-...`) with these scopes:
|
|
31
|
+
* - `chat:write` — Post and update messages
|
|
32
|
+
* - `chat:write.customize` — Post with custom username and icon
|
|
33
|
+
* - `channels:history` / `groups:history` / `im:history` — Read thread history
|
|
34
|
+
* - `users:read` / `users:read.email` — Look up user email addresses
|
|
35
|
+
* - `app_mentions:read` — Receive @mention events
|
|
36
|
+
*/
|
|
37
|
+
export declare class SlackAdapter extends BaseMessagingAdapter {
|
|
38
|
+
/** Slack Web API client. */
|
|
39
|
+
private client;
|
|
40
|
+
/** The bot's own Slack user ID (e.g., `U0123456`). */
|
|
41
|
+
private botUserID;
|
|
42
|
+
/**
|
|
43
|
+
* Message IDs of "Thinking..." indicators, keyed by `channelId:threadTs`.
|
|
44
|
+
* Per-thread keying prevents concurrent messages from overwriting each other's indicator.
|
|
45
|
+
*/
|
|
46
|
+
private thinkingMessageIds;
|
|
47
|
+
/**
|
|
48
|
+
* Slack's maximum message text length. Messages exceeding this cause `msg_too_long`.
|
|
49
|
+
* The `text` field is the plain-text fallback when blocks are present; the rich
|
|
50
|
+
* content is in Block Kit blocks (already limited to 50 blocks with "View Full" button).
|
|
51
|
+
*/
|
|
52
|
+
private static readonly MAX_TEXT_LENGTH;
|
|
53
|
+
protected get PlatformName(): string;
|
|
54
|
+
constructor(settings: MessagingAdapterSettings);
|
|
55
|
+
/**
|
|
56
|
+
* Convert a raw Slack event payload into a normalized `IncomingMessage`.
|
|
57
|
+
*
|
|
58
|
+
* Called by `SlackMessagingExtension` when a webhook event is received.
|
|
59
|
+
* Uses multi-word agent name matching against the loaded agent list.
|
|
60
|
+
*
|
|
61
|
+
* @param event - Raw Slack event object from the Events API.
|
|
62
|
+
* @returns Normalized incoming message.
|
|
63
|
+
*/
|
|
64
|
+
MapSlackEvent(event: Record<string, unknown>): IncomingMessage;
|
|
65
|
+
/**
|
|
66
|
+
* Fetch the bot's own user ID from the Slack API.
|
|
67
|
+
* This is needed to identify bot messages in thread history.
|
|
68
|
+
*/
|
|
69
|
+
protected onInitialize(): Promise<void>;
|
|
70
|
+
protected getBotUserId(): string;
|
|
71
|
+
/**
|
|
72
|
+
* Post a "Thinking..." message as the typing indicator.
|
|
73
|
+
* Shows the agent's identity if available. This message gets replaced
|
|
74
|
+
* in-place by the first streaming update.
|
|
75
|
+
*/
|
|
76
|
+
protected showTypingIndicator(message: IncomingMessage, agent?: MJAIAgentEntityExtended): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Fetch all messages in a Slack thread using `conversations.replies`.
|
|
79
|
+
*/
|
|
80
|
+
protected fetchThreadHistory(channelId: string, threadId: string): Promise<IncomingMessage[]>;
|
|
81
|
+
/**
|
|
82
|
+
* Post a new streaming message or update an existing one.
|
|
83
|
+
* Shows the agent's identity on new messages.
|
|
84
|
+
*/
|
|
85
|
+
protected sendOrUpdateStreamingMessage(originalMessage: IncomingMessage, currentContent: string, existingMessageId: string | null, agent?: MJAIAgentEntityExtended): Promise<string>;
|
|
86
|
+
/**
|
|
87
|
+
* Send the final formatted response. If a "Thinking..." message exists
|
|
88
|
+
* (no streaming occurred), update it in-place instead of posting a new message.
|
|
89
|
+
*/
|
|
90
|
+
protected sendFinalMessage(originalMessage: IncomingMessage, response: FormattedResponse): Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Update the streaming progress message with the final formatted response.
|
|
93
|
+
*/
|
|
94
|
+
protected updateFinalMessage(originalMessage: IncomingMessage, messageId: string, response: FormattedResponse): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Format agent response as rich Slack Block Kit blocks.
|
|
97
|
+
*
|
|
98
|
+
* When a full `ExecuteAgentResult` is available, builds a rich layout with
|
|
99
|
+
* agent header, artifact cards, action buttons, and metadata footer.
|
|
100
|
+
* Falls back to simple markdown→blocks conversion for plain text.
|
|
101
|
+
*/
|
|
102
|
+
protected formatResponse(result: ExecuteAgentResult | null, agent: MJAIAgentEntityExtended, responseText: string, metadata?: AgentResponseMetadata): Promise<FormattedResponse>;
|
|
103
|
+
/**
|
|
104
|
+
* Strip the bot's @mention from the message text.
|
|
105
|
+
* Slack @mentions use the format `<@U0123456>`.
|
|
106
|
+
*/
|
|
107
|
+
protected stripBotMention(text: string): string;
|
|
108
|
+
/**
|
|
109
|
+
* Look up a Slack user's email address via the Web API.
|
|
110
|
+
*
|
|
111
|
+
* Requires the `users:read.email` scope on the bot token.
|
|
112
|
+
*
|
|
113
|
+
* @param platformUserId - Slack user ID (e.g., `U0123456`).
|
|
114
|
+
* @returns Email address, or `null` if not available.
|
|
115
|
+
*/
|
|
116
|
+
protected lookupUserEmail(platformUserId: string): Promise<string | null>;
|
|
117
|
+
/** Build a unique key for per-thread state (thinking indicator). */
|
|
118
|
+
private threadKey;
|
|
119
|
+
/**
|
|
120
|
+
* Truncate text to Slack's message length limit.
|
|
121
|
+
* Appends an ellipsis note if truncated so users know content was cut.
|
|
122
|
+
*/
|
|
123
|
+
private truncateForSlack;
|
|
124
|
+
/**
|
|
125
|
+
* Truncate text for use as the `text` fallback when Block Kit blocks are present.
|
|
126
|
+
* The `text` field is only shown in notifications/accessibility — the blocks contain
|
|
127
|
+
* the rich content. Keeping it short avoids `msg_too_long` when blocks are large.
|
|
128
|
+
*/
|
|
129
|
+
private truncateForSlackFallback;
|
|
130
|
+
/**
|
|
131
|
+
* Build Slack API params for per-agent identity.
|
|
132
|
+
* Uses `username` and `icon_url` which require the `chat:write.customize` scope.
|
|
133
|
+
* Only includes `icon_url` if it's a valid HTTPS URL.
|
|
134
|
+
*/
|
|
135
|
+
private buildIdentityParams;
|
|
136
|
+
/** Build identity params from an agent entity. */
|
|
137
|
+
private buildSlackIdentityParams;
|
|
138
|
+
/** Build identity params from an AgentIdentity object. */
|
|
139
|
+
private buildSlackIdentityParamsFromIdentity;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=SlackAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SlackAdapter.d.ts","sourceRoot":"","sources":["../../src/slack/SlackAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAE3F,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAIvH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,YAAa,SAAQ,oBAAoB;IAClD,4BAA4B;IAC5B,OAAO,CAAC,MAAM,CAAY;IAE1B,sDAAsD;IACtD,OAAO,CAAC,SAAS,CAAc;IAE/B;;;OAGG;IACH,OAAO,CAAC,kBAAkB,CAA6B;IAEvD;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAU;IAEjD,SAAS,KAAK,YAAY,IAAI,MAAM,CAAoB;gBAE5C,QAAQ,EAAE,wBAAwB;IAK9C;;;;;;;;OAQG;IACI,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe;IAiBrE;;;OAGG;cACa,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAK7C,SAAS,CAAC,YAAY,IAAI,MAAM;IAIhC;;;;OAIG;cACa,mBAAmB,CAAC,OAAO,EAAE,eAAe,EAAE,KAAK,CAAC,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAe7G;;OAEG;cACa,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAqBnG;;;OAGG;cACa,4BAA4B,CACxC,eAAe,EAAE,eAAe,EAChC,cAAc,EAAE,MAAM,EACtB,iBAAiB,EAAE,MAAM,GAAG,IAAI,EAChC,KAAK,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC,MAAM,CAAC;IA2BlB;;;OAGG;cACa,gBAAgB,CAAC,eAAe,EAAE,eAAe,EAAE,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsB9G;;OAEG;cACa,kBAAkB,CAC9B,eAAe,EAAE,eAAe,EAChC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,iBAAiB,GAC5B,OAAO,CAAC,IAAI,CAAC;IAShB;;;;;;OAMG;cACa,cAAc,CAC1B,MAAM,EAAE,kBAAkB,GAAG,IAAI,EACjC,KAAK,EAAE,uBAAuB,EAC9B,YAAY,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE,qBAAqB,GACjC,OAAO,CAAC,iBAAiB,CAAC;IAiB7B;;;OAGG;IACH,SAAS,CAAC,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI/C;;;;;;;OAOG;cACa,eAAe,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAY/E,oEAAoE;IACpE,OAAO,CAAC,SAAS;IAIjB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAKxB;;;;OAIG;IACH,OAAO,CAAC,wBAAwB;IAMhC;;;;OAIG;IACH,OAAO,CAAC,mBAAmB;IAS3B,kDAAkD;IAClD,OAAO,CAAC,wBAAwB;IAIhC,0DAA0D;IAC1D,OAAO,CAAC,oCAAoC;CAG/C"}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @memberjunction/messaging-adapters
|
|
3
|
+
* @description Slack-specific messaging adapter implementation.
|
|
4
|
+
*
|
|
5
|
+
* Extends `BaseMessagingAdapter` with Slack API calls for:
|
|
6
|
+
* - Posting and updating messages via the Web API with per-agent identity
|
|
7
|
+
* - Fetching thread history via `conversations.replies`
|
|
8
|
+
* - Rich Block Kit formatting with agent context, artifact cards, and metadata
|
|
9
|
+
* - Multi-word agent name matching via known-name lookup
|
|
10
|
+
* - Looking up user email addresses
|
|
11
|
+
* - Stripping bot @mentions from message text
|
|
12
|
+
*/
|
|
13
|
+
import { WebClient } from '@slack/web-api';
|
|
14
|
+
import { LogStatus } from '@memberjunction/core';
|
|
15
|
+
import { BaseMessagingAdapter } from '../base/BaseMessagingAdapter.js';
|
|
16
|
+
import { buildRichResponse } from './slack-block-builder.js';
|
|
17
|
+
/**
|
|
18
|
+
* Slack-specific adapter that implements all platform operations
|
|
19
|
+
* using the Slack Web API (`@slack/web-api`).
|
|
20
|
+
*
|
|
21
|
+
* ## Features
|
|
22
|
+
* - Per-agent identity: each agent's name and avatar appear on their messages
|
|
23
|
+
* - Thread-based conversation context via `conversations.replies`
|
|
24
|
+
* - Progressive streaming updates via `chat.postMessage` / `chat.update`
|
|
25
|
+
* - Rich Block Kit formatting with agent headers, artifact cards, and metadata
|
|
26
|
+
* - Multi-word agent name matching (e.g., `@Research Agent`)
|
|
27
|
+
* - User email lookup via `users.info` for MJ user mapping
|
|
28
|
+
* - Bot mention stripping for clean agent input
|
|
29
|
+
*
|
|
30
|
+
* ## Authentication
|
|
31
|
+
* Requires a Bot User OAuth Token (`xoxb-...`) with these scopes:
|
|
32
|
+
* - `chat:write` — Post and update messages
|
|
33
|
+
* - `chat:write.customize` — Post with custom username and icon
|
|
34
|
+
* - `channels:history` / `groups:history` / `im:history` — Read thread history
|
|
35
|
+
* - `users:read` / `users:read.email` — Look up user email addresses
|
|
36
|
+
* - `app_mentions:read` — Receive @mention events
|
|
37
|
+
*/
|
|
38
|
+
export class SlackAdapter extends BaseMessagingAdapter {
|
|
39
|
+
/**
|
|
40
|
+
* Slack's maximum message text length. Messages exceeding this cause `msg_too_long`.
|
|
41
|
+
* The `text` field is the plain-text fallback when blocks are present; the rich
|
|
42
|
+
* content is in Block Kit blocks (already limited to 50 blocks with "View Full" button).
|
|
43
|
+
*/
|
|
44
|
+
static { this.MAX_TEXT_LENGTH = 39_000; }
|
|
45
|
+
get PlatformName() { return 'Slack'; }
|
|
46
|
+
constructor(settings) {
|
|
47
|
+
super(settings);
|
|
48
|
+
/** The bot's own Slack user ID (e.g., `U0123456`). */
|
|
49
|
+
this.botUserID = '';
|
|
50
|
+
/**
|
|
51
|
+
* Message IDs of "Thinking..." indicators, keyed by `channelId:threadTs`.
|
|
52
|
+
* Per-thread keying prevents concurrent messages from overwriting each other's indicator.
|
|
53
|
+
*/
|
|
54
|
+
this.thinkingMessageIds = new Map();
|
|
55
|
+
this.client = new WebClient(settings.BotToken);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Convert a raw Slack event payload into a normalized `IncomingMessage`.
|
|
59
|
+
*
|
|
60
|
+
* Called by `SlackMessagingExtension` when a webhook event is received.
|
|
61
|
+
* Uses multi-word agent name matching against the loaded agent list.
|
|
62
|
+
*
|
|
63
|
+
* @param event - Raw Slack event object from the Events API.
|
|
64
|
+
* @returns Normalized incoming message.
|
|
65
|
+
*/
|
|
66
|
+
MapSlackEvent(event) {
|
|
67
|
+
const text = event.text ?? '';
|
|
68
|
+
return {
|
|
69
|
+
MessageID: event.ts,
|
|
70
|
+
Text: text,
|
|
71
|
+
SenderID: event.user ?? event.bot_id ?? '',
|
|
72
|
+
SenderName: event.username ?? '',
|
|
73
|
+
ChannelID: event.channel,
|
|
74
|
+
ThreadID: event.thread_ts ?? null,
|
|
75
|
+
IsDirectMessage: event.channel_type === 'im',
|
|
76
|
+
IsBotMention: event.type === 'app_mention',
|
|
77
|
+
MentionedAgentNames: this.matchAgentMentions(text),
|
|
78
|
+
Timestamp: new Date(parseFloat(event.ts) * 1000),
|
|
79
|
+
RawEvent: event
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Fetch the bot's own user ID from the Slack API.
|
|
84
|
+
* This is needed to identify bot messages in thread history.
|
|
85
|
+
*/
|
|
86
|
+
async onInitialize() {
|
|
87
|
+
const authResult = await this.client.auth.test();
|
|
88
|
+
this.botUserID = authResult.user_id;
|
|
89
|
+
}
|
|
90
|
+
getBotUserId() {
|
|
91
|
+
return this.botUserID;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Post a "Thinking..." message as the typing indicator.
|
|
95
|
+
* Shows the agent's identity if available. This message gets replaced
|
|
96
|
+
* in-place by the first streaming update.
|
|
97
|
+
*/
|
|
98
|
+
async showTypingIndicator(message, agent) {
|
|
99
|
+
const threadTs = message.ThreadID ?? message.MessageID;
|
|
100
|
+
const identityParams = agent ? this.buildSlackIdentityParams(agent) : {};
|
|
101
|
+
const result = await this.client.chat.postMessage({
|
|
102
|
+
channel: message.ChannelID,
|
|
103
|
+
thread_ts: threadTs,
|
|
104
|
+
text: '_Thinking..._',
|
|
105
|
+
...identityParams
|
|
106
|
+
});
|
|
107
|
+
if (result.ts) {
|
|
108
|
+
this.thinkingMessageIds.set(this.threadKey(message), result.ts);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Fetch all messages in a Slack thread using `conversations.replies`.
|
|
113
|
+
*/
|
|
114
|
+
async fetchThreadHistory(channelId, threadId) {
|
|
115
|
+
const result = await this.client.conversations.replies({
|
|
116
|
+
channel: channelId,
|
|
117
|
+
ts: threadId,
|
|
118
|
+
limit: this.settings.MaxThreadMessages ?? 50
|
|
119
|
+
});
|
|
120
|
+
return (result.messages ?? []).map(msg => ({
|
|
121
|
+
MessageID: msg.ts,
|
|
122
|
+
Text: msg.text ?? '',
|
|
123
|
+
SenderID: msg.user ?? msg.bot_id ?? '',
|
|
124
|
+
SenderName: msg.username ?? '',
|
|
125
|
+
ChannelID: channelId,
|
|
126
|
+
ThreadID: threadId,
|
|
127
|
+
IsDirectMessage: false,
|
|
128
|
+
IsBotMention: false,
|
|
129
|
+
Timestamp: new Date(parseFloat(msg.ts) * 1000),
|
|
130
|
+
RawEvent: msg
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Post a new streaming message or update an existing one.
|
|
135
|
+
* Shows the agent's identity on new messages.
|
|
136
|
+
*/
|
|
137
|
+
async sendOrUpdateStreamingMessage(originalMessage, currentContent, existingMessageId, agent) {
|
|
138
|
+
// Reuse the "Thinking..." message for the first streaming update
|
|
139
|
+
const key = this.threadKey(originalMessage);
|
|
140
|
+
const messageToUpdate = existingMessageId ?? this.thinkingMessageIds.get(key) ?? null;
|
|
141
|
+
if (messageToUpdate) {
|
|
142
|
+
this.thinkingMessageIds.delete(key); // Consumed
|
|
143
|
+
await this.client.chat.update({
|
|
144
|
+
channel: originalMessage.ChannelID,
|
|
145
|
+
ts: messageToUpdate,
|
|
146
|
+
text: this.truncateForSlack(currentContent + ' ...')
|
|
147
|
+
});
|
|
148
|
+
return messageToUpdate;
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
const threadTs = originalMessage.ThreadID ?? originalMessage.MessageID;
|
|
152
|
+
const identityParams = agent ? this.buildSlackIdentityParams(agent) : {};
|
|
153
|
+
const result = await this.client.chat.postMessage({
|
|
154
|
+
channel: originalMessage.ChannelID,
|
|
155
|
+
thread_ts: threadTs,
|
|
156
|
+
text: this.truncateForSlack(currentContent + ' ...'),
|
|
157
|
+
...identityParams
|
|
158
|
+
});
|
|
159
|
+
return result.ts;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Send the final formatted response. If a "Thinking..." message exists
|
|
164
|
+
* (no streaming occurred), update it in-place instead of posting a new message.
|
|
165
|
+
*/
|
|
166
|
+
async sendFinalMessage(originalMessage, response) {
|
|
167
|
+
const key = this.threadKey(originalMessage);
|
|
168
|
+
const thinkingId = this.thinkingMessageIds.get(key);
|
|
169
|
+
if (thinkingId) {
|
|
170
|
+
this.thinkingMessageIds.delete(key);
|
|
171
|
+
await this.updateFinalMessage(originalMessage, thinkingId, response);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const threadTs = originalMessage.ThreadID ?? originalMessage.MessageID;
|
|
175
|
+
const identityParams = response.AgentIdentity
|
|
176
|
+
? this.buildSlackIdentityParamsFromIdentity(response.AgentIdentity)
|
|
177
|
+
: {};
|
|
178
|
+
await this.client.chat.postMessage({
|
|
179
|
+
channel: originalMessage.ChannelID,
|
|
180
|
+
thread_ts: threadTs,
|
|
181
|
+
text: this.truncateForSlackFallback(response.PlainText),
|
|
182
|
+
blocks: response.RichPayload.blocks,
|
|
183
|
+
...identityParams
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Update the streaming progress message with the final formatted response.
|
|
188
|
+
*/
|
|
189
|
+
async updateFinalMessage(originalMessage, messageId, response) {
|
|
190
|
+
await this.client.chat.update({
|
|
191
|
+
channel: originalMessage.ChannelID,
|
|
192
|
+
ts: messageId,
|
|
193
|
+
text: this.truncateForSlackFallback(response.PlainText),
|
|
194
|
+
blocks: response.RichPayload.blocks
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Format agent response as rich Slack Block Kit blocks.
|
|
199
|
+
*
|
|
200
|
+
* When a full `ExecuteAgentResult` is available, builds a rich layout with
|
|
201
|
+
* agent header, artifact cards, action buttons, and metadata footer.
|
|
202
|
+
* Falls back to simple markdown→blocks conversion for plain text.
|
|
203
|
+
*/
|
|
204
|
+
async formatResponse(result, agent, responseText, metadata) {
|
|
205
|
+
const identity = this.buildAgentIdentity(agent);
|
|
206
|
+
// Build rich Block Kit layout
|
|
207
|
+
const blocks = buildRichResponse(result, agent, responseText, {
|
|
208
|
+
explorerBaseURL: this.settings.ExplorerBaseURL,
|
|
209
|
+
artifactId: metadata?.ArtifactId,
|
|
210
|
+
conversationId: metadata?.ConversationId,
|
|
211
|
+
});
|
|
212
|
+
return {
|
|
213
|
+
PlainText: responseText,
|
|
214
|
+
RichPayload: { blocks },
|
|
215
|
+
AgentIdentity: identity
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Strip the bot's @mention from the message text.
|
|
220
|
+
* Slack @mentions use the format `<@U0123456>`.
|
|
221
|
+
*/
|
|
222
|
+
stripBotMention(text) {
|
|
223
|
+
return text.replace(new RegExp(`<@${this.botUserID}>`, 'g'), '').trim();
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Look up a Slack user's email address via the Web API.
|
|
227
|
+
*
|
|
228
|
+
* Requires the `users:read.email` scope on the bot token.
|
|
229
|
+
*
|
|
230
|
+
* @param platformUserId - Slack user ID (e.g., `U0123456`).
|
|
231
|
+
* @returns Email address, or `null` if not available.
|
|
232
|
+
*/
|
|
233
|
+
async lookupUserEmail(platformUserId) {
|
|
234
|
+
try {
|
|
235
|
+
const result = await this.client.users.info({ user: platformUserId });
|
|
236
|
+
return result.user?.profile?.email ?? null;
|
|
237
|
+
}
|
|
238
|
+
catch (error) {
|
|
239
|
+
LogStatus(`Slack user email lookup failed for '${platformUserId}' (falling back to service account)`);
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
// ─── Private helpers ─────────────────────────────────────────────
|
|
244
|
+
/** Build a unique key for per-thread state (thinking indicator). */
|
|
245
|
+
threadKey(message) {
|
|
246
|
+
return `${message.ChannelID}:${message.ThreadID ?? message.MessageID}`;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Truncate text to Slack's message length limit.
|
|
250
|
+
* Appends an ellipsis note if truncated so users know content was cut.
|
|
251
|
+
*/
|
|
252
|
+
truncateForSlack(text) {
|
|
253
|
+
if (text.length <= SlackAdapter.MAX_TEXT_LENGTH)
|
|
254
|
+
return text;
|
|
255
|
+
return text.slice(0, SlackAdapter.MAX_TEXT_LENGTH - 50) + '\n\n... (message truncated due to length)';
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Truncate text for use as the `text` fallback when Block Kit blocks are present.
|
|
259
|
+
* The `text` field is only shown in notifications/accessibility — the blocks contain
|
|
260
|
+
* the rich content. Keeping it short avoids `msg_too_long` when blocks are large.
|
|
261
|
+
*/
|
|
262
|
+
truncateForSlackFallback(text) {
|
|
263
|
+
const MAX_FALLBACK = 4000;
|
|
264
|
+
if (text.length <= MAX_FALLBACK)
|
|
265
|
+
return text;
|
|
266
|
+
return text.slice(0, MAX_FALLBACK - 30) + '\n\n(See full response above)';
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Build Slack API params for per-agent identity.
|
|
270
|
+
* Uses `username` and `icon_url` which require the `chat:write.customize` scope.
|
|
271
|
+
* Only includes `icon_url` if it's a valid HTTPS URL.
|
|
272
|
+
*/
|
|
273
|
+
buildIdentityParams(name, iconUrl) {
|
|
274
|
+
const params = {};
|
|
275
|
+
if (name)
|
|
276
|
+
params.username = name;
|
|
277
|
+
if (iconUrl && typeof iconUrl === 'string' && iconUrl.startsWith('https://')) {
|
|
278
|
+
params.icon_url = iconUrl;
|
|
279
|
+
}
|
|
280
|
+
return params;
|
|
281
|
+
}
|
|
282
|
+
/** Build identity params from an agent entity. */
|
|
283
|
+
buildSlackIdentityParams(agent) {
|
|
284
|
+
return this.buildIdentityParams(agent.Name, agent.LogoURL);
|
|
285
|
+
}
|
|
286
|
+
/** Build identity params from an AgentIdentity object. */
|
|
287
|
+
buildSlackIdentityParamsFromIdentity(identity) {
|
|
288
|
+
return this.buildIdentityParams(identity.Name, identity.IconURL);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
//# sourceMappingURL=SlackAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SlackAdapter.js","sourceRoot":"","sources":["../../src/slack/SlackAdapter.ts"],"names":[],"mappings":"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"}
|