@zhin.js/adapter-slack 4.1.0 → 4.1.1

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.
Files changed (118) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +58 -250
  3. package/adapters/slack.ts +34 -0
  4. package/agent/tools/add_reaction.ts +2 -2
  5. package/agent/tools/archive_channel.ts +2 -2
  6. package/agent/tools/edit_message.ts +5 -4
  7. package/agent/tools/invite_to_channel.ts +2 -2
  8. package/agent/tools/pin_message.ts +2 -2
  9. package/agent/tools/remove_reaction.ts +2 -2
  10. package/agent/tools/set_purpose.ts +2 -2
  11. package/agent/tools/set_topic.ts +2 -2
  12. package/agent/tools/unarchive.ts +2 -2
  13. package/agent/tools/unpin_message.ts +2 -2
  14. package/agent/tools/user_info.ts +2 -2
  15. package/lib/endpoint.d.ts +147 -0
  16. package/lib/endpoint.js +335 -0
  17. package/lib/index.d.ts +11 -0
  18. package/lib/index.js +11 -0
  19. package/lib/markdown-to-mrkdwn.d.ts +9 -0
  20. package/lib/markdown-to-mrkdwn.js +121 -0
  21. package/lib/mrkdwn-to-markdown.d.ts +4 -0
  22. package/lib/{src/mrkdwn-to-markdown.js → mrkdwn-to-markdown.js} +0 -1
  23. package/lib/platform-permit.d.ts +16 -0
  24. package/lib/{src/platform-permit.js → platform-permit.js} +1 -2
  25. package/lib/protocol.d.ts +143 -0
  26. package/lib/protocol.js +225 -0
  27. package/lib/slack-agent-deps.d.ts +28 -0
  28. package/lib/slack-agent-deps.js +30 -0
  29. package/lib/slack-inbound-filter.d.ts +12 -0
  30. package/lib/{src/slack-inbound-filter.js → slack-inbound-filter.js} +0 -1
  31. package/lib/slack-message-ref.d.ts +7 -0
  32. package/lib/{src/slack-message-ref.js → slack-message-ref.js} +0 -1
  33. package/lib/slack-outbound.d.ts +24 -0
  34. package/lib/slack-outbound.js +109 -0
  35. package/lib/slack-reaction.d.ts +1 -0
  36. package/lib/{src/slack-reaction.js → slack-reaction.js} +0 -1
  37. package/lib/slack-response-url.d.ts +5 -0
  38. package/lib/{src/slack-response-url.js → slack-response-url.js} +0 -1
  39. package/lib/webhook.d.ts +14 -0
  40. package/lib/webhook.js +69 -0
  41. package/package.json +41 -20
  42. package/plugin.ts +13 -0
  43. package/schema.json +38 -0
  44. package/src/endpoint.ts +317 -227
  45. package/src/index.ts +62 -66
  46. package/src/markdown-to-mrkdwn.ts +63 -4
  47. package/src/platform-permit.ts +1 -1
  48. package/src/protocol.ts +380 -0
  49. package/src/slack-agent-deps.ts +46 -11
  50. package/src/slack-inbound-filter.ts +1 -1
  51. package/src/slack-outbound.ts +32 -134
  52. package/src/webhook.ts +103 -0
  53. package/lib/agent/tools/add_reaction.js +0 -21
  54. package/lib/agent/tools/add_reaction.js.map +0 -1
  55. package/lib/agent/tools/archive_channel.js +0 -21
  56. package/lib/agent/tools/archive_channel.js.map +0 -1
  57. package/lib/agent/tools/edit_message.js +0 -22
  58. package/lib/agent/tools/edit_message.js.map +0 -1
  59. package/lib/agent/tools/invite_to_channel.js +0 -22
  60. package/lib/agent/tools/invite_to_channel.js.map +0 -1
  61. package/lib/agent/tools/pin_message.js +0 -22
  62. package/lib/agent/tools/pin_message.js.map +0 -1
  63. package/lib/agent/tools/remove_reaction.js +0 -21
  64. package/lib/agent/tools/remove_reaction.js.map +0 -1
  65. package/lib/agent/tools/set_purpose.js +0 -22
  66. package/lib/agent/tools/set_purpose.js.map +0 -1
  67. package/lib/agent/tools/set_topic.js +0 -22
  68. package/lib/agent/tools/set_topic.js.map +0 -1
  69. package/lib/agent/tools/unarchive.js +0 -21
  70. package/lib/agent/tools/unarchive.js.map +0 -1
  71. package/lib/agent/tools/unpin_message.js +0 -22
  72. package/lib/agent/tools/unpin_message.js.map +0 -1
  73. package/lib/agent/tools/user_info.js +0 -28
  74. package/lib/agent/tools/user_info.js.map +0 -1
  75. package/lib/src/adapter.js +0 -62
  76. package/lib/src/adapter.js.map +0 -1
  77. package/lib/src/endpoint.js +0 -312
  78. package/lib/src/endpoint.js.map +0 -1
  79. package/lib/src/event-dispatcher.js +0 -233
  80. package/lib/src/event-dispatcher.js.map +0 -1
  81. package/lib/src/index.js +0 -51
  82. package/lib/src/index.js.map +0 -1
  83. package/lib/src/markdown-to-mrkdwn.js +0 -61
  84. package/lib/src/markdown-to-mrkdwn.js.map +0 -1
  85. package/lib/src/mrkdwn-to-markdown.js.map +0 -1
  86. package/lib/src/platform-permit.js.map +0 -1
  87. package/lib/src/segment-mapper.js +0 -2
  88. package/lib/src/segment-mapper.js.map +0 -1
  89. package/lib/src/signing.js +0 -21
  90. package/lib/src/signing.js.map +0 -1
  91. package/lib/src/slack-agent-deps.js +0 -10
  92. package/lib/src/slack-agent-deps.js.map +0 -1
  93. package/lib/src/slack-inbound-filter.js.map +0 -1
  94. package/lib/src/slack-inbound.js +0 -127
  95. package/lib/src/slack-inbound.js.map +0 -1
  96. package/lib/src/slack-message-ref.js.map +0 -1
  97. package/lib/src/slack-outbound.js +0 -223
  98. package/lib/src/slack-outbound.js.map +0 -1
  99. package/lib/src/slack-reaction.js.map +0 -1
  100. package/lib/src/slack-response-url.js.map +0 -1
  101. package/lib/src/slack-side-events.js +0 -64
  102. package/lib/src/slack-side-events.js.map +0 -1
  103. package/lib/src/transport-http.js +0 -83
  104. package/lib/src/transport-http.js.map +0 -1
  105. package/lib/src/transport-socket.js +0 -68
  106. package/lib/src/transport-socket.js.map +0 -1
  107. package/lib/src/types.js +0 -5
  108. package/lib/src/types.js.map +0 -1
  109. package/plugin.yml +0 -3
  110. package/src/adapter.ts +0 -75
  111. package/src/event-dispatcher.ts +0 -255
  112. package/src/segment-mapper.ts +0 -1
  113. package/src/signing.ts +0 -28
  114. package/src/slack-inbound.ts +0 -140
  115. package/src/slack-side-events.ts +0 -74
  116. package/src/transport-http.ts +0 -95
  117. package/src/transport-socket.ts +0 -77
  118. package/src/types.ts +0 -113
@@ -1,140 +0,0 @@
1
- /**
2
- * Slack 入站消息解析 — 将 Slack mrkdwn 文本 + attachments + files 转为 wire segments
3
- */
4
- import type { MessageSegment } from 'zhin.js';
5
- import type { SlackMessageEvent, SlackEvent } from './types.js';
6
- import { mrkdwnToMarkdown } from './mrkdwn-to-markdown.js';
7
-
8
- export function parseSlackMessageToSegments(msg: SlackMessageEvent): MessageSegment[] {
9
- const segments: MessageSegment[] = [];
10
-
11
- if (msg.text) {
12
- segments.push(...parseSlackMrkdwn(msg.text));
13
- }
14
-
15
- if ('files' in msg && Array.isArray(msg.files)) {
16
- for (const file of msg.files as Record<string, unknown>[]) {
17
- segments.push(parseSlackFile(file));
18
- }
19
- }
20
-
21
- if ('attachments' in msg && Array.isArray(msg.attachments)) {
22
- for (const att of msg.attachments as Record<string, unknown>[]) {
23
- if (att.image_url) {
24
- segments.push({
25
- type: 'image',
26
- data: {
27
- url: att.image_url,
28
- title: att.title,
29
- text: att.text,
30
- },
31
- });
32
- }
33
- }
34
- }
35
-
36
- return segments.length > 0 ? segments : [{ type: 'text', data: { text: '' } }];
37
- }
38
-
39
- function parseSlackFile(file: Record<string, unknown>): MessageSegment {
40
- const mime = String(file.mimetype ?? '');
41
- let type: string;
42
- if (mime.startsWith('image/')) type = 'image';
43
- else if (mime.startsWith('video/')) type = 'video';
44
- else if (mime.startsWith('audio/')) type = 'audio';
45
- else type = 'file';
46
-
47
- return {
48
- type,
49
- data: {
50
- id: file.id,
51
- name: file.name,
52
- url: file.url_private ?? file.permalink,
53
- size: file.size,
54
- mimetype: file.mimetype,
55
- },
56
- };
57
- }
58
-
59
- export function parseSlackMrkdwn(text: string): MessageSegment[] {
60
- const segments: MessageSegment[] = [];
61
- let lastIndex = 0;
62
-
63
- for (const token of scanSlackTokens(text)) {
64
- const start = token.start;
65
- if (start > lastIndex) {
66
- const before = text.slice(lastIndex, start);
67
- if (before.trim()) {
68
- segments.push({ type: 'text', data: { text: mrkdwnToMarkdown(before) } });
69
- }
70
- }
71
-
72
- switch (token.kind) {
73
- case 'user':
74
- segments.push({ type: 'at', data: { id: token.id, name: token.label || token.id, text: token.raw } });
75
- break;
76
- case 'channel':
77
- segments.push({ type: 'channel_mention', data: { id: token.id, name: token.label || token.id, text: token.raw } });
78
- break;
79
- case 'link':
80
- segments.push({ type: 'link', data: { url: token.url, text: token.label || token.url } });
81
- break;
82
- }
83
- lastIndex = start + token.raw.length;
84
- }
85
-
86
- if (lastIndex < text.length) {
87
- const rest = text.slice(lastIndex);
88
- if (rest.trim()) {
89
- segments.push({ type: 'text', data: { text: mrkdwnToMarkdown(rest) } });
90
- }
91
- }
92
-
93
- return segments.length > 0 ? segments : [{ type: 'text', data: { text: mrkdwnToMarkdown(text) } }];
94
- }
95
-
96
- type SlackToken =
97
- | { kind: 'user' | 'channel'; start: number; raw: string; id: string; label?: string }
98
- | { kind: 'link'; start: number; raw: string; url: string; label?: string };
99
-
100
- function scanSlackTokens(text: string): SlackToken[] {
101
- const tokens: SlackToken[] = [];
102
- let cursor = 0;
103
- while (cursor < text.length) {
104
- const start = text.indexOf('<', cursor);
105
- if (start < 0) break;
106
- const end = text.indexOf('>', start + 1);
107
- if (end < 0) break;
108
- const raw = text.slice(start, end + 1);
109
- const body = raw.slice(1, -1);
110
- const sep = body.indexOf('|');
111
- const head = sep >= 0 ? body.slice(0, sep) : body;
112
- const label = sep >= 0 ? body.slice(sep + 1) : undefined;
113
-
114
- if ((head.startsWith('@U') || head.startsWith('@W')) && isSlackId(head.slice(1))) {
115
- tokens.push({ kind: 'user', start, raw, id: head.slice(1), label });
116
- } else if (head.startsWith('#C') && isSlackId(head.slice(1))) {
117
- tokens.push({ kind: 'channel', start, raw, id: head.slice(1), label });
118
- } else if (head.startsWith('http://') || head.startsWith('https://')) {
119
- tokens.push({ kind: 'link', start, raw, url: head, label });
120
- }
121
- cursor = end + 1;
122
- }
123
- return tokens;
124
- }
125
-
126
- function isSlackId(value: string): boolean {
127
- if (!value) return false;
128
- for (const ch of value) {
129
- const code = ch.charCodeAt(0);
130
- const isDigit = code >= 48 && code <= 57;
131
- const isUpper = code >= 65 && code <= 90;
132
- if (!isDigit && !isUpper) return false;
133
- }
134
- return true;
135
- }
136
-
137
- export function resolveSlackChannelType(event: SlackEvent): 'private' | 'group' {
138
- if (event.channel_type === 'im') return 'private';
139
- return 'group';
140
- }
@@ -1,74 +0,0 @@
1
- /**
2
- * Slack 事件 → zhin Notice 映射
3
- */
4
- import { mapNoticeParts, buildNotice, senderFromId } from 'zhin.js';
5
- import type { SlackEvent } from './types.js';
6
-
7
- export function isSlackNoticeEvent(eventType: string): boolean {
8
- return SLACK_NOTICE_EVENT_TYPES.has(eventType);
9
- }
10
-
11
- const SLACK_NOTICE_EVENT_TYPES = new Set([
12
- 'member_joined_channel',
13
- 'member_left_channel',
14
- 'reaction_added',
15
- 'reaction_removed',
16
- 'message_deleted',
17
- 'channel_archive',
18
- 'channel_unarchive',
19
- 'channel_rename',
20
- 'channel_created',
21
- 'channel_deleted',
22
- 'pin_added',
23
- 'pin_removed',
24
- 'app_home_opened',
25
- 'team_join',
26
- ]);
27
-
28
- export function formatSlackNotice(
29
- event: SlackEvent,
30
- endpointName: string,
31
- ) {
32
- const eventType = event.type;
33
- const { scene_type, sub_type } = mapNoticeParts('slack', eventType);
34
-
35
- const channelId = resolveNoticeChannelId(event);
36
- const ts = event.event_ts
37
- ? parseFloat(event.event_ts) * 1000
38
- : Date.now();
39
-
40
- const actorId = event.user ?? (event as any).inviter;
41
- const targetId =
42
- (event as any).item_user ??
43
- (event as any).user ??
44
- undefined;
45
-
46
- return buildNotice(event, {
47
- $id: resolveSlackSideEventDedupeKey(event),
48
- $adapter: 'slack',
49
- $endpoint: endpointName,
50
- $type: 'notice',
51
- $scene_id: channelId,
52
- $scene_type: scene_type,
53
- $sub_type: sub_type,
54
- $actor: senderFromId(actorId),
55
- $target: actorId !== targetId ? senderFromId(targetId) : undefined,
56
- $timestamp: ts,
57
- });
58
- }
59
-
60
- export function resolveSlackSideEventDedupeKey(event: SlackEvent): string {
61
- const ts = event.event_ts ?? event.ts ?? '';
62
- const type = event.type;
63
- const channel = event.channel ?? '';
64
- const user = event.user ?? '';
65
- return `slack:${ts}_${type}_${channel}_${user}`;
66
- }
67
-
68
- function resolveNoticeChannelId(event: SlackEvent): string {
69
- if (event.channel) return String(event.channel);
70
- const item = (event as any).item;
71
- if (item?.channel) return String(item.channel);
72
- const channel = (event as any).channel_id ?? (event as any).channel?.id;
73
- return channel ? String(channel) : '';
74
- }
@@ -1,95 +0,0 @@
1
- /**
2
- * HTTP 传输 — 在 zhin Router 上注册 /slack/events webhook
3
- */
4
- import { verifySlackSignature } from './signing.js';
5
- import type { SlackEventDispatcher } from './event-dispatcher.js';
6
- import type { SlackEndpointConfig, SlackEventEnvelope, SlackInteractionPayload, SlackSlashCommand, SlackUrlVerification } from './types.js';
7
- import type { Logger } from '@zhin.js/logger';
8
-
9
- export type RouterLike = {
10
- post: (path: string, ...args: any[]) => void;
11
- };
12
-
13
- export class SlackHttpTransport {
14
- constructor(
15
- private config: SlackEndpointConfig,
16
- private dispatcher: SlackEventDispatcher,
17
- private logger: Logger,
18
- ) {}
19
-
20
- registerRoutes(router: RouterLike): void {
21
- const signingSecret = this.config.signingSecret;
22
-
23
- router.post('/slack/events', async (ctx: any) => {
24
- const rawBody = await this.getRawBody(ctx);
25
- const timestamp = ctx.get?.('X-Slack-Request-Timestamp') ?? ctx.headers?.['x-slack-request-timestamp'] ?? '';
26
- const signature = ctx.get?.('X-Slack-Signature') ?? ctx.headers?.['x-slack-signature'] ?? '';
27
-
28
- if (!verifySlackSignature(signingSecret, rawBody, timestamp, signature)) {
29
- ctx.status = 401;
30
- ctx.body = 'Invalid signature';
31
- return;
32
- }
33
-
34
- const contentType: string = ctx.get?.('content-type') ?? ctx.headers?.['content-type'] ?? '';
35
- let body: unknown;
36
-
37
- if (contentType.includes('application/x-www-form-urlencoded')) {
38
- const params = new URLSearchParams(rawBody);
39
- const payloadStr = params.get('payload');
40
- if (payloadStr) {
41
- body = JSON.parse(payloadStr);
42
- ctx.status = 200;
43
- ctx.body = '';
44
- this.handleInteraction(body as SlackInteractionPayload);
45
- return;
46
- }
47
- body = Object.fromEntries(params);
48
- if ((body as any).command) {
49
- ctx.status = 200;
50
- ctx.body = '';
51
- this.dispatcher.routeSlashCommand(body as SlackSlashCommand);
52
- return;
53
- }
54
- } else {
55
- body = JSON.parse(rawBody);
56
- }
57
-
58
- const envelope = body as any;
59
-
60
- if (envelope.type === 'url_verification') {
61
- ctx.status = 200;
62
- ctx.body = { challenge: (envelope as SlackUrlVerification).challenge };
63
- return;
64
- }
65
-
66
- if (envelope.type === 'event_callback' && envelope.event) {
67
- ctx.status = 200;
68
- ctx.body = '';
69
- this.dispatcher.routeEvent((envelope as SlackEventEnvelope).event);
70
- return;
71
- }
72
-
73
- ctx.status = 200;
74
- ctx.body = '';
75
- });
76
- }
77
-
78
- private async getRawBody(ctx: any): Promise<string> {
79
- if (ctx.request?.rawBody) return ctx.request.rawBody;
80
- if (typeof ctx.request?.body === 'string') return ctx.request.body;
81
- if (ctx.req) {
82
- return new Promise<string>((resolve, reject) => {
83
- let data = '';
84
- ctx.req.on('data', (chunk: Buffer) => { data += chunk.toString(); });
85
- ctx.req.on('end', () => resolve(data));
86
- ctx.req.on('error', reject);
87
- });
88
- }
89
- return JSON.stringify(ctx.request?.body ?? {});
90
- }
91
-
92
- private handleInteraction(payload: SlackInteractionPayload): void {
93
- this.dispatcher.routeInteraction(payload);
94
- }
95
- }
@@ -1,77 +0,0 @@
1
- /**
2
- * Socket Mode 传输 — 包装 @slack/socket-mode SocketModeClient
3
- */
4
- import { SocketModeClient } from '@slack/socket-mode';
5
- import type { SlackEventDispatcher } from './event-dispatcher.js';
6
- import type { SlackEndpointConfig, SlackEventEnvelope, SlackInteractionPayload, SlackSlashCommand } from './types.js';
7
- import type { Logger } from '@zhin.js/logger';
8
-
9
- export class SlackSocketTransport {
10
- private socketClient: SocketModeClient;
11
- private connected = false;
12
-
13
- constructor(
14
- private config: SlackEndpointConfig,
15
- private dispatcher: SlackEventDispatcher,
16
- private logger: Logger,
17
- ) {
18
- if (!config.appToken) {
19
- throw new Error('Socket Mode requires appToken (xapp-...)');
20
- }
21
- this.socketClient = new SocketModeClient({
22
- appToken: config.appToken,
23
- clientPingTimeout: config.clientPingTimeout ?? 15_000,
24
- });
25
- }
26
-
27
- async connect(): Promise<void> {
28
- this.socketClient.on('slack_event', async ({ ack, body }) => {
29
- await ack();
30
- this.handleEnvelope(body);
31
- });
32
-
33
- this.socketClient.on('interactive', async ({ ack, body }) => {
34
- await ack();
35
- this.handleInteraction(body);
36
- });
37
-
38
- this.socketClient.on('slash_commands', async ({ ack, body }) => {
39
- await ack();
40
- this.handleSlashCommand(body);
41
- });
42
-
43
- await this.socketClient.start();
44
- this.connected = true;
45
- }
46
-
47
- async disconnect(): Promise<void> {
48
- if (!this.connected) return;
49
- try {
50
- await this.socketClient.disconnect();
51
- } catch { /* ignore */ }
52
- this.connected = false;
53
- }
54
-
55
- get isConnected(): boolean { return this.connected; }
56
-
57
- private handleEnvelope(body: unknown): void {
58
- const envelope = body as SlackEventEnvelope;
59
- if (envelope?.type === 'event_callback' && envelope.event) {
60
- this.dispatcher.routeEvent(envelope.event);
61
- }
62
- }
63
-
64
- private handleInteraction(body: unknown): void {
65
- const payload = body as SlackInteractionPayload;
66
- if (payload?.type) {
67
- this.dispatcher.routeInteraction(payload);
68
- }
69
- }
70
-
71
- private handleSlashCommand(body: unknown): void {
72
- const cmd = body as SlackSlashCommand;
73
- if (cmd?.command) {
74
- this.dispatcher.routeSlashCommand(cmd);
75
- }
76
- }
77
- }
package/src/types.ts DELETED
@@ -1,113 +0,0 @@
1
- /**
2
- * Slack 适配器类型定义
3
- */
4
-
5
- export interface SlackEndpointConfig {
6
- context: "slack";
7
- token: string;
8
- name: string;
9
- signingSecret: string;
10
- appToken?: string;
11
- socketMode?: boolean;
12
- /** Socket Mode 客户端 ping 超时(ms),默认 15000 */
13
- clientPingTimeout?: number;
14
- port?: number;
15
- }
16
-
17
- /** Slack Events API event_callback 外层包装 */
18
- export interface SlackEventEnvelope {
19
- token?: string;
20
- team_id?: string;
21
- api_app_id?: string;
22
- event: SlackEvent;
23
- type: "event_callback";
24
- event_id?: string;
25
- event_time?: number;
26
- authorizations?: unknown[];
27
- }
28
-
29
- /** Slack URL verification challenge */
30
- export interface SlackUrlVerification {
31
- type: "url_verification";
32
- token: string;
33
- challenge: string;
34
- }
35
-
36
- /** Slack interactive payload (block_actions, etc.) */
37
- export interface SlackInteractionPayload {
38
- type: "block_actions" | "message_action" | "shortcut" | "view_submission" | "view_closed";
39
- trigger_id?: string;
40
- user: { id: string; username?: string; name?: string; team_id?: string };
41
- channel?: { id: string; name?: string };
42
- message?: { ts: string; text?: string; [key: string]: unknown };
43
- actions?: SlackBlockAction[];
44
- response_url?: string;
45
- [key: string]: unknown;
46
- }
47
-
48
- export interface SlackBlockAction {
49
- type: string;
50
- action_id: string;
51
- block_id: string;
52
- value?: string;
53
- text?: { type: string; text: string };
54
- action_ts?: string;
55
- [key: string]: unknown;
56
- }
57
-
58
- /** Slack slash command payload */
59
- export interface SlackSlashCommand {
60
- token: string;
61
- team_id: string;
62
- channel_id: string;
63
- channel_name: string;
64
- user_id: string;
65
- user_name: string;
66
- command: string;
67
- text: string;
68
- response_url: string;
69
- trigger_id: string;
70
- api_app_id?: string;
71
- }
72
-
73
- /** Union of known Slack event shapes */
74
- export interface SlackEvent {
75
- type: string;
76
- ts?: string;
77
- event_ts?: string;
78
- user?: string;
79
- channel?: string;
80
- channel_type?: string;
81
- text?: string;
82
- thread_ts?: string;
83
- subtype?: string;
84
- [key: string]: unknown;
85
- }
86
-
87
- /** Slack message event (narrowed from SlackEvent) */
88
- export type SlackMessageEvent = SlackEvent & {
89
- type: "message" | "app_mention";
90
- ts: string;
91
- channel: string;
92
- };
93
-
94
- /** Assistant thread events */
95
- export interface SlackAssistantThreadStarted extends SlackEvent {
96
- type: "assistant_thread_started";
97
- assistant_thread: {
98
- user_id: string;
99
- context: Record<string, unknown>;
100
- channel_id: string;
101
- thread_ts: string;
102
- };
103
- }
104
-
105
- export interface SlackAssistantThreadContextChanged extends SlackEvent {
106
- type: "assistant_thread_context_changed";
107
- assistant_thread: {
108
- user_id: string;
109
- context: Record<string, unknown>;
110
- channel_id: string;
111
- thread_ts: string;
112
- };
113
- }