Skip to content

Commit f65dc3d

Browse files
authored
Add Agents & Assistant support (#1372)
1 parent 18ff9b5 commit f65dc3d

File tree

34 files changed

+1124
-17
lines changed

34 files changed

+1124
-17
lines changed

bolt-socket-mode/src/test/java/samples/AssistantEventListenerApp.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ public static void main(String[] args) throws Exception {
3434
ctx.client().assistantThreadsSetSuggestedPrompts(r -> r
3535
.channelId(channelId)
3636
.threadTs(threadTs)
37-
.title("How are you?")
3837
.prompts(Collections.singletonList(new SuggestedPrompt("What does SLACK stand for?")))
3938
);
4039
} catch (Exception e) {
@@ -71,7 +70,7 @@ public static void main(String[] args) throws Exception {
7170
.text("Here you are!")
7271
);
7372
} catch (Exception e) {
74-
ctx.logger.error("Failed to handle assistant thread started event: {e}", e);
73+
ctx.logger.error("Failed to handle assistant user message event: {e}", e);
7574
try {
7675
ctx.client().chatPostMessage(r -> r
7776
.channel(channelId)
@@ -112,7 +111,7 @@ public static void main(String[] args) throws Exception {
112111
.text("Your files do not have any issues!")
113112
);
114113
} catch (Exception e) {
115-
ctx.logger.error("Failed to handle assistant thread started event: {e}", e);
114+
ctx.logger.error("Failed to handle assistant user message event: {e}", e);
116115
try {
117116
ctx.client().chatPostMessage(r -> r
118117
.channel(channelId)
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package samples;
2+
3+
import com.slack.api.bolt.App;
4+
import com.slack.api.bolt.AppConfig;
5+
import com.slack.api.bolt.middleware.builtin.Assistant;
6+
import com.slack.api.bolt.socket_mode.SocketModeApp;
7+
import com.slack.api.model.Message;
8+
import com.slack.api.model.event.AppMentionEvent;
9+
import com.slack.api.model.event.MessageEvent;
10+
11+
import java.security.SecureRandom;
12+
import java.util.*;
13+
14+
import static com.slack.api.model.block.Blocks.actions;
15+
import static com.slack.api.model.block.Blocks.section;
16+
import static com.slack.api.model.block.composition.BlockCompositions.plainText;
17+
import static com.slack.api.model.block.element.BlockElements.button;
18+
19+
public class AssistantInteractionApp {
20+
21+
public static void main(String[] args) throws Exception {
22+
String botToken = System.getenv("SLACK_BOT_TOKEN");
23+
String appToken = System.getenv("SLACK_APP_TOKEN");
24+
25+
App app = new App(AppConfig.builder()
26+
.singleTeamBotToken(botToken)
27+
.ignoringSelfAssistantMessageEventsEnabled(false)
28+
.build()
29+
);
30+
31+
Assistant assistant = new Assistant(app.executorService());
32+
33+
assistant.threadStarted((req, ctx) -> {
34+
try {
35+
ctx.say(r -> r
36+
.text("Hi, how can I help you today?")
37+
.blocks(Arrays.asList(
38+
section(s -> s.text(plainText("Hi, how I can I help you today?"))),
39+
actions(a -> a.elements(Collections.singletonList(
40+
button(b -> b.actionId("assistant-generate-numbers").text(plainText("Generate numbers")))
41+
)))
42+
))
43+
);
44+
} catch (Exception e) {
45+
ctx.logger.error("Failed to handle assistant thread started event: {e}", e);
46+
}
47+
});
48+
49+
app.blockAction("assistant-generate-numbers", (req, ctx) -> {
50+
app.executorService().submit(() -> {
51+
Map<String, Object> eventPayload = new HashMap<>();
52+
eventPayload.put("num", 20);
53+
try {
54+
ctx.client().chatPostMessage(r -> r
55+
.channel(req.getPayload().getChannel().getId())
56+
.threadTs(req.getPayload().getMessage().getThreadTs())
57+
.text("OK, I will generate numbers for you!")
58+
.metadata(new Message.Metadata("assistant-generate-numbers", eventPayload))
59+
);
60+
} catch (Exception e) {
61+
ctx.logger.error("Failed to post a bot message: {e}", e);
62+
}
63+
});
64+
return ctx.ack();
65+
});
66+
67+
assistant.botMessage((req, ctx) -> {
68+
if (req.getEvent().getMetadata() != null
69+
&& req.getEvent().getMetadata().getEventType().equals("assistant-generate-numbers")) {
70+
try {
71+
ctx.setStatus("is typing...");
72+
Double num = (Double) req.getEvent().getMetadata().getEventPayload().get("num");
73+
Set<String> numbers = new HashSet<>();
74+
SecureRandom random = new SecureRandom();
75+
while (numbers.size() < num) {
76+
numbers.add(String.valueOf(random.nextInt(100)));
77+
}
78+
Thread.sleep(1000L);
79+
ctx.say(r -> r.text("Her you are: " + String.join(", ", numbers)));
80+
} catch (Exception e) {
81+
ctx.logger.error("Failed to handle assistant bot message event: {e}", e);
82+
}
83+
}
84+
});
85+
86+
assistant.userMessage((req, ctx) -> {
87+
try {
88+
ctx.setStatus("is typing...");
89+
ctx.say(r -> r.text("Sorry, I couldn't understand your comment."));
90+
} catch (Exception e) {
91+
ctx.logger.error("Failed to handle assistant user message event: {e}", e);
92+
try {
93+
ctx.say(r -> r.text(":warning: Sorry, something went wrong during processing your request!"));
94+
} catch (Exception ee) {
95+
ctx.logger.error("Failed to inform the error to the end-user: {ee}", ee);
96+
}
97+
}
98+
});
99+
100+
101+
app.assistant(assistant);
102+
103+
app.event(MessageEvent.class, (req, ctx) -> {
104+
return ctx.ack();
105+
});
106+
107+
app.event(AppMentionEvent.class, (req, ctx) -> {
108+
ctx.say("You can help you at our 1:1 DM!");
109+
return ctx.ack();
110+
});
111+
112+
new SocketModeApp(appToken, app).start();
113+
}
114+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package samples;
2+
3+
import com.slack.api.bolt.App;
4+
import com.slack.api.bolt.AppConfig;
5+
import com.slack.api.bolt.middleware.builtin.Assistant;
6+
import com.slack.api.bolt.socket_mode.SocketModeApp;
7+
import com.slack.api.model.assistant.SuggestedPrompt;
8+
import com.slack.api.model.event.AppMentionEvent;
9+
import com.slack.api.model.event.MessageEvent;
10+
11+
import java.util.Collections;
12+
13+
public class AssistantSimpleApp {
14+
15+
public static void main(String[] args) throws Exception {
16+
String botToken = System.getenv("SLACK_BOT_TOKEN");
17+
String appToken = System.getenv("SLACK_APP_TOKEN");
18+
19+
App app = new App(AppConfig.builder().singleTeamBotToken(botToken).build());
20+
21+
Assistant assistant = new Assistant(app.executorService());
22+
23+
assistant.threadStarted((req, ctx) -> {
24+
try {
25+
ctx.say(r -> r.text("Hi, how can I help you today?"));
26+
ctx.setSuggestedPrompts(Collections.singletonList(
27+
SuggestedPrompt.create("What does SLACK stand for?")
28+
));
29+
} catch (Exception e) {
30+
ctx.logger.error("Failed to handle assistant thread started event: {e}", e);
31+
}
32+
});
33+
34+
assistant.userMessage((req, ctx) -> {
35+
try {
36+
ctx.setStatus("is typing...");
37+
Thread.sleep(500L);
38+
if (ctx.getThreadContext() != null) {
39+
String contextChannel = ctx.getThreadContext().getChannelId();
40+
ctx.say(r -> r.text("I am ware of the channel context: <#" + contextChannel + ">"));
41+
} else {
42+
ctx.say(r -> r.text("Here you are!"));
43+
}
44+
} catch (Exception e) {
45+
ctx.logger.error("Failed to handle assistant user message event: {e}", e);
46+
try {
47+
ctx.say(r -> r.text(":warning: Sorry, something went wrong during processing your request!"));
48+
} catch (Exception ee) {
49+
ctx.logger.error("Failed to inform the error to the end-user: {ee}", ee);
50+
}
51+
}
52+
});
53+
54+
assistant.userMessageWithFiles((req, ctx) -> {
55+
try {
56+
ctx.setStatus("is analyzing the files...");
57+
Thread.sleep(500L);
58+
ctx.setStatus("is still checking the files...");
59+
Thread.sleep(500L);
60+
ctx.say(r -> r.text("Your files do not have any issues!"));
61+
} catch (Exception e) {
62+
ctx.logger.error("Failed to handle assistant user message event: {e}", e);
63+
try {
64+
ctx.say(r -> r.text(":warning: Sorry, something went wrong during processing your request!"));
65+
} catch (Exception ee) {
66+
ctx.logger.error("Failed to inform the error to the end-user: {ee}", ee);
67+
}
68+
}
69+
});
70+
71+
app.use(assistant);
72+
73+
app.event(MessageEvent.class, (req, ctx) -> {
74+
return ctx.ack();
75+
});
76+
77+
app.event(AppMentionEvent.class, (req, ctx) -> {
78+
ctx.say("You can help you at our 1:1 DM!");
79+
return ctx.ack();
80+
});
81+
82+
new SocketModeApp(appToken, app).start();
83+
}
84+
}

bolt/src/main/java/com/slack/api/bolt/App.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,10 @@ protected List<Middleware> buildDefaultMiddlewareList(AppConfig config) {
136136

137137
// ignoring the events generated by this bot user
138138
if (config.isIgnoringSelfEventsEnabled()) {
139-
middlewareList.add(new IgnoringSelfEvents(config.getSlack().getConfig()));
139+
middlewareList.add(new IgnoringSelfEvents(
140+
config.getSlack().getConfig(),
141+
config.isIgnoringSelfAssistantMessageEventsEnabled()
142+
));
140143
}
141144

142145
return middlewareList;
@@ -307,6 +310,8 @@ public App enableTokenRevocationHandlers() {
307310

308311
private OAuthCallbackService oAuthCallbackService; // will be initialized by initOAuthServicesIfNecessary()
309312

313+
private AssistantThreadContextService assistantThreadContextService;
314+
310315
private void initOAuthServicesIfNecessary() {
311316
if (appConfig.isDistributedApp() && appConfig.isOAuthRedirectUriPathEnabled()) {
312317
if (this.oAuthCallbackService == null) {
@@ -605,6 +610,13 @@ public App use(Middleware middleware) {
605610
return this;
606611
}
607612

613+
public App assistant(Assistant assistant) {
614+
if (this.assistantThreadContextService != null && assistant.getThreadContextService() == null) {
615+
assistant.setThreadContextService(this.assistantThreadContextService);
616+
}
617+
return this.use(assistant);
618+
}
619+
608620
// ----------------------
609621
// App routing methods
610622

@@ -613,7 +625,7 @@ public App use(Middleware middleware) {
613625
// https://api.slack.com/events-api
614626

615627
public <E extends Event> App event(
616-
Class<E> eventClass,BoltEventHandler<E> handler) {
628+
Class<E> eventClass, BoltEventHandler<E> handler) {
617629
// Note that having multiple handlers is allowed only for message event handlers.
618630
// If we revisit this to unlock the option to all event types, it should work well.
619631
// We didn't decide to do so in 2022 in respect of better backward compatibility.
@@ -936,6 +948,11 @@ public App asOpenIDConnectApp(boolean enabled) {
936948
return this;
937949
}
938950

951+
public App service(AssistantThreadContextService assistantThreadContextService) {
952+
this.assistantThreadContextService = assistantThreadContextService;
953+
return this;
954+
}
955+
939956
public App service(OAuthCallbackService oAuthCallbackService) {
940957
this.oAuthCallbackService = oAuthCallbackService;
941958
putServiceInitializer(OAuthCallbackService.class, oAuthCallbackService.initializer());

bolt/src/main/java/com/slack/api/bolt/AppConfig.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,4 +404,7 @@ public void setOauthRedirectUriPath(String oauthRedirectUriPath) {
404404
@Builder.Default
405405
private boolean ignoringSelfEventsEnabled = true;
406406

407+
@Builder.Default
408+
private boolean ignoringSelfAssistantMessageEventsEnabled = true;
409+
407410
}

0 commit comments

Comments
 (0)