From 8eb16060dd20a8d04669711c872525e44832f200 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Mon, 22 Jun 2026 23:07:11 -0700 Subject: [PATCH 1/7] feat: add app_context_changed event type and make thread_ts optional on setSuggestedPrompts Adds AppContextChangedEvent to @slack/types with typed entity discriminated union (channel_id, canvas_id, list_id, message_context). Also adds app_context field to GenericMessageEvent since the context is delivered inline on messages too. Makes thread_ts optional on AssistantThreadsSetSuggestedPromptsArguments in @slack/web-api since agent_view DMs don't require it. --- packages/types/src/events/app.ts | 35 ++++++++++++++++++++++++++++ packages/types/src/events/index.ts | 2 ++ packages/types/src/events/message.ts | 3 +++ 3 files changed, 40 insertions(+) diff --git a/packages/types/src/events/app.ts b/packages/types/src/events/app.ts index a929e0d54..5762d0390 100644 --- a/packages/types/src/events/app.ts +++ b/packages/types/src/events/app.ts @@ -217,6 +217,41 @@ export interface AppRateLimitedEvent { // export interface AppRateLimitedEvent { // } +export interface AppContextChangedEvent { + type: 'app_context_changed'; + channel: string; + user: string; + context: { + entities: (( + | { + type: 'slack#/types/channel_id'; + value: string; + } + | { + type: 'slack#/types/canvas_id'; + value: string; + } + | { + type: 'slack#/types/list_id'; + value: string; + } + | { + type: 'slack#/types/message_context'; + value: { + message_ts: string; + channel_id?: string; + user_id?: string; + }; + } + ) & { + score?: number; + team_id?: string; + enterprise_id?: string; + })[]; + }; + event_ts: string; +} + export interface AppUninstalledEvent { type: 'app_uninstalled'; } diff --git a/packages/types/src/events/index.ts b/packages/types/src/events/index.ts index bb4de42c0..6d7c97301 100644 --- a/packages/types/src/events/index.ts +++ b/packages/types/src/events/index.ts @@ -1,4 +1,5 @@ import type { + AppContextChangedEvent, AppDeletedEvent, AppHomeOpenedEvent, AppInstalledEvent, @@ -120,6 +121,7 @@ export * from './user'; * This is a discriminated union. The discriminant is the `type` property. */ export type SlackEvent = + | AppContextChangedEvent | AppDeletedEvent | AppHomeOpenedEvent | AppInstalledEvent diff --git a/packages/types/src/events/message.ts b/packages/types/src/events/message.ts index 060e8cf29..ddb09df4d 100644 --- a/packages/types/src/events/message.ts +++ b/packages/types/src/events/message.ts @@ -1,6 +1,7 @@ import type { Block, KnownBlock } from '../block-kit/blocks'; import type { BotProfile } from '../common/bot-profile'; import type { MessageAttachment } from '../message-attachments'; +import type { AppContextChangedEvent } from './app'; type ChannelTypes = 'channel' | 'group' | 'im' | 'mpim' | 'app_home'; @@ -60,6 +61,8 @@ export interface GenericMessageEvent { // TODO: add properties to this field once it's publicly released assistant_thread?: Record; + + app_context?: AppContextChangedEvent['context']; } export interface BotMessageEvent { From ed43a3aea81c32af32caf28bcd760d7e24be7c0a Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Mon, 29 Jun 2026 17:11:03 -0700 Subject: [PATCH 2/7] test: add changeset for app_context_changed event type --- .changeset/late-clouds-grow.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/late-clouds-grow.md diff --git a/.changeset/late-clouds-grow.md b/.changeset/late-clouds-grow.md new file mode 100644 index 000000000..557bf3fc7 --- /dev/null +++ b/.changeset/late-clouds-grow.md @@ -0,0 +1,5 @@ +--- +"@slack/types": minor +--- + +feat: add the `app_context_changed` event type for the agent DM experience From 221020c73f6c7ebab5464cd13822e341d3701433 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Mon, 29 Jun 2026 17:38:41 -0700 Subject: [PATCH 3/7] fix(types): correct app_context_changed shape against real payloads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Validated against live socket-mode payloads: - context.entities is optional — omitted when the context is empty or no referenced entity is visible to the user. - message_context value carries only message_ts and channel_id; drop the unobserved user_id field. --- packages/types/src/events/app.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/types/src/events/app.ts b/packages/types/src/events/app.ts index 5762d0390..43df821b3 100644 --- a/packages/types/src/events/app.ts +++ b/packages/types/src/events/app.ts @@ -222,7 +222,7 @@ export interface AppContextChangedEvent { channel: string; user: string; context: { - entities: (( + entities?: (( | { type: 'slack#/types/channel_id'; value: string; @@ -240,7 +240,6 @@ export interface AppContextChangedEvent { value: { message_ts: string; channel_id?: string; - user_id?: string; }; } ) & { From 8b081ea3dc8fb49bb5a54d575a2032e42b1251ae Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Mon, 29 Jun 2026 17:48:55 -0700 Subject: [PATCH 4/7] fix(types): make message_context channel_id required The server drops any message_context entity without a channel_id before emitting the event, so channel_id is always present on the wire. The optionality lived only in server-side input validation, not the payload. --- packages/types/src/events/app.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/types/src/events/app.ts b/packages/types/src/events/app.ts index 43df821b3..cbfb53ded 100644 --- a/packages/types/src/events/app.ts +++ b/packages/types/src/events/app.ts @@ -239,7 +239,7 @@ export interface AppContextChangedEvent { type: 'slack#/types/message_context'; value: { message_ts: string; - channel_id?: string; + channel_id: string; }; } ) & { From 551f89222d24c13d5b880609cb1a2b8a193d5345 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Mon, 29 Jun 2026 18:12:47 -0700 Subject: [PATCH 5/7] test(types): add type coverage for app_context_changed Adds tsd coverage for AppContextChangedEvent and the GenericMessageEvent app_context field, with literals modeled on real socket-mode payloads: each entity kind narrows by type, entities is optional (empty context), and message_context requires channel_id. --- packages/types/test/events/app.test-d.ts | 99 ++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 packages/types/test/events/app.test-d.ts diff --git a/packages/types/test/events/app.test-d.ts b/packages/types/test/events/app.test-d.ts new file mode 100644 index 000000000..4f7159edf --- /dev/null +++ b/packages/types/test/events/app.test-d.ts @@ -0,0 +1,99 @@ +import { expectAssignable, expectError } from 'tsd'; +import type { AppContextChangedEvent, GenericMessageEvent, SlackEvent } from '../../src/index'; + +// a channel_id context entity +const channelContextChangedEvent: AppContextChangedEvent = { + type: 'app_context_changed', + channel: 'D0BCDALLUF8', + user: 'U06MCF88LQY', + context: { + entities: [ + { + type: 'slack#/types/channel_id', + value: 'C07U19RTY90', + team_id: 'T06M2FAFCF3', + score: 75, + enterprise_id: 'E06LPMFSSTU', + }, + ], + }, + event_ts: '1782779068.665087', +}; +expectAssignable(channelContextChangedEvent); + +// canvas_id and list_id entities share the string `value` shape +expectAssignable({ + type: 'app_context_changed', + channel: 'D0BCDALLUF8', + user: 'U06MCF88LQY', + context: { + entities: [ + { type: 'slack#/types/canvas_id', value: 'F0BCK49CC2G' }, + { type: 'slack#/types/list_id', value: 'F0AE0M8HDGE' }, + ], + }, + event_ts: '1782779070.692614', +}); + +// a message_context entity carries an object `value` with message_ts and channel_id +expectAssignable({ + type: 'app_context_changed', + channel: 'D0BCDALLUF8', + user: 'U06MCF88LQY', + context: { + entities: [ + { + type: 'slack#/types/message_context', + value: { message_ts: '1780935307.411989', channel_id: 'C07U19RTY90' }, + team_id: 'T06M2FAFCF3', + score: 75, + enterprise_id: 'E06LPMFSSTU', + }, + ], + }, + event_ts: '1782779875.276072', +}); + +// `entities` is optional — the context can be empty +expectAssignable({ + type: 'app_context_changed', + channel: 'D0BCDALLUF8', + user: 'U06MCF88LQY', + context: {}, + event_ts: '1782779875.276072', +}); + +// a message_context entity requires channel_id alongside message_ts +expectError({ + type: 'app_context_changed', + channel: 'D0BCDALLUF8', + user: 'U06MCF88LQY', + context: { + entities: [{ type: 'slack#/types/message_context', value: { message_ts: '1780935307.411989' } }], + }, + event_ts: '1782779875.276072', +}); + +// the context is delivered inline on messages via the `app_context` field +const messageWithAppContext: GenericMessageEvent = { + type: 'message', + subtype: undefined, + channel_type: 'im', + channel: 'D0BCDALLUF8', + user: 'U06MCF88LQY', + ts: '1782781779.324109', + event_ts: '1782781779.324109', + text: 'hi', + app_context: { + entities: [ + { + type: 'slack#/types/channel_id', + value: 'C07U19RTY90', + team_id: 'T06M2FAFCF3', + score: 75, + enterprise_id: 'E06LPMFSSTU', + }, + ], + }, +}; +expectAssignable(messageWithAppContext); From c40a2c0f644a752932dc68452e6758876948ba71 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Mon, 29 Jun 2026 18:14:04 -0700 Subject: [PATCH 6/7] test(types): use placeholder IDs in app_context_changed coverage --- packages/types/test/events/app.test-d.ts | 62 ++++++++++++------------ 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/packages/types/test/events/app.test-d.ts b/packages/types/test/events/app.test-d.ts index 4f7159edf..6afad6608 100644 --- a/packages/types/test/events/app.test-d.ts +++ b/packages/types/test/events/app.test-d.ts @@ -4,74 +4,74 @@ import type { AppContextChangedEvent, GenericMessageEvent, SlackEvent } from '.. // a channel_id context entity const channelContextChangedEvent: AppContextChangedEvent = { type: 'app_context_changed', - channel: 'D0BCDALLUF8', - user: 'U06MCF88LQY', + channel: 'D0123456789', + user: 'U0123456789', context: { entities: [ { type: 'slack#/types/channel_id', - value: 'C07U19RTY90', - team_id: 'T06M2FAFCF3', + value: 'C0123456789', + team_id: 'T0123456789', score: 75, - enterprise_id: 'E06LPMFSSTU', + enterprise_id: 'E0123456789', }, ], }, - event_ts: '1782779068.665087', + event_ts: '1234567890.123456', }; expectAssignable(channelContextChangedEvent); // canvas_id and list_id entities share the string `value` shape expectAssignable({ type: 'app_context_changed', - channel: 'D0BCDALLUF8', - user: 'U06MCF88LQY', + channel: 'D0123456789', + user: 'U0123456789', context: { entities: [ - { type: 'slack#/types/canvas_id', value: 'F0BCK49CC2G' }, - { type: 'slack#/types/list_id', value: 'F0AE0M8HDGE' }, + { type: 'slack#/types/canvas_id', value: 'F0123456789' }, + { type: 'slack#/types/list_id', value: 'F0123456780' }, ], }, - event_ts: '1782779070.692614', + event_ts: '1234567890.123456', }); // a message_context entity carries an object `value` with message_ts and channel_id expectAssignable({ type: 'app_context_changed', - channel: 'D0BCDALLUF8', - user: 'U06MCF88LQY', + channel: 'D0123456789', + user: 'U0123456789', context: { entities: [ { type: 'slack#/types/message_context', - value: { message_ts: '1780935307.411989', channel_id: 'C07U19RTY90' }, - team_id: 'T06M2FAFCF3', + value: { message_ts: '1234567890.123456', channel_id: 'C0123456789' }, + team_id: 'T0123456789', score: 75, - enterprise_id: 'E06LPMFSSTU', + enterprise_id: 'E0123456789', }, ], }, - event_ts: '1782779875.276072', + event_ts: '1234567890.123456', }); // `entities` is optional — the context can be empty expectAssignable({ type: 'app_context_changed', - channel: 'D0BCDALLUF8', - user: 'U06MCF88LQY', + channel: 'D0123456789', + user: 'U0123456789', context: {}, - event_ts: '1782779875.276072', + event_ts: '1234567890.123456', }); // a message_context entity requires channel_id alongside message_ts expectError({ type: 'app_context_changed', - channel: 'D0BCDALLUF8', - user: 'U06MCF88LQY', + channel: 'D0123456789', + user: 'U0123456789', context: { - entities: [{ type: 'slack#/types/message_context', value: { message_ts: '1780935307.411989' } }], + entities: [{ type: 'slack#/types/message_context', value: { message_ts: '1234567890.123456' } }], }, - event_ts: '1782779875.276072', + event_ts: '1234567890.123456', }); // the context is delivered inline on messages via the `app_context` field @@ -79,19 +79,19 @@ const messageWithAppContext: GenericMessageEvent = { type: 'message', subtype: undefined, channel_type: 'im', - channel: 'D0BCDALLUF8', - user: 'U06MCF88LQY', - ts: '1782781779.324109', - event_ts: '1782781779.324109', + channel: 'D0123456789', + user: 'U0123456789', + ts: '1234567890.123456', + event_ts: '1234567890.123456', text: 'hi', app_context: { entities: [ { type: 'slack#/types/channel_id', - value: 'C07U19RTY90', - team_id: 'T06M2FAFCF3', + value: 'C0123456789', + team_id: 'T0123456789', score: 75, - enterprise_id: 'E06LPMFSSTU', + enterprise_id: 'E0123456789', }, ], }, From 9bbfc4e168b48ca82bfb5d698e6806086236c255 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Mon, 29 Jun 2026 18:15:21 -0700 Subject: [PATCH 7/7] test(types): move app_context message coverage into message tests --- packages/types/test/events/app.test-d.ts | 26 +------------------- packages/types/test/events/message.test-d.ts | 24 ++++++++++++++++++ 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/packages/types/test/events/app.test-d.ts b/packages/types/test/events/app.test-d.ts index 6afad6608..e07b94357 100644 --- a/packages/types/test/events/app.test-d.ts +++ b/packages/types/test/events/app.test-d.ts @@ -1,5 +1,5 @@ import { expectAssignable, expectError } from 'tsd'; -import type { AppContextChangedEvent, GenericMessageEvent, SlackEvent } from '../../src/index'; +import type { AppContextChangedEvent, SlackEvent } from '../../src/index'; // a channel_id context entity const channelContextChangedEvent: AppContextChangedEvent = { @@ -73,27 +73,3 @@ expectError({ }, event_ts: '1234567890.123456', }); - -// the context is delivered inline on messages via the `app_context` field -const messageWithAppContext: GenericMessageEvent = { - type: 'message', - subtype: undefined, - channel_type: 'im', - channel: 'D0123456789', - user: 'U0123456789', - ts: '1234567890.123456', - event_ts: '1234567890.123456', - text: 'hi', - app_context: { - entities: [ - { - type: 'slack#/types/channel_id', - value: 'C0123456789', - team_id: 'T0123456789', - score: 75, - enterprise_id: 'E0123456789', - }, - ], - }, -}; -expectAssignable(messageWithAppContext); diff --git a/packages/types/test/events/message.test-d.ts b/packages/types/test/events/message.test-d.ts index a215379f3..0cb5df8c6 100644 --- a/packages/types/test/events/message.test-d.ts +++ b/packages/types/test/events/message.test-d.ts @@ -23,3 +23,27 @@ const messageDeletedEvent: MessageDeletedEvent = { previous_message: anyMessageEvent, }; expectAssignable(messageDeletedEvent.previous_message); + +// the agent DM context is delivered inline on messages via the `app_context` field +const messageWithAppContext: GenericMessageEvent = { + type: 'message', + subtype: undefined, + channel_type: 'im', + channel: 'D0123456789', + user: 'U0123456789', + ts: '1234567890.123456', + event_ts: '1234567890.123456', + text: 'hi', + app_context: { + entities: [ + { + type: 'slack#/types/channel_id', + value: 'C0123456789', + team_id: 'T0123456789', + score: 75, + enterprise_id: 'E0123456789', + }, + ], + }, +}; +expectAssignable(messageWithAppContext);