wordMeanings;
21 | String locations[];
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/t4a/annotations/Agent.java:
--------------------------------------------------------------------------------
1 | package com.t4a.annotations;
2 |
3 | import com.t4a.api.ToolsConstants;
4 |
5 | import java.lang.annotation.ElementType;
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.RetentionPolicy;
8 | import java.lang.annotation.Target;
9 |
10 |
11 | /**
12 | * This annotation is used to mark the class as a Agent group
13 | */
14 | @Retention(RetentionPolicy.RUNTIME)
15 | @Target(ElementType.TYPE)
16 | public @interface Agent {
17 | String groupName() default ToolsConstants.GROUP_NAME;
18 | String groupDescription() default ToolsConstants.GROUP_DESCRIPTION;
19 | }
--------------------------------------------------------------------------------
/src/main/java/com/t4a/detect/FactDetector.java:
--------------------------------------------------------------------------------
1 | package com.t4a.detect;
2 |
3 | import com.t4a.api.ActionType;
4 | import com.t4a.api.DetectorAction;
5 | import com.t4a.api.GuardRailException;
6 |
7 | public class FactDetector implements DetectorAction {
8 | @Override
9 | public ActionType getActionType() {
10 | return ActionType.FACT;
11 | }
12 |
13 | @Override
14 | public String getDescription() {
15 | return "Fact Check in response";
16 | }
17 |
18 | @Override
19 | public DetectValueRes execute(DetectValues dd) throws GuardRailException {
20 | return null;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/pojo/Employee.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples.pojo;
2 |
3 | import com.t4a.annotations.Prompt;
4 | import lombok.*;
5 |
6 | import java.util.Date;
7 |
8 | @Getter
9 | @Setter
10 | @NoArgsConstructor
11 | @AllArgsConstructor
12 | @ToString
13 | public class Employee {
14 | private String name;
15 | @Prompt(ignore = true)
16 | private int id;
17 | private String department;
18 | private double salary;
19 | private String location;
20 | @Prompt(dateFormat = "ddMMyyyy" ,describe = "convert to actual date")
21 | private Date dateJoined;
22 | private String[] tasks;
23 | }
24 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/test/HallucinationDetectorTypeTest.java:
--------------------------------------------------------------------------------
1 | package com.t4a.test;
2 |
3 | import com.t4a.detect.HallucinationDetectorType;
4 | import org.junit.jupiter.api.Test;
5 |
6 | import static org.junit.jupiter.api.Assertions.*;
7 |
8 | public class HallucinationDetectorTypeTest {
9 |
10 | @Test
11 | public void testEnumValues() {
12 | assertEquals(2, HallucinationDetectorType.values().length);
13 | assertEquals(HallucinationDetectorType.GOOGLE, HallucinationDetectorType.values()[0]);
14 | assertEquals(HallucinationDetectorType.SELF, HallucinationDetectorType.values()[1]);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/actions/SimpleAction.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples.actions;
2 |
3 | import com.t4a.annotations.Action;
4 | import com.t4a.annotations.Agent;
5 |
6 | @Agent
7 | public class SimpleAction {
8 |
9 | @Action( description = "what is the food preference of this person")
10 | public String whatFoodDoesThisPersonLike(String name) {
11 | if("vishal".equalsIgnoreCase(name))
12 | return "Paneer Butter Masala";
13 | else if ("vinod".equalsIgnoreCase(name)) {
14 | return "aloo kofta";
15 | }else
16 | return "something yummy";
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/agriculture/EnvironmentConditions.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples.agriculture;
2 |
3 | import lombok.Getter;
4 | import lombok.NoArgsConstructor;
5 | import lombok.Setter;
6 | import lombok.ToString;
7 |
8 | @NoArgsConstructor
9 | @Getter
10 | @Setter
11 | @ToString
12 | public class EnvironmentConditions {
13 | private double waterPercentage;
14 | private double soilPercentage;
15 | private double sunlightPercentage;
16 | private double temperature;
17 | private boolean hasFrost;
18 | private boolean hasHeatWave;
19 | private boolean hasDrought;
20 | private boolean hasFlood;
21 | }
--------------------------------------------------------------------------------
/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | # Maven
2 | # Build your Java project and run tests with Apache Maven.
3 | # Add steps that analyze code, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/java
5 |
6 | trigger:
7 | - main
8 |
9 | pool:
10 | vmImage: ubuntu-latest
11 |
12 | steps:
13 | - task: Maven@3
14 | inputs:
15 | mavenPomFile: 'pom.xml'
16 | mavenOptions: '-Xmx3072m'
17 | javaHomeOption: 'JDKVersion'
18 | jdkVersionOption: '1.8'
19 | jdkArchitectureOption: 'x64'
20 | publishJUnitResults: true
21 | testResultsFiles: '**/surefire-reports/TEST-*.xml'
22 | goals: 'package'
23 |
--------------------------------------------------------------------------------
/src/main/java/com/t4a/detect/ExplainDecision.java:
--------------------------------------------------------------------------------
1 | package com.t4a.detect;
2 | /**
3 | * The {@code ExplainDecision} interface represents a mechanism for AI to explain decisions
4 | * regarding a particular prompt text, method name, and reason. AI will call this back
5 | *
6 | * This interface defines a method {@link #explain(String, String, String)} that can be used
7 | * to provide an explanation by AI to a human regarding a decision made based on a prompt text,
8 | * method name, and reason.
9 | *
10 | */
11 | public interface ExplainDecision {
12 | public String explain(String promptText, String methodName, String reason) ;
13 | }
14 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/actions/ServerRestartAction.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples.actions;
2 |
3 | import com.t4a.annotations.Action;
4 | import com.t4a.annotations.Agent;
5 | import com.t4a.api.ActionRisk;
6 |
7 | @Agent(groupName = "server support", groupDescription = "actions related to server support")
8 | public class ServerRestartAction {
9 | @Action(riskLevel = ActionRisk.HIGH, description = "Restart the ECOM server")
10 | public String restartTheECOMServer(String reasonForRestart, String requestedBy) {
11 | return " Server has been restarted by "+requestedBy+" due to following reason "+reasonForRestart;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/t4a/api/DefaultMethodFinder.java:
--------------------------------------------------------------------------------
1 | package com.t4a.api;
2 |
3 |
4 | import com.t4a.processor.AIProcessingException;
5 |
6 | import java.lang.reflect.Method;
7 |
8 | public class DefaultMethodFinder implements MethodFinder {
9 | @Override
10 | public Method findMethod(Class> clazz, String methodName) throws AIProcessingException {
11 | for (Method method : clazz.getMethods()) {
12 | if (method.getName().equals(methodName)) {
13 | return method;
14 | }
15 | }
16 | throw new AIProcessingException(methodName + " method not found in class " + clazz.getName());
17 | }
18 | }
--------------------------------------------------------------------------------
/src/main/java/com/t4a/api/GeminiGuardRails.java:
--------------------------------------------------------------------------------
1 | package com.t4a.api;
2 |
3 | /**
4 | * Uses Gemini to check the user prompts
5 | */
6 | public class GeminiGuardRails implements GuardRails{
7 | String validateOffensive = "Does this sentence contain anything offensive - ";
8 | String validatePII;
9 |
10 |
11 | public GeminiGuardRails() {
12 | }
13 |
14 | @Override
15 | public boolean validateResponse(String response) throws GuardRailException {
16 | return false;
17 | }
18 |
19 | @Override
20 | public boolean validateRequest(String prompt) throws GuardRailException {
21 | return false;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/actions/ListAction.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples.actions;
2 |
3 | import com.t4a.annotations.Action;
4 | import com.t4a.annotations.Agent;
5 | import com.t4a.examples.pojo.Organization;
6 | import lombok.Getter;
7 | import lombok.Setter;
8 | import lombok.ToString;
9 |
10 | @Getter
11 | @Setter
12 | @ToString
13 | @Agent(groupName = "Organization", groupDescription = "Organization actions")
14 | public class ListAction {
15 |
16 | @Action(description = "add new orgranization")
17 | public Organization addOrganization(Organization org) {
18 |
19 | System.out.println(org);
20 | return org;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/test/LogginggExplainDecisionTest.java:
--------------------------------------------------------------------------------
1 | package com.t4a.test;
2 |
3 | import com.t4a.processor.LogginggExplainDecision;
4 | import org.junit.jupiter.api.Assertions;
5 | import org.junit.jupiter.api.Test;
6 |
7 | public class LogginggExplainDecisionTest {
8 |
9 | @Test
10 | void testExplain() {
11 |
12 | LogginggExplainDecision decision = new LogginggExplainDecision();
13 |
14 | String promptText = "promptText";
15 | String methodName = "methodName";
16 | String reason = "reason";
17 |
18 | Assertions.assertEquals(reason,decision.explain(promptText, methodName, reason));
19 |
20 |
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/actions/MapAction.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples.actions;
2 |
3 | import com.t4a.annotations.Action;
4 | import com.t4a.annotations.MapKeyType;
5 | import com.t4a.annotations.MapValueType;
6 | import com.t4a.annotations.Agent;
7 | import lombok.Getter;
8 | import lombok.Setter;
9 |
10 | import java.util.Map;
11 |
12 | @Getter
13 | @Setter
14 | @Agent
15 | public class MapAction {
16 |
17 |
18 |
19 | @Action(description = "add new Sports into the map")
20 | public Map addSports(@MapKeyType(Integer.class) @MapValueType(String.class) Map mapOfSportsName) {
21 |
22 | return mapOfSportsName;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/t4a/detect/HallucinationQA.java:
--------------------------------------------------------------------------------
1 | package com.t4a.detect;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 | import lombok.NoArgsConstructor;
6 | import lombok.Setter;
7 |
8 | @NoArgsConstructor
9 | @AllArgsConstructor
10 | @Getter
11 | @Setter
12 | public class HallucinationQA {
13 | private String question;
14 | private String answer;
15 | private String context;
16 | private String truthPercentage;
17 |
18 |
19 | public double calculateTruthPercent() {
20 | String numberString = truthPercentage.replaceAll("[^\\d.]", "");
21 | double doublePer = Double.parseDouble(numberString);
22 | return doublePer;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/actions/Customer.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples.actions;
2 |
3 | import com.t4a.annotations.Prompt;
4 | import lombok.*;
5 |
6 | import java.util.Date;
7 |
8 | @NoArgsConstructor
9 | @AllArgsConstructor
10 | @Getter
11 | @Setter
12 | @ToString
13 | @EqualsAndHashCode
14 | public class Customer {
15 | private String firstName;
16 | private String lastName;
17 | @Prompt(describe = "convert this to Hindi")
18 | private String reasonForCalling;
19 | @Prompt(ignore = true)
20 | private String location;
21 | @Prompt(dateFormat = "yyyy-MM-dd" ,describe = "if you dont find date provide todays date in fieldValue")
22 | private Date dateJoined;
23 | }
24 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/test/GeminiGuardRailsTest.java:
--------------------------------------------------------------------------------
1 | package com.t4a.test;
2 |
3 | import com.t4a.api.GeminiGuardRails;
4 | import com.t4a.api.GuardRailException;
5 | import org.junit.jupiter.api.Assertions;
6 | import org.junit.jupiter.api.BeforeEach;
7 | import org.junit.jupiter.api.Test;
8 |
9 | public class GeminiGuardRailsTest {
10 |
11 | private GeminiGuardRails geminiGuardRails;
12 |
13 | @BeforeEach
14 | public void setUp() {
15 | geminiGuardRails = new GeminiGuardRails();
16 |
17 | }
18 |
19 | @Test
20 | public void testMethod1() throws GuardRailException {
21 | Assertions.assertFalse(geminiGuardRails.validateRequest("test"));
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/t4a/processor/scripts/ScriptResult.java:
--------------------------------------------------------------------------------
1 | package com.t4a.processor.scripts;
2 |
3 | import lombok.Getter;
4 | import lombok.Setter;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | @Setter
10 | @Getter
11 | public class ScriptResult {
12 | private List results;
13 | public ScriptResult() {
14 | results = new ArrayList<>();
15 | }
16 |
17 | public void addResult(ScriptLineResult result) {
18 | results.add(result);
19 | }
20 |
21 | public void addResult(String line, String resultStr) {
22 | ScriptLineResult result = new ScriptLineResult(line,resultStr);
23 | results.add(result);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 | !**/src/main/**/target/
4 | !**/src/test/**/target/
5 |
6 | ### IntelliJ IDEA ###
7 | .idea/modules.xml
8 | .idea/jarRepositories.xml
9 | .idea/compiler.xml
10 | .idea/libraries/
11 | .idea/sonarlint/
12 | .idea/sonarlint/issuestore/
13 | *.iws
14 | *.iml
15 | *.ipr
16 |
17 | ### Eclipse ###
18 | .apt_generated
19 | .classpath
20 | .factorypath
21 | .project
22 | .settings
23 | .springBeans
24 | .sts4-cache
25 |
26 | ### NetBeans ###
27 | /nbproject/private/
28 | /nbbuild/
29 | /dist/
30 | /nbdist/
31 | /.nb-gradle/
32 | build/
33 | !**/src/main/**/build/
34 | !**/src/test/**/build/
35 |
36 | ### VS Code ###
37 | .vscode/
38 |
39 | ### Mac OS ###
40 | .DS_Store
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/actions/CustomerWithQueryAction.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples.actions;
2 |
3 | import com.t4a.annotations.Action;
4 | import com.t4a.annotations.Agent;
5 | import com.t4a.annotations.Prompt;
6 |
7 | import java.util.Date;
8 |
9 | @Agent(groupName = "customer support", groupDescription = "actions related to customer support")
10 | public class CustomerWithQueryAction {
11 |
12 | @Action(description = "Customer has problem create ticket for him")
13 | public String computerRepairWithDetails(Customer customer, @Prompt(dateFormat = "yyyy-MM-dd") Date dateOfComp , @Prompt(describe = "this is customer complaint") String query) {
14 | return customer.toString();
15 | }
16 | }
--------------------------------------------------------------------------------
/src/test/java/com/t4a/test/MockAction.java:
--------------------------------------------------------------------------------
1 | package com.t4a.test;
2 |
3 | import com.t4a.api.ActionRisk;
4 | import com.t4a.api.ActionType;
5 | import com.t4a.api.JavaMethodAction;
6 |
7 | public class MockAction implements JavaMethodAction {
8 |
9 | public Person p;
10 | public String name;
11 | @Override
12 | public String getActionName() {
13 | return "mockAction";
14 | }
15 |
16 | public String mockAction(String mockName,Person mockPerson) {
17 | p = mockPerson;
18 | name = mockName;
19 | return mockName;
20 | }
21 |
22 | @Override
23 | public String getDescription() {
24 | return "mockActionDescription";
25 | }
26 |
27 |
28 |
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/t4a/processor/spring/SpringOpenAIProcessor.java:
--------------------------------------------------------------------------------
1 | package com.t4a.processor.spring;
2 |
3 | import com.t4a.predict.PredictionLoader;
4 | import com.t4a.processor.OpenAiActionProcessor;
5 | import org.springframework.context.ApplicationContext;
6 | /**
7 | * This will ensure that the action classes are loaded from Spring Applicaiton Context rather than
8 | * creating the new one , the advantage of that is we can maintain spring dependency injection for all the beans
9 | * Uses OpenAI for processing
10 | */
11 | public class SpringOpenAIProcessor extends OpenAiActionProcessor {
12 | public SpringOpenAIProcessor(ApplicationContext context) {
13 | PredictionLoader.getInstance(context);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/t4a/processor/spring/SpringGeminiProcessor.java:
--------------------------------------------------------------------------------
1 | package com.t4a.processor.spring;
2 |
3 | import com.t4a.predict.PredictionLoader;
4 | import com.t4a.processor.GeminiV2ActionProcessor;
5 | import org.springframework.context.ApplicationContext;
6 |
7 | /**
8 | * This will ensure that the action classes are loaded from Spring Applicaiton Context rather than
9 | * creating the new one , the advantage of that is we can maintain spring dependency injection for all the beans
10 | * Uses Gemini for processing
11 | */
12 | public class SpringGeminiProcessor extends GeminiV2ActionProcessor {
13 |
14 | public SpringGeminiProcessor(ApplicationContext context) {
15 | PredictionLoader.getInstance(context);
16 |
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/test/ToolsConstantsTest.java:
--------------------------------------------------------------------------------
1 | package com.t4a.test;
2 |
3 | import com.t4a.api.ToolsConstants;
4 | import org.junit.jupiter.api.Test;
5 |
6 | import static org.junit.jupiter.api.Assertions.*;
7 |
8 | public class ToolsConstantsTest {
9 |
10 | @Test
11 | public void testConstants() {
12 | assertEquals("BlankAction", ToolsConstants.BLANK_ACTION);
13 | assertEquals("SeleniumAction", ToolsConstants.SELENIUM_ACTION);
14 | assertEquals("AIProcessor", ToolsConstants.AI_PROCESSOR);
15 | assertEquals("Agent", ToolsConstants.PREDICT);
16 | assertEquals("No Group", ToolsConstants.GROUP_NAME);
17 | assertEquals("tasks which are not categorized", ToolsConstants.GROUP_DESCRIPTION);
18 | }
19 | }
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/SingletonResetter.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples;
2 |
3 | import java.lang.reflect.Constructor;
4 | import java.lang.reflect.Field;
5 |
6 | public class SingletonResetter {
7 |
8 | public static void resetSingleton(Class> singletonClass) throws Exception {
9 | // Access the private constructor
10 | Constructor> constructor = singletonClass.getDeclaredConstructor();
11 | constructor.setAccessible(true);
12 |
13 | // Reset the instance to null
14 | Field instanceField = singletonClass.getDeclaredField("predictionLoader");
15 | instanceField.setAccessible(true);
16 | instanceField.set(null, null);
17 | }
18 | }
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/agriculture/HealthStatus.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples.agriculture;
2 |
3 | import com.t4a.annotations.Prompt;
4 | import lombok.Getter;
5 | import lombok.NoArgsConstructor;
6 | import lombok.Setter;
7 | import lombok.ToString;
8 |
9 | @NoArgsConstructor
10 | @Getter
11 | @Setter
12 | @ToString
13 | public class HealthStatus {
14 | @Prompt(describe ="if it looks healthy then give 100% else give a percentage")
15 | private double healthPercentage;
16 | private boolean hasPest;
17 | private boolean hasDisease;
18 | private boolean hasNutrientDeficiency;
19 | private boolean doesItHaveAnyDisease;
20 | @Prompt(describe ="based on picture do you think the plant has any disease, if none then return NONE")
21 | private String typeOfDisease;
22 | }
--------------------------------------------------------------------------------
/src/test/resources/tools4ai.properties:
--------------------------------------------------------------------------------
1 | ##Gemini related settings
2 | gemini.modelName=gemini-1.0-pro
3 | #gemini.modelName=test
4 | #gemini.modelName=gemini-1.5-pro-preview-0409
5 | gemini.location=us-central1
6 | gemini.projectId=cookgptserver
7 | #gemini.projectId=test
8 | gemini.vision.modelName=gemini-1.0-pro-vision
9 |
10 | ##Anthropic related settings
11 | anthropic.modelName=claude-3-haiku-20240307
12 | anthropic.logRequests=true
13 | anthropic.logResponse=true
14 |
15 | #set it here or use -DclaudeKey parameter
16 | claudeKey=
17 |
18 | ##Open AI Key
19 | #set it here or use -DopenAiKey parameter
20 | openAiKey=
21 | ##Open AI Base URL keep it empty or set it here or in vm option
22 | openAiBaseURL=
23 |
24 | openAiModelName=grok-2-1212
25 |
26 | ##Serper Key for google search or hallucination detection
27 | serperKey=
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/basic/RestaurantDetails.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples.basic;
2 |
3 | public class RestaurantDetails {
4 | String name;
5 | //@Prompt(describe = "convert location to hindi")
6 | String location;
7 |
8 | public String getLocation() {
9 | return location;
10 | }
11 |
12 | public void setLocation(String location) {
13 | this.location = location;
14 | }
15 |
16 | @Override
17 | public String toString() {
18 | return "RestaurantDetails{" +
19 | "name='" + name + '\'' +
20 | ", location='" + location + '\'' +
21 | '}';
22 | }
23 |
24 | public String getName() {
25 | return name;
26 | }
27 |
28 | public void setName(String name) {
29 | this.name = name;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/t4a/processor/selenium/SeleniumAction.java:
--------------------------------------------------------------------------------
1 | package com.t4a.processor.selenium;
2 |
3 | import com.t4a.annotations.Action;
4 | import com.t4a.annotations.Agent;
5 | import lombok.Getter;
6 | import lombok.Setter;
7 | import lombok.extern.java.Log;
8 |
9 | @Log
10 | @Setter
11 | @Getter
12 | @Agent(groupName = "Selenium", groupDescription = "Selenium actions")
13 | public class SeleniumAction {
14 |
15 | @Action(description = "Perform action on web page")
16 | public DriverActions webPageAction(DriverActions webDriverActions) {
17 | if (webDriverActions == null) {
18 | return null;
19 | }
20 | DriverActions copy = new DriverActions();
21 | copy.setTypeOfActionToTakeOnWebDriver(webDriverActions.getTypeOfActionToTakeOnWebDriver());
22 | return copy;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/t4a/processor/selenium/DriverActions.java:
--------------------------------------------------------------------------------
1 | package com.t4a.processor.selenium;
2 |
3 | import com.t4a.annotations.Prompt;
4 | import lombok.Getter;
5 | import lombok.NoArgsConstructor;
6 | import lombok.Setter;
7 | import lombok.ToString;
8 |
9 | @Setter
10 | @Getter
11 | @NoArgsConstructor
12 | @ToString
13 | public class DriverActions {
14 | @Prompt(describe = "What method should i invoke on org.openqa.selenium.WebDriver " +
15 | "{navigate, get," +
16 | "click, " +
17 | "takescreenshot, sendKeys,clear,submit,getText," +
18 | "isDisplayed,isEnabled," +
19 | "isSelected,getAttribute,switchTo,selectByVisibleText," +
20 | "selectByValue,selectByIndex" +
21 | "}" +
22 | "")
23 | String typeOfActionToTakeOnWebDriver;
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/t4a/detect/HumanInLoop.java:
--------------------------------------------------------------------------------
1 | package com.t4a.detect;
2 |
3 | import java.util.Map;
4 |
5 | /**
6 | * The {@code HumanInLoop} interface represents a mechanism for allowing human involvement
7 | * in a feedback loop process.
8 | *
9 | * This interface defines a method {@link #allow(String, String, Map)} that can be used
10 | * to request human input for a given prompt text and method name with optional parameters.
11 | *
12 | */
13 | public interface HumanInLoop {
14 | public FeedbackLoop allow(String promptText, String methodName, Map params) ;
15 | public FeedbackLoop allow(String promptText, String methodName, String params) ;
16 |
17 | default void setCallback(ActionCallback callback) {
18 |
19 | }
20 | default ActionCallback getCallback() {
21 | return null;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/t4a/predict/LoaderException.java:
--------------------------------------------------------------------------------
1 | package com.t4a.predict;
2 |
3 | /**
4 | * LoaderException is a custom exception class that extends Exception. Its thrown when a config file
5 | * is not being parsed correctly.
6 |
7 | */
8 | public class LoaderException extends Exception {
9 | public LoaderException() {
10 | }
11 |
12 | public LoaderException(String message) {
13 | super(message);
14 | }
15 |
16 | public LoaderException(String message, Throwable cause) {
17 | super(message, cause);
18 | }
19 |
20 | public LoaderException(Throwable cause) {
21 | super(cause);
22 | }
23 |
24 | public LoaderException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
25 | super(message, cause, enableSuppression, writableStackTrace);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/com/t4a/detect/BiasDetector.java:
--------------------------------------------------------------------------------
1 | package com.t4a.detect;
2 |
3 | import com.t4a.api.ActionType;
4 | import com.t4a.api.DetectorAction;
5 | import com.t4a.api.GuardRailException;
6 |
7 | /**
8 | * Detect Bias in response using Zero-shot classification
9 | * To detect bias, look for unequal treatment in outputs, analyze the data source,
10 | * and challenge the AI's assumptions with follow-up questions.
11 | */
12 | public class BiasDetector implements DetectorAction {
13 | @Override
14 | public ActionType getActionType() {
15 | return ActionType.BIAS;
16 | }
17 |
18 | @Override
19 | public String getDescription() {
20 | return "Detect Bias in response";
21 | }
22 |
23 | @Override
24 | public DetectValueRes execute(DetectValues dd) throws GuardRailException {
25 | return null;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/test/DriverActionsTest.java:
--------------------------------------------------------------------------------
1 | package com.t4a.test;
2 |
3 | import com.t4a.processor.selenium.DriverActions;
4 | import org.junit.jupiter.api.BeforeEach;
5 | import org.junit.jupiter.api.Test;
6 |
7 | import static org.junit.jupiter.api.Assertions.assertEquals;
8 |
9 | public class DriverActionsTest {
10 | private DriverActions driverActions;
11 |
12 | @BeforeEach
13 | public void setUp() {
14 | driverActions = new DriverActions();
15 | }
16 |
17 | @Test
18 | public void testTypeOfActionToTakeOnWebDriver() {
19 | String expectedAction = "navigate";
20 | driverActions.setTypeOfActionToTakeOnWebDriver(expectedAction);
21 | String actualAction = driverActions.getTypeOfActionToTakeOnWebDriver();
22 | assertEquals(expectedAction, actualAction, "The action should be navigate");
23 | }
24 | }
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/actions/PlayerWithRestaurant.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples.actions;
2 |
3 | import com.t4a.annotations.Action;
4 | import com.t4a.annotations.Agent;
5 | import com.t4a.examples.basic.RestaurantPojo;
6 | import lombok.Getter;
7 | import lombok.extern.slf4j.Slf4j;
8 |
9 | @Slf4j
10 | @Agent
11 | public class PlayerWithRestaurant {
12 | @Getter
13 | private Player player;
14 | @Getter
15 | private RestaurantPojo restaurantPojo;
16 | @Action( description = "add restaurant and player details")
17 | public String notifyPlayerAndRestaurant(Player player, RestaurantPojo restaurantPojo) {
18 | log.debug(player.toString());
19 | log.debug(restaurantPojo.toString());
20 | this.player = player;
21 | this.restaurantPojo = restaurantPojo;
22 | return "yes i have notified";
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/agriculture/Plant.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples.agriculture;
2 |
3 | import com.t4a.annotations.Prompt;
4 | import lombok.Getter;
5 | import lombok.NoArgsConstructor;
6 | import lombok.Setter;
7 | import lombok.ToString;
8 |
9 | @NoArgsConstructor
10 | @Getter
11 | @Setter
12 | @ToString
13 | public class Plant {
14 | @Prompt(describe ="what type is it CROP or FRUIT or VEGETABLE or FLOWER or TREE or SHRUB or GRASS or WEED or OTHER")
15 | private String platType;
16 | private String plantName;
17 | private HealthStatus healthStatus;
18 | private EnvironmentConditions environmentConditions;
19 | private boolean hasWaterDeficiency = false;;
20 | private boolean hasSunlightDeficiency = false;;
21 | private boolean hasSoilDeficiency = false;;
22 | private boolean hasTemperatureDeficiency = false;;
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/regression/TestHelperOpenAI.java:
--------------------------------------------------------------------------------
1 | package com.t4a.regression;
2 |
3 | import com.t4a.predict.PredictionLoader;
4 | import dev.langchain4j.model.chat.ChatLanguageModel;
5 | import lombok.extern.slf4j.Slf4j;
6 |
7 | @Slf4j
8 | public class TestHelperOpenAI {
9 |
10 |
11 | private ChatLanguageModel openAiChatModel;
12 | private static TestHelperOpenAI testAIHelper;
13 |
14 | private void initProp() {
15 | openAiChatModel = PredictionLoader.getInstance().getOpenAiChatModel();
16 | }
17 |
18 | private TestHelperOpenAI() {
19 | initProp();
20 | }
21 |
22 | public static TestHelperOpenAI getInstance() {
23 | if (testAIHelper == null)
24 | testAIHelper = new TestHelperOpenAI();
25 | return testAIHelper;
26 | }
27 |
28 | public String sendMessage(String msg) {
29 | return openAiChatModel.generate(msg);
30 | }
31 | }
--------------------------------------------------------------------------------
/src/test/java/com/t4a/test/ExtendedInputParameterTest.java:
--------------------------------------------------------------------------------
1 | package com.t4a.test;
2 |
3 |
4 |
5 |
6 |
7 | import com.t4a.action.ExtendedInputParameter;
8 | import org.junit.jupiter.api.Test;
9 |
10 | import static org.junit.jupiter.api.Assertions.assertEquals;
11 | import static org.junit.jupiter.api.Assertions.assertNull;
12 |
13 | public class ExtendedInputParameterTest {
14 |
15 | @Test
16 | public void testExtendedInputParameter() {
17 | // Create an instance of ExtendedInputParameter
18 | ExtendedInputParameter inputParameter = new ExtendedInputParameter("TestName", "TestValue");
19 |
20 | // Test the methods of ExtendedInputParameter
21 | assertEquals("TestName", inputParameter.getName());
22 | assertEquals(false, inputParameter.hasDefaultValue());
23 | assertEquals("TestValue", inputParameter.getType());
24 | assertNull(inputParameter.getDefaultValueStr());
25 | }
26 | }
--------------------------------------------------------------------------------
/src/main/java/com/t4a/processor/scripts/LoggingSeleniumCallback.java:
--------------------------------------------------------------------------------
1 | package com.t4a.processor.scripts;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.openqa.selenium.WebDriver;
5 |
6 | @Slf4j
7 | public class LoggingSeleniumCallback implements SeleniumCallback{
8 | @Override
9 | public boolean beforeWebAction(String lineToBeProcessed,WebDriver driver) {
10 | log.info("Before Web Action: " + driver.getCurrentUrl());
11 | return true; // Return true to continue processing the line
12 | }
13 |
14 | @Override
15 | public void afterWebAction(String lineProcssed,WebDriver driver) {
16 | log.info("After Web Action: " + driver.getCurrentUrl());
17 | }
18 |
19 | @Override
20 | public String handleError(String line, String errorMessage, WebDriver driver, int retryCount) {
21 | log.info("Error during web action: " + errorMessage);
22 | return null;
23 | }
24 |
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/test/MimeTypeTest.java:
--------------------------------------------------------------------------------
1 | package com.t4a.test;
2 |
3 | import com.t4a.api.MimeType;
4 | import org.junit.jupiter.api.Assertions;
5 | import org.junit.jupiter.api.Test;
6 |
7 | public class MimeTypeTest {
8 | @Test
9 | void testGetMimeType() {
10 | Assertions.assertEquals("image/jpeg", MimeType.JPEG.getMimeType());
11 | Assertions.assertEquals("image/png", MimeType.PNG.getMimeType());
12 | Assertions.assertEquals("image/gif", MimeType.GIF.getMimeType());
13 | Assertions.assertEquals("text/html", MimeType.HTML.getMimeType());
14 | Assertions.assertEquals("text/plain", MimeType.TEXT.getMimeType());
15 | Assertions.assertEquals("application/pdf", MimeType.PDF.getMimeType());
16 | Assertions.assertEquals("application/msword", MimeType.MS_WORD.getMimeType());
17 | Assertions.assertEquals("application/vnd.oasis.opendocument.text", MimeType.OPEN_DOCUMENT_TEXT.getMimeType());
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/t4a/detect/ActionState.java:
--------------------------------------------------------------------------------
1 | package com.t4a.detect;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonValue;
5 | import com.github.dockerjava.api.model.TaskState;
6 |
7 | public enum ActionState {
8 | SUBMITTED("submitted"),
9 | WORKING("working"),
10 | INPUT_REQUIRED("input-required"),
11 | COMPLETED("completed"),
12 | CANCELED("canceled"),
13 | FAILED("failed"),
14 | UNKNOWN("unknown");
15 |
16 | private final String value;
17 |
18 | ActionState(String value) {
19 | this.value = value;
20 | }
21 |
22 |
23 | public String getValue() {
24 | return value;
25 | }
26 |
27 | public static ActionState forValue(String value) {
28 | for (ActionState state : values()) {
29 | if (state.value.equals(value)) {
30 | return state;
31 | }
32 | }
33 | return UNKNOWN;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/test/PromptInjectionValidatorTest.java:
--------------------------------------------------------------------------------
1 | package com.t4a.test;
2 |
3 | import com.t4a.detect.PromptInjectionValidator;
4 | import org.junit.jupiter.api.BeforeEach;
5 | import org.junit.jupiter.api.Test;
6 |
7 | import static org.junit.jupiter.api.Assertions.assertFalse;
8 | import static org.junit.jupiter.api.Assertions.assertTrue;
9 |
10 | class PromptInjectionValidatorTest {
11 |
12 | private PromptInjectionValidator promptInjectionValidator;
13 |
14 | @BeforeEach
15 | public void setup() {
16 | promptInjectionValidator = new PromptInjectionValidator();
17 | }
18 |
19 | @Test
20 | public void testIsValidPrompt() {
21 | assertTrue(promptInjectionValidator.isValidPrompt("This is a safe prompt."));
22 | assertFalse(promptInjectionValidator.isValidPrompt("This prompt contains a threat: delete"));
23 | assertFalse(promptInjectionValidator.isValidPrompt("This prompt contains a disallowed character: #"));
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/test/FactDetectorTest.java:
--------------------------------------------------------------------------------
1 | package com.t4a.test;
2 |
3 | import com.t4a.api.ActionType;
4 | import com.t4a.api.GuardRailException;
5 | import com.t4a.detect.DetectValues;
6 | import com.t4a.detect.FactDetector;
7 | import org.junit.jupiter.api.BeforeEach;
8 | import org.junit.jupiter.api.Test;
9 |
10 | import static org.junit.jupiter.api.Assertions.*;
11 |
12 | class FactDetectorTest {
13 |
14 | private FactDetector factDetector;
15 |
16 | @BeforeEach
17 | public void setup() {
18 | factDetector = new FactDetector();
19 | }
20 |
21 | @Test
22 | void testGetActionType() {
23 | assertEquals(ActionType.FACT, factDetector.getActionType());
24 | }
25 |
26 | @Test
27 | void testGetDescription() {
28 | assertEquals("Fact Check in response", factDetector.getDescription());
29 | }
30 |
31 | @Test
32 | void testExecute() throws GuardRailException {
33 | assertNull(factDetector.execute(new DetectValues()));
34 | }
35 | }
--------------------------------------------------------------------------------
/src/main/java/com/t4a/action/http/InputParameter.java:
--------------------------------------------------------------------------------
1 | package com.t4a.action.http;
2 |
3 | import lombok.*;
4 |
5 | /**
6 | * Maps to Input parameter in the config file, this is the input which will be sent to HTTP request
7 | */
8 | @Setter
9 | @Getter
10 | @AllArgsConstructor
11 | @ToString
12 | @NoArgsConstructor
13 | public class InputParameter {
14 | /**
15 | * Name of the input will be used as is in the request for http
16 | */
17 | private String name;
18 | /**
19 | * can be either path_parameter, query_parameter or body
20 | */
21 | private String type;
22 | private String description;
23 | private String defaultValue;
24 | private ParamLocation location;
25 |
26 |
27 | public InputParameter(String name, String type, String description) {
28 | this.name = name;
29 | this.type = type;
30 | this.description = description;
31 | }
32 |
33 | public boolean hasDefaultValue() {
34 | return defaultValue!= null;
35 | }
36 |
37 |
38 | }
--------------------------------------------------------------------------------
/src/main/java/com/t4a/action/BlankAction.java:
--------------------------------------------------------------------------------
1 | package com.t4a.action;
2 |
3 | import com.t4a.annotations.Action;
4 | import com.t4a.api.JavaMethodAction;
5 |
6 | /**
7 | * This Action can be used when you want the AI to get back with answer and if you do not have any
8 | * specific action to be performed. For example
9 | * "Hey can you provide weather for tornto and get back with places to see?"
10 | *
11 | * In this case the first action is WeatherAction with method called getTemperature and the second action
12 | * could be blank action as you want it to answer the question.
13 | *
14 | */
15 |
16 | public final class BlankAction implements JavaMethodAction {
17 | @Action
18 | public String askAdditionalQuestion(String additionalQuestion) {
19 | if (additionalQuestion == null) {
20 | return null;
21 | }
22 | if (additionalQuestion.isEmpty()) {
23 | return "";
24 | }
25 | return "provide answer for this query : " + additionalQuestion;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/basic/JsonBuilder.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples.basic;
2 |
3 | import com.t4a.deperecated.GeminiPromptTransformer;
4 | import com.t4a.processor.AIProcessingException;
5 | import lombok.extern.slf4j.Slf4j;
6 |
7 | @Slf4j
8 | public class JsonBuilder {
9 | public static void main(String[] args) throws AIProcessingException {
10 | GeminiPromptTransformer builder = new GeminiPromptTransformer();
11 | String jsonString = "{\"name\":\"String\",\"age\":\"number\",\"address\":{\"street\":\"String\",\"city\":\"String\",\"zip\":\"int\"},\"contacts\":[{\"type\":\"string\",\"value\":\"String\"},{\"type\":\"string\",\"value\":\"string\"}]}";
12 | String prompt = "Can you make sure you add this info about my friend John Doe, aged 30, lives at 123 Main St in New York, zip code 10001. He can be reached via email at john@example.com or by phone at 555-1234.";
13 | jsonString = builder.transformIntoJson(jsonString,prompt,"MyFriend","get friend details");
14 | log.debug(jsonString);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/t4a/api/GroupInfo.java:
--------------------------------------------------------------------------------
1 | package com.t4a.api;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 | import lombok.NoArgsConstructor;
6 | import lombok.Setter;
7 |
8 | import java.util.Objects;
9 |
10 | @Setter
11 | @Getter
12 | @NoArgsConstructor
13 | @AllArgsConstructor
14 | public class GroupInfo {
15 | private String groupName;
16 | private String groupDescription;
17 |
18 | @Override
19 | public boolean equals(Object o) {
20 | if (this == o) return true;
21 | if (o == null || getClass() != o.getClass()) return false;
22 | GroupInfo groupInfo = (GroupInfo) o;
23 | return Objects.equals(groupName, groupInfo.groupName);
24 | }
25 |
26 | @Override
27 | public int hashCode() {
28 | return Objects.hash(groupName);
29 | }
30 |
31 | @Override
32 | public String toString() {
33 | return "GroupInfo{" +
34 | "groupName='" + groupName + '\'' +
35 | ", groupDescription='" + groupDescription + '\'' +
36 | '}';
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/test/InputParameterTest.java:
--------------------------------------------------------------------------------
1 | package com.t4a.test;
2 |
3 |
4 |
5 | import com.t4a.action.http.InputParameter;
6 | import org.junit.jupiter.api.Test;
7 |
8 | import static org.junit.jupiter.api.Assertions.*;
9 |
10 | public class InputParameterTest {
11 |
12 | @Test
13 | public void testInputParameter() {
14 | String name = "Test name";
15 | String type = "Test type";
16 | String description = "Test description";
17 | InputParameter inputParameter = new InputParameter(name, type, description);
18 |
19 | assertEquals(name, inputParameter.getName());
20 | assertEquals(type, inputParameter.getType());
21 | assertEquals(description, inputParameter.getDescription());
22 | }
23 |
24 | @Test
25 | public void testHasDefaultValue() {
26 | InputParameter inputParameter = new InputParameter();
27 | assertFalse(inputParameter.hasDefaultValue());
28 |
29 | inputParameter.setDefaultValue("Default value");
30 | assertTrue(inputParameter.hasDefaultValue());
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/.github/workflows/codecov.yml:
--------------------------------------------------------------------------------
1 | name: Code Coverage
2 | on: [push, pull_request]
3 | jobs:
4 | run:
5 | runs-on: ubuntu-latest
6 | steps:
7 | - name: Checkout
8 | uses: actions/checkout@v4
9 | - name: Set up JDK 18
10 | uses: actions/setup-java@v1
11 | with:
12 | java-version: 18
13 | - name: Install dependencies
14 | run: mvn package -DskipTests=true -Dmaven.javadoc.skip=true -B -V
15 | - name: Run tests and collect coverage
16 | run: mvn -B test jacoco:report
17 | - name: Upload coverage to Codecov
18 | uses: codecov/codecov-action@v4
19 | env:
20 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
21 | - name: Upload test custom
22 | env:
23 | GIST_TOKEN: ${{ secrets.GIST_TOKEN }}
24 | GIST_ID: ${{ secrets.GIST_ID }}
25 | run: bash uploadnumber.sh
26 | - name: Upload test numbers
27 | uses: gaelgirodon/ci-badges-action@v1
28 | with:
29 | gist-id: ${{ secrets.GIST_ID }}
30 | token: ${{ secrets.GIST_TOKEN }}
31 |
32 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/test/PromptTest.java:
--------------------------------------------------------------------------------
1 | package com.t4a.test;
2 | import com.t4a.processor.chain.Prompt;
3 | import com.t4a.processor.chain.SubPrompt;
4 | import org.junit.jupiter.api.Test;
5 |
6 | import java.util.Arrays;
7 | import java.util.List;
8 |
9 | import static org.junit.jupiter.api.Assertions.assertEquals;
10 |
11 | public class PromptTest {
12 |
13 | @Test
14 | public void testPrompt() {
15 | // Arrange
16 | SubPrompt subPrompt1 = new SubPrompt();
17 | subPrompt1.setId("1");
18 | subPrompt1.setSubprompt("SubPrompt 1");
19 | subPrompt1.setDepend_on("Depend 1");
20 |
21 | SubPrompt subPrompt2 = new SubPrompt();
22 | subPrompt2.setId("2");
23 | subPrompt2.setSubprompt("SubPrompt 2");
24 | subPrompt2.setDepend_on("Depend 2");
25 |
26 | List subPrompts = Arrays.asList(subPrompt1, subPrompt2);
27 |
28 | // Act
29 | Prompt prompt = new Prompt();
30 | prompt.setPrmpt(subPrompts);
31 |
32 | // Assert
33 | assertEquals(subPrompts, prompt.getPrmpt());
34 | }
35 | }
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/basic/DateDeserializer.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples.basic;
2 |
3 | import com.google.gson.JsonDeserializationContext;
4 | import com.google.gson.JsonDeserializer;
5 | import com.google.gson.JsonElement;
6 | import com.google.gson.JsonParseException;
7 |
8 | import java.lang.reflect.Type;
9 | import java.text.DateFormat;
10 | import java.text.ParseException;
11 | import java.text.SimpleDateFormat;
12 | import java.util.Date;
13 | import java.util.Locale;
14 |
15 | public class DateDeserializer implements JsonDeserializer {
16 | private final DateFormat dateFormat;
17 |
18 | public DateDeserializer(String format) {
19 | this.dateFormat = new SimpleDateFormat(format, Locale.ENGLISH);
20 | }
21 |
22 | @Override
23 | public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
24 | try {
25 | return dateFormat.parse(json.getAsString().replaceAll("(st|nd|rd|th),", ","));
26 | } catch (ParseException e) {
27 | return new Date();
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/test/ActionKeyTest.java:
--------------------------------------------------------------------------------
1 | package com.t4a.test;
2 |
3 | import com.t4a.api.ActionKey;
4 | import org.junit.jupiter.api.Test;
5 |
6 | import static org.junit.jupiter.api.Assertions.assertNotEquals;
7 |
8 | public class ActionKeyTest {
9 | @Test
10 | void testEqualsAndHashCode() {
11 | // Create two identical AIAction objects
12 | MockAction action1 = new MockAction();
13 |
14 |
15 | MockAction action2 = new MockAction();
16 |
17 |
18 | // Create two ActionKey objects using the identical AIAction objects
19 | ActionKey key1 = new ActionKey(action1);
20 | ActionKey key2 = new ActionKey(action2);
21 |
22 |
23 | assertNotEquals(key1, key2);
24 |
25 |
26 | assertNotEquals(key1.hashCode(), key2.hashCode());
27 |
28 |
29 | ActionKey key3 = new ActionKey(action1);
30 |
31 |
32 | assertNotEquals(key1, key3);
33 |
34 | // The hash codes of the first ActionKey object and the third ActionKey object should noy be the same
35 | assertNotEquals(key1.hashCode(), key3.hashCode());
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/test/BiasDetectorTest.java:
--------------------------------------------------------------------------------
1 | package com.t4a.test;
2 |
3 | import com.t4a.api.ActionType;
4 | import com.t4a.api.GuardRailException;
5 | import com.t4a.detect.BiasDetector;
6 | import org.junit.jupiter.api.BeforeEach;
7 | import org.junit.jupiter.api.Test;
8 |
9 | import static org.junit.jupiter.api.Assertions.*;
10 |
11 | public class BiasDetectorTest {
12 |
13 | private BiasDetector biasDetector;
14 |
15 | @BeforeEach
16 | public void setup() {
17 | biasDetector = new BiasDetector();
18 | }
19 |
20 | @Test
21 | public void testGetActionType() {
22 | assertEquals(ActionType.BIAS, biasDetector.getActionType());
23 | }
24 |
25 | @Test
26 | public void testGetDescription() {
27 | assertEquals("Detect Bias in response", biasDetector.getDescription());
28 | }
29 |
30 | @Test
31 | public void testExecute() throws GuardRailException {
32 | assertNull(biasDetector.execute(null));
33 | assertNotNull(biasDetector.getActionName());
34 | assertEquals("execute", biasDetector.getActionName());
35 |
36 | }
37 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 vishal mysore
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/main/java/com/t4a/predict/ConfigManager.java:
--------------------------------------------------------------------------------
1 | package com.t4a.predict;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 |
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 | import java.util.Properties;
8 |
9 | @Slf4j
10 | public class ConfigManager {
11 | private Properties properties;
12 |
13 | public ConfigManager() {
14 | loadProperties("prompt.properties");
15 | }
16 |
17 | private void loadProperties(String fileName) {
18 | properties = new Properties();
19 | try (InputStream inputStream = PredictionLoader.class.getClassLoader().getResourceAsStream(fileName)) {
20 | if (inputStream != null) {
21 | properties.load(inputStream);
22 | } else {
23 | log.warn(fileName + " properties not found will use default values");
24 | }
25 | } catch (IOException e) {
26 | log.warn("Failed to load properties: " + e.getMessage());
27 | }
28 | }
29 |
30 | public String getProperty(String key, String defaultValue) {
31 | return properties.getProperty(key, defaultValue);
32 | }
33 | }
34 |
35 |
--------------------------------------------------------------------------------
/uploadnumber.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Assuming Maven generates XML test reports in the "target/surefire-reports" directory
4 | TEST_REPORT_DIR="target/surefire-reports"
5 | # Print current directory
6 | echo "Current directory: $(pwd)"
7 |
8 | xml_files=$(find "$(pwd)" -name "TEST-*.xml")
9 |
10 | # Concatenate all XML files and count the occurrences of " /dev/null
26 | exec 2>&1
27 |
28 | # Create or update the Gist with the test count
29 | curl -s -X PATCH \
30 | -H "Authorization: token $GIST_TOKEN" \
31 | -H "Content-Type: application/vnd.github+json" \
32 | -d '{"files":{"test.json":{"content": "{\"schemaVersion\": 1,\"label\": \"testcount\", \"message\": \"'$test_count'\", \"color\":\"orange\"}" }}}' \
33 | "https://api.github.com/gists/$GIST_ID"
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/ShowActionsExample.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples;
2 |
3 | import com.google.gson.Gson;
4 | import com.t4a.api.GroupInfo;
5 | import com.t4a.predict.PredictionLoader;
6 | import lombok.extern.slf4j.Slf4j;
7 |
8 | import java.util.Map;
9 |
10 | @Slf4j
11 | public class ShowActionsExample {
12 |
13 | public ShowActionsExample() throws Exception {
14 |
15 | }
16 | public static void main(String[] args) throws Exception {
17 |
18 | ShowActionsExample sample = new ShowActionsExample();
19 | sample.showActionList();
20 |
21 | Map ga = PredictionLoader.getInstance().getActionGroupList().getGroupActions();
22 | ga.forEach((key, value) -> {
23 | System.out.println("Key: " + key + ", Value: " + value);
24 | });
25 | Gson gsr = new Gson();
26 | String groupInfo = gsr.toJson(PredictionLoader.getInstance().getActionGroupList().getGroupInfo());
27 | System.out.println(groupInfo);
28 | }
29 |
30 | private void showActionList() {
31 | log.debug(PredictionLoader.getInstance().getActionNameList().toString());
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/qodana.yaml:
--------------------------------------------------------------------------------
1 | #-------------------------------------------------------------------------------#
2 | # Qodana analysis is configured by qodana.yaml file #
3 | # https://www.jetbrains.com/help/qodana/qodana-yaml.html #
4 | #-------------------------------------------------------------------------------#
5 | version: "1.0"
6 |
7 | #Specify inspection profile for code analysis
8 | profile:
9 | name: qodana.starter
10 |
11 | #Enable inspections
12 | #include:
13 | # - name:
14 |
15 | #Disable inspections
16 | #exclude:
17 | # - name:
18 | # paths:
19 | # -
20 |
21 | projectJDK: 18 #(Applied in CI/CD pipeline)
22 |
23 | #Execute shell command before Qodana execution (Applied in CI/CD pipeline)
24 | #bootstrap: sh ./prepare-qodana.sh
25 |
26 | #Install IDE plugins before Qodana execution (Applied in CI/CD pipeline)
27 | #plugins:
28 | # - id: #(plugin id can be found at https://plugins.jetbrains.com)
29 |
30 | #Specify Qodana linter for analysis (Applied in CI/CD pipeline)
31 | linter: jetbrains/qodana-jvm-community:latest
32 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/enterprise/fly/BookingHelper.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples.enterprise.fly;
2 |
3 | import java.util.function.Function;
4 |
5 | /**
6 | * In real world this will call the flight booking API we have got all the details here
7 | */
8 | public class BookingHelper {
9 | public static String bookFlight(FlightDetails bookingRequest) {
10 | // Define the book function inside this method
11 | Function book = (request) -> {
12 | // Here you can implement the booking logic
13 | // For simplicity, we'll just return a success message
14 | return "Flight booked successfully!\n" +
15 | "Onward Date: " + request.getDate() + "\n" +
16 | // "Return Date: " + request.getReturnDate() + "\n" +
17 | "From: " + request.getFromLocation() + "\n" +
18 | "To: " + request.getToLocation() + "\n" +
19 | "Passenger Names: " + String.join(", ", request.getName());
20 | };
21 |
22 | // Call the book function with the booking request
23 | return book.apply(bookingRequest);
24 | }
25 | }
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/shell/ShellTester.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples.shell;
2 |
3 | import com.t4a.action.shell.ShellPredictedAction;
4 |
5 | import java.io.File;
6 | import java.io.IOException;
7 | import java.net.URL;
8 |
9 | public class ShellTester {
10 | public static void main(String[] args) throws IOException, InterruptedException {
11 |
12 | URL resourceUrl = ShellTester.class.getClassLoader().getResource("test_script.cmd");
13 | if (resourceUrl != null) {
14 | // Convert URL to file path
15 | String filePath = resourceUrl.getFile();
16 |
17 | // Get the absolute path of the file
18 | File file = new File(filePath);
19 | String absolutePath = file.getAbsolutePath();
20 | ShellPredictedAction action = new ShellPredictedAction("This is action to run shelll command", absolutePath,"testMyScript");
21 | action.executeShell(args);
22 | // Output the absolute path
23 | System.out.println("Absolute path of the file: " + absolutePath);
24 | } else {
25 | System.out.println("File not found.");
26 | }
27 |
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/test/LoggingHumanDecisionTest.java:
--------------------------------------------------------------------------------
1 | package com.t4a.test;
2 |
3 | import com.t4a.processor.LoggingHumanDecision;
4 | import org.junit.jupiter.api.Assertions;
5 | import org.junit.jupiter.api.Test;
6 |
7 | import java.util.HashMap;
8 | import java.util.Map;
9 |
10 | public class LoggingHumanDecisionTest {
11 |
12 | @Test
13 | void testAllowWithMap() {
14 |
15 | LoggingHumanDecision decision = new LoggingHumanDecision();
16 |
17 |
18 | String promptText = "promptText";
19 | String methodName = "methodName";
20 | Map params = new HashMap<>();
21 | params.put("key", "value");
22 |
23 | Assertions.assertTrue(decision.allow(promptText, methodName, params).isAIResponseValid());
24 |
25 |
26 | }
27 |
28 | @Test
29 | void testAllowWithString() {
30 |
31 | LoggingHumanDecision decision = new LoggingHumanDecision();
32 |
33 |
34 | String promptText = "promptText";
35 | String methodName = "methodName";
36 | String params = "params";
37 |
38 | Assertions.assertTrue(decision.allow(promptText, methodName, params).isAIResponseValid());
39 |
40 |
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/t4a/processor/LoggingHumanDecision.java:
--------------------------------------------------------------------------------
1 | package com.t4a.processor;
2 |
3 | import com.t4a.detect.FeedbackLoop;
4 | import com.t4a.detect.HumanInLoop;
5 | import lombok.extern.slf4j.Slf4j;
6 |
7 | import java.util.Map;
8 |
9 | /**
10 | * Simple implementation of Human IN Loop, all it does is logging but in real world this could trigger a full
11 | * human validation and return true or false
12 | */
13 | @Slf4j
14 | public class LoggingHumanDecision implements HumanInLoop {
15 | @Override
16 | public FeedbackLoop allow(String promptText, String methodName, Map params) {
17 |
18 | log.debug(" Do you allow "+methodName+" for "+promptText);
19 | for (Map.Entry entry : params.entrySet()) {
20 | String key = entry.getKey();
21 | Object value = entry.getValue();
22 | log.debug("Key: " + key + ", Value: " + value);
23 | }
24 | return () -> true;
25 | }
26 | @Override
27 | public FeedbackLoop allow(String promptText, String methodName, String params) {
28 |
29 | log.debug(" Do you allow "+methodName+" for "+promptText);
30 |
31 | return () -> true;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/test/AIActionTest.java:
--------------------------------------------------------------------------------
1 | package com.t4a.test;
2 |
3 | import com.t4a.api.AIAction;
4 | import com.t4a.api.ActionRisk;
5 | import com.t4a.api.ActionType;
6 | import org.junit.jupiter.api.Test;
7 |
8 | import static org.junit.jupiter.api.Assertions.assertEquals;
9 |
10 | public class AIActionTest {
11 | @Test
12 | void testDefaultMethods() {
13 | AIAction action = new AIAction() {
14 | @Override
15 | public String getActionName() {
16 | return "testAction";
17 | }
18 |
19 | @Override
20 | public ActionType getActionType() {
21 | return ActionType.JAVAMETHOD;
22 | }
23 |
24 | @Override
25 | public String getDescription() {
26 | return "Test description";
27 | }
28 |
29 | @Override
30 | public String getActionParameters() {
31 | return "";
32 | }
33 | };
34 |
35 | assertEquals(ActionRisk.LOW, action.getActionRisk());
36 | assertEquals("default", action.getActionGroup());
37 | assertEquals("default", action.getGroupDescription());
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/test/resources/swagger_actions.json:
--------------------------------------------------------------------------------
1 | {
2 | "endpoints" : [
3 | {
4 | "swaggerurl": "https://fakerestapi.azurewebsites.net/swagger/v1/swagger.json",
5 | "group": "Books Author Activity",
6 | "description": "This is for all the actions related books , Authors, photos and users trying to read books and view photos",
7 | "baseurl": "https://fakerestapi.azurewebsites.net/",
8 | "id": "fakerestapi"
9 | },
10 | {
11 | "swaggerurl": "https://petstore3.swagger.io/api/v3/openapi.json",
12 | "baseurl": "https://petstore3.swagger.io/",
13 | "group": "Petstore API",
14 | "description": "This is for all the actions related to pets",
15 | "id": "petstore"
16 | },
17 | {
18 | "swaggerurl": "https://huggingface.co/spaces/VishalMysore/mock/raw/main/kibernetes.json",
19 | "group": "kubernetes cluster",
20 | "description": "This is for all the actions related to the kubernetes cluster management",
21 | "baseurl": "https://vishalmysore-mock.hf.space",
22 | "id": "openshift",
23 | "headers": [
24 | {
25 | "key": "Authorization",
26 | "value": "apiKey=samplekey"
27 | }
28 | ]
29 | }
30 | ]
31 | }
--------------------------------------------------------------------------------
/src/test/resources/customerJson.json:
--------------------------------------------------------------------------------
1 | {
2 | "methodName": "computerRepairWithDetails",
3 | "parameters": [
4 | {
5 | "name": "customer",
6 | "fields": [
7 | {
8 | "fieldName": "firstName",
9 | "fieldType": "String",
10 | "value": "John"
11 | },
12 | {
13 | "fieldName": "lastName",
14 | "fieldType": "String",
15 | "value": "Doe"
16 | },
17 | {
18 | "fieldName": "reasonForCalling",
19 | "fieldType": "String",
20 | "value": "Laptop Repair"
21 | },
22 | {
23 | "fieldName": "location",
24 | "fieldType": "String",
25 | "value": "New York"
26 | },
27 | {
28 | "fieldName": "dateJoined",
29 | "fieldType": "Date",
30 | "value": "2019-08-24"
31 | }
32 | ],
33 | "type": "com.t4a.examples.actions.Customer"
34 | },
35 | {
36 | "name": "dateOfComp",
37 | "type": "Date",
38 | "value": "2024-04-05"
39 | },
40 | {
41 | "name": "query",
42 | "type": "String",
43 | "value": "Screen replacement"
44 | }
45 | ],
46 | "returnType": "String"
47 | }
48 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/ScriptExample.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples;
2 |
3 | import com.t4a.processor.scripts.ScriptResult;
4 | import com.t4a.processor.scripts.SeleniumScriptProcessor;
5 | import com.t4a.processor.selenium.SeleniumGeminiProcessor;
6 | import io.github.bonigarcia.wdm.WebDriverManager;
7 | import lombok.extern.java.Log;
8 | import org.openqa.selenium.chrome.ChromeDriver;
9 |
10 | @Log
11 | public class ScriptExample {
12 | public static void main(String[] args) {
13 | //ScriptProcessor script = new ScriptProcessor();
14 | // ScriptResult result= script.process("test.action");
15 | // log.info(script.summarize(result));
16 |
17 | // script = new ScriptProcessor(new OpenAiActionProcessor());
18 | // ScriptResult result= script.process("test.action");
19 | //log.info(script.summarize(result));
20 | WebDriverManager.chromedriver().setup();
21 |
22 | ChromeDriver driver = new ChromeDriver();
23 | SeleniumGeminiProcessor processor = new SeleniumGeminiProcessor(driver);
24 | SeleniumScriptProcessor scriptProcessor = new SeleniumScriptProcessor(processor);
25 | ScriptResult result= scriptProcessor.process("web.action");
26 |
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/t4a/api/ActionKey.java:
--------------------------------------------------------------------------------
1 | package com.t4a.api;
2 |
3 | import lombok.Getter;
4 | import lombok.NoArgsConstructor;
5 | import lombok.Setter;
6 | import lombok.extern.slf4j.Slf4j;
7 |
8 | import java.util.Objects;
9 | import java.util.UUID;
10 |
11 |
12 | @Getter
13 | @Setter
14 | @NoArgsConstructor
15 | @Slf4j
16 | public class ActionKey {
17 | private String actionName;
18 | private String actionDescription;
19 | private long uniqueKey ; public ActionKey(AIAction action) {
20 | generateUniqueKey();
21 | if (action != null) {
22 | actionName = action.getActionName();
23 | actionDescription = action.getDescription();
24 | }
25 | }
26 |
27 | private void generateUniqueKey() {
28 | UUID uuid = UUID.randomUUID();
29 | uniqueKey = uuid.getMostSignificantBits() & Long.MAX_VALUE;
30 |
31 | } @Override
32 | public boolean equals(Object o) {
33 | if (this == o) return true;
34 | if (o == null || getClass() != o.getClass()) return false;
35 | ActionKey actionKey = (ActionKey) o;
36 | return uniqueKey == actionKey.uniqueKey;
37 | }
38 |
39 | @Override
40 | public int hashCode() {
41 | return Objects.hash(uniqueKey);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/enterprise/fly/FlightBookingRequest.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples.enterprise.fly;
2 |
3 | import java.util.Date;
4 | import java.util.List;
5 |
6 | class FlightBookingRequest {
7 | private final Date onwardDate;
8 | private final Date returnDate;
9 | private final List passengerNames;
10 | private final String fromDestination;
11 | private final String toDestination;
12 |
13 | public FlightBookingRequest(Date onwardDate, Date returnDate, List passengerNames, String fromDestination, String toDestination) {
14 | this.onwardDate = onwardDate;
15 | this.returnDate = returnDate;
16 | this.passengerNames = passengerNames;
17 | this.fromDestination = fromDestination;
18 | this.toDestination = toDestination;
19 | }
20 |
21 | public Date getOnwardDate() {
22 | return onwardDate;
23 | }
24 |
25 | public Date getReturnDate() {
26 | return returnDate;
27 | }
28 |
29 | public List getPassengerNames() {
30 | return passengerNames;
31 | }
32 |
33 | public String getFromDestination() {
34 | return fromDestination;
35 | }
36 |
37 | public String getToDestination() {
38 | return toDestination;
39 | }
40 | }
--------------------------------------------------------------------------------
/src/test/java/com/t4a/test/JavaClassExecutorTest.java:
--------------------------------------------------------------------------------
1 | package com.t4a.test;
2 |
3 | import com.google.cloud.vertexai.api.FunctionDeclaration;
4 | import com.t4a.api.JavaClassExecutor;
5 | import com.t4a.examples.actions.Customer;
6 | import org.junit.jupiter.api.BeforeEach;
7 | import org.junit.jupiter.api.Test;
8 |
9 | import static org.junit.jupiter.api.Assertions.assertEquals;
10 | import static org.junit.jupiter.api.Assertions.assertNotNull;
11 |
12 | public class JavaClassExecutorTest {
13 |
14 | private JavaClassExecutor javaClassExecutor;
15 |
16 | @BeforeEach
17 | public void setUp() {
18 | javaClassExecutor = new JavaClassExecutor();
19 | }
20 |
21 | @Test
22 | public void testBuildFunctionFromClass() throws ClassNotFoundException {
23 | String className = Customer.class.getName();
24 | String funName = "testFunction";
25 | String description = "Test function description";
26 |
27 | FunctionDeclaration functionDeclaration = javaClassExecutor.buildFunctionFromClass(className, funName, description);
28 |
29 | assertNotNull(functionDeclaration);
30 | assertEquals(funName, functionDeclaration.getName());
31 | assertEquals(description, functionDeclaration.getDescription());
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/.github/workflows/maven.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven
3 |
4 | # This workflow uses actions that are not certified by GitHub.
5 | # They are provided by a third-party and are governed by
6 | # separate terms of service, privacy policy, and support
7 | # documentation.
8 |
9 | name: Maven Build
10 |
11 | on:
12 | push:
13 | branches: [ "main" ]
14 | pull_request:
15 | branches: [ "main" ]
16 |
17 | jobs:
18 | build:
19 |
20 | runs-on: ubuntu-latest
21 |
22 | steps:
23 | - uses: actions/checkout@v4
24 | - name: Set up JDK 17
25 | uses: actions/setup-java@v3
26 | with:
27 | java-version: '17'
28 | distribution: 'temurin'
29 | cache: maven
30 | - name: Build with Maven
31 | run: mvn -B package --file pom.xml
32 |
33 | # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive
34 | - name: Update dependency graph
35 | uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6
36 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/test/JavaMethodExecutorTest.java:
--------------------------------------------------------------------------------
1 | package com.t4a.test;
2 |
3 | import com.t4a.action.BlankAction;
4 | import com.t4a.api.GenericJavaMethodAction;
5 | import com.t4a.api.JavaMethodExecutor;
6 | import com.t4a.processor.AIProcessingException;
7 | import org.junit.jupiter.api.Assertions;
8 | import org.junit.jupiter.api.Test;
9 |
10 | public class JavaMethodExecutorTest {
11 | @Test
12 | void mapMethodTest() throws AIProcessingException {
13 | JavaMethodExecutor executor = new JavaMethodExecutor();
14 | BlankAction action = new BlankAction();
15 | GenericJavaMethodAction genericJavaMethodAction = new GenericJavaMethodAction(action);
16 | executor.mapMethod(genericJavaMethodAction);
17 | Assertions.assertNotNull(executor.getProperties());
18 | Assertions.assertNotNull(executor.getProperties().get("additionalQuestion"));
19 | }
20 |
21 | @Test
22 | void mapMethodTestAction() throws AIProcessingException {
23 | JavaMethodExecutor executor = new JavaMethodExecutor();
24 | MockAction action = new MockAction();
25 |
26 | executor.mapMethod(action);
27 | Assertions.assertNotNull(executor.getProperties());
28 | Assertions.assertNotNull(executor.getProperties().get("mockName"));
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/test/ActionListTest.java:
--------------------------------------------------------------------------------
1 | package com.t4a.test;
2 |
3 |
4 | import com.t4a.api.ActionGroup;
5 | import com.t4a.api.ActionList;
6 | import com.t4a.api.GroupInfo;
7 | import org.junit.jupiter.api.Test;
8 |
9 | import java.util.ArrayList;
10 | import java.util.HashMap;
11 |
12 | import static org.junit.jupiter.api.Assertions.assertEquals;
13 | import static org.junit.jupiter.api.Assertions.assertNotNull;
14 |
15 | public class ActionListTest {
16 |
17 | @Test
18 | public void testDefaultConstructor() {
19 | ActionList actionList = new ActionList();
20 |
21 | assertNotNull(actionList.getGroups());
22 | assertNotNull(actionList.getGroupInfo());
23 | assertNotNull(actionList.getGroupActions());
24 | }
25 |
26 | @Test
27 | public void testAllArgsConstructor() {
28 | ArrayList groups = new ArrayList<>();
29 | ArrayList groupInfo = new ArrayList<>();
30 | HashMap groupActions = new HashMap<>();
31 |
32 | ActionList actionList = new ActionList(groups, groupInfo, groupActions);
33 |
34 | assertEquals(groups, actionList.getGroups());
35 | assertEquals(groupInfo, actionList.getGroupInfo());
36 | assertEquals(groupActions, actionList.getGroupActions());
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/test/TestClass.java:
--------------------------------------------------------------------------------
1 | package com.t4a.test;
2 |
3 | import com.t4a.annotations.MapKeyType;
4 | import com.t4a.annotations.MapValueType;
5 | import com.t4a.examples.pojo.Employee;
6 | import lombok.Getter;
7 | import lombok.NoArgsConstructor;
8 | import lombok.Setter;
9 |
10 | import java.util.Date;
11 | import java.util.List;
12 | import java.util.Map;
13 |
14 | @Getter
15 | @Setter
16 | @NoArgsConstructor
17 | public class TestClass {
18 | private String name;
19 | private int age;
20 | private double salary;
21 | private boolean isActive;
22 | private List hobbies;
23 | private Map scores;
24 | private Map testMap;
25 | @MapValueType(Integer.class)
26 | @MapKeyType(String.class)
27 | private Map testCustomers;
28 | // getters and setters
29 | private int[] intArray;
30 | private boolean[] booleanArray;
31 | private double[] doubleArray;
32 | private String[] stringArray;
33 | private long[] longArray;
34 | private Date[] dateArray;
35 | private List testList;
36 | private List employeeList;
37 | public void testAddMap(@MapKeyType(String.class) @MapValueType(Integer.class) Map testMapEmployees) {
38 | testMapEmployees.put("test", 1);
39 | }
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/test/AnthropicTransformerTest.java:
--------------------------------------------------------------------------------
1 | package com.t4a.test;
2 |
3 | import com.t4a.predict.PredictionLoader;
4 | import com.t4a.transform.AnthropicTransformer;
5 | import dev.langchain4j.model.anthropic.AnthropicChatModel;
6 | import org.junit.jupiter.api.Assertions;
7 | import org.junit.jupiter.api.Test;
8 | import org.mockito.MockedStatic;
9 | import org.mockito.Mockito;
10 |
11 | public class AnthropicTransformerTest {
12 | @Test
13 | void testTransform() {
14 |
15 | try (MockedStatic responseHandlerMock = Mockito.mockStatic(PredictionLoader.class)) {
16 |
17 | PredictionLoader mockGRP = Mockito.mock(PredictionLoader.class);
18 | responseHandlerMock.when(() -> PredictionLoader.getInstance()).thenReturn(mockGRP);
19 | AnthropicChatModel mockOpenAiChatModel = Mockito.mock(AnthropicChatModel.class);
20 | Mockito.when(mockOpenAiChatModel.generate(Mockito.anyString())).thenReturn("{'response':'success'}");
21 | Mockito.when(mockGRP.getAnthropicChatModel()).thenReturn(mockOpenAiChatModel);
22 | AnthropicTransformer transformer = new AnthropicTransformer();
23 | String json = transformer.getJSONResponseFromAI("My name is vishal and I am from India. I love vegetarian food","{}");
24 | Assertions.assertEquals("{'response':'success'}", json);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/test/resources/http_actions.json:
--------------------------------------------------------------------------------
1 | {
2 | "endpoints": [
3 | {
4 | "actionName": "getUserDetails",
5 | "description" : " this will fetch User details from the user inventory corporate application",
6 | "url": "https://api.example.com/users/",
7 | "type": "GET",
8 | "input_object": [
9 | {
10 | "name": "userId",
11 | "type": "path_parameter",
12 | "description": "User ID"
13 | }
14 | ],
15 |
16 | "output_object": {
17 | "type": "json",
18 | "description": "User object"
19 | },
20 | "auth_interface": {
21 | "type": "Bearer Token",
22 | "description": "Authentication token required"
23 | }
24 | },
25 | {
26 | "actionName": "somethingNotVeryUseful",
27 | "url": "https://api.example.com/temperature",
28 | "description" : " this will get real time temperature from the weather api",
29 | "type": "GET",
30 | "input_object":[
31 | {
32 | "name": "locationId",
33 | "type": "query_parameter",
34 | "description": "Location ID"
35 | }
36 | ],
37 | "output_object": {
38 | "type": "json",
39 | "description": "Real-time temperature data"
40 | },
41 | "auth_interface": {
42 | "type": "API Key",
43 | "description": "API key required"
44 | }
45 | }
46 | ]
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/com/t4a/api/ActionList.java:
--------------------------------------------------------------------------------
1 | package com.t4a.api;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 | import lombok.NoArgsConstructor;
6 | import lombok.Setter;
7 | import lombok.extern.slf4j.Slf4j;
8 |
9 | import java.util.ArrayList;
10 | import java.util.HashMap;
11 | import java.util.List;
12 | import java.util.Map;
13 |
14 | @Getter
15 | @Setter
16 | @NoArgsConstructor
17 | @AllArgsConstructor
18 | @Slf4j
19 | public class ActionList {
20 | private List groups = new ArrayList<>();
21 | private List groupInfo = new ArrayList<>();
22 | private Map groupActions = new HashMap<>();
23 | public void addAction(AIAction action) {
24 | ActionGroup group = new ActionGroup(action.getActionGroup(),action.getGroupDescription());
25 | if(groups.contains(group)) {
26 | group = groups.get(groups.indexOf(group));
27 | } else {
28 | groups.add(group);
29 | groupInfo.add(group.getGroupInfo());
30 | }
31 | group.addAction(action);
32 | String oldValue = groupActions.get(group.getGroupInfo());
33 |
34 |
35 | String value = action.getActionName();
36 |
37 | if(oldValue == null) {
38 | groupActions.put(group.getGroupInfo(),value);
39 | } else {
40 | value= oldValue+","+value;
41 | groupActions.put(group.getGroupInfo(),value);
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/basic/SimpleTalker.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples.basic;
2 |
3 | import com.google.cloud.vertexai.VertexAI;
4 | import com.google.cloud.vertexai.api.GenerateContentResponse;
5 | import com.google.cloud.vertexai.generativeai.*;
6 |
7 | import java.io.IOException;
8 |
9 | /**
10 | * Just basic example demonstrating chatting with Gemini
11 | */
12 | public class SimpleTalker {
13 | public static void main(String[] args) {
14 | String projectId = "cookgptserver";
15 | String location = "us-central1";
16 | String modelName = "gemini-1.0-pro";
17 | try (VertexAI vertexAI = new VertexAI(projectId, location)) {
18 | GenerateContentResponse response;
19 |
20 | GenerativeModel model = new GenerativeModel(modelName, vertexAI);
21 | ChatSession chatSession = new ChatSession(model);
22 |
23 | response = chatSession.sendMessage("Hello CookGPT.");
24 | System.out.println(ResponseHandler.getText(response));
25 |
26 | response = chatSession.sendMessage("I want to eat really spicy Indian Food Today?");
27 | System.out.println(ResponseHandler.getText(response));
28 |
29 | response = chatSession.sendMessage("What is the recipe for Paneer Butter Masala?");
30 | System.out.println(ResponseHandler.getText(response));
31 | } catch (IOException e) {
32 | throw new RuntimeException(e);
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/enterprise/fly/FlightDetails.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples.enterprise.fly;
2 |
3 | public class FlightDetails {
4 | private String date;
5 | private String name;
6 | private String fromLocation;
7 | private String toLocation;
8 |
9 | public FlightDetails() {
10 | }
11 |
12 | public FlightDetails(String date, String name, String fromLocation, String toLocation) {
13 | this.date = date;
14 | this.name = name;
15 | this.fromLocation = fromLocation;
16 | this.toLocation = toLocation;
17 | }
18 |
19 | public String getDate() {
20 | return date;
21 | }
22 |
23 | public void setDate(String date) {
24 | this.date = date;
25 | }
26 |
27 | public String getName() {
28 | return name;
29 | }
30 |
31 | public void setName(String name) {
32 | this.name = name;
33 | }
34 |
35 | public String getFromLocation() {
36 | return fromLocation;
37 | }
38 |
39 | public void setFromLocation(String fromLocation) {
40 | this.fromLocation = fromLocation;
41 | }
42 |
43 | public String getToLocation() {
44 | return toLocation;
45 | }
46 |
47 | public void setToLocation(String toLocation) {
48 | this.toLocation = toLocation;
49 | }
50 | }
51 |
52 |
--------------------------------------------------------------------------------
/src/main/java/com/t4a/processor/LocalAIActionProcessor.java:
--------------------------------------------------------------------------------
1 | package com.t4a.processor;
2 |
3 | import com.t4a.api.AIAction;
4 | import com.t4a.detect.ActionCallback;
5 | import com.t4a.detect.ExplainDecision;
6 | import com.t4a.detect.HumanInLoop;
7 |
8 | public class LocalAIActionProcessor implements AIProcessor {
9 | @Override
10 | public Object processSingleAction(String promptText, HumanInLoop humanVerification, ExplainDecision explain) {
11 | return null;
12 | }
13 |
14 | @Override
15 | public String query(String promptText) throws AIProcessingException {
16 | return null;
17 | }
18 |
19 | @Override
20 | public Object processSingleAction(String prompt, AIAction action, HumanInLoop humanVerification, ExplainDecision explain, ActionCallback callback) throws AIProcessingException {
21 | return null;
22 | }
23 |
24 | @Override
25 | public Object processSingleAction(String promptText, AIAction action, HumanInLoop humanVerification, ExplainDecision explain) throws AIProcessingException {
26 | return null;
27 | }
28 | public Object processSingleAction(String promptText) throws AIProcessingException {
29 | return processSingleAction(promptText, null, new LoggingHumanDecision(), new LogginggExplainDecision());
30 | }
31 |
32 | @Override
33 | public Object processSingleAction(String promptText, ActionCallback callback) throws AIProcessingException {
34 | return null;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/com/t4a/api/ActionGroup.java:
--------------------------------------------------------------------------------
1 | package com.t4a.api;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 | import lombok.NoArgsConstructor;
6 | import lombok.Setter;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 | import java.util.Objects;
11 |
12 | @Getter
13 | @Setter
14 | @NoArgsConstructor
15 | @AllArgsConstructor
16 | public class ActionGroup {
17 | private List actions = new ArrayList<>();
18 | private GroupInfo groupInfo = new GroupInfo();
19 |
20 | public ActionGroup(String groupName) {
21 | groupInfo.setGroupName(groupName);
22 | groupInfo.setGroupDescription(""); // Initialize with empty string
23 | }
24 |
25 | public ActionGroup(String groupName, String groupDescription) {
26 | groupInfo.setGroupName(groupName);
27 | groupInfo.setGroupDescription(groupDescription);
28 | } public void addAction(ActionKey key) {
29 | actions.add(key);
30 | }
31 |
32 | public void addAction(AIAction action) {
33 | actions.add(new ActionKey(action));
34 | }@Override
35 | public boolean equals(Object o) {
36 | if (this == o) return true;
37 | if (o == null || getClass() != o.getClass()) return false;
38 | ActionGroup that = (ActionGroup) o;
39 | return Objects.equals(groupInfo, that.groupInfo);
40 | }
41 |
42 | @Override
43 | public int hashCode() {
44 | return Objects.hash(groupInfo);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: Automated Deployment
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | environment:
7 | description: 'Environment to deploy to'
8 | required: true
9 | default: 'production'
10 | jobs:
11 | build:
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v3
16 | - name: Set up JDK 11
17 | uses: actions/setup-java@v3
18 | with:
19 | distribution: 'temurin'
20 | java-version: '18'
21 |
22 | - name: Build with Maven
23 | run: mvn -B package --file pom.xml
24 |
25 | - name: Set up Apache Maven Central
26 | uses: actions/setup-java@v3
27 | with: # running setup-java again overwrites the settings.xml
28 | distribution: 'temurin'
29 | java-version: '18'
30 | server-id: central # Value of the distributionManagement/repository/id field of the pom.xml
31 | server-username: MAVEN_USERNAME # env variable for username in deploy
32 | server-password: MAVEN_CENTRAL_TOKEN # env variable for token in deploy
33 | gpg-private-key: ${{ secrets.GPG }} # Value of the GPG private key to import
34 | gpg-passphrase: ${{ secrets.PASSPHRASE }} # env variable for GPG private key passphrase
35 |
36 | - name: Publish to Apache Maven Central
37 | run: mvn deploy
38 | env:
39 | MAVEN_USERNAME: ${{ secrets.MVN_USER }}
40 | MAVEN_CENTRAL_TOKEN: ${{ secrets.MVN_PASS}}
41 | MAVEN_GPG_PASSPHRASE: ${{ secrets.PASSPHRASE }}
42 |
--------------------------------------------------------------------------------
/src/main/java/com/t4a/processor/MimeTypeResolver.java:
--------------------------------------------------------------------------------
1 | package com.t4a.processor;
2 |
3 | import com.t4a.api.MimeType;
4 |
5 | import java.io.File;
6 | import java.io.IOException;
7 | import java.net.HttpURLConnection;
8 | import java.net.URI;
9 | import java.net.URISyntaxException;
10 | import java.net.URL;
11 | import javax.activation.MimetypesFileTypeMap;
12 | import lombok.extern.slf4j.Slf4j;
13 |
14 | @Slf4j
15 | public class MimeTypeResolver {
16 | public static String getMimeType(URL url) throws URISyntaxException, IOException {
17 | String scheme = url.toURI().getScheme();
18 | if (scheme == null) {
19 | log.debug("URL scheme is null");
20 | return MimeType.PNG.getMimeType();
21 | }
22 |
23 | switch (scheme.toLowerCase()) {
24 | case "http":
25 | case "https":
26 | HttpURLConnection connection = (HttpURLConnection) url.openConnection();
27 | connection.setRequestMethod("GET");
28 | return connection.getHeaderField("Content-Type");
29 | case "file":
30 | log.debug("URL is a local file");
31 | File file = new File(url.toURI());
32 | return new MimetypesFileTypeMap().getContentType(file.getPath());
33 | default:
34 | log.debug("Unknown URL scheme: " + scheme);
35 | return MimeType.PNG.getMimeType();
36 | }
37 | }
38 |
39 | public static String getMimeType(String url) throws IOException, URISyntaxException {
40 | return getMimeType(URI.create(url).toURL());
41 | }
42 | }
--------------------------------------------------------------------------------
/src/test/java/com/t4a/deperecated/TextProcessor.java:
--------------------------------------------------------------------------------
1 | package com.t4a.deperecated;
2 |
3 | import com.t4a.api.AIAction;
4 | import com.t4a.detect.ActionCallback;
5 | import com.t4a.detect.ExplainDecision;
6 | import com.t4a.detect.HumanInLoop;
7 | import com.t4a.processor.AIProcessingException;
8 | import com.t4a.processor.AIProcessor;
9 | import com.t4a.processor.LoggingHumanDecision;
10 | import com.t4a.processor.LogginggExplainDecision;
11 |
12 | public class TextProcessor implements AIProcessor {
13 | @Override
14 | public Object processSingleAction(String promptText, HumanInLoop humanVerification, ExplainDecision explain) {
15 | return null;
16 | }
17 |
18 | @Override
19 | public String query(String promptText) throws AIProcessingException {
20 | return null;
21 | }
22 |
23 | @Override
24 | public Object processSingleAction(String prompt, AIAction action, HumanInLoop humanVerification, ExplainDecision explain, ActionCallback callback) throws AIProcessingException {
25 | return null;
26 | }
27 |
28 | public Object processSingleAction(String promptText, AIAction action, HumanInLoop humanVerification, ExplainDecision explain) {
29 | return null;
30 | }
31 | public Object processSingleAction(String promptText) throws AIProcessingException {
32 | return processSingleAction(promptText, null, new LoggingHumanDecision(), new LogginggExplainDecision());
33 | }
34 |
35 | @Override
36 | public Object processSingleAction(String promptText, ActionCallback callback) throws AIProcessingException {
37 | return null;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/basic/RestaurantPojo.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples.basic;
2 |
3 | public class RestaurantPojo {
4 | String name;
5 | int numberOfPeople;
6 |
7 | RestaurantDetails restaurantDetails;
8 | boolean cancel;
9 | String reserveDate;
10 |
11 | public RestaurantPojo() {
12 | }
13 |
14 | public RestaurantDetails getRestaurantDetails() {
15 | return restaurantDetails;
16 | }
17 |
18 | public void setName(String name) {
19 | this.name = name;
20 | }
21 |
22 | public void setNumberOfPeople(int numberOfPeople) {
23 | this.numberOfPeople = numberOfPeople;
24 | }
25 |
26 |
27 | public void setCancel(boolean cancel) {
28 | this.cancel = cancel;
29 | }
30 |
31 | public void setReserveDate(String reserveDate) {
32 | this.reserveDate = reserveDate;
33 | }
34 |
35 | public String getName() {
36 | return name;
37 | }
38 |
39 | public int getNumberOfPeople() {
40 | return numberOfPeople;
41 | }
42 |
43 |
44 | public boolean isCancel() {
45 | return cancel;
46 | }
47 |
48 | public String getReserveDate() {
49 | return reserveDate;
50 | }
51 |
52 | @Override
53 | public String toString() {
54 | return "RestaurantPojo{" +
55 | "name='" + name + '\'' +
56 | ", numberOfPeople=" + numberOfPeople +
57 | ", restaurantDetails=" + restaurantDetails +
58 | ", cancel=" + cancel +
59 | ", reserveDate='" + reserveDate + '\'' +
60 | '}';
61 | }
62 | }
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/enterprise/fly/FlightCustomer.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples.enterprise.fly;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 |
5 | import java.io.IOException;
6 |
7 | /**
8 | * Class to test various prompts and see if the booking works
9 | */
10 | @Slf4j
11 | public class FlightCustomer {
12 | public static void main(String[] args) throws IOException {
13 |
14 | String projectId = "cookgptserver";
15 | String location = "us-central1";
16 | String modelName = "gemini-1.0-pro";
17 |
18 | String promptText = "My name is vishal i need to fly from toronto to bangalore on 25th of june, what a great day it is";
19 | String status = AIFlightAssistant.bookFlight(projectId, location, modelName, promptText);
20 | log.debug(promptText+ " : "+status);
21 |
22 | try {
23 | promptText = "My name is vishal i need to fly from toronto to delhi on 25th of December, I saw the movie Sholay again , what a great actiing by amitabh bacchan";
24 | status = AIFlightAssistant.bookFlight(projectId, location, modelName, promptText);
25 | log.debug(promptText + " : " + status);
26 | }catch (Exception e) {
27 | log.debug(promptText +": "+e.getMessage());
28 | }
29 | try {
30 | promptText = "My name is vishal row mysore can i fly from toronto to delhi on 25th of December";
31 | status = AIFlightAssistant.bookFlight(projectId, location, modelName, promptText);
32 | log.debug(promptText + " : " + status);
33 | }catch (Exception e) {
34 | log.debug(promptText +": "+e.getMessage());
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/examples/actions/SearchAction.java:
--------------------------------------------------------------------------------
1 | package com.t4a.examples.actions;
2 |
3 | import com.t4a.annotations.Action;
4 | import com.t4a.annotations.Agent;
5 | import com.t4a.predict.PredictionLoader;
6 | import kong.unirest.core.HttpResponse;
7 | import kong.unirest.core.Unirest;
8 | import lombok.extern.slf4j.Slf4j;
9 |
10 | /**
11 | * Uses Serper API to search the web for real time information. Can we used for Hallucination detection as well
12 | * You need to set serperKey in tools4ai.properties or as System property
13 | */
14 | @Slf4j
15 | @Agent(groupName = "Search",groupDescription = "Search the web for the given string")
16 | public class SearchAction {
17 | public String searchString;
18 | public boolean isNews;
19 |
20 | @Action(description = "Search the web for the given string")
21 | public String googleSearch(String searchString, boolean isNews) {
22 | this.isNews = isNews;
23 | this.searchString = searchString;
24 | return "bhelpuri, panipuri";
25 | }
26 |
27 | public String googleRealSearch(String searchString, boolean isNews) {
28 | this.isNews = isNews;
29 | this.searchString = searchString;
30 |
31 | log.debug(searchString+" : "+isNews);
32 | HttpResponse response = Unirest.post("https://google.serper.dev/search")
33 | .header("X-API-KEY", PredictionLoader.getInstance().getSerperKey())
34 | .header("Content-Type", "application/json")
35 | .body("{\"q\":\""+searchString+"\"}")
36 | .asString();
37 | String resStr = response.getBody().toString();
38 | return resStr;
39 | }
40 |
41 |
42 |
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/test/java/com/t4a/test/LoaderExceptionTest.java:
--------------------------------------------------------------------------------
1 | package com.t4a.test;
2 |
3 | import com.t4a.predict.LoaderException;
4 | import org.junit.jupiter.api.Assertions;
5 | import org.junit.jupiter.api.Test;
6 |
7 | public class LoaderExceptionTest {
8 |
9 |
10 | @Test
11 | void testLoaderExceptionMessage() {
12 | String message = "Test message";
13 | LoaderException exception = new LoaderException(message);
14 | Assertions.assertEquals(message, exception.getMessage());
15 | }
16 |
17 | @Test
18 | void testLoaderExceptionCause() {
19 | String message = "Test message";
20 | Throwable cause = new RuntimeException("Test cause");
21 | LoaderException exception = new LoaderException(message, cause);
22 | Assertions.assertEquals(message, exception.getMessage());
23 | Assertions.assertEquals(cause, exception.getCause());
24 | }
25 |
26 | @Test
27 | void testLoaderExceptionCauseOnly() {
28 | Throwable cause = new RuntimeException("Test cause");
29 | LoaderException exception = new LoaderException(cause);
30 | Assertions.assertEquals(cause, exception.getCause());
31 | }
32 |
33 | @Test
34 | void testLoaderExceptionAllParameters() {
35 | String message = "Test message";
36 | Throwable cause = new RuntimeException("Test cause");
37 | boolean enableSuppression = true;
38 | boolean writableStackTrace = false;
39 | LoaderException exception = new LoaderException(message, cause, enableSuppression, writableStackTrace);
40 | Assertions.assertEquals(message, exception.getMessage());
41 | Assertions.assertEquals(cause, exception.getCause());
42 |
43 | Assertions.assertEquals(writableStackTrace, exception.getStackTrace().length > 0);
44 | }
45 | }
--------------------------------------------------------------------------------