Skip to content

Commit fd33c21

Browse files
authored
Merge pull request #1 from milderhc/completion-agent
Avoid notify thread when auto-invoke is not active
2 parents 3c39538 + b568818 commit fd33c21

File tree

6 files changed

+130
-25
lines changed

6 files changed

+130
-25
lines changed

agents/semantickernel-agents-core/src/main/java/com/microsoft/semantickernel/agents/chatcompletion/ChatCompletionAgent.java

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
import com.microsoft.semantickernel.agents.AgentThread;
77
import com.microsoft.semantickernel.agents.KernelAgent;
88
import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
9+
import com.microsoft.semantickernel.functionchoice.AutoFunctionChoiceBehavior;
910
import com.microsoft.semantickernel.orchestration.InvocationContext;
1011
import com.microsoft.semantickernel.orchestration.InvocationReturnMode;
1112
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
12-
import com.microsoft.semantickernel.orchestration.ToolCallBehavior;
1313
import com.microsoft.semantickernel.semanticfunctions.KernelArguments;
1414
import com.microsoft.semantickernel.semanticfunctions.PromptTemplate;
1515
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
@@ -62,7 +62,7 @@ private ChatCompletionAgent(
6262
@Override
6363
public Mono<List<AgentResponseItem<ChatMessageContent<?>>>> invokeAsync(
6464
List<ChatMessageContent<?>> messages,
65-
AgentThread thread,
65+
@Nullable AgentThread thread,
6666
@Nullable AgentInvokeOptions options
6767
) {
6868
return ensureThreadExistsWithMessagesAsync(messages, thread, ChatHistoryAgentThread::new)
@@ -76,22 +76,20 @@ public Mono<List<AgentResponseItem<ChatMessageContent<?>>>> invokeAsync(
7676
// Invoke the agent with the chat history
7777
return internalInvokeAsync(
7878
history,
79+
agentThread,
7980
options
8081
)
81-
.flatMapMany(Flux::fromIterable)
82-
// notify on the new thread instance
83-
.concatMap(agentMessage -> this.notifyThreadOfNewMessageAsync(agentThread, agentMessage).thenReturn(agentMessage))
84-
.collectList()
8582
.map(chatMessageContents ->
8683
chatMessageContents.stream()
87-
.map(message -> new AgentResponseItem<ChatMessageContent<?>>(message, agentThread))
88-
.collect(Collectors.toList())
84+
.map(message -> new AgentResponseItem<ChatMessageContent<?>>(message, agentThread))
85+
.collect(Collectors.toList())
8986
);
9087
});
9188
}
9289

9390
private Mono<List<ChatMessageContent<?>>> internalInvokeAsync(
9491
ChatHistory history,
92+
AgentThread thread,
9593
@Nullable AgentInvokeOptions options
9694
) {
9795
if (options == null) {
@@ -144,6 +142,20 @@ private Mono<List<ChatMessageContent<?>>> internalInvokeAsync(
144142
// Add the chat history to the new chat
145143
chat.addAll(history);
146144

145+
// Retrieve the chat message contents asynchronously and notify the thread
146+
if (shouldNotifyFunctionCalls(agentInvocationContext)) {
147+
// Notify all messages including function calls
148+
return chatCompletionService.getChatMessageContentsAsync(chat, kernel, agentInvocationContext)
149+
.flatMapMany(Flux::fromIterable)
150+
.concatMap(message -> notifyThreadOfNewMessageAsync(thread, message).thenReturn(message))
151+
// Filter out function calls and their results
152+
.filter(message -> message.getContent() != null && message.getAuthorRole() != AuthorRole.TOOL)
153+
.collect(Collectors.toList());
154+
}
155+
156+
// Return chat completion messages without notifying the thread
157+
// We shouldn't add the function call content to the thread, since
158+
// we don't know if the user will execute the call. They should add it themselves.
147159
return chatCompletionService.getChatMessageContentsAsync(chat, kernel, agentInvocationContext);
148160
}
149161
);
@@ -153,6 +165,22 @@ private Mono<List<ChatMessageContent<?>>> internalInvokeAsync(
153165
}
154166
}
155167

168+
boolean shouldNotifyFunctionCalls(InvocationContext invocationContext) {
169+
if (invocationContext == null) {
170+
return false;
171+
}
172+
173+
if (invocationContext.getFunctionChoiceBehavior() != null && invocationContext.getFunctionChoiceBehavior() instanceof AutoFunctionChoiceBehavior) {
174+
return ((AutoFunctionChoiceBehavior) invocationContext.getFunctionChoiceBehavior()).isAutoInvoke();
175+
}
176+
177+
if (invocationContext.getToolCallBehavior() != null) {
178+
return invocationContext.getToolCallBehavior().isAutoInvokeAllowed();
179+
}
180+
181+
return false;
182+
}
183+
156184

157185
@Override
158186
public Mono<Void> notifyThreadOfNewMessageAsync(AgentThread thread, ChatMessageContent<?> message) {

agents/semantickernel-agents-core/src/main/java/com/microsoft/semantickernel/agents/chatcompletion/ChatHistoryAgentThread.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,25 @@
1616
public class ChatHistoryAgentThread extends BaseAgentThread {
1717
private ChatHistory chatHistory;
1818

19+
/**
20+
* Constructor for ChatHistoryAgentThread.
21+
*
22+
*/
1923
public ChatHistoryAgentThread() {
2024
this(UUID.randomUUID().toString(), new ChatHistory());
2125
}
2226

2327
/**
24-
* Constructor for com.microsoft.semantickernel.agents.chatcompletion.ChatHistoryAgentThread.
28+
* Constructor for ChatHistoryAgentThread.
29+
*
30+
* @param chatHistory The chat history.
31+
*/
32+
public ChatHistoryAgentThread(@Nullable ChatHistory chatHistory) {
33+
this(UUID.randomUUID().toString(), chatHistory);
34+
}
35+
36+
/**
37+
* Constructor for ChatHistoryAgentThread.
2538
*
2639
* @param id The ID of the thread.
2740
* @param chatHistory The chat history.
@@ -31,6 +44,8 @@ public ChatHistoryAgentThread(String id, @Nullable ChatHistory chatHistory) {
3144
this.chatHistory = chatHistory != null ? chatHistory : new ChatHistory();
3245
}
3346

47+
48+
3449
/**
3550
* Get the chat history.
3651
*

samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/agents/CompletionAgent.java

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,17 @@
66
import com.azure.core.credential.KeyCredential;
77
import com.microsoft.semantickernel.Kernel;
88
import com.microsoft.semantickernel.agents.AgentInvokeOptions;
9+
import com.microsoft.semantickernel.agents.AgentThread;
910
import com.microsoft.semantickernel.agents.chatcompletion.ChatCompletionAgent;
1011
import com.microsoft.semantickernel.agents.chatcompletion.ChatHistoryAgentThread;
1112
import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion;
1213
import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter;
14+
import com.microsoft.semantickernel.contextvariables.ContextVariableTypes;
1315
import com.microsoft.semantickernel.functionchoice.FunctionChoiceBehavior;
1416
import com.microsoft.semantickernel.implementation.templateengine.tokenizer.DefaultPromptTemplate;
1517
import com.microsoft.semantickernel.orchestration.InvocationContext;
1618
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
19+
import com.microsoft.semantickernel.orchestration.ToolCallBehavior;
1720
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
1821
import com.microsoft.semantickernel.samples.plugins.github.GitHubModel;
1922
import com.microsoft.semantickernel.samples.plugins.github.GitHubPlugin;
@@ -105,7 +108,7 @@ public static void main(String[] args) {
105108
)
106109
).build();
107110

108-
ChatHistoryAgentThread agentThread = new ChatHistoryAgentThread();
111+
AgentThread agentThread = new ChatHistoryAgentThread();
109112
Scanner scanner = new Scanner(System.in);
110113

111114
while (true) {
@@ -118,22 +121,19 @@ public static void main(String[] args) {
118121

119122
var message = new ChatMessageContent<>(AuthorRole.USER, input);
120123
KernelArguments arguments = KernelArguments.builder()
121-
.withVariable("now", System.currentTimeMillis())
122-
.build();
124+
.withVariable("now", System.currentTimeMillis())
125+
.build();
123126

124127
var response = agent.invokeAsync(
125-
List.of(message),
126-
agentThread,
127-
AgentInvokeOptions.builder()
128-
.withKernel(kernel)
129-
.withKernelArguments(arguments)
130-
.build()
131-
).block();
132-
133-
var lastResponse = response.get(response.size() - 1);
128+
message,
129+
agentThread,
130+
AgentInvokeOptions.builder()
131+
.withKernelArguments(arguments)
132+
.build()
133+
).block().get(0);
134134

135-
System.out.println("> " + lastResponse.getMessage());
136-
agentThread = (ChatHistoryAgentThread) lastResponse.getThread();
135+
System.out.println("> " + response.getMessage());
136+
agentThread = response.getThread();
137137
}
138138
}
139139
}

semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/Agent.java

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
import reactor.core.publisher.Flux;
1818
import reactor.core.publisher.Mono;
1919

20+
import javax.annotation.Nullable;
21+
2022
/**
2123
* Interface for a semantic kernel agent.
2224
*/
@@ -43,6 +45,36 @@ public interface Agent {
4345
*/
4446
String getDescription();
4547

48+
/**
49+
* Invokes the agent with the given message.
50+
*
51+
* @param message The message to process
52+
* @return A Mono containing the agent response
53+
*/
54+
Mono<List<AgentResponseItem<ChatMessageContent<?>>>> invokeAsync(@Nullable ChatMessageContent<?> message);
55+
56+
/**
57+
* Invokes the agent with the given message and thread.
58+
*
59+
* @param message The message to process
60+
* @param thread The agent thread to use
61+
* @return A Mono containing the agent response
62+
*/
63+
Mono<List<AgentResponseItem<ChatMessageContent<?>>>> invokeAsync(@Nullable ChatMessageContent<?> message,
64+
@Nullable AgentThread thread);
65+
66+
/**
67+
* Invokes the agent with the given message, thread, and options.
68+
*
69+
* @param message The message to process
70+
* @param thread The agent thread to use
71+
* @param options The options for invoking the agent
72+
* @return A Mono containing the agent response
73+
*/
74+
Mono<List<AgentResponseItem<ChatMessageContent<?>>>> invokeAsync(@Nullable ChatMessageContent<?> message,
75+
@Nullable AgentThread thread,
76+
@Nullable AgentInvokeOptions options);
77+
4678
/**
4779
* Invoke the agent with the given chat history.
4880
*
@@ -51,7 +83,9 @@ public interface Agent {
5183
* @param options The options for invoking the agent
5284
* @return A Mono containing the agent response
5385
*/
54-
Mono<List<AgentResponseItem<ChatMessageContent<?>>>> invokeAsync(List<ChatMessageContent<?>> messages, AgentThread thread, AgentInvokeOptions options);
86+
Mono<List<AgentResponseItem<ChatMessageContent<?>>>> invokeAsync(List<ChatMessageContent<?>> messages,
87+
@Nullable AgentThread thread,
88+
@Nullable AgentInvokeOptions options);
5589

5690
/**
5791
* Notifies the agent of a new message.

semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/AgentInvokeOptions.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@
1313
*/
1414
public class AgentInvokeOptions {
1515

16+
@Nullable
1617
private final KernelArguments kernelArguments;
18+
@Nullable
1719
private final Kernel kernel;
20+
@Nullable
1821
private final String additionalInstructions;
22+
@Nullable
1923
private final InvocationContext invocationContext;
2024

2125
/**

semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/KernelAgent.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import reactor.core.publisher.Flux;
1212
import reactor.core.publisher.Mono;
1313

14+
import javax.annotation.Nullable;
15+
import java.util.ArrayList;
1416
import java.util.HashMap;
1517
import java.util.List;
1618
import java.util.Map;
@@ -114,7 +116,6 @@ public PromptTemplate getTemplate() {
114116
return template;
115117
}
116118

117-
118119
/**
119120
* Merges the provided arguments with the current arguments.
120121
* Provided arguments will override the current arguments.
@@ -167,4 +168,27 @@ protected <T extends AgentThread> Mono<T> ensureThreadExistsWithMessagesAsync(Li
167168
.then(Mono.just((T) newThread));
168169
});
169170
}
171+
172+
@Override
173+
public Mono<List<AgentResponseItem<ChatMessageContent<?>>>> invokeAsync(@Nullable ChatMessageContent<?> message) {
174+
return invokeAsync(message, null, null);
175+
}
176+
177+
@Override
178+
public Mono<List<AgentResponseItem<ChatMessageContent<?>>>> invokeAsync(@Nullable ChatMessageContent<?> message,
179+
@Nullable AgentThread thread) {
180+
return invokeAsync(message, thread, null);
181+
}
182+
183+
@Override
184+
public Mono<List<AgentResponseItem<ChatMessageContent<?>>>> invokeAsync(
185+
@Nullable ChatMessageContent<?> message,
186+
@Nullable AgentThread thread,
187+
@Nullable AgentInvokeOptions options) {
188+
ArrayList<ChatMessageContent<?>> messages = new ArrayList<>();
189+
if (message != null) {
190+
messages.add(message);
191+
}
192+
return invokeAsync(messages, thread, options);
193+
}
170194
}

0 commit comments

Comments
 (0)