diff --git a/pom.xml b/pom.xml
index 11f44de..29ed5af 100755
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
lm-lib
de.extio
lm-lib
- 1.6.4
+ 1.6.6
21
diff --git a/src/main/java/de/extio/lmlib/agent/Agent.java b/src/main/java/de/extio/lmlib/agent/Agent.java
index 08c085a..7724214 100755
--- a/src/main/java/de/extio/lmlib/agent/Agent.java
+++ b/src/main/java/de/extio/lmlib/agent/Agent.java
@@ -27,6 +27,14 @@ public record Agent(String name,
throw new IllegalArgumentException("Agent type cannot be null");
}
}
+
+ @Override
+ public AgentType agentType(final AgentContext context) {
+ if (agentType != null) {
+ return agentType;
+ }
+ return BaseAgent.super.agentType(context);
+ }
@Override
public void preProcess(final AgentContext context) {
diff --git a/src/main/java/de/extio/lmlib/agent/AgentExecutorService.java b/src/main/java/de/extio/lmlib/agent/AgentExecutorService.java
index 267a4f0..175a284 100755
--- a/src/main/java/de/extio/lmlib/agent/AgentExecutorService.java
+++ b/src/main/java/de/extio/lmlib/agent/AgentExecutorService.java
@@ -67,7 +67,7 @@ public class AgentExecutorService implements InitializingBean, DisposableBean {
LOGGER.debug("Agent: {}", agent.name());
Client client = null;
- if (agent.agentType() != AgentType.PROCESSING_ONLY) {
+ if (agent.agentType(context) != AgentType.PROCESSING_ONLY) {
client = this.clientService.getClient(agent.modelCategory());
}
context.setAgentContextUpdateConsumer(agentContextUpdateConsumer);
diff --git a/src/main/java/de/extio/lmlib/agent/BaseAgent.java b/src/main/java/de/extio/lmlib/agent/BaseAgent.java
index 066a006..50b114b 100644
--- a/src/main/java/de/extio/lmlib/agent/BaseAgent.java
+++ b/src/main/java/de/extio/lmlib/agent/BaseAgent.java
@@ -34,10 +34,6 @@ public interface BaseAgent {
throw new UnsupportedOperationException("Name must be implemented in the agent");
}
- default AgentType agentType() {
- throw new UnsupportedOperationException("Agent type must be implemented in the agent");
- }
-
default ModelCategory modelCategory() {
return ModelCategory.MEDIUM;
}
@@ -53,6 +49,10 @@ public interface BaseAgent {
default AgentResponseHandler responseHandler() {
return new TextAgentResponseHandler("response");
}
+
+ default AgentType agentType(final AgentContext context) {
+ throw new UnsupportedOperationException("Agent type must be implemented in the agent");
+ }
default void preProcess(final AgentContext context) {
@@ -82,7 +82,7 @@ public interface BaseAgent {
for (final var split : splits) {
tasks.add(CompletableFuture.runAsync(() -> {
try {
- final boolean skipCompletion = split.context().isSkipNextCompletion() || this.agentType() == AgentType.PROCESSING_ONLY;
+ final boolean skipCompletion = split.context().isSkipNextCompletion() || this.agentType(split.context()) == AgentType.PROCESSING_ONLY;
if (skipCompletion) {
split.context().setSkipNextCompletion(false);
split.context().getGraph().add("○");
@@ -263,13 +263,23 @@ public interface BaseAgent {
conversation = Conversation.create(this.systemPrompt(), split.text());
split.context().setConversation(conversation);
}
- else if (this.agentType() == AgentType.START_CONVERSATION) {
- conversation = Conversation.create(this.systemPrompt() + "\n" + split.text());
+ else if (this.agentType(split.context()) == AgentType.START_CONVERSATION) {
+ if (this.systemPrompt() == null || this.systemPrompt().isEmpty()) {
+ conversation = Conversation.create(split.text());
+ }
+ else {
+ conversation = Conversation.create(this.systemPrompt() + "\n" + split.text());
+ }
split.context().setConversation(conversation);
}
else {
- if (conversation.getConversation().get(0).type() == TurnType.SYSTEM && this.agentType() != AgentType.CONVERSATION_WITH_SYSTEM_PROMPT) {
- final var mergedSysAndUser = conversation.getConversation().get(0).text() + "\n" + conversation.getConversation().get(1).text();
+ if (conversation.getConversation().get(0).type() == TurnType.SYSTEM && this.agentType(split.context()) != AgentType.CONVERSATION_WITH_SYSTEM_PROMPT) {
+ final String mergedSysAndUser;
+ if (conversation.getConversation().size() > 1) {
+ mergedSysAndUser = conversation.getConversation().get(0).text() + "\n" + conversation.getConversation().get(1).text();
+ } else {
+ mergedSysAndUser = conversation.getConversation().get(0).text();
+ }
final var newConversation = Conversation.create(mergedSysAndUser);
for (int n = 2; n < conversation.getConversation().size(); n++) {
@@ -280,7 +290,12 @@ public interface BaseAgent {
conversation = newConversation;
}
if (conversation.getConversation().get(conversation.getConversation().size() - 1).type() == TurnType.ASSISTANT) {
- conversation.addTurn(new Conversation.Turn(TurnType.USER, String.join("\n", this.systemPrompt(), split.text())));
+ if (this.systemPrompt() == null || this.systemPrompt().isEmpty() ||conversation.getConversation().size() > 1) {
+ conversation.addTurn(new Conversation.Turn(TurnType.USER, split.text()));
+ }
+ else {
+ conversation.addTurn(new Conversation.Turn(TurnType.USER, String.join("\n", this.systemPrompt(), split.text())));
+ }
}
}
return conversation;
@@ -312,30 +327,30 @@ public interface BaseAgent {
context.setNextAgent(null);
}
- case final BaseAgent a when a.agentType() == AgentType.COMPLETION -> {
+ case final BaseAgent a when a.agentType(context) == AgentType.COMPLETION -> {
context.getGraph().add("→");
context.setConversation(null);
}
- case final BaseAgent a when a.agentType() == AgentType.START_CONVERSATION -> {
+ case final BaseAgent a when a.agentType(context) == AgentType.START_CONVERSATION -> {
context.getGraph().add("🗨");
context.setConversation(null);
}
- case final BaseAgent a when a.agentType() == AgentType.CONVERSATION || a.agentType() == AgentType.CONVERSATION_WITH_SYSTEM_PROMPT -> {
+ case final BaseAgent a when a.agentType(context) == AgentType.CONVERSATION || a.agentType(context) == AgentType.CONVERSATION_WITH_SYSTEM_PROMPT -> {
context.getGraph().add("↴");
if (context.getConversation().getConversation().getLast().type() != TurnType.ASSISTANT) {
context.getConversation().addTurn(new Conversation.Turn(TurnType.ASSISTANT, context.getLastCompletion().response()));
}
}
- case final BaseAgent a when a.agentType() == AgentType.PROCESSING_ONLY -> {
-
+ case final BaseAgent a when a.agentType(context) == AgentType.PROCESSING_ONLY -> {
+
}
default -> {
context.getGraph().add("☢");
- LOGGER.error("Unknown agent type: {}", nextAgent.agentType());
+ LOGGER.error("Unknown agent type: {}", nextAgent.agentType(context));
context.setNextAgent(null);
}
}
diff --git a/src/test/java/de/extio/lmlib/agent/AgentTest.java b/src/test/java/de/extio/lmlib/agent/AgentTest.java
index f3ca591..1faa3d8 100644
--- a/src/test/java/de/extio/lmlib/agent/AgentTest.java
+++ b/src/test/java/de/extio/lmlib/agent/AgentTest.java
@@ -10,7 +10,6 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
@@ -126,6 +125,7 @@ public class AgentTest {
@Test
void streamedAgenticFlow() throws IOException {
+ final var lastStreamedSummary = new AtomicReference();
final var agents = Map.of(
"CodeSummarizer",
new Agent("CodeSummarizer",
@@ -133,7 +133,17 @@ public class AgentTest {
ModelCategory.MEDIUM,
"Generate a summary of the following Java source code.",
"The source code is:\n{{code}}",
- new TextAgentResponseHandler("summary"),
+ new TextAgentResponseHandler("summary",
+ null,
+ null,
+ null,
+ context -> {
+ if ("summary".equals(context.getStringValue(TextAgentResponseHandler.UPDATE_KEY))) { // UPDATE_KEY helps you to identify the streamed chunk
+ System.out.print(context.getStringValue("summary_chunk")); // Single chunks can be accessed via _chunk suffix, depends on the StreamedAgentResponseHandler implementation
+ lastStreamedSummary.set(context.getStringValue("summary")); // The current key value can also be accessed (e.g. concatenated, depends on the StreamedAgentResponseHandler implementation)
+ }
+ }
+ ),
null,
context -> {
context.setStringValue("summary", context.getStringValue("summary") + "\npostprocessed");
@@ -145,16 +155,12 @@ public class AgentTest {
context.setStreaming(true);
context.getContext().put("code", List.of(Files.readString(Path.of("src/main/java/de/extio/lmlib/agent/BaseAgent.java"))));
- final var lastStreamedSummary = new AtomicReference();
final var resultContexts = this.agentExecutor.walk(agents.get("CodeSummarizer"), context, contextUpdate -> {
- if ("summary".equals(contextUpdate.getStringValue(TextAgentResponseHandler.UPDATE_KEY))) { // UPDATE_KEY helps you to identify the streamed chunk
- System.out.print(contextUpdate.getStringValue("summary_chunk")); // Single chunks can be accessed via _chunk suffix, depends on the StreamedAgentResponseHandler implementation
- lastStreamedSummary.set(contextUpdate.getStringValue("summary")); // The current key value can also be accessed (e.g. concatenated, depends on the StreamedAgentResponseHandler implementation)
- }
+ // This is an optional consumer that can be used to receive updates from the agent context
});
assertEquals(1, resultContexts.size());
- assertEquals(lastStreamedSummary.get(), resultContexts.getFirst().getStringValue("summary"));
+ assertEquals(lastStreamedSummary.get() + "\npostprocessed", resultContexts.getFirst().getStringValue("summary"));
assertTrue(resultContexts.getFirst().getStringValue("summary").endsWith("postprocessed"));
System.out.println();