Skip to content

suggestedPrompts resolver receives no teamId on the app_home_opened path, breaking multi-workspace agent-view apps #874

Closed

Description

@hasanyaprak

Package: @chat-adapter/slack@4.38.1

Summary

SlackAdapter invokes applyConfiguredSuggestedPrompts from two places, with
different context. handleAssistantThreadStarted forwards the team id;
handleAppHomeOpened does not.

Under agentView: true, app_home_opened is the only trigger — so a
multi-workspace app can never identify which workspace the viewer belongs to,
and any per-installation lookup in the resolver fails. The suggestedPrompts
option is effectively unusable in that configuration.

Where

handleAssistantThreadStarted — forwards teamId:

const promptsTask = this.applyConfiguredSuggestedPrompts({
  channelId: channel_id,
  enterpriseId: context.enterprise_id,
  teamId: context.team_id,      // <-- present
  threadTs: thread_ts,
  userId: user_id
});

handleAppHomeOpened — does not:

if (this.agentView && event.tab === "messages") {
  const promptsTask = this.applyConfiguredSuggestedPrompts({
    channelId: event.channel,
    userId: event.user,
    ...event.context ? { entities: normalizeAppContextEntities(event.context) } : {}
  });                            // <-- no teamId
  options?.waitUntil?.(promptsTask);
}

SlackSuggestedPromptsContext.teamId is optional, so nothing type-errors. It is
simply always undefined on this path.

Why it bites specifically under agentView

The two are mutually exclusive in practice. An app declaring agent_view in its
manifest cannot subscribe to assistant_thread_started — Slack's manifest
validation rejects the legacy event in that mode — so app_home_opened is the
only DM-open signal available. That is also exactly what the adapter's own
agentView docs describe. The result is that the code path which can resolve
a workspace is unreachable for agent-view apps, and the one that is reachable
cannot.

Reproduction

  1. Configure the adapter for multi-workspace (clientId + clientSecret +
    installationProvider) with agentView: true.
  2. Pass a suggestedPrompts resolver that needs to identify the workspace,
    e.g. one that maps (teamId, userId) to an application user before deciding
    which prompts to show.
  3. Manifest: agent_view, and subscribe app_home_opened + message.im.
  4. Open the app's DM in an installed workspace.

Expected: the resolver receives a context sufficient to identify the viewer.
Actual: context.teamId is undefined, the lookup cannot be performed, and
the resolver returns null — so no prompts are ever set. It fails closed and
silently; nothing is logged, because returning null is a legitimate outcome.

Suggested fix

Forward the team id the way the sibling handler does. app_home_opened carries
it on the event envelope (team_id), and the adapter already extracts
installation info from that envelope in order to resolve the bot token for the
call, so the value is available at this point:

const promptsTask = this.applyConfiguredSuggestedPrompts({
  channelId: event.channel,
  teamId: event.team ?? /* envelope team_id */,
  userId: event.user,
  ...event.context ? { entities: normalizeAppContextEntities(event.context) } : {}
});

Related, smaller

setSuggestedPrompts's doc comment says threadTs "is optional under the Agent
messaging experience (agent_view), where prompts can sit at the top of the agent
conversation without a thread". We called it that way from our own handler,
where the team id was available. Slack accepted the call and returned no
error — and rendered nothing, because the conversation had never been opened as
an assistant thread. A caveat that this only applies where
assistant_thread_started opened one would have saved us the experiment.

Activity

  1. added a commit that references this issue on Sep 3, 2026
    78021c0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions