Save progress

This commit is contained in:
2025-08-16 20:46:23 -04:00
parent 04b52792d3
commit aa593433bc
28 changed files with 513 additions and 11 deletions

1
agent/.sdkmanrc Normal file
View File

@@ -0,0 +1 @@
java=21.0.4-tem

View File

@@ -35,10 +35,32 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Ensure core Spring Context is present for IDE builds -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<!-- SQLite JDBC driver -->
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.46.0.0</version>
</dependency>
<!-- Hibernate community dialects (includes SQLiteDialect) -->
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-community-dialects</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- OpenAPI/Swagger UI via springdoc -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>org.springframework.modulith</groupId>
<artifactId>spring-modulith-starter-core</artifactId>
@@ -63,6 +85,48 @@
<artifactId>spring-modulith-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/io.projectreactor/reactor-core -->
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>3.7.9</version>
</dependency>
<!-- LLM and agent orchestration -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-ollama-spring-boot-starter</artifactId>
<version>1.3.0-beta9</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
<version>1.3.0-beta9</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-reactor</artifactId>
<version>1.3.0-beta9</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
<version>1.3.0</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.bsc.langgraph4j</groupId>-->
<!-- <artifactId>langgraph4j-core</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-ollama</artifactId>
<version>1.3.0</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
@@ -78,6 +142,27 @@
<build>
<plugins>
<!-- Enforce building with JDK 21 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.5.0</version>
<executions>
<execution>
<id>enforce-java</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireJavaVersion>
<version>[21,)</version>
</requireJavaVersion>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>

View File

@@ -7,6 +7,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
public class AgentApplication {
public static void main(String[] args) {
DataDirectoryInitializer.createDataDirectory();
SpringApplication.run(AgentApplication.class, args);
}

View File

@@ -0,0 +1,29 @@
package com.clortox.agent;
import java.io.UncheckedIOException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* Ensures the application's data directory exists before Spring Boot starts.
*/
public final class DataDirectoryInitializer {
private static final String DATA_DIR = "data";
private DataDirectoryInitializer() {}
public static void createDataDirectory() {
Path path = Paths.get(DATA_DIR);
try {
if (Files.notExists(path)) {
Files.createDirectories(path);
}
} catch (IOException e) {
throw new UncheckedIOException("Failed to create data directory: " + path.toAbsolutePath(), e);
}
}
}

View File

@@ -0,0 +1,4 @@
package com.clortox.agent.agent;
public interface IAgent {
}

View File

@@ -0,0 +1,17 @@
package com.clortox.agent.agent.controllers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController("Agent")
public class AgentController {
@GetMapping(path = "/assistant")
public ResponseEntity<?> get(String message) {
return ResponseEntity.status(HttpStatus.OK).body("lol");
}
}

View File

@@ -0,0 +1,49 @@
package com.clortox.agent.agent.llm;
import dev.langchain4j.http.client.HttpClientBuilder;
import dev.langchain4j.http.client.spring.restclient.SpringRestClient;
import dev.langchain4j.http.client.spring.restclient.SpringRestClientBuilder;
import dev.langchain4j.model.chat.Capability;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.ollama.OllamaChatModel;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.http.client.HttpClientSettings;
import org.springframework.boot.http.client.JdkHttpClientBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.VirtualThreadTaskExecutor;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestClient;
import java.net.http.HttpClient;
import java.util.Set;
@Configuration
public class LLMConfiguration {
@Bean
public ChatModel getOllama(
@Value("${agent.ollama.baseUrl}") String baseUrl,
@Value("${agent.ollama.model}") String model,
@Value("${agent.ollama.temp}") Double temp
) {
RestClient.Builder restClientBuilder = RestClient.builder()
.requestFactory(new HttpComponentsClientHttpRequestFactory());
SpringRestClientBuilder springRestClientBuilder = SpringRestClient.builder()
.restClientBuilder(restClientBuilder)
.streamingRequestExecutor(new VirtualThreadTaskExecutor());
return OllamaChatModel.builder()
.baseUrl(baseUrl)
.httpClientBuilder(springRestClientBuilder)
.modelName(model)
.temperature(temp)
.maxRetries(3)
.returnThinking(false)
.logResponses(true)
.logResponses(true)
.build();
}
}

View File

@@ -0,0 +1,24 @@
package com.clortox.agent.agent.memory;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import java.util.List;
public class PersistentChatMemoryStore implements ChatMemoryStore {
@Override
public List<ChatMessage> getMessages(Object memoryId) {
return List.of();
}
@Override
public void updateMessages(Object memoryId, List<ChatMessage> messages) {
}
@Override
public void deleteMessages(Object memoryId) {
}
}

View File

@@ -0,0 +1,30 @@
package com.clortox.agent.agent.memory.persistence;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.*;
@Entity
@Table(name = "message")
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Message {
@Id
@Getter
@Setter
@Column(name = "ID", nullable = false, updatable = false)
private Long id;
@Column(name = "conversationId", nullable = false, updatable = false)
private String conversationId;
@Column(name = "content", nullable = false, updatable = false)
private String content;
}

View File

@@ -0,0 +1,19 @@
package com.clortox.agent.agent.service;
import dev.langchain4j.model.chat.ChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class Agent {
private final ChatModel model;
@Autowired
public Agent(
ChatModel model
) {
this.model = model;
}
}

View File

@@ -0,0 +1,32 @@
package com.clortox.agent.starters;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class StarterListener {
@EventListener
public void onApplicationReady(ApplicationReadyEvent event) {
printBanner();
}
private void printBanner() {
log.info(" █████╗ ██████╗ ███████╗███╗ ██╗████████╗");
log.info("██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝");
log.info("███████║██║ ███╗█████╗ ██╔██╗ ██║ ██║");
log.info("██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║");
log.info("██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║");
log.info("╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝");
log.info("Welcome to the local agent!");
log.info("View documentation at http://localhost:{}/swagger-ui/index.html", 8080);
}
}

View File

@@ -1 +0,0 @@
spring.application.name=agent

View File

@@ -0,0 +1,37 @@
spring:
datasource:
url: jdbc:sqlite:${SQLITE_DB_LOCATION:./data/agent.db}
driver-class-name: org.sqlite.JDBC
jpa:
hibernate:
ddl-auto: none
properties:
hibernate:
dialect: org.hibernate.community.dialect.SQLiteDialect
format_sql: true
open-in-view: false
logging:
level:
org.hibernate.SQL: warn
org.hibernate.type.descriptor.sql.BasicBinder: warn
springdoc:
swagger-ui:
path: /swagger-ui
agent:
ollama:
baseUrl: "${OLLAMA_BASEURL:http://10.0.3.2:8080}"
model: "${OLLAMA_MODEL:llama3.2}"
temp: "${OLLAMA_TEMP:0.2}"
#langchain4j:
# ollama:
# chat-model:
# base-url: "${OLLAMA_BASEURL:http://10.0.3.2:8080}"
# model-name: "${OLLAMA_MODEL:llama3.2}"
# log-requests: true
# log-responses: true
# return-thinking: false

View File

@@ -0,0 +1,5 @@
CREATE TABLE message (
ID INTEGER PRIMARY KEY AUTOINCREMENT,
conversationId VARCHAR(32) NOT NULL,
content VARCHAR(4096) NOT NULL
)

View File

@@ -0,0 +1,12 @@
package com.clortox.agent;
import org.junit.jupiter.api.Test;
import org.springframework.modulith.core.ApplicationModules;
public class ModularityTest {
@Test
public void verify() {
ApplicationModules.of(AgentApplication.class).verify();
}
}