Reflection Agent Example
This commit is contained in:
35
agents/reflection/.gitignore
vendored
Normal file
35
agents/reflection/.gitignore
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
HELP.md
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
shell.log
|
||||
BIN
agents/reflection/.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
BIN
agents/reflection/.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
Binary file not shown.
2
agents/reflection/.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
2
agents/reflection/.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar
|
||||
263
agents/reflection/AgentMergeSort.md
Normal file
263
agents/reflection/AgentMergeSort.md
Normal file
@@ -0,0 +1,263 @@
|
||||
Let's chat!
|
||||
|
||||
USER: Generate a Java implementation of the Merge Sort algorithm
|
||||
|
||||
## Generation
|
||||
|
||||
Certainly! Here's a Java implementation of the Merge Sort algorithm. This implementation includes a `mergeSort` method
|
||||
that recursively divides the array and a `merge` method that combines the sorted subarrays:
|
||||
|
||||
```java
|
||||
public class MergeSort {
|
||||
|
||||
public static void mergeSort(int[] array) {
|
||||
if (array == null || array.length < 2) {
|
||||
return;
|
||||
}
|
||||
mergeSort(array, 0, array.length - 1);
|
||||
}
|
||||
|
||||
private static void mergeSort(int[] array, int left, int right) {
|
||||
if (left < right) {
|
||||
int middle = (left + right) / 2;
|
||||
|
||||
// Recursively sort the two halves
|
||||
mergeSort(array, left, middle);
|
||||
mergeSort(array, middle + 1, right);
|
||||
|
||||
// Merge the sorted halves
|
||||
merge(array, left, middle, right);
|
||||
}
|
||||
}
|
||||
|
||||
private static void merge(int[] array, int left, int middle, int right) {
|
||||
int n1 = middle - left + 1;
|
||||
int n2 = right - middle;
|
||||
|
||||
// Temporary arrays
|
||||
int[] leftArray = new int[n1];
|
||||
int[] rightArray = new int[n2];
|
||||
|
||||
// Copy data to temp arrays
|
||||
System.arraycopy(array, left, leftArray, 0, n1);
|
||||
System.arraycopy(array, middle + 1, rightArray, 0, n2);
|
||||
|
||||
int i = 0, j = 0;
|
||||
int k = left;
|
||||
|
||||
// Merge the temp arrays back into the original array
|
||||
while (i < n1 && j < n2) {
|
||||
if (leftArray[i] <= rightArray[j]) {
|
||||
array[k] = leftArray[i];
|
||||
i++;
|
||||
} else {
|
||||
array[k] = rightArray[j];
|
||||
j++;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
|
||||
// Copy remaining elements of leftArray, if any
|
||||
while (i < n1) {
|
||||
array[k] = leftArray[i];
|
||||
i++;
|
||||
k++;
|
||||
}
|
||||
|
||||
// Copy remaining elements of rightArray, if any
|
||||
while (j < n2) {
|
||||
array[k] = rightArray[j];
|
||||
j++;
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
int[] array = {12, 11, 13, 5, 6, 7};
|
||||
System.out.println("Given Array");
|
||||
printArray(array);
|
||||
|
||||
mergeSort(array);
|
||||
|
||||
System.out.println("\nSorted Array");
|
||||
printArray(array);
|
||||
}
|
||||
|
||||
private static void printArray(int[] array) {
|
||||
for (int value : array) {
|
||||
System.out.print(value + " ");
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Explanation:
|
||||
|
||||
- **`mergeSort` Method**: This method is the entry point for the sorting process. It checks if the array is null or has
|
||||
less than two elements, in which case it returns immediately. Otherwise, it calls the recursive method that handles
|
||||
sorting.
|
||||
|
||||
- **`mergeSort` Recursive Method**: This method divides the array into two halves and recursively sorts each half. It
|
||||
then merges the sorted halves using the `merge` method.
|
||||
|
||||
- **`merge` Method**: It combines the two sorted subarrays into a single sorted array. Temporary arrays are used to hold
|
||||
the divided parts, and the merging process ensures elements are placed in the correct order.
|
||||
|
||||
- **`printArray` Method**: This utility method is used to print the contents of the array before and after sorting.
|
||||
|
||||
This implementation is efficient with a time complexity of O(n log n) and a space complexity of O(n).
|
||||
|
||||
## Critique
|
||||
|
||||
The Java Merge Sort implementation you provided is well-structured and follows the standard approach for implementing
|
||||
this algorithm. However, I have a few recommendations to improve code readability and efficiency:
|
||||
|
||||
1. **Variable Naming:**
|
||||
- Consider using clearer variable names for the indices, such as `start`, `end`, and `mid` instead of `left`,
|
||||
`right`, and `middle`. This can improve readability by making it clearer that these indices refer to the start and
|
||||
end of the partitions.
|
||||
|
||||
2. **Handling Edge Cases:**
|
||||
- The `mergeSort` method already checks for null or very small arrays, which is good. However, confirm that this
|
||||
check is needed if you assume the input will always be at least partially valid.
|
||||
|
||||
3. **Efficiency Consideration:**
|
||||
- The current implementation creates new temporary arrays for each merge operation, which can be inefficient in
|
||||
terms of space. You might consider an approach where a single auxiliary array is used for all merge operations,
|
||||
reducing the space overhead.
|
||||
|
||||
4. **Documentation:**
|
||||
- Adding brief comments directly above each method or section of code could help others understand the purpose and
|
||||
functionality of each part more quickly.
|
||||
|
||||
5. **Main Method:**
|
||||
- Consider adding more test cases in the `main` method to ensure that the algorithm handles edge cases correctly,
|
||||
such as arrays with duplicate values, already sorted arrays, or arrays with negative numbers.
|
||||
|
||||
6. **Code Formatting:**
|
||||
- Ensure consistent use of spaces and indentation, following Java conventions, to improve readability further.
|
||||
|
||||
Here is a minor suggestion for the change in variable naming:
|
||||
|
||||
```java
|
||||
private static void mergeSort(int[] array, int start, int end) {
|
||||
if (start < end) {
|
||||
int mid = (start + end) / 2;
|
||||
mergeSort(array, start, mid);
|
||||
mergeSort(array, mid + 1, end);
|
||||
merge(array, start, mid, end);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Overall, your implementation is correct and functional. These recommendations are mostly for enhancing code readability
|
||||
and potential optimization for space efficiency.
|
||||
AGENT: Thank you for the feedback! To incorporate your suggestions, I've made the following improvements to the original
|
||||
Java Merge Sort implementation:
|
||||
|
||||
1. **Variable Naming**: Changed the variable names for indices to `start`, `end`, and `mid` for clarity.
|
||||
2. **Single Auxiliary Array**: Introduced a single auxiliary array to reduce the space overhead during the merge
|
||||
operations.
|
||||
3. **Improved Documentation**: Added comments to explain the purpose and functionality of methods and key sections of
|
||||
code.
|
||||
4. **Expanded Test Cases**: Included additional test cases in the `main` method to verify the algorithm's robustness
|
||||
against various edge cases.
|
||||
|
||||
Here is the revised implementation:
|
||||
|
||||
```java
|
||||
public class MergeSort {
|
||||
|
||||
public static void mergeSort(int[] array) {
|
||||
if (array == null || array.length < 2) {
|
||||
return;
|
||||
}
|
||||
int[] tempArray = new int[array.length];
|
||||
mergeSort(array, tempArray, 0, array.length - 1);
|
||||
}
|
||||
|
||||
private static void mergeSort(int[] array, int[] tempArray, int start, int end) {
|
||||
if (start < end) {
|
||||
int mid = (start + end) / 2;
|
||||
|
||||
// Recursively sort the two halves
|
||||
mergeSort(array, tempArray, start, mid);
|
||||
mergeSort(array, tempArray, mid + 1, end);
|
||||
|
||||
// Merge the sorted halves
|
||||
merge(array, tempArray, start, mid, end);
|
||||
}
|
||||
}
|
||||
|
||||
private static void merge(int[] array, int[] tempArray, int start, int mid, int end) {
|
||||
// Copy data to temporary array for merging
|
||||
System.arraycopy(array, start, tempArray, start, end - start + 1);
|
||||
|
||||
int leftIndex = start;
|
||||
int rightIndex = mid + 1;
|
||||
int currentIndex = start;
|
||||
|
||||
// Merge the temp arrays back into the original array
|
||||
while (leftIndex <= mid && rightIndex <= end) {
|
||||
if (tempArray[leftIndex] <= tempArray[rightIndex]) {
|
||||
array[currentIndex] = tempArray[leftIndex];
|
||||
leftIndex++;
|
||||
} else {
|
||||
array[currentIndex] = tempArray[rightIndex];
|
||||
rightIndex++;
|
||||
}
|
||||
currentIndex++;
|
||||
}
|
||||
|
||||
// Copy remaining elements of left half, if any
|
||||
while (leftIndex <= mid) {
|
||||
array[currentIndex] = tempArray[leftIndex];
|
||||
leftIndex++;
|
||||
currentIndex++;
|
||||
}
|
||||
|
||||
// No need to copy the right half because it's already in place
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
int[][] testCases = {
|
||||
{12, 11, 13, 5, 6, 7},
|
||||
{5, 5, 5, 5, 5, 5},
|
||||
{},
|
||||
{-1, -3, -2, -5, -4},
|
||||
{1, 2, 3, 4, 5, 6},
|
||||
{9, 7, 5, 3, 1, 0}
|
||||
};
|
||||
|
||||
for (int i = 0; i < testCases.length; i++) {
|
||||
System.out.println("Test Case " + (i + 1) + ":");
|
||||
System.out.println("Original Array:");
|
||||
printArray(testCases[i]);
|
||||
|
||||
mergeSort(testCases[i]);
|
||||
|
||||
System.out.println("Sorted Array:");
|
||||
printArray(testCases[i]);
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
|
||||
private static void printArray(int[] array) {
|
||||
for (int value : array) {
|
||||
System.out.print(value + " ");
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Key Changes:
|
||||
|
||||
- **Single Auxiliary Array**: A single temporary array `tempArray` is used throughout the merge process, which reduces
|
||||
the space complexity from O(n log n) to O(n).
|
||||
- **Comments**: Added comments to guide through the code's logic, making it easier to understand.
|
||||
- **Test Cases**: The `main` method now includes various test cases to ensure the algorithm's effectiveness across
|
||||
different scenarios.
|
||||
|
||||
These enhancements should make the code more efficient and understandable.
|
||||
309
agents/reflection/JacksonTestAgent.md
Normal file
309
agents/reflection/JacksonTestAgent.md
Normal file
@@ -0,0 +1,309 @@
|
||||
Let's chat!
|
||||
|
||||
USER: generate a junit5 test for a Person class that tests for appropriate serialization and deserialization
|
||||
##generation
|
||||
|
||||
To generate a JUnit 5 test for a `Person` class that tests appropriate serialization and deserialization, we need to assume that the `Person` class implements the `Serializable` interface. Additionally, we'll use Java's built-in serialization mechanisms.
|
||||
|
||||
Below is a sample `Person` class and a corresponding JUnit 5 test class that tests the serialization and deserialization process:
|
||||
|
||||
### Person.java
|
||||
```java
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Person implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
private int age;
|
||||
|
||||
public Person(String firstName, String lastName, int age) {
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
// Getters and setters
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(int age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
// Override equals and hashCode for comparison in tests
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Person person = (Person) o;
|
||||
return age == person.age && Objects.equals(firstName, person.firstName) && Objects.equals(lastName, person.lastName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(firstName, lastName, age);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### PersonTest.java
|
||||
```java
|
||||
import org.junit.jupiter.api.Test;
|
||||
import java.io.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class PersonTest {
|
||||
|
||||
@Test
|
||||
void testSerializationAndDeserialization() {
|
||||
Person originalPerson = new Person("John", "Doe", 30);
|
||||
Person deserializedPerson = null;
|
||||
|
||||
// Serialize the object
|
||||
try (ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
|
||||
ObjectOutputStream outStream = new ObjectOutputStream(byteOutStream)) {
|
||||
outStream.writeObject(originalPerson);
|
||||
outStream.flush();
|
||||
|
||||
// Deserialize the object
|
||||
try (ByteArrayInputStream byteInStream = new ByteArrayInputStream(byteOutStream.toByteArray());
|
||||
ObjectInputStream inStream = new ObjectInputStream(byteInStream)) {
|
||||
deserializedPerson = (Person) inStream.readObject();
|
||||
}
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
fail("Exception during serialization/deserialization: " + e.getMessage());
|
||||
}
|
||||
|
||||
// Assert that the original and deserialized objects are equal
|
||||
assertEquals(originalPerson, deserializedPerson, "The deserialized person should be equal to the original person");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Explanation
|
||||
|
||||
- **Person Class**: This class is serializable and includes basic attributes like first name, last name, and age. It overrides `equals` and `hashCode` for comparison purposes.
|
||||
|
||||
- **Test Class**: The `testSerializationAndDeserialization` method in `PersonTest`:
|
||||
- Creates a `Person` object.
|
||||
- Serializes it using `ObjectOutputStream`.
|
||||
- Deserializes it back using `ObjectInputStream`.
|
||||
- Asserts that the original and deserialized `Person` objects are equal, using `assertEquals`.
|
||||
|
||||
This test ensures that the `Person` class can be serialized and deserialized correctly, maintaining data integrity.
|
||||
##Critique
|
||||
|
||||
Here are some recommendations and critiques for the provided content:
|
||||
|
||||
1. **Error Handling Improvement**:
|
||||
- Instead of catching and handling exceptions with a `fail` method, consider using `assertThrows` for expected exceptions or add more detailed error handling logic, especially in production code where it's crucial to handle exceptions gracefully.
|
||||
|
||||
2. **Code Readability**:
|
||||
- Consider adding comments within the test method to separate the serialization and deserialization logic more clearly. This can help in understanding each step easily.
|
||||
|
||||
3. **Testing Edge Cases**:
|
||||
- Add tests for edge cases, such as null values for `firstName` and `lastName`, and negative values or maximum integer value for `age`, to ensure that serialization handles these cases without any issues.
|
||||
|
||||
4. **Test Structure**:
|
||||
- While the test correctly checks for equality, consider separating serialization and deserialization into distinct test methods for better modularity and easier debugging if something goes wrong.
|
||||
|
||||
5. **Test Coverage**:
|
||||
- Introduce tests for other scenarios like modifying object attributes after deserialization to ensure object integrity and correct behavior of getters and setters.
|
||||
|
||||
6. **Java Class Structure**:
|
||||
- Ensure fields in the `Person` class are initialized properly, possibly with default values, to avoid null-related issues during serialization and deserialization.
|
||||
|
||||
7. **Use of Modern Java Features**:
|
||||
- Consider using Java's `try-with-resources` more explicitly with braces for better clarity and consistency.
|
||||
|
||||
By addressing these points, you can improve the robustness, readability, and coverage of your test code.
|
||||
##Critique
|
||||
|
||||
<OK>
|
||||
|
||||
|
||||
Stop sequence found
|
||||
|
||||
|
||||
AGENT: Thank you for the detailed feedback. Let's incorporate your recommendations into a revised version of the code:
|
||||
|
||||
### Revised Person.java
|
||||
```java
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Person implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
private int age;
|
||||
|
||||
public Person(String firstName, String lastName, int age) {
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
// Getters and setters
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(int age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
// Override equals and hashCode for comparison in tests
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Person person = (Person) o;
|
||||
return age == person.age && Objects.equals(firstName, person.firstName) && Objects.equals(lastName, person.lastName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(firstName, lastName, age);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Revised PersonTest.java
|
||||
```java
|
||||
import org.junit.jupiter.api.Test;
|
||||
import java.io.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class PersonTest {
|
||||
|
||||
@Test
|
||||
void testSerialization() {
|
||||
Person originalPerson = new Person("John", "Doe", 30);
|
||||
|
||||
// Serialize the object
|
||||
byte[] serializedPerson;
|
||||
try (ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
|
||||
ObjectOutputStream outStream = new ObjectOutputStream(byteOutStream)) {
|
||||
outStream.writeObject(originalPerson);
|
||||
serializedPerson = byteOutStream.toByteArray();
|
||||
} catch (IOException e) {
|
||||
fail("Serialization failed: " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
assertNotNull(serializedPerson, "Serialized person should not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeserialization() {
|
||||
Person originalPerson = new Person("John", "Doe", 30);
|
||||
byte[] serializedPerson;
|
||||
|
||||
// Serialize first to get byte array
|
||||
try (ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
|
||||
ObjectOutputStream outStream = new ObjectOutputStream(byteOutStream)) {
|
||||
outStream.writeObject(originalPerson);
|
||||
serializedPerson = byteOutStream.toByteArray();
|
||||
} catch (IOException e) {
|
||||
fail("Serialization failed: " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
// Deserialize the object
|
||||
Person deserializedPerson;
|
||||
try (ByteArrayInputStream byteInStream = new ByteArrayInputStream(serializedPerson);
|
||||
ObjectInputStream inStream = new ObjectInputStream(byteInStream)) {
|
||||
deserializedPerson = (Person) inStream.readObject();
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
fail("Deserialization failed: " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
// Assert that the original and deserialized objects are equal
|
||||
assertEquals(originalPerson, deserializedPerson, "Deserialized person should be equal to the original person");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSerializationWithNullValues() {
|
||||
Person originalPerson = new Person(null, null, 30);
|
||||
|
||||
// Serialize and deserialize
|
||||
byte[] serializedPerson;
|
||||
try (ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
|
||||
ObjectOutputStream outStream = new ObjectOutputStream(byteOutStream)) {
|
||||
outStream.writeObject(originalPerson);
|
||||
serializedPerson = byteOutStream.toByteArray();
|
||||
} catch (IOException e) {
|
||||
fail("Serialization failed: " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
Person deserializedPerson;
|
||||
try (ByteArrayInputStream byteInStream = new ByteArrayInputStream(serializedPerson);
|
||||
ObjectInputStream inStream = new ObjectInputStream(byteInStream)) {
|
||||
deserializedPerson = (Person) inStream.readObject();
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
fail("Deserialization failed: " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
// Assert that the original and deserialized objects are equal
|
||||
assertEquals(originalPerson, deserializedPerson, "Deserialized person with null values should be equal to the original person");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Key Changes:
|
||||
|
||||
1. **Separate Test Methods**: The tests for serialization and deserialization have been separated for better modularity.
|
||||
|
||||
2. **Error Handling**: We continue to use `fail` for handling exceptions but ensure detailed messages. `assertThrows` is more suitable for expected exceptions, which isn't the primary focus here.
|
||||
|
||||
3. **Code Readability**: Added comments and structured the code for clarity, particularly separating serialization and deserialization steps.
|
||||
|
||||
4. **Edge Case Testing**: Added a test for null values in `firstName` and `lastName`.
|
||||
|
||||
By addressing your critiques, the revised code offers improved readability, modularity, and coverage.
|
||||
|
||||
114
agents/reflection/README.md
Normal file
114
agents/reflection/README.md
Normal file
@@ -0,0 +1,114 @@
|
||||
# Spring AI Hello World Chat Application
|
||||
|
||||
A simple command-line chat application demonstrating Spring AI's ChatClient capabilities with AI models.
|
||||
|
||||
It is based on the code in the repository https://github.com/neural-maze/agentic_patterns
|
||||
|
||||
## Prerequisites
|
||||
- Java 17 or higher
|
||||
- Maven
|
||||
|
||||
This examples uses OpenAI as the model provider.
|
||||
|
||||
Before using the AI commands, make sure you have a developer token from OpenAI.
|
||||
|
||||
Create an account at [OpenAI Signup](https://platform.openai.com/signup) and generate the token at [API Keys](https://platform.openai.com/account/api-keys).
|
||||
|
||||
The Spring AI project defines a configuration property named `spring.ai.openai.api-key` that you should set to the value of the API key obtained from OpenAI.
|
||||
|
||||
Exporting an environment variable is one way to set that configuration property:
|
||||
|
||||
```shell
|
||||
export SPRING_AI_OPENAI_API_KEY=<INSERT KEY HERE>
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Running the Application
|
||||
1. Clone the repository
|
||||
2. Navigate to the project directory
|
||||
3. Run the application using Maven wrapper:
|
||||
`./mvnw spring-boot:run`
|
||||
|
||||
## Reflection Agent Demo
|
||||
This project demonstrates the use of Spring AI to create a self-improving code generation system. The Reflection Agent uses two ChatClient instances in an iterative loop - one for generation and one for critique - to produce high-quality Java code.
|
||||
|
||||
## Overview
|
||||
The application implements a reflection-based system where the Reflection Agent:
|
||||
|
||||
1. Uses a generation `ChatClient` instance to create code based on user prompts
|
||||
2. Uses a critique `ChatClient` instance to review the generated code
|
||||
3. Iteratively improves the code by feeding critique back to the generation ChatClient
|
||||
4. Continues this loop until the critique ChatClient is satisfied with the quality
|
||||
|
||||
## Project Structure
|
||||
### Main Components
|
||||
|
||||
* `Application.java`: The main Spring Boot application that provides the command-line interface
|
||||
* `ReflectionAgent.java`: The core component that manages the iteration between generation and critique
|
||||
|
||||
|
||||
## How It Works
|
||||
|
||||
### Initial Setup
|
||||
|
||||
The Reflection Agent creates two `ChatClient` instances:
|
||||
|
||||
- **generateChatClient**: For generating Java code based on user requests
|
||||
- **critiqueChatClient**: For reviewing and critiquing the generated code
|
||||
|
||||
## Generation Process
|
||||
|
||||
- **User inputs a request**
|
||||
- The **generation ChatClient** creates initial code
|
||||
- The **critique ChatClient** reviews the code
|
||||
- If improvements are needed, the **generation ChatClient** creates a revised version
|
||||
- This continues for up to `maxIterations` or until the **critique ChatClient** approves (`<OK>`)
|
||||
-
|
||||
## ChatClient Configurations
|
||||
|
||||
- **Generation ChatClient**:
|
||||
|
||||
```text
|
||||
You are a Java programmer tasked with generating high quality Java code. Your task is to generate the best content possible for the user's request.
|
||||
```
|
||||
- **Critique ChatClient**:
|
||||
```text
|
||||
You are tasked with generating critique and recommendations for the user's generated content. If the user content has something wrong or something to be improved, output a list of recommendations and critiques."
|
||||
```
|
||||
|
||||
## Example Run
|
||||
|
||||
In this sample run, the user requested a JUnit 5 test for a `Person` class. See the file `JacksonTestAgent.md` for the actual output.
|
||||
|
||||
### Initial Generation
|
||||
|
||||
- The generation `ChatClient` created a basic `Person` class and test class
|
||||
- Included serialization/deserialization functionality
|
||||
- Implemented basic test cases
|
||||
|
||||
### Critique Phase
|
||||
|
||||
The critique `ChatClient identified several improvements:
|
||||
|
||||
- Better error handling
|
||||
- Improved code readability
|
||||
- Need for edge case testing
|
||||
- Better test structure
|
||||
- Expanded test coverage
|
||||
- Enhanced Java class structure
|
||||
- Modern Java feature usage
|
||||
|
||||
### Final Result
|
||||
|
||||
The generation `ChatClient` created improved code with:
|
||||
|
||||
- Separated test methods for better modularity
|
||||
- Enhanced error handling with detailed messages
|
||||
- Added edge case testing for null values
|
||||
- Improved code structure and readability
|
||||
- Better test coverage
|
||||
|
||||
## MergeSort
|
||||
|
||||
The file `AgentMergeSort.md` shows a similar run to create a merge sort algorithm.
|
||||
305
agents/reflection/mvnw
vendored
Executable file
305
agents/reflection/mvnw
vendored
Executable file
@@ -0,0 +1,305 @@
|
||||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------------
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Maven2 Start Up Batch script
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# JAVA_HOME - location of a JDK home dir
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# M2_HOME - location of maven2's installed home dir
|
||||
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
# e.g. to debug Maven itself, use
|
||||
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if [ -z "$MAVEN_SKIP_RC" ] ; then
|
||||
|
||||
if [ -f /etc/mavenrc ] ; then
|
||||
. /etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f "$HOME/.mavenrc" ] ; then
|
||||
. "$HOME/.mavenrc"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# OS specific support. $var _must_ be set to either true or false.
|
||||
cygwin=false;
|
||||
darwin=false;
|
||||
mingw=false
|
||||
case "`uname`" in
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true;;
|
||||
Darwin*) darwin=true
|
||||
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
|
||||
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
if [ -x "/usr/libexec/java_home" ]; then
|
||||
export JAVA_HOME="`/usr/libexec/java_home`"
|
||||
else
|
||||
export JAVA_HOME="/Library/Java/Home"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
if [ -r /etc/gentoo-release ] ; then
|
||||
JAVA_HOME=`java-config --jre-home`
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$M2_HOME" ] ; then
|
||||
## resolve links - $0 may be a link to maven's home
|
||||
PRG="$0"
|
||||
|
||||
# need this for relative symlinks
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG="`dirname "$PRG"`/$link"
|
||||
fi
|
||||
done
|
||||
|
||||
saveddir=`pwd`
|
||||
|
||||
M2_HOME=`dirname "$PRG"`/..
|
||||
|
||||
# make it fully qualified
|
||||
M2_HOME=`cd "$M2_HOME" && pwd`
|
||||
|
||||
cd "$saveddir"
|
||||
# echo Using m2 at $M2_HOME
|
||||
fi
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||
if $cygwin ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --unix "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
|
||||
fi
|
||||
|
||||
# For Mingw, ensure paths are in UNIX format before anything is touched
|
||||
if $mingw ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME="`(cd "$M2_HOME"; pwd)`"
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
javaExecutable="`which javac`"
|
||||
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
|
||||
# readlink(1) is not available as standard on Solaris 10.
|
||||
readLink=`which readlink`
|
||||
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
|
||||
if $darwin ; then
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
|
||||
else
|
||||
javaExecutable="`readlink -f \"$javaExecutable\"`"
|
||||
fi
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
|
||||
JAVA_HOME="$javaHome"
|
||||
export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$JAVACMD" ] ; then
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
else
|
||||
JAVACMD="`which java`"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||
echo " We cannot execute $JAVACMD" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
echo "Warning: JAVA_HOME environment variable is not set."
|
||||
fi
|
||||
|
||||
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
|
||||
|
||||
# traverses directory structure from process work directory to filesystem root
|
||||
# first directory with .mvn subdirectory is considered project base directory
|
||||
find_maven_basedir() {
|
||||
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo "Path not specified to find_maven_basedir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
basedir="$1"
|
||||
wdir="$1"
|
||||
while [ "$wdir" != '/' ] ; do
|
||||
if [ -d "$wdir"/.mvn ] ; then
|
||||
basedir=$wdir
|
||||
break
|
||||
fi
|
||||
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||
if [ -d "${wdir}" ]; then
|
||||
wdir=`cd "$wdir/.."; pwd`
|
||||
fi
|
||||
# end of workaround
|
||||
done
|
||||
echo "${basedir}"
|
||||
}
|
||||
|
||||
# concatenates all lines of a file
|
||||
concat_lines() {
|
||||
if [ -f "$1" ]; then
|
||||
echo "$(tr -s '\n' ' ' < "$1")"
|
||||
fi
|
||||
}
|
||||
|
||||
BASE_DIR=`find_maven_basedir "$(pwd)"`
|
||||
if [ -z "$BASE_DIR" ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
##########################################################################################
|
||||
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
# This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
##########################################################################################
|
||||
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found .mvn/wrapper/maven-wrapper.jar"
|
||||
fi
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
|
||||
fi
|
||||
if [ "$MVNW_REPOURL" = true]; then
|
||||
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.2/maven-wrapper-0.5.2.jar"
|
||||
else
|
||||
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.2/maven-wrapper-0.5.2.jar"
|
||||
fi
|
||||
while IFS="=" read key value; do
|
||||
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
|
||||
esac
|
||||
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Downloading from: $jarUrl"
|
||||
fi
|
||||
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
|
||||
if $cygwin; then
|
||||
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
|
||||
fi
|
||||
|
||||
if command -v wget > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found wget ... using wget"
|
||||
fi
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
wget "$jarUrl" -O "$wrapperJarPath"
|
||||
else
|
||||
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
|
||||
fi
|
||||
elif command -v curl > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found curl ... using curl"
|
||||
fi
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
curl -o "$wrapperJarPath" "$jarUrl" -f
|
||||
else
|
||||
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
|
||||
fi
|
||||
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Falling back to using Java to download"
|
||||
fi
|
||||
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||
# For Cygwin, switch paths to Windows format before running javac
|
||||
if $cygwin; then
|
||||
javaClass=`cygpath --path --windows "$javaClass"`
|
||||
fi
|
||||
if [ -e "$javaClass" ]; then
|
||||
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Compiling MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
# Compiling the Java class
|
||||
("$JAVA_HOME/bin/javac" "$javaClass")
|
||||
fi
|
||||
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
# Running the downloader
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Running MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
##########################################################################################
|
||||
# End of extension
|
||||
##########################################################################################
|
||||
|
||||
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo $MAVEN_PROJECTBASEDIR
|
||||
fi
|
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --path --windows "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
|
||||
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
|
||||
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
|
||||
fi
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
||||
172
agents/reflection/mvnw.cmd
vendored
Executable file
172
agents/reflection/mvnw.cmd
vendored
Executable file
@@ -0,0 +1,172 @@
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Maven2 Start Up Batch script
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM M2_HOME - location of maven2's installed home dir
|
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
|
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
@REM e.g. to debug Maven itself, use
|
||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||
@echo off
|
||||
@REM set title of command window
|
||||
title %0
|
||||
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
|
||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||
|
||||
@REM set %HOME% to equivalent of $HOME
|
||||
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||
|
||||
@REM Execute a user defined script before this one
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
|
||||
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
|
||||
:skipRcPre
|
||||
|
||||
@setlocal
|
||||
|
||||
set ERROR_CODE=0
|
||||
|
||||
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||
@setlocal
|
||||
|
||||
@REM ==== START VALIDATION ====
|
||||
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME not found in your environment. >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
:OkJHome
|
||||
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
@REM ==== END VALIDATION ====
|
||||
|
||||
:init
|
||||
|
||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||
@REM Fallback to current working directory if not found.
|
||||
|
||||
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||
|
||||
set EXEC_DIR=%CD%
|
||||
set WDIR=%EXEC_DIR%
|
||||
:findBaseDir
|
||||
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||
cd ..
|
||||
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||
set WDIR=%CD%
|
||||
goto findBaseDir
|
||||
|
||||
:baseDirFound
|
||||
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||
cd "%EXEC_DIR%"
|
||||
goto endDetectBaseDir
|
||||
|
||||
:baseDirNotFound
|
||||
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||
cd "%EXEC_DIR%"
|
||||
|
||||
:endDetectBaseDir
|
||||
|
||||
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||
|
||||
@setlocal EnableExtensions EnableDelayedExpansion
|
||||
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||
|
||||
:endReadAdditionalConfig
|
||||
|
||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.2/maven-wrapper-0.5.2.jar"
|
||||
|
||||
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
|
||||
)
|
||||
|
||||
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
if exist %WRAPPER_JAR% (
|
||||
echo Found %WRAPPER_JAR%
|
||||
) else (
|
||||
if not "%MVNW_REPOURL%" == "" (
|
||||
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.2/maven-wrapper-0.5.2.jar"
|
||||
)
|
||||
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||
echo Downloading from: %DOWNLOAD_URL%
|
||||
|
||||
powershell -Command "&{"^
|
||||
"$webclient = new-object System.Net.WebClient;"^
|
||||
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
|
||||
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
|
||||
"}"^
|
||||
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
|
||||
"}"
|
||||
echo Finished downloading %WRAPPER_JAR%
|
||||
)
|
||||
@REM End of extension
|
||||
|
||||
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
|
||||
if ERRORLEVEL 1 goto error
|
||||
goto end
|
||||
|
||||
:error
|
||||
set ERROR_CODE=1
|
||||
|
||||
:end
|
||||
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
|
||||
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
|
||||
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
|
||||
:skipRcPost
|
||||
|
||||
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||
if "%MAVEN_BATCH_PAUSE%" == "on" pause
|
||||
|
||||
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
|
||||
|
||||
exit /B %ERROR_CODE%
|
||||
84
agents/reflection/pom.xml
Normal file
84
agents/reflection/pom.xml
Normal file
@@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>ai-openai-helloworld</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>ai-openai-helloworld</name>
|
||||
<description>Simple AI Application using OpenAPI Service</description>
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ai</groupId>
|
||||
<artifactId>spring-ai-bom</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.ai</groupId>
|
||||
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.springframework.ai.openai.samples.helloworld;
|
||||
|
||||
import org.springframework.ai.chat.client.ChatClient;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import java.util.Scanner;
|
||||
|
||||
@SpringBootApplication
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
CommandLineRunner cli(ReflectionAgent reflectionAgent) {
|
||||
return args -> {
|
||||
var scanner = new Scanner(System.in);
|
||||
System.out.println("\nLet's chat!");
|
||||
|
||||
// Generate a Java implementation of the Merge Sort algorithm
|
||||
while (true) {
|
||||
System.out.print("\nUSER: ");
|
||||
System.out.println("AGENT: " +
|
||||
reflectionAgent.run(scanner.nextLine(), 2));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2024 - 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ai.openai.samples.helloworld;
|
||||
|
||||
import org.springframework.ai.chat.client.ChatClient;
|
||||
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
|
||||
import org.springframework.ai.chat.memory.InMemoryChatMemory;
|
||||
import org.springframework.ai.chat.model.ChatModel;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class ReflectionAgent {
|
||||
|
||||
private final ChatClient generateChatClient;
|
||||
|
||||
private final ChatClient critiqueChatClient;
|
||||
|
||||
|
||||
public ReflectionAgent(ChatModel chatModel) {
|
||||
this.generateChatClient = ChatClient.builder(chatModel)
|
||||
.defaultSystem("""
|
||||
You are a Java programmer tasked with generating high quality Java code.
|
||||
Your task is to Generate the best content possible for the user's request. If the user provides critique,
|
||||
respond with a revised version of your previous attempt.
|
||||
""")
|
||||
.defaultAdvisors(new MessageChatMemoryAdvisor(new InMemoryChatMemory()))
|
||||
.build();
|
||||
|
||||
this.critiqueChatClient = ChatClient.builder(chatModel)
|
||||
.defaultSystem("""
|
||||
You are tasked with generating critique and recommendations to the user's generated content.
|
||||
If the user content has something wrong or something to be improved, output a list of recommendations
|
||||
and critiques. If the user content is ok and there's nothing to change, output this: <OK>
|
||||
""")
|
||||
.defaultAdvisors(new MessageChatMemoryAdvisor(new InMemoryChatMemory()))
|
||||
.build();
|
||||
}
|
||||
|
||||
public String run(String userQuestion, int maxIterations) {
|
||||
|
||||
String generation = generateChatClient.prompt(userQuestion).call().content();
|
||||
System.out.println("##generation\n\n" + generation);
|
||||
String critique;
|
||||
for (int i = 0; i < maxIterations; i++) {
|
||||
|
||||
critique = critiqueChatClient.prompt(generation).call().content();
|
||||
|
||||
System.out.println("##Critique\n\n" + critique);
|
||||
if (critique.contains("<OK>")) {
|
||||
System.out.println("\n\nStop sequence found\n\n");
|
||||
break;
|
||||
}
|
||||
generation = generateChatClient.prompt(critique).call().content();
|
||||
}
|
||||
return generation;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
29
agents/reflection/src/main/resources/application.yaml
Normal file
29
agents/reflection/src/main/resources/application.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
spring:
|
||||
ai:
|
||||
azure:
|
||||
openai:
|
||||
chat:
|
||||
options:
|
||||
function-callbacks:
|
||||
- name: "functionName1"
|
||||
description: "Description of what function1 does"
|
||||
input-type-schema: |
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"param1": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
- name: "functionName2"
|
||||
description: "Description of what function2 does"
|
||||
input-type-schema: |
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"param2": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2024 - 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ai.openai.samples.helloworld;
|
||||
|
||||
public class MergeSort {
|
||||
|
||||
public static void mergeSort(int[] array) {
|
||||
if (array == null || array.length < 2) {
|
||||
return;
|
||||
}
|
||||
int[] tempArray = new int[array.length];
|
||||
mergeSort(array, tempArray, 0, array.length - 1);
|
||||
}
|
||||
|
||||
private static void mergeSort(int[] array, int[] tempArray, int start, int end) {
|
||||
if (start < end) {
|
||||
int mid = (start + end) / 2;
|
||||
|
||||
// Recursively sort the two halves
|
||||
mergeSort(array, tempArray, start, mid);
|
||||
mergeSort(array, tempArray, mid + 1, end);
|
||||
|
||||
// Merge the sorted halves
|
||||
merge(array, tempArray, start, mid, end);
|
||||
}
|
||||
}
|
||||
|
||||
private static void merge(int[] array, int[] tempArray, int start, int mid, int end) {
|
||||
// Copy data to temporary array for merging
|
||||
System.arraycopy(array, start, tempArray, start, end - start + 1);
|
||||
|
||||
int leftIndex = start;
|
||||
int rightIndex = mid + 1;
|
||||
int currentIndex = start;
|
||||
|
||||
// Merge the temp arrays back into the original array
|
||||
while (leftIndex <= mid && rightIndex <= end) {
|
||||
if (tempArray[leftIndex] <= tempArray[rightIndex]) {
|
||||
array[currentIndex] = tempArray[leftIndex];
|
||||
leftIndex++;
|
||||
} else {
|
||||
array[currentIndex] = tempArray[rightIndex];
|
||||
rightIndex++;
|
||||
}
|
||||
currentIndex++;
|
||||
}
|
||||
|
||||
// Copy remaining elements of left half, if any
|
||||
while (leftIndex <= mid) {
|
||||
array[currentIndex] = tempArray[leftIndex];
|
||||
leftIndex++;
|
||||
currentIndex++;
|
||||
}
|
||||
|
||||
// No need to copy the right half because it's already in place
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
int[][] testCases = {
|
||||
{12, 11, 13, 5, 6, 7},
|
||||
{5, 5, 5, 5, 5, 5},
|
||||
{},
|
||||
{-1, -3, -2, -5, -4},
|
||||
{1, 2, 3, 4, 5, 6},
|
||||
{9, 7, 5, 3, 1, 0}
|
||||
};
|
||||
|
||||
for (int i = 0; i < testCases.length; i++) {
|
||||
System.out.println("Test Case " + (i + 1) + ":");
|
||||
System.out.println("Original Array:");
|
||||
printArray(testCases[i]);
|
||||
|
||||
mergeSort(testCases[i]);
|
||||
|
||||
System.out.println("Sorted Array:");
|
||||
printArray(testCases[i]);
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
|
||||
private static void printArray(int[] array) {
|
||||
for (int value : array) {
|
||||
System.out.print(value + " ");
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package org.springframework.ai.openai.samples.helloworld;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class ResultFromAgentTest {
|
||||
|
||||
@Test
|
||||
void testMergeSortWithRandomArray() {
|
||||
int[] array = {12, 11, 13, 5, 6, 7};
|
||||
int[] expected = {5, 6, 7, 11, 12, 13};
|
||||
|
||||
MergeSort.mergeSort(array);
|
||||
assertArrayEquals(expected, array);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMergeSortWithAllSameElements() {
|
||||
int[] array = {5, 5, 5, 5, 5};
|
||||
int[] expected = {5, 5, 5, 5, 5};
|
||||
|
||||
MergeSort.mergeSort(array);
|
||||
assertArrayEquals(expected, array);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMergeSortWithEmptyArray() {
|
||||
int[] array = {};
|
||||
int[] expected = {};
|
||||
|
||||
MergeSort.mergeSort(array);
|
||||
assertArrayEquals(expected, array);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMergeSortWithNegativeNumbers() {
|
||||
int[] array = {-1, -3, -2, -5, -4};
|
||||
int[] expected = {-5, -4, -3, -2, -1};
|
||||
|
||||
MergeSort.mergeSort(array);
|
||||
assertArrayEquals(expected, array);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMergeSortWithAlreadySortedArray() {
|
||||
int[] array = {1, 2, 3, 4, 5, 6};
|
||||
int[] expected = {1, 2, 3, 4, 5, 6};
|
||||
|
||||
MergeSort.mergeSort(array);
|
||||
assertArrayEquals(expected, array);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMergeSortWithReverseSortedArray() {
|
||||
int[] array = {9, 7, 5, 3, 1, 0};
|
||||
int[] expected = {0, 1, 3, 5, 7, 9};
|
||||
|
||||
MergeSort.mergeSort(array);
|
||||
assertArrayEquals(expected, array);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMergeSortWithNullArray() {
|
||||
int[] array = null;
|
||||
|
||||
// Should not throw an exception
|
||||
assertDoesNotThrow(() -> MergeSort.mergeSort(array));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMergeSortWithSingleElement() {
|
||||
int[] array = {1};
|
||||
int[] expected = {1};
|
||||
|
||||
MergeSort.mergeSort(array);
|
||||
assertArrayEquals(expected, array);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user