3
3
package software .aws .toolkits .eclipse .amazonq .chat ;
4
4
5
5
import java .util .concurrent .CompletableFuture ;
6
+ import java .util .function .Function ;
7
+ import java .util .Objects ;
6
8
import java .util .UUID ;
7
9
8
- import org .eclipse .swt . browser . Browser ;
10
+ import org .eclipse .lsp4j . ProgressParams ;
9
11
10
12
import software .aws .toolkits .eclipse .amazonq .chat .models .ChatRequestParams ;
11
13
import software .aws .toolkits .eclipse .amazonq .chat .models .ChatResult ;
12
14
import software .aws .toolkits .eclipse .amazonq .chat .models .ChatUIInboundCommand ;
15
+ import software .aws .toolkits .eclipse .amazonq .chat .models .ChatUIInboundCommandName ;
13
16
import software .aws .toolkits .eclipse .amazonq .chat .models .GenericTabParams ;
14
17
import software .aws .toolkits .eclipse .amazonq .exception .AmazonQPluginException ;
15
18
import software .aws .toolkits .eclipse .amazonq .util .JsonHandler ;
16
19
import software .aws .toolkits .eclipse .amazonq .util .PluginLogger ;
20
+ import software .aws .toolkits .eclipse .amazonq .util .ProgressNotficationUtils ;
21
+ import software .aws .toolkits .eclipse .amazonq .views .ChatUiRequestListener ;
17
22
import software .aws .toolkits .eclipse .amazonq .views .model .Command ;
18
23
19
24
/**
@@ -29,6 +34,7 @@ public final class ChatCommunicationManager {
29
34
private final JsonHandler jsonHandler ;
30
35
private final CompletableFuture <ChatMessageProvider > chatMessageProvider ;
31
36
private final ChatPartialResultMap chatPartialResultMap ;
37
+ private ChatUiRequestListener chatUiRequestListener ;
32
38
33
39
private ChatCommunicationManager () {
34
40
this .jsonHandler = new JsonHandler ();
@@ -43,13 +49,17 @@ public static synchronized ChatCommunicationManager getInstance() {
43
49
return instance ;
44
50
}
45
51
46
- public CompletableFuture <ChatResult > sendMessageToChatServer (final Browser browser , final Command command , final Object params ) {
52
+ public CompletableFuture <ChatResult > sendMessageToChatServer (final Command command , final Object params ) {
47
53
return chatMessageProvider .thenCompose (chatMessageProvider -> {
48
54
try {
49
55
switch (command ) {
50
56
case CHAT_SEND_PROMPT :
51
57
ChatRequestParams chatRequestParams = jsonHandler .convertObject (params , ChatRequestParams .class );
52
- return chatMessageProvider .sendChatPrompt (browser , chatRequestParams );
58
+ return sendChatRequest (chatRequestParams .getTabId (), token -> {
59
+ chatRequestParams .setPartialResultToken (token );
60
+
61
+ return chatMessageProvider .sendChatPrompt (chatRequestParams );
62
+ });
53
63
case CHAT_READY :
54
64
chatMessageProvider .sendChatReady ();
55
65
return CompletableFuture .completedFuture (null );
@@ -67,39 +77,102 @@ public CompletableFuture<ChatResult> sendMessageToChatServer(final Browser brows
67
77
});
68
78
}
69
79
70
- public void sendMessageToChatUI (final Browser browser , final ChatUIInboundCommand command ) {
71
- String message = jsonHandler .serialize (command );
72
-
73
- String script = "window.postMessage(" + message + ");" ;
74
- browser .getDisplay ().asyncExec (() -> {
75
- browser .evaluate (script );
80
+ private CompletableFuture <ChatResult > sendChatRequest (final String tabId ,
81
+ final Function <String , CompletableFuture <ChatResult >> action ) {
82
+ // Retrieving the chat result is expected to be a long-running process with
83
+ // intermittent progress notifications being sent
84
+ // from the LSP server. The progress notifications provide a token and a partial
85
+ // result Object - we are utilizing a token to
86
+ // ChatMessage mapping to acquire the associated ChatMessage so we can formulate
87
+ // a message for the UI.
88
+ String partialResultToken = addPartialChatMessage (tabId );
89
+
90
+ return action .apply (partialResultToken ).thenApply (result -> {
91
+ // The mapping entry no longer needs to be maintained once the final result is
92
+ // retrieved.
93
+ removePartialChatMessage (partialResultToken );
94
+ // show chat response in Chat UI
95
+ ChatUIInboundCommand chatUIInboundCommand = new ChatUIInboundCommand (
96
+ ChatUIInboundCommandName .ChatPrompt .toString (), tabId , result , false );
97
+ sendMessageToChatUI (chatUIInboundCommand );
98
+ return result ;
76
99
});
77
100
}
78
101
102
+ public void setChatUiRequestListener (final ChatUiRequestListener listener ) {
103
+ chatUiRequestListener = listener ;
104
+ }
105
+
106
+ public void removeListener () {
107
+ chatUiRequestListener = null ;
108
+ }
109
+
79
110
/*
80
- * Gets the partial chat message using the provided token.
111
+ * Sends message to Chat UI to show in webview
81
112
*/
82
- public ChatMessage getPartialChatMessage (final String partialResultToken ) {
83
- return chatPartialResultMap .getValue (partialResultToken );
113
+ public void sendMessageToChatUI (final ChatUIInboundCommand command ) {
114
+ if (chatUiRequestListener != null ) {
115
+ String message = jsonHandler .serialize (command );
116
+ chatUiRequestListener .onSendToChatUi (message );
117
+ }
84
118
}
85
119
86
120
/*
87
- * Adds an entry to the partialResultToken to ChatMessage map.
121
+ * Handles chat progress notifications from the Amazon Q LSP server.
122
+ * - Process partial results for Chat messages if provided token is maintained by ChatCommunicationManager
123
+ * - Other notifications are ignored at this time.
124
+ * - Sends a partial chat prompt message to the webview.
88
125
*/
89
- public String addPartialChatMessage (final ChatMessage chatMessage ) {
90
- String partialResultToken = UUID .randomUUID ().toString ();
126
+ public void handlePartialResultProgressNotification (final ProgressParams params ) {
127
+ String token = ProgressNotficationUtils .getToken (params );
128
+ String tabId = getPartialChatMessage (token );
129
+
130
+ if (tabId == null || tabId .isEmpty ()) {
131
+ return ;
132
+ }
133
+
134
+ // Check to ensure Object is sent in params
135
+ if (params .getValue ().isLeft () || Objects .isNull (params .getValue ().getRight ())) {
136
+ throw new AmazonQPluginException ("Error occurred while handling partial result notification: expected Object value" );
137
+ }
91
138
92
- // Indicator for the server to send partial result notifications
93
- chatMessage .getChatRequestParams ().setPartialResultToken (partialResultToken );
139
+ ChatResult partialChatResult = ProgressNotficationUtils .getObject (params , ChatResult .class );
94
140
95
- chatPartialResultMap .setEntry (partialResultToken , chatMessage );
141
+ // Check to ensure the body has content in order to keep displaying the spinner while loading
142
+ if (partialChatResult .body () == null || partialChatResult .body ().length () == 0 ) {
143
+ return ;
144
+ }
145
+
146
+ ChatUIInboundCommand chatUIInboundCommand = new ChatUIInboundCommand (
147
+ ChatUIInboundCommandName .ChatPrompt .toString (),
148
+ tabId ,
149
+ partialChatResult ,
150
+ true
151
+ );
152
+
153
+ sendMessageToChatUI (chatUIInboundCommand );
154
+ }
155
+
156
+ /*
157
+ * Gets the partial chat message represented by the tabId using the provided token.
158
+ */
159
+ private String getPartialChatMessage (final String partialResultToken ) {
160
+ return chatPartialResultMap .getValue (partialResultToken );
161
+ }
162
+
163
+ /*
164
+ * Adds an entry to the partialResultToken to ChatMessage's tabId map.
165
+ */
166
+ private String addPartialChatMessage (final String tabId ) {
167
+ String partialResultToken = UUID .randomUUID ().toString ();
168
+ chatPartialResultMap .setEntry (partialResultToken , tabId );
96
169
return partialResultToken ;
97
170
}
98
171
99
172
/*
100
- * Removes an entry from the partialResultToken to ChatMessage map.
173
+ * Removes an entry from the partialResultToken to ChatMessage's tabId map.
101
174
*/
102
- public void removePartialChatMessage (final String partialResultToken ) {
175
+ private void removePartialChatMessage (final String partialResultToken ) {
103
176
chatPartialResultMap .removeEntry (partialResultToken );
104
177
}
105
178
}
0 commit comments