# AI-app threads

Set an AI app thread's status, title and suggested prompts as Bolt's Assistant class does, and open the app's container as a person so your app hears assistant_thread_started.

An app built on Bolt's `Assistant` class sets a thread's status, title and suggested prompts with [`assistant.threads.setStatus`](https://docs.slack.dev/reference/methods/assistant.threads.setStatus), [`assistant.threads.setTitle`](https://docs.slack.dev/reference/methods/assistant.threads.setTitle) and [`assistant.threads.setSuggestedPrompts`](https://docs.slack.dev/reference/methods/assistant.threads.setSuggestedPrompts). Each takes a bot token and the `thread_ts` of a thread's root: any top-level message the bot can read, in a DM or a channel, as on Slack. A reply's `ts` returns `invalid_thread_ts`. The title reads back on the root as `assistant_app_thread`:

```bash
curl -s -X POST "$RYSTIC_URL/_rystic/scenario" -d '{"name":"design_studio"}' -o /dev/null
curl -s -X POST "$RYSTIC_URL/api/chat.postMessage" -H 'Authorization: Bearer xoxb-local' -d channel=DWDC0000001 -d 'text=How can I help?' | jq -c '{ok, ts}'
# -> {"ok":true,"ts":"1772323200.000001"}
curl -s -X POST "$RYSTIC_URL/api/assistant.threads.setTitle" -H 'Authorization: Bearer xoxb-local' -d channel_id=DWDC0000001 -d thread_ts=1772323200.000001 -d 'title=Holiday plans' | jq -c .
# -> {"ok":true}
curl -s "$RYSTIC_URL/api/conversations.replies?channel=DWDC0000001&ts=1772323200.000001" -H 'Authorization: Bearer xoxb-local' | jq -c '.messages[0].assistant_app_thread.title'
# -> "Holiday plans"
```

A status and suggested prompts are shown by the Slack client and returned by no Web API read, here as on Slack. An empty `status` clears the status. `loading_messages` takes 1 to 10 items and `prompts` at most 4, each with a `title` and a `message`. `setSuggestedPrompts` without `thread_ts` returns `not_agent_app`. A user token returns `not_allowed_token_type` from all five methods.

The Agent messaging replacements, [`agents.sessions.setStatus`](https://docs.slack.dev/reference/methods/agents.sessions.setstatus) and [`agents.sessions.rename`](https://docs.slack.dev/reference/methods/agents.sessions.rename), check their arguments as Slack does. Past those checks, `agents.sessions.rename` returns `not_authorized`, as Slack does for an app that is not declared an agent, while `agents.sessions.setStatus` creates or updates the thread's session and returns its `status` as Slack's docs describe. **Differs from Slack:** neither success was measured, because the Slack app the simulator is measured with is not declared an agent.

### Opening the container

A person opens an AI app's container, or views another channel while it is open, in the Slack client, and no Web API method does either. The simulator serves both as client methods that answer only with `X-Rystic-Surface: client` and the person's identity (a bound token or `X-Rystic-Actor`):

- `assistant.threads.open` starts a thread in the person's DM with the simulator's app (its bot user, `UWDCBOT0001` in `design_studio`): a root of subtype `assistant_app_thread`, theirs, titled `Chats from <time>`. It then sends [`assistant_thread_started`](https://docs.slack.dev/reference/events/assistant_thread_started). `context_channel_id` names the channel in view. The DM must exist; open it with `conversations.open` first.
- `assistant.threads.setContext` takes the thread's `channel_id` and `thread_ts` and the new `context_channel_id`, and sends [`assistant_thread_context_changed`](https://docs.slack.dev/reference/events/assistant_thread_context_changed).

Both events reach your app over Socket Mode or the request URL like every other [event](https://www.rystic.ai/docs/simulators/slack/features/events-api.md):

```bash
curl -s -X POST "$RYSTIC_URL/_rystic/scenario" -d '{"name":"design_studio"}' -o /dev/null
curl -s -X POST "$RYSTIC_URL/api/assistant.threads.open" -H 'Authorization: Bearer xoxp-anything' -H 'X-Rystic-Actor: UWDC0000003' -H 'X-Rystic-Surface: client' -d context_channel_id=CWDC0000004 | jq -c .
# -> {"channel_id":"DWDC0000001","ok":true,"thread_ts":"1772323200.000001"}
curl -s "$RYSTIC_URL/_rystic/egress" | jq -c '.events[] | {type, thread: .payload.assistant_thread}'
# -> {"type":"assistant_thread_started","thread":{"channel_id":"DWDC0000001","context":{"channel_id":"CWDC0000004","team_id":"TWDC0000001"},"thread_ts":"1772323200.000001","user_id":"UWDC0000003"}}
```

**Differs from Slack:** both events, and the root `assistant.threads.open` writes, follow Slack's documented examples and were never measured against Slack. The Slack app the simulator is measured with has no Agent experience, so the Slack client offers it no container, and turning that experience on cannot be undone. The simulator sends the events for any app's bot user, where Slack sends them only to an app with the Agents feature on.

---

Source: https://www.rystic.ai/docs/simulators/slack/features/ai-app-threads · Markdown: https://www.rystic.ai/docs/simulators/slack/features/ai-app-threads.md
