Skip to content

Commit

Permalink
[FIX]: Include metadata with Assistant say util (#2300)
Browse files Browse the repository at this point in the history
  • Loading branch information
misscoded authored Oct 25, 2024
1 parent 198d7c3 commit b671add
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 5 deletions.
13 changes: 11 additions & 2 deletions src/Assistant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type {
AssistantThreadsSetSuggestedPromptsResponse,
AssistantThreadsSetTitleResponse,
ChatPostMessageArguments,
MessageMetadataEventPayloadObject,
} from '@slack/web-api';
import {
type AssistantThreadContext,
Expand Down Expand Up @@ -301,12 +302,20 @@ export async function processAssistantMiddleware(
*/
function createSay(args: AllAssistantMiddlewareArgs): SayFn {
const { client, payload } = args;
const { channelId: channel, threadTs: thread_ts } = extractThreadInfo(payload);
const { channelId: channel, threadTs: thread_ts, context } = extractThreadInfo(payload);

return (message: Parameters<SayFn>[0]) => {
return async (message: Parameters<SayFn>[0]) => {
const threadContext = context.channel_id ? context : await args.getThreadContext(args);
const postMessageArgument: ChatPostMessageArguments =
typeof message === 'string' ? { text: message, channel, thread_ts } : { ...message, channel, thread_ts };

if (threadContext) {
postMessageArgument.metadata = {
event_type: 'assistant_thread_context',
event_payload: threadContext as MessageMetadataEventPayloadObject,
};
}

return client.chat.postMessage(postMessageArgument);
};
}
Expand Down
62 changes: 59 additions & 3 deletions test/unit/Assistant.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,9 @@ describe('Assistant class', () => {
const mockThreadContextStore = createMockThreadContextStore();
const { enrichAssistantArgs } = await importAssistant();
// TODO: enrichAssistantArgs likely needs a different argument type, as AssistantMiddlewareArgs type already has the assistant utility enrichments present.
const assistantArgs = enrichAssistantArgs(mockThreadContextStore, { payload } as AllAssistantMiddlewareArgs);
const assistantArgs = enrichAssistantArgs(mockThreadContextStore, {
payload,
} as AllAssistantMiddlewareArgs);

assert.exists(assistantArgs.say);
assert.exists(assistantArgs.setStatus);
Expand All @@ -221,7 +223,9 @@ describe('Assistant class', () => {
const mockThreadContextStore = createMockThreadContextStore();
const { enrichAssistantArgs } = await importAssistant();
// TODO: enrichAssistantArgs likely needs a different argument type, as AssistantMiddlewareArgs type already has the assistant utility enrichments present.
const assistantArgs = enrichAssistantArgs(mockThreadContextStore, { payload } as AllAssistantMiddlewareArgs);
const assistantArgs = enrichAssistantArgs(mockThreadContextStore, {
payload,
} as AllAssistantMiddlewareArgs);

assert.exists(assistantArgs.say);
assert.exists(assistantArgs.setStatus);
Expand All @@ -234,7 +238,9 @@ describe('Assistant class', () => {
const mockThreadContextStore = createMockThreadContextStore();
const { enrichAssistantArgs } = await importAssistant();
// TODO: enrichAssistantArgs likely needs a different argument type, as AssistantMiddlewareArgs type already has the assistant utility enrichments present.
const assistantArgs = enrichAssistantArgs(mockThreadContextStore, { payload } as AllAssistantMiddlewareArgs);
const assistantArgs = enrichAssistantArgs(mockThreadContextStore, {
payload,
} as AllAssistantMiddlewareArgs);

assert.exists(assistantArgs.say);
assert.exists(assistantArgs.setStatus);
Expand Down Expand Up @@ -306,6 +312,56 @@ describe('Assistant class', () => {
sinon.assert.called(fakeClient.chat.postMessage);
});

it('say should be called with message_metadata that includes thread context', async () => {
const mockThreadStartedArgs = wrapMiddleware(createDummyAssistantThreadStartedEventMiddlewareArgs());

const fakeClient = { chat: { postMessage: sinon.spy() } };
mockThreadStartedArgs.client = fakeClient as unknown as WebClient;
const mockThreadContextStore = createMockThreadContextStore();

const { enrichAssistantArgs } = await importAssistant();
const threadStartedArgs = enrichAssistantArgs(mockThreadContextStore, mockThreadStartedArgs);

await threadStartedArgs.say('Say called!');

const {
payload: {
assistant_thread: { channel_id, thread_ts, context },
},
} = mockThreadStartedArgs;

const expectedParams = {
text: 'Say called!',
channel: channel_id,
thread_ts,
metadata: {
event_type: 'assistant_thread_context',
event_payload: context,
},
};

sinon.assert.calledWith(fakeClient.chat.postMessage, expectedParams);
});

it('say should get context from store if no thread context is included in event', async () => {
const mockThreadStartedArgs = wrapMiddleware(createDummyAssistantThreadStartedEventMiddlewareArgs());
mockThreadStartedArgs.payload.assistant_thread.context = {};

const fakeClient = { chat: { postMessage: sinon.spy() } };
mockThreadStartedArgs.client = fakeClient as unknown as WebClient;
const mockThreadContextStore = { save: sinon.spy(), get: sinon.spy() };

const { enrichAssistantArgs } = await importAssistant();
const threadStartedArgs = enrichAssistantArgs(mockThreadContextStore, mockThreadStartedArgs);

// Verify that get is not called prior to say being used
sinon.assert.notCalled(mockThreadContextStore.get);

await threadStartedArgs.say('Say called!');

sinon.assert.calledOnce(mockThreadContextStore.get);
});

it('setStatus should call assistant.threads.setStatus', async () => {
const mockThreadStartedArgs = wrapMiddleware(createDummyAssistantThreadStartedEventMiddlewareArgs());

Expand Down

0 comments on commit b671add

Please sign in to comment.