diff --git a/pom.xml b/pom.xml index 311f68d95..b97fc03f9 100644 --- a/pom.xml +++ b/pom.xml @@ -54,7 +54,11 @@ UTF-8 UTF-8 17 + + + 3.1.2 + 4.0.2 1.6.2 @@ -239,7 +243,7 @@ - + test-coverage @@ -292,7 +296,6 @@ - diff --git a/spring-ai-core/pom.xml b/spring-ai-core/pom.xml index 0d5034768..78462cf22 100644 --- a/spring-ai-core/pom.xml +++ b/spring-ai-core/pom.xml @@ -19,8 +19,20 @@ + - + + org.antlr + stringtemplate + ${stringtemplate.version} + + + + + org.springframework.boot + spring-boot-starter-test + test + diff --git a/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/AbstractPromptTemplate.java b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/AbstractPromptTemplate.java new file mode 100644 index 000000000..c18e7dda5 --- /dev/null +++ b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/AbstractPromptTemplate.java @@ -0,0 +1,39 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ai.core.prompts; + +import java.util.Map; +import java.util.Optional; + +public abstract class AbstractPromptTemplate implements PromptInput { + + private Optional outputParser = Optional.empty(); + + public AbstractPromptTemplate(Optional outputParser) { + this.outputParser = outputParser; + } + + @Override + public Optional getOutputParser() { + return this.outputParser; + } + + public abstract String formatAsString(Map inputVariables); + + public abstract PromptValue formatAsPrompt(Map inputVariables); + +} diff --git a/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/AbstractStringPromptTemplate.java b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/AbstractStringPromptTemplate.java new file mode 100644 index 000000000..cb6013121 --- /dev/null +++ b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/AbstractStringPromptTemplate.java @@ -0,0 +1,34 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ai.core.prompts; + +import java.util.Map; +import java.util.Optional; + +public abstract class AbstractStringPromptTemplate extends AbstractPromptTemplate implements PromptTemplateInput { + + public AbstractStringPromptTemplate(Optional outputParser) { + super(outputParser); + } + + @Override + public PromptValue formatAsPrompt(Map inputVariables) { + String formattedPrompt = formatAsString(inputVariables); + return new StringPromptValue(formattedPrompt); + } + +} diff --git a/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/Generation.java b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/Generation.java new file mode 100644 index 000000000..76be53095 --- /dev/null +++ b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/Generation.java @@ -0,0 +1,31 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ai.core.prompts; + +import java.util.Map; + +public class Generation { + + private final String text; + + private Map info; + + public Generation(String text) { + this.text = text; + } + +} diff --git a/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/OutputParser.java b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/OutputParser.java new file mode 100644 index 000000000..e880f6490 --- /dev/null +++ b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/OutputParser.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ai.core.prompts; + +import java.util.List; + +public interface OutputParser { + + Object parseResut(List generations); + +} diff --git a/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/PromptInput.java b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/PromptInput.java new file mode 100644 index 000000000..3bcae2b56 --- /dev/null +++ b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/PromptInput.java @@ -0,0 +1,30 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ai.core.prompts; + +import java.util.Optional; +import java.util.Set; + +public interface PromptInput { + + Set getInputVariables(); + + Optional getOutputParser(); + + // Leave out Partial Input Variables for now + +} diff --git a/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/PromptTemplate.java b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/PromptTemplate.java new file mode 100644 index 000000000..7e023a64c --- /dev/null +++ b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/PromptTemplate.java @@ -0,0 +1,134 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ai.core.prompts; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import org.antlr.runtime.Token; +import org.antlr.runtime.TokenStream; +import org.stringtemplate.v4.ST; +import org.stringtemplate.v4.compiler.STLexer; + +public class PromptTemplate extends AbstractStringPromptTemplate implements PromptTemplateInput { + + private String template; + + private TemplateFormat templateFormat = TemplateFormat.FSTRING; + + public PromptTemplate(String template) { + super(Optional.empty()); + this.template = template; + } + + public PromptTemplate(String template, boolean validate) { + super(Optional.empty()); + validateTemplate(validate); + this.template = template; + } + + public PromptTemplate(String template, TemplateFormat templateFormat) { + super(Optional.empty()); + this.template = template; + this.templateFormat = templateFormat; + } + + public PromptTemplate(String template, TemplateFormat templateFormat, boolean validate) { + super(Optional.empty()); + validateTemplate(validate); + this.template = template; + this.templateFormat = templateFormat; + } + + public PromptTemplate(String template, Optional outputParser) { + super(outputParser); + this.template = template; + } + + public PromptTemplate(String template, Optional outputParser, boolean validate) { + super(outputParser); + validateTemplate(validate); + this.template = template; + } + + public PromptTemplate(String template, Optional outputParser, TemplateFormat templateFormat) { + super(outputParser); + this.template = template; + this.templateFormat = templateFormat; + } + + public PromptTemplate(String template, Optional outputParser, TemplateFormat templateFormat, + boolean validate) { + super(outputParser); + validateTemplate(validate); + this.template = template; + this.templateFormat = templateFormat; + } + + @Override + public String formatAsString(Map inputVariables) { + // Only "F-String" for now + ST st = new ST(this.template, '{', '}'); + for (Entry stringObjectEntry : inputVariables.entrySet()) { + st.add(stringObjectEntry.getKey(), stringObjectEntry.getValue()); + } + return st.render(); + } + + @Override + public String getTemplate() { + return this.template; + } + + @Override + public TemplateFormat getTemplateFormat() { + return this.templateFormat; + } + + @Override + public Set getInputVariables() { + ST st = new ST(this.template, '{', '}'); + TokenStream tokens = st.impl.tokens; + return IntStream.range(0, tokens.range()) + .mapToObj(tokens::get) + .filter(token -> token.getType() == STLexer.ID) + .map(Token::getText) + .collect(Collectors.toSet()); + } + + private void validateTemplate(boolean validate) { + if (!validate) { + return; + } + try { + ST st = new ST(this.template, '{', '}'); + Set inputVariables = getInputVariables(); + for (String inputVariable : inputVariables) { + st.add(inputVariable, "foo"); + } + st.render(); + } + catch (Exception ex) { + throw new IllegalArgumentException("The template string is not valid.", ex); + } + } + +} diff --git a/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/PromptTemplateInput.java b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/PromptTemplateInput.java new file mode 100644 index 000000000..30990cff4 --- /dev/null +++ b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/PromptTemplateInput.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ai.core.prompts; + +public interface PromptTemplateInput extends PromptInput { + + String getTemplate(); + + TemplateFormat getTemplateFormat(); + +} diff --git a/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/PromptValue.java b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/PromptValue.java new file mode 100644 index 000000000..8743818f7 --- /dev/null +++ b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/PromptValue.java @@ -0,0 +1,29 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ai.core.prompts; + +import java.util.List; + +import org.springframework.ai.core.prompts.messages.Message; + +public interface PromptValue { + + String toStringValue(); + + List toMessages(); + +} diff --git a/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/StringPromptValue.java b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/StringPromptValue.java new file mode 100644 index 000000000..56007804f --- /dev/null +++ b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/StringPromptValue.java @@ -0,0 +1,43 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ai.core.prompts; + +import java.util.Collections; +import java.util.List; + +import org.springframework.ai.core.prompts.messages.HumanMessage; +import org.springframework.ai.core.prompts.messages.Message; + +public class StringPromptValue implements PromptValue { + + private String value; + + public StringPromptValue(String formattedPrompt) { + this.value = formattedPrompt; + } + + @Override + public String toStringValue() { + return this.value; + } + + @Override + public List toMessages() { + return Collections.singletonList(new HumanMessage(this.value)); + } + +} diff --git a/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/TemplateFormat.java b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/TemplateFormat.java new file mode 100644 index 000000000..daa8a240d --- /dev/null +++ b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/TemplateFormat.java @@ -0,0 +1,42 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ai.core.prompts; + +public enum TemplateFormat { + + FSTRING("f-string"); + + private final String value; + + TemplateFormat(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public static TemplateFormat fromValue(String value) { + for (TemplateFormat templateFormat : TemplateFormat.values()) { + if (templateFormat.getValue().equals(value)) { + return templateFormat; + } + } + throw new IllegalArgumentException("Invalid TemplateFormat value: " + value); + } + +} diff --git a/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/AbstractMessage.java b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/AbstractMessage.java new file mode 100644 index 000000000..78caec75c --- /dev/null +++ b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/AbstractMessage.java @@ -0,0 +1,56 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ai.core.prompts.messages; + +import java.util.HashMap; +import java.util.Map; + +public abstract class AbstractMessage implements Message { + + private String content; + + private Map properties = new HashMap<>(); + + private MessageType messageType; + + protected AbstractMessage(MessageType messageType, String content) { + this.messageType = messageType; + this.content = content; + } + + protected AbstractMessage(MessageType messageType, String content, Map properties) { + this.messageType = messageType; + this.content = content; + this.properties = properties; + } + + @Override + public String getContent() { + return this.content; + } + + @Override + public Map getProperties() { + return this.properties; + } + + @Override + public MessageType getMessageType() { + return this.messageType; + } + +} diff --git a/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/AiMessage.java b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/AiMessage.java new file mode 100644 index 000000000..f9328071e --- /dev/null +++ b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/AiMessage.java @@ -0,0 +1,31 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ai.core.prompts.messages; + +import java.util.Map; + +public class AiMessage extends AbstractMessage { + + public AiMessage(String content) { + super(MessageType.AI, content); + } + + public AiMessage(String content, Map properties) { + super(MessageType.AI, content, properties); + } + +} diff --git a/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/ChatMessage.java b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/ChatMessage.java new file mode 100644 index 000000000..7e4818bc3 --- /dev/null +++ b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/ChatMessage.java @@ -0,0 +1,39 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ai.core.prompts.messages; + +import java.util.Map; + +public class ChatMessage extends AbstractMessage { + + private String role; + + public ChatMessage(String content, String role) { + super(MessageType.SYSTEM, content); + this.role = role; + } + + public ChatMessage(String content, Map properties, String role) { + super(MessageType.SYSTEM, content, properties); + this.role = role; + } + + public String getRole() { + return role; + } + +} diff --git a/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/FunctionMessage.java b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/FunctionMessage.java new file mode 100644 index 000000000..0ca950204 --- /dev/null +++ b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/FunctionMessage.java @@ -0,0 +1,39 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ai.core.prompts.messages; + +import java.util.Map; + +public class FunctionMessage extends AbstractMessage { + + private String functionName; + + public FunctionMessage(String content, String functionName) { + super(MessageType.SYSTEM, content); + this.functionName = functionName; + } + + public FunctionMessage(String content, Map properties, String functionName) { + super(MessageType.SYSTEM, content, properties); + this.functionName = functionName; + } + + public String getFunctionName() { + return functionName; + } + +} diff --git a/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/HumanMessage.java b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/HumanMessage.java new file mode 100644 index 000000000..eaaa3cf46 --- /dev/null +++ b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/HumanMessage.java @@ -0,0 +1,31 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ai.core.prompts.messages; + +import java.util.Map; + +public class HumanMessage extends AbstractMessage { + + public HumanMessage(String content) { + super(MessageType.HUMAN, content); + } + + public HumanMessage(String content, Map properties) { + super(MessageType.HUMAN, content, properties); + } + +} diff --git a/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/Message.java b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/Message.java new file mode 100644 index 000000000..77f4df346 --- /dev/null +++ b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/Message.java @@ -0,0 +1,29 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ai.core.prompts.messages; + +import java.util.Map; + +public interface Message { + + String getContent(); + + Map getProperties(); + + MessageType getMessageType(); + +} diff --git a/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/MessageType.java b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/MessageType.java new file mode 100644 index 000000000..5a8d22457 --- /dev/null +++ b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/MessageType.java @@ -0,0 +1,49 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.ai.core.prompts.messages; + +public enum MessageType { + + HUMAN("human"), + + AI("ai"), + + GENERIC("generic"), + + SYSTEM("system"), + + FUNCTION("function"); + + private final String value; + + MessageType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public static MessageType fromValue(String value) { + for (MessageType messageType : MessageType.values()) { + if (messageType.getValue().equals(value)) { + return messageType; + } + } + throw new IllegalArgumentException("Invalid MessageType value: " + value); + } + +} diff --git a/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/SystemMessage.java b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/SystemMessage.java new file mode 100644 index 000000000..71f90f6d4 --- /dev/null +++ b/spring-ai-core/src/main/java/org/springframework/ai/core/prompts/messages/SystemMessage.java @@ -0,0 +1,31 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ai.core.prompts.messages; + +import java.util.Map; + +public class SystemMessage extends AbstractMessage { + + public SystemMessage(String content) { + super(MessageType.SYSTEM, content); + } + + public SystemMessage(String content, Map properties) { + super(MessageType.SYSTEM, content, properties); + } + +} diff --git a/spring-ai-core/src/test/java/org/springframework/ai/core/prompts/PromptTests.java b/spring-ai-core/src/test/java/org/springframework/ai/core/prompts/PromptTests.java new file mode 100644 index 000000000..fd4e5fb26 --- /dev/null +++ b/spring-ai-core/src/test/java/org/springframework/ai/core/prompts/PromptTests.java @@ -0,0 +1,66 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ai.core.prompts; + +import java.util.Set; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class PromptTests { + + @Test + void testSingleInputVariable() { + String template = "This is a {foo} test"; + PromptTemplate promptTemplate = new PromptTemplate(template); + Set inputVariables = promptTemplate.getInputVariables(); + assertThat(inputVariables).isNotEmpty(); + assertThat(inputVariables).hasSize(1); + assertThat(inputVariables).contains("foo"); + } + + @Test + void testMultipleInputVariables() { + String template = "This {bar} is a {foo} test"; + PromptTemplate promptTemplate = new PromptTemplate(template); + Set inputVariables = promptTemplate.getInputVariables(); + assertThat(inputVariables).isNotEmpty(); + assertThat(inputVariables).hasSize(2); + assertThat(inputVariables).contains("foo", "bar"); + } + + @Test + void testMultipleInputVariablesWithRepeats() { + String template = "This {bar} is a {foo} test {foo}."; + PromptTemplate promptTemplate = new PromptTemplate(template); + Set inputVariables = promptTemplate.getInputVariables(); + assertThat(inputVariables).isNotEmpty(); + assertThat(inputVariables).hasSize(2); + assertThat(inputVariables).contains("foo", "bar"); + } + + @Test + void testBadTemplateString() { + String template = "This is a {foo test"; + Assertions.assertThatThrownBy(() -> { + PromptTemplate promptTemplate = new PromptTemplate(template, true); + }).isInstanceOf(IllegalArgumentException.class).hasMessage("The template string is not valid."); + } + +}