From 3cf414c3f6cb6a2bd728fb2b9528aa72db2f9df4 Mon Sep 17 00:00:00 2001 From: Kewin Wereszczynski Date: Mon, 16 Dec 2024 15:13:57 +0100 Subject: [PATCH 1/5] chore: add plugin to remove slack new chat message --- .changeset/bright-garlics-lick.md | 6 +++++ examples/slack/src/index.ts | 3 ++- .../{messagaes.test.ts => messages.test.ts} | 0 packages/slack/src/__tests__/plugins.test.ts | 24 +++++++++++++++++++ packages/slack/src/index.ts | 1 + .../slack/src/plugins/thread-normalization.ts | 17 +++++++++++++ 6 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 .changeset/bright-garlics-lick.md rename packages/slack/src/__tests__/{messagaes.test.ts => messages.test.ts} (100%) create mode 100644 packages/slack/src/__tests__/plugins.test.ts create mode 100644 packages/slack/src/plugins/thread-normalization.ts diff --git a/.changeset/bright-garlics-lick.md b/.changeset/bright-garlics-lick.md new file mode 100644 index 0000000..04b86d4 --- /dev/null +++ b/.changeset/bright-garlics-lick.md @@ -0,0 +1,6 @@ +--- +'slack-example': patch +'@callstack/byorg-slack': patch +--- + +Added useful plugins for normalizing threads (Slack started adding "New chat" message). Updated example slack app. diff --git a/examples/slack/src/index.ts b/examples/slack/src/index.ts index d9c8583..9847171 100644 --- a/examples/slack/src/index.ts +++ b/examples/slack/src/index.ts @@ -1,7 +1,7 @@ import { VercelChatModelAdapter, createApp } from '@callstack/byorg-core'; import { createOpenAI } from '@ai-sdk/openai'; import { logger, requireEnv } from '@callstack/byorg-utils'; -import { createSlackApp } from '@callstack/byorg-slack'; +import { createSlackApp, slackThreadNormalizerPlugin } from '@callstack/byorg-slack'; const LANGUAGE_MODEL = 'gpt-4o-2024-11-20'; const API_KEY = requireEnv('OPENAI_API_KEY'); @@ -27,6 +27,7 @@ const SYSTEM_PROMPT = 'Your name is Byorg. You are a helpful AI Assistant.'; const app = createApp({ chatModel, systemPrompt: SYSTEM_PROMPT, + plugins: [slackThreadNormalizerPlugin], }); const slack = createSlackApp({ diff --git a/packages/slack/src/__tests__/messagaes.test.ts b/packages/slack/src/__tests__/messages.test.ts similarity index 100% rename from packages/slack/src/__tests__/messagaes.test.ts rename to packages/slack/src/__tests__/messages.test.ts diff --git a/packages/slack/src/__tests__/plugins.test.ts b/packages/slack/src/__tests__/plugins.test.ts new file mode 100644 index 0000000..028d0b3 --- /dev/null +++ b/packages/slack/src/__tests__/plugins.test.ts @@ -0,0 +1,24 @@ +import { createApp, createMockChatModel, Message } from '@callstack/byorg-core'; +import { describe, expect, it, vitest } from 'vitest'; +import { slackThreadNormalizerPlugin } from '../plugins/thread-normalization.js'; + +describe('threadNormalizer', () => { + it('should remove slack "New chat" initial message', async () => { + const messages: Message[] = [ + { role: 'user', content: 'New chat\n' }, + { role: 'user', content: 'Hello!' }, + ]; + const baseModel = createMockChatModel({ delay: 0, seed: 3 }); + + const modelSpy = vitest.spyOn(baseModel, 'generateResponse'); + + const app = createApp({ + chatModel: baseModel, + plugins: [slackThreadNormalizerPlugin], + }); + + await app.processMessages(messages); + + expect(modelSpy.mock.calls[0][0]['messages']).toEqual([{ role: 'user', content: 'Hello!' }]); + }); +}); diff --git a/packages/slack/src/index.ts b/packages/slack/src/index.ts index 3e31263..947ebf7 100644 --- a/packages/slack/src/index.ts +++ b/packages/slack/src/index.ts @@ -6,3 +6,4 @@ export { slackEntityResolverPlugin, extractUserMentionsFromMessage, } from './plugins/entity-resolver.js'; +export { slackThreadNormalizerPlugin } from './plugins/thread-normalization.js'; diff --git a/packages/slack/src/plugins/thread-normalization.ts b/packages/slack/src/plugins/thread-normalization.ts new file mode 100644 index 0000000..7a04dce --- /dev/null +++ b/packages/slack/src/plugins/thread-normalization.ts @@ -0,0 +1,17 @@ +import { ApplicationPlugin, MessageResponse } from '@callstack/byorg-core'; +import { logger } from '@callstack/byorg-utils'; + +export const slackThreadNormalizerPlugin: ApplicationPlugin = { + name: 'slack-thread-normalizer-resolver', + middleware: async (context, next): Promise => { + const { messages } = context; + + if (messages[0].content === 'New chat\n' && messages[1]?.role === 'user') { + context.messages = messages.slice(1); + logger.debug('Removed Slack "New Chat" message'); + } + + // Continue middleware chain + return await next(); + }, +}; From b98dd6e55e02957f9f8a75dc01e80d8a052e14ba Mon Sep 17 00:00:00 2001 From: Kewin Wereszczynski Date: Mon, 16 Dec 2024 15:15:18 +0100 Subject: [PATCH 2/5] fix: error in plugin name --- packages/slack/src/plugins/thread-normalization.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/slack/src/plugins/thread-normalization.ts b/packages/slack/src/plugins/thread-normalization.ts index 7a04dce..e2416c7 100644 --- a/packages/slack/src/plugins/thread-normalization.ts +++ b/packages/slack/src/plugins/thread-normalization.ts @@ -2,7 +2,7 @@ import { ApplicationPlugin, MessageResponse } from '@callstack/byorg-core'; import { logger } from '@callstack/byorg-utils'; export const slackThreadNormalizerPlugin: ApplicationPlugin = { - name: 'slack-thread-normalizer-resolver', + name: 'slack-thread-normalizer', middleware: async (context, next): Promise => { const { messages } = context; From 129b1b3e1adef322cf6ac33c4ffbea2a4968bec2 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Tue, 17 Dec 2024 09:48:00 +0100 Subject: [PATCH 3/5] Update packages/slack/src/plugins/thread-normalization.ts --- packages/slack/src/plugins/thread-normalization.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/slack/src/plugins/thread-normalization.ts b/packages/slack/src/plugins/thread-normalization.ts index e2416c7..d296598 100644 --- a/packages/slack/src/plugins/thread-normalization.ts +++ b/packages/slack/src/plugins/thread-normalization.ts @@ -1,6 +1,9 @@ import { ApplicationPlugin, MessageResponse } from '@callstack/byorg-core'; import { logger } from '@callstack/byorg-utils'; +/** + * Slack plugin for normalizing messages coming from Slack [AI apps](https://api.slack.com/docs/apps/ai). + */ export const slackThreadNormalizerPlugin: ApplicationPlugin = { name: 'slack-thread-normalizer', middleware: async (context, next): Promise => { From 2cd3faee552a79b63b9adbd1cd2a841dd1637088 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Tue, 17 Dec 2024 09:48:50 +0100 Subject: [PATCH 4/5] Update examples/slack/src/index.ts --- examples/slack/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/slack/src/index.ts b/examples/slack/src/index.ts index 9847171..8a447dc 100644 --- a/examples/slack/src/index.ts +++ b/examples/slack/src/index.ts @@ -27,6 +27,7 @@ const SYSTEM_PROMPT = 'Your name is Byorg. You are a helpful AI Assistant.'; const app = createApp({ chatModel, systemPrompt: SYSTEM_PROMPT, + // Normalize messages coming from Slack AI apps plugins: [slackThreadNormalizerPlugin], }); From 151815e15430fe423e5bd2265c0956d93ece1ba0 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Tue, 17 Dec 2024 09:52:07 +0100 Subject: [PATCH 5/5] lint --- packages/slack/src/plugins/thread-normalization.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/slack/src/plugins/thread-normalization.ts b/packages/slack/src/plugins/thread-normalization.ts index d296598..f0ad7cd 100644 --- a/packages/slack/src/plugins/thread-normalization.ts +++ b/packages/slack/src/plugins/thread-normalization.ts @@ -2,7 +2,7 @@ import { ApplicationPlugin, MessageResponse } from '@callstack/byorg-core'; import { logger } from '@callstack/byorg-utils'; /** - * Slack plugin for normalizing messages coming from Slack [AI apps](https://api.slack.com/docs/apps/ai). + * Slack plugin for normalizing messages coming from Slack [AI apps](https://api.slack.com/docs/apps/ai). */ export const slackThreadNormalizerPlugin: ApplicationPlugin = { name: 'slack-thread-normalizer',