diff --git a/agents/semantickernel-agents-core/pom.xml b/agents/semantickernel-agents-core/pom.xml
new file mode 100644
index 000000000..4eec1b768
--- /dev/null
+++ b/agents/semantickernel-agents-core/pom.xml
@@ -0,0 +1,25 @@
+
+
+ 4.0.0
+
+ com.microsoft.semantic-kernel
+ semantickernel-parent
+ 1.4.4-SNAPSHOT
+ ../../pom.xml
+
+
+ semantickernel-agents-core
+
+ Semantic Kernel Chat Completion Agent
+ Chat Completion Agent for Semantic Kernel
+
+
+
+ com.microsoft.semantic-kernel
+ semantickernel-api
+
+
+
+
\ No newline at end of file
diff --git a/agents/semantickernel-agents-core/src/main/java/com/microsoft/semantickernel/agents/chatcompletion/ChatCompletionAgent.java b/agents/semantickernel-agents-core/src/main/java/com/microsoft/semantickernel/agents/chatcompletion/ChatCompletionAgent.java
new file mode 100644
index 000000000..f8423f3d7
--- /dev/null
+++ b/agents/semantickernel-agents-core/src/main/java/com/microsoft/semantickernel/agents/chatcompletion/ChatCompletionAgent.java
@@ -0,0 +1,303 @@
+package com.microsoft.semantickernel.agents.chatcompletion;
+
+import com.microsoft.semantickernel.Kernel;
+import com.microsoft.semantickernel.agents.AgentInvokeOptions;
+import com.microsoft.semantickernel.agents.AgentResponseItem;
+import com.microsoft.semantickernel.agents.AgentThread;
+import com.microsoft.semantickernel.agents.KernelAgent;
+import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
+import com.microsoft.semantickernel.orchestration.InvocationContext;
+import com.microsoft.semantickernel.orchestration.InvocationReturnMode;
+import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
+import com.microsoft.semantickernel.orchestration.ToolCallBehavior;
+import com.microsoft.semantickernel.semanticfunctions.KernelArguments;
+import com.microsoft.semantickernel.semanticfunctions.PromptTemplate;
+import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
+import com.microsoft.semantickernel.semanticfunctions.PromptTemplateFactory;
+import com.microsoft.semantickernel.services.ServiceNotFoundException;
+import com.microsoft.semantickernel.services.chatcompletion.AuthorRole;
+import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
+import com.microsoft.semantickernel.services.chatcompletion.ChatHistory;
+import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import javax.annotation.Nullable;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class ChatCompletionAgent extends KernelAgent {
+
+ private ChatCompletionAgent(
+ String id,
+ String name,
+ String description,
+ Kernel kernel,
+ KernelArguments kernelArguments,
+ InvocationContext context,
+ String instructions,
+ PromptTemplate template
+ ) {
+ super(
+ id,
+ name,
+ description,
+ kernel,
+ kernelArguments,
+ context,
+ instructions,
+ template
+ );
+ }
+
+ /**
+ * Invoke the agent with the given chat history.
+ *
+ * @param messages The chat history to process
+ * @param thread The agent thread to use
+ * @param options The options for invoking the agent
+ * @return A Mono containing the agent response
+ */
+ @Override
+ public Mono>>> invokeAsync(
+ List> messages,
+ AgentThread thread,
+ @Nullable AgentInvokeOptions options
+ ) {
+ return ensureThreadExistsWithMessagesAsync(messages, thread, ChatHistoryAgentThread::new)
+ .cast(ChatHistoryAgentThread.class)
+ .flatMap(agentThread -> {
+ // Extract the chat history from the thread
+ ChatHistory history = new ChatHistory(
+ agentThread.getChatHistory().getMessages()
+ );
+
+ // Invoke the agent with the chat history
+ return internalInvokeAsync(
+ history,
+ options
+ )
+ .flatMapMany(Flux::fromIterable)
+ // notify on the new thread instance
+ .concatMap(agentMessage -> this.notifyThreadOfNewMessageAsync(agentThread, agentMessage).thenReturn(agentMessage))
+ .collectList()
+ .map(chatMessageContents ->
+ chatMessageContents.stream()
+ .map(message -> new AgentResponseItem>(message, agentThread))
+ .collect(Collectors.toList())
+ );
+ });
+ }
+
+ private Mono>> internalInvokeAsync(
+ ChatHistory history,
+ @Nullable AgentInvokeOptions options
+ ) {
+ if (options == null) {
+ options = new AgentInvokeOptions();
+ }
+
+ final Kernel kernel = options.getKernel() != null ? options.getKernel() : this.kernel;
+ final KernelArguments arguments = mergeArguments(options.getKernelArguments());
+ final String additionalInstructions = options.getAdditionalInstructions();
+ final InvocationContext invocationContext = options.getInvocationContext() != null ? options.getInvocationContext() : this.invocationContext;
+
+ try {
+ ChatCompletionService chatCompletionService = kernel.getService(ChatCompletionService.class, arguments);
+
+ PromptExecutionSettings executionSettings = invocationContext != null && invocationContext.getPromptExecutionSettings() != null
+ ? invocationContext.getPromptExecutionSettings()
+ : kernelArguments.getExecutionSettings().get(chatCompletionService.getServiceId());
+
+ ToolCallBehavior toolCallBehavior = invocationContext != null
+ ? invocationContext.getToolCallBehavior()
+ : ToolCallBehavior.allowAllKernelFunctions(true);
+
+ // Build base invocation context
+ InvocationContext.Builder builder = InvocationContext.builder()
+ .withPromptExecutionSettings(executionSettings)
+ .withToolCallBehavior(toolCallBehavior)
+ .withReturnMode(InvocationReturnMode.NEW_MESSAGES_ONLY);
+
+ if (invocationContext != null) {
+ builder = builder
+ .withTelemetry(invocationContext.getTelemetry())
+ .withContextVariableConverter(invocationContext.getContextVariableTypes())
+ .withKernelHooks(invocationContext.getKernelHooks());
+ }
+
+ InvocationContext agentInvocationContext = builder.build();
+
+ return renderInstructionsAsync(kernel, arguments, agentInvocationContext).flatMap(
+ instructions -> {
+ // Create a new chat history with the instructions
+ ChatHistory chat = new ChatHistory(
+ instructions
+ );
+
+ // Add agent additional instructions
+ if (additionalInstructions != null) {
+ chat.addMessage(new ChatMessageContent<>(
+ AuthorRole.SYSTEM,
+ additionalInstructions
+ ));
+ }
+
+ // Add the chat history to the new chat
+ chat.addAll(history);
+
+ return chatCompletionService.getChatMessageContentsAsync(chat, kernel, agentInvocationContext);
+ }
+ );
+
+ } catch (ServiceNotFoundException e) {
+ return Mono.error(e);
+ }
+ }
+
+
+ @Override
+ public Mono notifyThreadOfNewMessageAsync(AgentThread thread, ChatMessageContent> message) {
+ return Mono.defer(() -> {
+ return thread.onNewMessageAsync(message);
+ });
+ }
+
+ /**
+ * Builder for creating instances of ChatCompletionAgent.
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder implements SemanticKernelBuilder {
+ private String id;
+ private String name;
+ private String description;
+ private Kernel kernel;
+ private KernelArguments kernelArguments;
+ private InvocationContext invocationContext;
+ private String instructions;
+ private PromptTemplate template;
+
+ /**
+ * Set the ID of the agent.
+ *
+ * @param id The ID of the agent.
+ */
+ public Builder withId(String id) {
+ this.id = id;
+ return this;
+ }
+
+ /**
+ * Set the name of the agent.
+ *
+ * @param name The name of the agent.
+ */
+ public Builder withName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ /**
+ * Set the description of the agent.
+ *
+ * @param description The description of the agent.
+ */
+ public Builder withDescription(String description) {
+ this.description = description;
+ return this;
+ }
+
+ /**
+ * Set the kernel to use for the agent.
+ *
+ * @param kernel The kernel to use.
+ */
+ public Builder withKernel(Kernel kernel) {
+ this.kernel = kernel;
+ return this;
+ }
+
+ /**
+ * Set the kernel arguments to use for the agent.
+ *
+ * @param KernelArguments The kernel arguments to use.
+ */
+ @SuppressFBWarnings("EI_EXPOSE_REP2")
+ public Builder withKernelArguments(KernelArguments KernelArguments) {
+ this.kernelArguments = KernelArguments;
+ return this;
+ }
+
+ /**
+ * Set the instructions for the agent.
+ *
+ * @param instructions The instructions for the agent.
+ */
+ public Builder withInstructions(String instructions) {
+ this.instructions = instructions;
+ return this;
+ }
+
+ /**
+ * Set the invocation context for the agent.
+ *
+ * @param invocationContext The invocation context to use.
+ */
+ public Builder withInvocationContext(InvocationContext invocationContext) {
+ this.invocationContext = invocationContext;
+ return this;
+ }
+
+ /**
+ * Set the template for the agent.
+ *
+ * @param template The template to use.
+ */
+ public Builder withTemplate(PromptTemplate template) {
+ this.template = template;
+ return this;
+ }
+
+ /**
+ * Build the ChatCompletionAgent instance.
+ *
+ * @return The ChatCompletionAgent instance.
+ */
+ public ChatCompletionAgent build() {
+ return new ChatCompletionAgent(
+ id,
+ name,
+ description,
+ kernel,
+ kernelArguments,
+ invocationContext,
+ instructions,
+ template
+ );
+ }
+
+ /**
+ * Build the ChatCompletionAgent instance with the given prompt template config and factory.
+ *
+ * @param promptTemplateConfig The prompt template config to use.
+ * @param promptTemplateFactory The prompt template factory to use.
+ * @return The ChatCompletionAgent instance.
+ */
+ public ChatCompletionAgent build(PromptTemplateConfig promptTemplateConfig, PromptTemplateFactory promptTemplateFactory) {
+ return new ChatCompletionAgent(
+ id,
+ name,
+ description,
+ kernel,
+ kernelArguments,
+ invocationContext,
+ promptTemplateConfig.getTemplate(),
+ promptTemplateFactory.tryCreate(promptTemplateConfig)
+ );
+ }
+ }
+}
diff --git a/agents/semantickernel-agents-core/src/main/java/com/microsoft/semantickernel/agents/chatcompletion/ChatHistoryAgentThread.java b/agents/semantickernel-agents-core/src/main/java/com/microsoft/semantickernel/agents/chatcompletion/ChatHistoryAgentThread.java
new file mode 100644
index 000000000..1a68f8c44
--- /dev/null
+++ b/agents/semantickernel-agents-core/src/main/java/com/microsoft/semantickernel/agents/chatcompletion/ChatHistoryAgentThread.java
@@ -0,0 +1,116 @@
+package com.microsoft.semantickernel.agents.chatcompletion;
+
+import com.microsoft.semantickernel.agents.AgentThread;
+import com.microsoft.semantickernel.agents.BaseAgentThread;
+import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
+import com.microsoft.semantickernel.services.chatcompletion.ChatHistory;
+import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import reactor.core.publisher.Mono;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.List;
+import java.util.UUID;
+
+public class ChatHistoryAgentThread extends BaseAgentThread {
+ private ChatHistory chatHistory;
+
+ public ChatHistoryAgentThread() {
+ this(UUID.randomUUID().toString(), new ChatHistory());
+ }
+
+ /**
+ * Constructor for com.microsoft.semantickernel.agents.chatcompletion.ChatHistoryAgentThread.
+ *
+ * @param id The ID of the thread.
+ * @param chatHistory The chat history.
+ */
+ public ChatHistoryAgentThread(String id, @Nullable ChatHistory chatHistory) {
+ super(id);
+ this.chatHistory = chatHistory != null ? chatHistory : new ChatHistory();
+ }
+
+ /**
+ * Get the chat history.
+ *
+ * @return The chat history.
+ */
+ @SuppressFBWarnings("EI_EXPOSE_REP")
+ public ChatHistory getChatHistory() {
+ return chatHistory;
+ }
+
+ @Override
+ public Mono createAsync() {
+ if (this.id == null) {
+ this.id = UUID.randomUUID().toString();
+ chatHistory = new ChatHistory();
+ }
+ return Mono.just(id);
+ }
+
+ @Override
+ public Mono deleteAsync() {
+ return Mono.fromRunnable(chatHistory::clear);
+ }
+
+ /**
+ * Create a copy of the thread.
+ *
+ * @return A new instance of the thread.
+ */
+ @Override
+ public ChatHistoryAgentThread copy() {
+ return new ChatHistoryAgentThread(this.id, new ChatHistory(chatHistory.getMessages()));
+ }
+
+ @Override
+ public Mono onNewMessageAsync(ChatMessageContent> newMessage) {
+ return Mono.fromRunnable(() -> {
+ chatHistory.addMessage(newMessage);
+ });
+ }
+
+ public List> getMessages() {
+ return chatHistory.getMessages();
+ }
+
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder implements SemanticKernelBuilder {
+ private String id;
+ private ChatHistory chatHistory;
+
+ /**
+ * Set the ID of the thread.
+ *
+ * @param id The ID of the thread.
+ * @return The builder instance.
+ */
+ public Builder withId(String id) {
+ this.id = id;
+ return this;
+ }
+
+ /**
+ * Set the chat history.
+ *
+ * @param chatHistory The chat history.
+ * @return The builder instance.
+ */
+ @SuppressFBWarnings("EI_EXPOSE_REP2")
+ public Builder withChatHistory(ChatHistory chatHistory) {
+ this.chatHistory = chatHistory;
+ return this;
+ }
+
+ @Override
+ public ChatHistoryAgentThread build() {
+ return new ChatHistoryAgentThread(id, chatHistory);
+ }
+ }
+}
diff --git a/pom.xml b/pom.xml
index 30963f54b..0d31715dd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -77,6 +77,7 @@
data/semantickernel-data-azureaisearch
data/semantickernel-data-jdbc
data/semantickernel-data-redis
+ agents/semantickernel-agents-core
diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml b/samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml
index 1f6bc1811..3ccc114c1 100644
--- a/samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml
+++ b/samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml
@@ -49,6 +49,11 @@
semantickernel-data-redis
+
+ com.microsoft.semantic-kernel
+ semantickernel-agents-core
+
+
com.microsoft.semantic-kernel
semantickernel-experimental
diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/github/GitHubModel.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/github/GitHubModel.java
new file mode 100644
index 000000000..180ec8ed2
--- /dev/null
+++ b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/github/GitHubModel.java
@@ -0,0 +1,219 @@
+package com.microsoft.semantickernel.samples.plugins.github;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public abstract class GitHubModel {
+ public final static ObjectMapper objectMapper = new ObjectMapper()
+ .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+ @Override
+ public String toString() {
+ try {
+ return objectMapper.writeValueAsString(this);
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static class User extends GitHubModel {
+ @JsonProperty("login")
+ private String login;
+ @JsonProperty("id")
+ private long id;
+ @JsonProperty("name")
+ private String name;
+ @JsonProperty("company")
+ private String company;
+ @JsonProperty("html_url")
+ private String url;
+ @JsonCreator
+ public User(@JsonProperty("login") String login,
+ @JsonProperty("id") long id,
+ @JsonProperty("name") String name,
+ @JsonProperty("company") String company,
+ @JsonProperty("html_url") String url) {
+ this.login = login;
+ this.id = id;
+ this.name = name;
+ this.company = company;
+ this.url = url;
+ }
+
+ public String getLogin() {
+ return login;
+ }
+ public long getId() {
+ return id;
+ }
+ public String getName() {
+ return name;
+ }
+ public String getCompany() {
+ return company;
+ }
+ public String getUrl() {
+ return url;
+ }
+ }
+
+ public static class Repository extends GitHubModel {
+ @JsonProperty("id")
+ private long id;
+ @JsonProperty("full_name")
+ private String name;
+ @JsonProperty("description")
+ private String description;
+ @JsonProperty("html_url")
+ private String url;
+ @JsonCreator
+ public Repository(@JsonProperty("id") long id,
+ @JsonProperty("full_name") String name,
+ @JsonProperty("description") String description,
+ @JsonProperty("html_url") String url) {
+ this.id = id;
+ this.name = name;
+ this.description = description;
+ this.url = url;
+ }
+
+ public long getId() {
+ return id;
+ }
+ public String getName() {
+ return name;
+ }
+ public String getDescription() {
+ return description;
+ }
+ public String getUrl() {
+ return url;
+ }
+
+ @Override
+ public String toString() {
+ try {
+ return objectMapper.writeValueAsString(this);
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ public static class Issue extends GitHubModel {
+ @JsonProperty("id")
+ private long id;
+ @JsonProperty("number")
+ private long number;
+ @JsonProperty("title")
+ private String title;
+ @JsonProperty("state")
+ private String state;
+ @JsonProperty("html_url")
+ private String url;
+ @JsonProperty("labels")
+ private Label[] labels;
+ @JsonProperty("created_at")
+ private String createdAt;
+ @JsonProperty("closed_at")
+ private String closedAt;
+
+ @JsonCreator
+ public Issue(@JsonProperty("id") long id,
+ @JsonProperty("number") long number,
+ @JsonProperty("title") String title,
+ @JsonProperty("state") String state,
+ @JsonProperty("html_url") String url,
+ @JsonProperty("labels") Label[] labels,
+ @JsonProperty("created_at") String createdAt,
+ @JsonProperty("closed_at") String closedAt) {
+ this.id = id;
+ this.number = number;
+ this.title = title;
+ this.state = state;
+ this.url = url;
+ this.labels = labels;
+ this.createdAt = createdAt;
+ this.closedAt = closedAt;
+ }
+
+ public long getId() {
+ return id;
+ }
+ public long getNumber() {
+ return number;
+ }
+ public String getTitle() {
+ return title;
+ }
+ public String getState() {
+ return state;
+ }
+ public String getUrl() {
+ return url;
+ }
+ public Label[] getLabels() {
+ return labels;
+ }
+ public String getCreatedAt() {
+ return createdAt;
+ }
+ public String getClosedAt() {
+ return closedAt;
+ }
+ }
+
+ public static class IssueDetail extends Issue {
+ @JsonProperty("body")
+ private String body;
+
+ @JsonCreator
+ public IssueDetail(@JsonProperty("id") long id,
+ @JsonProperty("number") long number,
+ @JsonProperty("title") String title,
+ @JsonProperty("state") String state,
+ @JsonProperty("html_url") String url,
+ @JsonProperty("labels") Label[] labels,
+ @JsonProperty("created_at") String createdAt,
+ @JsonProperty("closed_at") String closedAt,
+ @JsonProperty("body") String body) {
+ super(id, number, title, state, url, labels, createdAt, closedAt);
+ this.body = body;
+ }
+
+ public String getBody() {
+ return body;
+ }
+ }
+
+ public static class Label extends GitHubModel {
+ @JsonProperty("id")
+ private long id;
+ @JsonProperty("name")
+ private String name;
+ @JsonProperty("description")
+ private String description;
+
+ @JsonCreator
+ public Label(@JsonProperty("id") long id,
+ @JsonProperty("name") String name,
+ @JsonProperty("description") String description) {
+ this.id = id;
+ this.name = name;
+ this.description = description;
+ }
+
+ public long getId() {
+ return id;
+ }
+ public String getName() {
+ return name;
+ }
+ public String getDescription() {
+ return description;
+ }
+ }
+}
diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/github/GitHubPlugin.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/github/GitHubPlugin.java
new file mode 100644
index 000000000..d3c59a152
--- /dev/null
+++ b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/github/GitHubPlugin.java
@@ -0,0 +1,165 @@
+package com.microsoft.semantickernel.samples.plugins.github;
+
+import reactor.core.publisher.Mono;
+import reactor.netty.http.client.HttpClient;
+import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction;
+import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter;
+
+import java.io.IOException;
+import java.util.List;
+
+public class GitHubPlugin {
+ public static final String baseUrl = "https://api.github.com";
+ private final String token;
+
+ public GitHubPlugin(String token) {
+ this.token = token;
+ }
+
+ @DefineKernelFunction(name = "get_user_info", description = "Get user information from GitHub",
+ returnType = "com.microsoft.semantickernel.samples.plugins.github.GitHubModel$User")
+ public Mono getUserProfileAsync() {
+ HttpClient client = createClient();
+
+ return makeRequestAsync(client, "/user")
+ .map(json -> {
+ try {
+ return GitHubModel.objectMapper.readValue(json, GitHubModel.User.class);
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to deserialize GitHubUser", e);
+ }
+ });
+ }
+
+ @DefineKernelFunction(name = "get_repo_info", description = "Get repository information from GitHub",
+ returnType = "com.microsoft.semantickernel.samples.plugins.github.GitHubModel$Repository")
+ public Mono getRepositoryAsync(
+ @KernelFunctionParameter(
+ name = "organization",
+ description = "The name of the repository to retrieve information for"
+ ) String organization,
+ @KernelFunctionParameter(
+ name = "repo_name",
+ description = "The name of the repository to retrieve information for"
+ ) String repoName
+ ) {
+ HttpClient client = createClient();
+
+ return makeRequestAsync(client, String.format("/repos/%s/%s", organization, repoName))
+ .map(json -> {
+ try {
+ return GitHubModel.objectMapper.readValue(json, GitHubModel.Repository.class);
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to deserialize GitHubRepository", e);
+ }
+ });
+ }
+
+ @DefineKernelFunction(name = "get_issues", description = "Get issues from GitHub",
+ returnType = "java.util.List")
+ public Mono> getIssuesAsync(
+ @KernelFunctionParameter(
+ name = "organization",
+ description = "The name of the organization to retrieve issues for"
+ ) String organization,
+ @KernelFunctionParameter(
+ name = "repo_name",
+ description = "The name of the repository to retrieve issues for"
+ ) String repoName,
+ @KernelFunctionParameter(
+ name = "max_results",
+ description = "The maximum number of issues to retrieve",
+ required = false,
+ defaultValue = "10",
+ type = int.class
+ ) int maxResults,
+ @KernelFunctionParameter(
+ name = "state",
+ description = "The state of the issues to retrieve",
+ required = false,
+ defaultValue = "open"
+ ) String state,
+ @KernelFunctionParameter(
+ name = "assignee",
+ description = "The assignee of the issues to retrieve",
+ required = false
+ ) String assignee
+ ) {
+ HttpClient client = createClient();
+
+ String query = String.format("/repos/%s/%s/issues", organization, repoName);
+ query = buildQueryString(query, "state", state);
+ query = buildQueryString(query, "assignee", assignee);
+ query = buildQueryString(query, "per_page", String.valueOf(maxResults));
+
+ return makeRequestAsync(client, query)
+ .flatMap(json -> {
+ try {
+ GitHubModel.Issue[] issues = GitHubModel.objectMapper.readValue(json, GitHubModel.Issue[].class);
+ return Mono.just(List.of(issues));
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to deserialize GitHubIssues", e);
+ }
+ });
+ }
+
+ @DefineKernelFunction(name = "get_issue_detail_info", description = "Get detail information of a single issue from GitHub",
+ returnType = "com.microsoft.semantickernel.samples.plugins.github.GitHubModel$IssueDetail")
+ public GitHubModel.IssueDetail getIssueDetailAsync(
+ @KernelFunctionParameter(
+ name = "organization",
+ description = "The name of the repository to retrieve information for"
+ ) String organization,
+ @KernelFunctionParameter(
+ name = "repo_name",
+ description = "The name of the repository to retrieve information for"
+ ) String repoName,
+ @KernelFunctionParameter(
+ name = "issue_number",
+ description = "The issue number to retrieve information for",
+ type = int.class
+ ) int issueNumber
+ ) {
+ HttpClient client = createClient();
+
+ return makeRequestAsync(client, String.format("/repos/%s/%s/issues/%d", organization, repoName, issueNumber))
+ .map(json -> {
+ try {
+ return GitHubModel.objectMapper.readValue(json, GitHubModel.IssueDetail.class);
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to deserialize GitHubIssue", e);
+ }
+ }).block();
+ }
+
+ private HttpClient createClient() {
+ return HttpClient.create()
+ .baseUrl(baseUrl)
+ .headers(headers -> {
+ headers.add("User-Agent", "request");
+ headers.add("Accept", "application/vnd.github+json");
+ headers.add("Authorization", "Bearer " + token);
+ headers.add("X-GitHub-Api-Version", "2022-11-28");
+ });
+ }
+
+ private static String buildQueryString(String path, String param, String value) {
+ if (value == null || value.isEmpty() || value.equals(KernelFunctionParameter.NO_DEFAULT_VALUE)) {
+ return path;
+ }
+
+ return path + (path.contains("?") ? "&" : "?") + param + "=" + value;
+ }
+
+ private Mono makeRequestAsync(HttpClient client, String path) {
+ return client
+ .get()
+ .uri(path)
+ .responseSingle((res, content) -> {
+ if (res.status().code() != 200) {
+ return Mono.error(new IllegalStateException("Request failed: " + res.status()));
+ }
+ return content.asString();
+ });
+ }
+}
diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/agents/CompletionAgent.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/agents/CompletionAgent.java
new file mode 100644
index 000000000..1e5a665a9
--- /dev/null
+++ b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/agents/CompletionAgent.java
@@ -0,0 +1,140 @@
+package com.microsoft.semantickernel.samples.syntaxexamples.agents;
+
+import com.azure.ai.openai.OpenAIAsyncClient;
+import com.azure.ai.openai.OpenAIClientBuilder;
+import com.azure.core.credential.AzureKeyCredential;
+import com.azure.core.credential.KeyCredential;
+import com.microsoft.semantickernel.Kernel;
+import com.microsoft.semantickernel.agents.AgentInvokeOptions;
+import com.microsoft.semantickernel.agents.chatcompletion.ChatCompletionAgent;
+import com.microsoft.semantickernel.agents.chatcompletion.ChatHistoryAgentThread;
+import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion;
+import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter;
+import com.microsoft.semantickernel.contextvariables.ContextVariableTypes;
+import com.microsoft.semantickernel.implementation.templateengine.tokenizer.DefaultPromptTemplate;
+import com.microsoft.semantickernel.orchestration.InvocationContext;
+import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
+import com.microsoft.semantickernel.orchestration.ToolCallBehavior;
+import com.microsoft.semantickernel.plugin.KernelPluginFactory;
+import com.microsoft.semantickernel.samples.plugins.github.GitHubModel;
+import com.microsoft.semantickernel.samples.plugins.github.GitHubPlugin;
+import com.microsoft.semantickernel.semanticfunctions.KernelArguments;
+import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
+import com.microsoft.semantickernel.services.chatcompletion.AuthorRole;
+import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
+import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent;
+
+import java.util.List;
+import java.util.Scanner;
+
+public class CompletionAgent {
+ private static final String CLIENT_KEY = System.getenv("CLIENT_KEY");
+ private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY");
+
+ // Only required if AZURE_CLIENT_KEY is set
+ private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT");
+ private static final String MODEL_ID = System.getenv()
+ .getOrDefault("MODEL_ID", "gpt-4o");
+
+ private static final String GITHUB_PAT = System.getenv("GITHUB_PAT");
+ public static void main(String[] args) {
+ System.out.println("======== ChatCompletion Agent ========");
+
+ OpenAIAsyncClient client;
+
+ if (AZURE_CLIENT_KEY != null) {
+ client = new OpenAIClientBuilder()
+ .credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
+ .endpoint(CLIENT_ENDPOINT)
+ .buildAsyncClient();
+
+ } else {
+ client = new OpenAIClientBuilder()
+ .credential(new KeyCredential(CLIENT_KEY))
+ .buildAsyncClient();
+ }
+
+ System.out.println("------------------------");
+
+ ChatCompletionService chatCompletion = OpenAIChatCompletion.builder()
+ .withModelId(MODEL_ID)
+ .withOpenAIAsyncClient(client)
+ .build();
+
+ Kernel kernel = Kernel.builder()
+ .withAIService(ChatCompletionService.class, chatCompletion)
+ .withPlugin(KernelPluginFactory.createFromObject(new GitHubPlugin(GITHUB_PAT),
+ "GitHubPlugin"))
+ .build();
+
+ InvocationContext invocationContext = InvocationContext.builder()
+ .withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true))
+ .withContextVariableConverter(new ContextVariableTypeConverter<>(
+ GitHubModel.Issue.class,
+ o -> (GitHubModel.Issue) o,
+ o -> o.toString(),
+ s -> null
+ ))
+ .build();
+
+ ChatCompletionAgent agent = ChatCompletionAgent.builder()
+ .withKernel(kernel)
+ .withKernelArguments(
+ KernelArguments.builder()
+ .withVariable("repository", "microsoft/semantic-kernel-java")
+ .withExecutionSettings(PromptExecutionSettings.builder()
+ .build())
+ .build()
+ )
+ .withInvocationContext(invocationContext)
+ .withTemplate(
+ DefaultPromptTemplate.build(
+ PromptTemplateConfig.builder()
+ .withTemplate(
+ """
+ You are an agent designed to query and retrieve information from a single GitHub repository in a read-only manner.
+ You are also able to access the profile of the active user.
+
+ Use the current date and time to provide up-to-date details or time-sensitive responses.
+
+ The repository you are querying is a public repository with the following name: {{$repository}}
+
+ The current date and time is: {{$now}}.
+ """
+ )
+ .build()
+ )
+ ).build();
+
+ ChatHistoryAgentThread agentThread = new ChatHistoryAgentThread();
+ Scanner scanner = new Scanner(System.in);
+
+ while (true) {
+ System.out.print("> ");
+
+ String input = scanner.nextLine();
+ if (input.equalsIgnoreCase("exit")) {
+ break;
+ }
+
+ var message = new ChatMessageContent<>(AuthorRole.USER, input);
+ KernelArguments arguments = KernelArguments.builder()
+ .withVariable("now", System.currentTimeMillis())
+ .build();
+
+ var response = agent.invokeAsync(
+ List.of(message),
+ agentThread,
+ AgentInvokeOptions.builder()
+ .withKernel(kernel)
+ .withKernelArguments(arguments)
+ .build()
+ ).block();
+
+ var lastResponse = response.get(response.size() - 1);
+
+ System.out.println("> " + lastResponse.getMessage());
+ agentThread = (ChatHistoryAgentThread) lastResponse.getThread();
+ }
+ }
+}
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/Agent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/Agent.java
new file mode 100644
index 000000000..3a82550c6
--- /dev/null
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/Agent.java
@@ -0,0 +1,62 @@
+package com.microsoft.semantickernel.agents;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import com.microsoft.semantickernel.Kernel;
+import com.microsoft.semantickernel.orchestration.InvocationContext;
+import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
+import com.microsoft.semantickernel.semanticfunctions.KernelArguments;
+import com.microsoft.semantickernel.semanticfunctions.PromptTemplate;
+import com.microsoft.semantickernel.services.chatcompletion.ChatHistory;
+import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+/**
+ * Interface for a semantic kernel agent.
+ */
+public interface Agent {
+
+ /**
+ * Gets the agent's ID.
+ *
+ * @return The agent's ID
+ */
+ String getId();
+
+ /**
+ * Gets the agent's name.
+ *
+ * @return The agent's name
+ */
+ String getName();
+
+ /**
+ * Gets the agent's description.
+ *
+ * @return The agent's description
+ */
+ String getDescription();
+
+ /**
+ * Invoke the agent with the given chat history.
+ *
+ * @param messages The chat history to process
+ * @param thread The agent thread to use
+ * @param options The options for invoking the agent
+ * @return A Mono containing the agent response
+ */
+ Mono>>> invokeAsync(List> messages, AgentThread thread, AgentInvokeOptions options);
+
+ /**
+ * Notifies the agent of a new message.
+ *
+ * @param thread The agent thread to use
+ */
+ Mono notifyThreadOfNewMessageAsync(AgentThread thread, ChatMessageContent> newMessage);
+}
\ No newline at end of file
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/AgentInvokeOptions.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/AgentInvokeOptions.java
new file mode 100644
index 000000000..3fb4cba18
--- /dev/null
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/AgentInvokeOptions.java
@@ -0,0 +1,159 @@
+package com.microsoft.semantickernel.agents;
+
+import com.microsoft.semantickernel.Kernel;
+import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
+import com.microsoft.semantickernel.orchestration.InvocationContext;
+import com.microsoft.semantickernel.semanticfunctions.KernelArguments;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+import javax.annotation.Nullable;
+
+/**
+ * Options for invoking an agent.
+ */
+public class AgentInvokeOptions {
+
+ private final KernelArguments kernelArguments;
+ private final Kernel kernel;
+ private final String additionalInstructions;
+ private final InvocationContext invocationContext;
+
+ /**
+ * Default constructor for AgentInvokeOptions.
+ */
+ public AgentInvokeOptions() {
+ this(null, null, null, null);
+ }
+
+ /**
+ * Constructor for AgentInvokeOptions.
+ *
+ * @param kernelArguments The arguments for the kernel function.
+ * @param kernel The kernel to use.
+ * @param additionalInstructions Additional instructions for the agent.
+ * @param invocationContext The invocation context.
+ */
+ public AgentInvokeOptions(@Nullable KernelArguments kernelArguments,
+ @Nullable Kernel kernel,
+ @Nullable String additionalInstructions,
+ @Nullable InvocationContext invocationContext) {
+ this.kernelArguments = kernelArguments != null ? kernelArguments.copy() : null;
+ this.kernel = kernel;
+ this.additionalInstructions = additionalInstructions;
+ this.invocationContext = invocationContext;
+ }
+
+ /**
+ * Get the kernel arguments.
+ *
+ * @return The kernel arguments.
+ */
+ @SuppressFBWarnings("EI_EXPOSE_REP")
+ public KernelArguments getKernelArguments() {
+ return kernelArguments;
+ }
+
+ /**
+ * Get the kernel.
+ *
+ * @return The kernel.
+ */
+ public Kernel getKernel() {
+ return kernel;
+ }
+
+ /**
+ * Get additional instructions.
+ *
+ * @return The additional instructions.
+ */
+ public String getAdditionalInstructions() {
+ return additionalInstructions;
+ }
+
+ /**
+ * Get the invocation context.
+ *
+ * @return The invocation context.
+ */
+ public InvocationContext getInvocationContext() {
+ return invocationContext;
+ }
+
+
+
+ /**
+ * Builder for AgentInvokeOptions.
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder implements SemanticKernelBuilder {
+
+ private KernelArguments kernelArguments;
+ private Kernel kernel;
+ private String additionalInstructions;
+ private InvocationContext invocationContext;
+
+ /**
+ * Set the kernel arguments.
+ *
+ * @param kernelArguments The kernel arguments.
+ * @return The builder.
+ */
+ @SuppressFBWarnings("EI_EXPOSE_REP2")
+ public Builder withKernelArguments(KernelArguments kernelArguments) {
+ this.kernelArguments = kernelArguments;
+ return this;
+ }
+
+ /**
+ * Set the kernel.
+ *
+ * @param kernel The kernel.
+ * @return The builder.
+ */
+ public Builder withKernel(Kernel kernel) {
+ this.kernel = kernel;
+ return this;
+ }
+
+ /**
+ * Set additional instructions.
+ *
+ * @param additionalInstructions The additional instructions.
+ * @return The builder.
+ */
+ public Builder withAdditionalInstructions(String additionalInstructions) {
+ this.additionalInstructions = additionalInstructions;
+ return this;
+ }
+
+ /**
+ * Set the invocation context.
+ *
+ * @param invocationContext The invocation context.
+ * @return The builder.
+ */
+ public Builder withInvocationContext(InvocationContext invocationContext) {
+ this.invocationContext = invocationContext;
+ return this;
+ }
+
+ /**
+ * Build the object.
+ *
+ * @return a constructed object.
+ */
+ @Override
+ public AgentInvokeOptions build() {
+ return new AgentInvokeOptions(
+ kernelArguments,
+ kernel,
+ additionalInstructions,
+ invocationContext
+ );
+ }
+ }
+}
\ No newline at end of file
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/AgentResponseItem.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/AgentResponseItem.java
new file mode 100644
index 000000000..f585bfeab
--- /dev/null
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/AgentResponseItem.java
@@ -0,0 +1,33 @@
+package com.microsoft.semantickernel.agents;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+public class AgentResponseItem {
+ private final T message;
+ private final AgentThread thread;
+
+ @SuppressFBWarnings("EI_EXPOSE_REP2")
+ public AgentResponseItem(T message, AgentThread thread) {
+ this.message = message;
+ this.thread = thread;
+ }
+
+ /**
+ * Gets the agent response message.
+ *
+ * @return The message.
+ */
+ public T getMessage() {
+ return message;
+ }
+
+ /**
+ * Gets the thread.
+ *
+ * @return The thread.
+ */
+ @SuppressFBWarnings("EI_EXPOSE_REP")
+ public AgentThread getThread() {
+ return thread;
+ }
+}
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/AgentThread.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/AgentThread.java
new file mode 100644
index 000000000..d369d999d
--- /dev/null
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/AgentThread.java
@@ -0,0 +1,52 @@
+package com.microsoft.semantickernel.agents;
+
+import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent;
+import reactor.core.publisher.Mono;
+
+/**
+ * Interface for an agent thread.
+ */
+public interface AgentThread {
+ /**
+ * Get the thread ID.
+ *
+ * @return The thread ID.
+ */
+ String getId();
+
+ /**
+ * Create a new thread.
+ *
+ * @return A Mono containing the thread ID.
+ */
+ Mono createAsync();
+
+ /**
+ * Delete the thread.
+ *
+ * @return A Mono indicating completion.
+ */
+ Mono deleteAsync();
+
+ /**
+ * Check if the thread is deleted.
+ *
+ * @return A Mono containing true if the thread is deleted, false otherwise.
+ */
+ boolean isDeleted();
+
+ /**
+ * Create a copy of the thread.
+ *
+ * @return A new instance of the thread.
+ */
+ AgentThread copy();
+
+ /**
+ * Handle a new message in the thread.
+ *
+ * @param newMessage The new message to handle.
+ * @return A Mono indicating completion.
+ */
+ Mono onNewMessageAsync(ChatMessageContent> newMessage);
+}
\ No newline at end of file
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/BaseAgentThread.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/BaseAgentThread.java
new file mode 100644
index 000000000..b7c97eea9
--- /dev/null
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/BaseAgentThread.java
@@ -0,0 +1,23 @@
+package com.microsoft.semantickernel.agents;
+
+public abstract class BaseAgentThread implements AgentThread {
+
+ protected String id;
+ protected boolean isDeleted;
+
+ public BaseAgentThread() {
+ }
+
+ public BaseAgentThread(String id) {
+ this.id = id;
+ }
+
+ @Override
+ public String getId() {
+ return id;
+ }
+ @Override
+ public boolean isDeleted() {
+ return isDeleted;
+ }
+}
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/KernelAgent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/KernelAgent.java
new file mode 100644
index 000000000..71e81951d
--- /dev/null
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/KernelAgent.java
@@ -0,0 +1,170 @@
+package com.microsoft.semantickernel.agents;
+
+import com.microsoft.semantickernel.Kernel;
+import com.microsoft.semantickernel.orchestration.InvocationContext;
+import com.microsoft.semantickernel.orchestration.InvocationReturnMode;
+import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
+import com.microsoft.semantickernel.semanticfunctions.KernelArguments;
+import com.microsoft.semantickernel.semanticfunctions.PromptTemplate;
+import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.function.Supplier;
+
+public abstract class KernelAgent implements Agent {
+
+ protected final String id;
+ protected final String name;
+ protected final String description;
+ protected final Kernel kernel;
+ protected final KernelArguments kernelArguments;
+ protected final InvocationContext invocationContext;
+ protected final String instructions;
+ protected final PromptTemplate template;
+
+ protected KernelAgent(
+ String id,
+ String name,
+ String description,
+ Kernel kernel,
+ KernelArguments kernelArguments,
+ InvocationContext invocationContext,
+ String instructions,
+ PromptTemplate template
+ ) {
+ this.id = id != null ? id : UUID.randomUUID().toString();
+ this.name = name;
+ this.description = description;
+ this.kernel = kernel;
+ this.kernelArguments = kernelArguments != null
+ ? kernelArguments.copy() : KernelArguments.builder().build();
+ this.invocationContext = invocationContext != null
+ ? invocationContext : InvocationContext.builder().build();
+ this.instructions = instructions;
+ this.template = template;
+ }
+
+ /**
+ * Gets the agent's ID.
+ *
+ * @return The agent's ID
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Gets the agent's name.
+ *
+ * @return The agent's name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Gets the agent's description.
+ *
+ * @return The agent's description
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Gets the kernel used by the agent.
+ *
+ * @return The kernel used by the agent
+ */
+ public Kernel getKernel() {
+ return kernel;
+ }
+
+ /**
+ * Gets the invocation context used by the agent.
+ *
+ * @return The invocation context used by the agent
+ */
+ @SuppressFBWarnings("EI_EXPOSE_REP")
+ public KernelArguments getKernelArguments() {
+ return kernelArguments;
+ }
+
+ /**
+ * Gets the invocation context used by the agent.
+ *
+ * @return The invocation context used by the agent
+ */
+ public String getInstructions() {
+ return instructions;
+ }
+
+ /**
+ * Gets the invocation context used by the agent.
+ *
+ * @return The invocation context used by the agent
+ */
+ public PromptTemplate getTemplate() {
+ return template;
+ }
+
+
+ /**
+ * Merges the provided arguments with the current arguments.
+ * Provided arguments will override the current arguments.
+ *
+ * @param arguments The arguments to merge with the current arguments.
+ */
+ protected KernelArguments mergeArguments(KernelArguments arguments) {
+ if (arguments == null) {
+ return kernelArguments;
+ }
+
+ Map executionSettings = new HashMap<>(kernelArguments.getExecutionSettings());
+ executionSettings.putAll(arguments.getExecutionSettings());
+
+ return KernelArguments.builder()
+ .withVariables(kernelArguments)
+ .withVariables(arguments)
+ .withExecutionSettings(executionSettings)
+ .build();
+ }
+
+ /**
+ * Formats the instructions using the provided kernel, arguments, and context.
+ *
+ * @param kernel The kernel to use for formatting.
+ * @param arguments The arguments to use for formatting.
+ * @param context The context to use for formatting.
+ * @return A Mono that resolves to the formatted instructions.
+ */
+ protected Mono renderInstructionsAsync(Kernel kernel, KernelArguments arguments, InvocationContext context) {
+ if (template != null) {
+ return template.renderAsync(kernel, arguments, context);
+ } else {
+ return Mono.just(instructions);
+ }
+ }
+
+ protected Mono ensureThreadExistsWithMessagesAsync(List> messages, AgentThread thread, Supplier threadSupplier) {
+ return Mono.defer(() -> {
+ // Check if the thread already exists
+ // If it does, we can work with a copy of it
+ AgentThread newThread = thread == null ? threadSupplier.get() : thread.copy();
+
+ return newThread.createAsync()
+ .thenMany(Flux.fromIterable(messages))
+ .concatMap(message -> {
+ return notifyThreadOfNewMessageAsync(newThread, message)
+ .then(Mono.just(message));
+ })
+ .then(Mono.just((T) newThread));
+ });
+ }
+}
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/ChatHistory.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/ChatHistory.java
index 25cd8ea89..df5f18322 100644
--- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/ChatHistory.java
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/ChatHistory.java
@@ -187,6 +187,13 @@ public ChatHistory addSystemMessage(String content) {
return addMessage(AuthorRole.SYSTEM, content);
}
+ /**
+ * Clear the chat history
+ */
+ public void clear() {
+ chatMessageContents.clear();
+ }
+
/**
* Add all messages to the chat history
* @param messages The messages to add to the chat history
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/ChatMessageContent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/ChatMessageContent.java
index 9784648b3..0408860e9 100644
--- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/ChatMessageContent.java
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/ChatMessageContent.java
@@ -23,7 +23,6 @@
* @param the type of the inner content within the messages
*/
public class ChatMessageContent extends KernelContentImpl {
-
private final AuthorRole authorRole;
@Nullable
private final String content;
@@ -52,6 +51,28 @@ public ChatMessageContent(
null);
}
+ /**
+ * Creates a new instance of the {@link ChatMessageContent} class. Defaults to
+ * {@link ChatMessageContentType#TEXT} content type.
+ *
+ * @param authorRole the author role that generated the content
+ * @param authorName the author name
+ * @param content the content
+ */
+ public ChatMessageContent(
+ AuthorRole authorRole,
+ String authorName,
+ String content) {
+ this(
+ authorRole,
+ authorName,
+ content,
+ null,
+ null,
+ null,
+ null);
+ }
+
/**
* Creates a new instance of the {@link ChatMessageContent} class. Defaults to
* {@link ChatMessageContentType#TEXT} content type.
diff --git a/semantickernel-bom/pom.xml b/semantickernel-bom/pom.xml
index bb4d766fd..32ca102b1 100644
--- a/semantickernel-bom/pom.xml
+++ b/semantickernel-bom/pom.xml
@@ -112,6 +112,12 @@
${project.version}
+
+ com.microsoft.semantic-kernel
+ semantickernel-agents-core
+ ${project.version}
+
+
com.azure
azure-ai-openai