eerste check in
This commit is contained in:
@@ -1,142 +0,0 @@
|
||||
package org.example.nl.trivion.softwarefabric
|
||||
|
||||
import ai.koog.agents.core.agent.AIAgent
|
||||
import ai.koog.agents.core.agent.config.AIAgentConfig
|
||||
import ai.koog.agents.core.dsl.builder.forwardTo
|
||||
import ai.koog.agents.core.dsl.builder.strategy
|
||||
import ai.koog.agents.core.dsl.extension.nodeExecuteTool
|
||||
import ai.koog.agents.core.dsl.extension.nodeLLMRequest
|
||||
import ai.koog.agents.core.dsl.extension.nodeLLMSendToolResult
|
||||
import ai.koog.agents.core.dsl.extension.onAssistantMessage
|
||||
import ai.koog.agents.core.dsl.extension.onToolCall
|
||||
import ai.koog.agents.core.feature.handler.AgentFinishedContext
|
||||
import ai.koog.agents.core.feature.handler.AgentStartContext
|
||||
import ai.koog.agents.core.tools.ToolRegistry
|
||||
import ai.koog.agents.core.tools.annotations.LLMDescription
|
||||
import ai.koog.agents.core.tools.annotations.Tool
|
||||
import ai.koog.agents.core.tools.reflect.ToolSet
|
||||
import ai.koog.agents.core.tools.reflect.asTools
|
||||
import ai.koog.agents.features.eventHandler.feature.EventHandler
|
||||
import ai.koog.prompt.dsl.Prompt
|
||||
import ai.koog.prompt.executor.llms.all.simpleOllamaAIExecutor
|
||||
import ai.koog.prompt.llm.LLMCapability
|
||||
import ai.koog.prompt.llm.LLMProvider
|
||||
import ai.koog.prompt.llm.LLModel
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
// Use the OpenAI executor with an API key from an environment variable
|
||||
val promptExecutor = simpleOllamaAIExecutor("http://localhost:11434")
|
||||
|
||||
val customModel: LLModel = LLModel(
|
||||
provider = LLMProvider.Ollama,
|
||||
id = "gpt-oss:20b",
|
||||
capabilities = listOf(
|
||||
LLMCapability.Temperature,
|
||||
LLMCapability.Tools
|
||||
),
|
||||
contextLength = 2048
|
||||
)
|
||||
|
||||
// Create a simple strategy
|
||||
val agentStrategy = strategy("Simple calculator") {
|
||||
// Define nodes for the strategy
|
||||
val nodeSendInput by nodeLLMRequest()
|
||||
val nodeExecuteTool by nodeExecuteTool()
|
||||
val nodeSendToolResult by nodeLLMSendToolResult()
|
||||
|
||||
// Define edges between nodes
|
||||
// Start -> Send input
|
||||
edge(nodeStart forwardTo nodeSendInput)
|
||||
|
||||
// Send input -> Finish
|
||||
edge(
|
||||
(nodeSendInput forwardTo nodeFinish)
|
||||
transformed { it }
|
||||
onAssistantMessage { true }
|
||||
)
|
||||
|
||||
// Send input -> Execute tool
|
||||
edge(
|
||||
(nodeSendInput forwardTo nodeExecuteTool)
|
||||
onToolCall { true }
|
||||
)
|
||||
|
||||
// Execute tool -> Send the tool result
|
||||
edge(nodeExecuteTool forwardTo nodeSendToolResult)
|
||||
|
||||
// Send the tool result -> finish
|
||||
edge(
|
||||
(nodeSendToolResult forwardTo nodeFinish)
|
||||
transformed { it }
|
||||
onAssistantMessage { true }
|
||||
)
|
||||
}
|
||||
|
||||
// Configure the agent
|
||||
val agentConfig = AIAgentConfig(
|
||||
prompt = Prompt.build("simple-calculator") {
|
||||
system(
|
||||
"""
|
||||
You are a simple calculator assistant.
|
||||
You can add two numbers together using the calculator tool.
|
||||
When the user provides input, extract the numbers they want to add.
|
||||
The input might be in various formats like "add 5 and 7", "5 + 7", or just "5 7".
|
||||
Extract the two numbers and use the calculator tool to add them.
|
||||
Always respond with a clear, friendly message showing the calculation and result.
|
||||
""".trimIndent()
|
||||
)
|
||||
},
|
||||
model = customModel,
|
||||
maxAgentIterations = 10
|
||||
)
|
||||
|
||||
// Implement a simple calculator tool that can add two numbers
|
||||
@LLMDescription("Tools for performing basic arithmetic operations")
|
||||
class CalculatorTools : ToolSet {
|
||||
@Tool
|
||||
@LLMDescription("Add two numbers together and return their sum")
|
||||
fun add(
|
||||
@LLMDescription("First number to add (integer value)")
|
||||
num1: Int,
|
||||
|
||||
@LLMDescription("Second number to add (integer value)")
|
||||
num2: Int
|
||||
): String {
|
||||
val sum = num1 + num2
|
||||
return "The sum of $num1 and $num2 is: $sum"
|
||||
}
|
||||
}
|
||||
|
||||
// Add the tool to the tool registry
|
||||
val toolRegistry = ToolRegistry {
|
||||
tools(CalculatorTools().asTools())
|
||||
}
|
||||
|
||||
// Create the agent
|
||||
val agent = AIAgent(
|
||||
promptExecutor = promptExecutor,
|
||||
toolRegistry = toolRegistry,
|
||||
strategy = agentStrategy,
|
||||
agentConfig = agentConfig,
|
||||
installFeatures = {
|
||||
install(EventHandler) {
|
||||
onBeforeAgentStarted { eventContext: AgentStartContext<*> ->
|
||||
println("Starting strategy: ${eventContext.strategy.name}")
|
||||
}
|
||||
onAgentFinished { eventContext: AgentFinishedContext ->
|
||||
println("Result: ${eventContext.result}")
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
fun main() {
|
||||
runBlocking {
|
||||
println("Enter two numbers to add (e.g., 'add 5 and 7' or '5 + 7'):")
|
||||
|
||||
// Read the user input and send it to the agent
|
||||
val userInput = readlnOrNull() ?: ""
|
||||
val agentResult = agent.run(userInput)
|
||||
println("The agent returned: $agentResult")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package nl.trivion.softwarefabric
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.runApplication
|
||||
import org.springframework.scheduling.annotation.EnableScheduling
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableScheduling
|
||||
class SoftwareFabricApplication
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
runApplication<SoftwareFabricApplication>(*args)
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
package nl.trivion.softwarefabric.agents
|
||||
|
||||
import ai.koog.agents.core.agent.AIAgent
|
||||
import ai.koog.agents.core.agent.config.AIAgentConfig
|
||||
import ai.koog.agents.core.dsl.builder.forwardTo
|
||||
import ai.koog.agents.core.dsl.builder.strategy
|
||||
import ai.koog.agents.core.dsl.extension.nodeExecuteTool
|
||||
import ai.koog.agents.core.dsl.extension.nodeLLMRequest
|
||||
import ai.koog.agents.core.dsl.extension.nodeLLMSendToolResult
|
||||
import ai.koog.agents.core.dsl.extension.onAssistantMessage
|
||||
import ai.koog.agents.core.dsl.extension.onToolCall
|
||||
import ai.koog.agents.core.tools.ToolRegistry
|
||||
import ai.koog.agents.core.tools.reflect.asTools
|
||||
import ai.koog.agents.features.eventHandler.feature.EventHandler
|
||||
import ai.koog.prompt.dsl.Prompt
|
||||
import ai.koog.prompt.executor.llms.all.simpleOllamaAIExecutor
|
||||
import ai.koog.prompt.llm.LLMCapability
|
||||
import ai.koog.prompt.llm.LLMProvider
|
||||
import ai.koog.prompt.llm.LLModel
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import lombok.extern.slf4j.Slf4j
|
||||
import nl.trivion.softwarefabric.service.GiteaService
|
||||
import nl.trivion.softwarefabric.service.Issue
|
||||
import org.example.nl.trivion.softwarefabric.tools.GitTools
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.scheduling.annotation.Scheduled
|
||||
import org.springframework.stereotype.Service
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
class DeveloperAgent(private val giteaService: GiteaService) {
|
||||
|
||||
companion object {
|
||||
private val log = LoggerFactory.getLogger(DeveloperAgent::class.java)
|
||||
}
|
||||
|
||||
// Flag to track if agent is busy
|
||||
private val isAgentBusy = AtomicBoolean(false)
|
||||
|
||||
val promptExecutor = simpleOllamaAIExecutor("http://localhost:11434")
|
||||
|
||||
val customModel: LLModel = LLModel(
|
||||
provider = LLMProvider.Ollama,
|
||||
id = "gpt-oss:20b",
|
||||
capabilities = listOf(
|
||||
LLMCapability.Temperature,
|
||||
LLMCapability.Tools
|
||||
),
|
||||
contextLength = 2048
|
||||
)
|
||||
|
||||
// Create a simple strategy
|
||||
val agentStrategy = strategy("Developer") {
|
||||
// Define nodes for the strategy
|
||||
val nodeSendInput by nodeLLMRequest()
|
||||
val nodeExecuteTool by nodeExecuteTool()
|
||||
val nodeSendToolResult by nodeLLMSendToolResult()
|
||||
|
||||
// Define edges between nodes
|
||||
// Start -> Send input
|
||||
edge(nodeStart forwardTo nodeSendInput)
|
||||
|
||||
// Send input -> Finish
|
||||
edge(
|
||||
(nodeSendInput forwardTo nodeFinish)
|
||||
transformed { it }
|
||||
onAssistantMessage { true }
|
||||
)
|
||||
|
||||
// Send input -> Execute tool
|
||||
edge(
|
||||
(nodeSendInput forwardTo nodeExecuteTool)
|
||||
onToolCall { true }
|
||||
)
|
||||
|
||||
// Execute tool -> Send the tool result
|
||||
edge(nodeExecuteTool forwardTo nodeSendToolResult)
|
||||
|
||||
// Send the tool result -> finish
|
||||
edge(
|
||||
(nodeSendToolResult forwardTo nodeFinish)
|
||||
transformed { it }
|
||||
onAssistantMessage { true }
|
||||
)
|
||||
}
|
||||
|
||||
// Configure the agent
|
||||
val agentConfig = AIAgentConfig(
|
||||
prompt = Prompt.build("developer") {
|
||||
system(
|
||||
"""
|
||||
You are a git repository managing agent. You have the git tool to clone a remote git repo.
|
||||
The remote url you can use is "http://dixienas:3001/Trivion/tasklist.git".
|
||||
The project name is "tasklist".
|
||||
""".trimIndent()
|
||||
)
|
||||
},
|
||||
model = customModel,
|
||||
maxAgentIterations = 10
|
||||
)
|
||||
|
||||
// Add the tool to the tool registry
|
||||
val toolRegistry = ToolRegistry {
|
||||
tools(GitTools().asTools()
|
||||
)
|
||||
}
|
||||
|
||||
// Create the agent
|
||||
// val agent = AIAgent(
|
||||
// promptExecutor = promptExecutor,
|
||||
// toolRegistry = toolRegistry,
|
||||
// strategy = agentStrategy,
|
||||
// agentConfig = agentConfig,
|
||||
// installFeatures = {
|
||||
// install(EventHandler) {
|
||||
// onAgentCompleted { it ->
|
||||
// log.info("Result: ${it.result}")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// )
|
||||
|
||||
fun createAgent(): AIAgent<String, String> {
|
||||
return AIAgent(
|
||||
promptExecutor = promptExecutor,
|
||||
toolRegistry = toolRegistry,
|
||||
strategy = agentStrategy,
|
||||
agentConfig = agentConfig,
|
||||
installFeatures = {
|
||||
install(EventHandler) {
|
||||
onAgentCompleted { it ->
|
||||
log.info("Result: ${it.result}")
|
||||
isAgentBusy.set(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Scheduled(fixedRate = 5000)
|
||||
fun checkIssueToDo() {
|
||||
// Check if agent is already busy
|
||||
if (isAgentBusy.get()) {
|
||||
log.info("Agent is still busy processing previous issue, skipping this cycle")
|
||||
return
|
||||
}
|
||||
|
||||
val issues = giteaService.getIssues().filter { it: Issue ->
|
||||
it.labels.contains("Backlog")
|
||||
&& it.assigned.isNullOrEmpty()
|
||||
}
|
||||
|
||||
if (issues.isEmpty()) {
|
||||
log.info("No issues found")
|
||||
return
|
||||
}
|
||||
|
||||
val issue = issues.first()
|
||||
log.info("Processing issue ${issue.number}: ${issue.title}")
|
||||
|
||||
// Set agent as busy before starting
|
||||
if (!isAgentBusy.compareAndSet(false, true)) {
|
||||
log.info("Agent became busy while checking, skipping")
|
||||
return
|
||||
}
|
||||
|
||||
GlobalScope.launch {
|
||||
try {
|
||||
giteaService.updateIssueLabels(issue.number, listOf("Build"))
|
||||
val agent = createAgent()
|
||||
val result = agent.run(issue.body)
|
||||
log.info("Agent completed with result: $result")
|
||||
giteaService.updateIssueLabels(issue.number, listOf("Verify"))
|
||||
} catch (e: Exception) {
|
||||
log.error("Error processing issue: ${e.message}", e)
|
||||
} finally {
|
||||
// Always reset the busy flag
|
||||
isAgentBusy.set(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
package nl.trivion.softwarefabric.service
|
||||
|
||||
import ai.koog.agents.core.tools.annotations.LLMDescription
|
||||
import ai.koog.agents.core.tools.annotations.Tool
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import lombok.extern.slf4j.Slf4j
|
||||
import nl.trivion.softwarefabric.agents.DeveloperAgent
|
||||
import okhttp3.*
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
// Model classes
|
||||
data class Issue(
|
||||
val number: Int,
|
||||
val title: String,
|
||||
val body: String,
|
||||
val assigned: String?,
|
||||
val labels: List<String>
|
||||
)
|
||||
|
||||
// Response classes voor parsing
|
||||
data class GiteaIssueResponse(
|
||||
val id: Int,
|
||||
val number: Int,
|
||||
val title: String,
|
||||
val body: String,
|
||||
val assignee: Assignee?,
|
||||
val labels: List<Label>
|
||||
)
|
||||
|
||||
data class Assignee(
|
||||
val login: String,
|
||||
@SerializedName("full_name")
|
||||
val fullName: String
|
||||
)
|
||||
|
||||
data class Label(
|
||||
val id: Int,
|
||||
val name: String,
|
||||
val color: String
|
||||
)
|
||||
|
||||
// Request classes
|
||||
data class CreateIssueRequest(
|
||||
val title: String,
|
||||
val body: String,
|
||||
val assignee: String? = null,
|
||||
val labels: List<Int>? = null
|
||||
)
|
||||
|
||||
data class UpdateLabelsRequest(
|
||||
val labels: List<Int>
|
||||
)
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
class GiteaService {
|
||||
@Value("\${gitea.username}")
|
||||
private lateinit var username: String
|
||||
|
||||
@Value("\${gitea.password}")
|
||||
private lateinit var password: String
|
||||
|
||||
@Value("\${gitea.owner}")
|
||||
private lateinit var owner: String
|
||||
|
||||
@Value("\${gitea.repo}")
|
||||
private lateinit var repo: String
|
||||
|
||||
@Value("\${gitea.base-url}")
|
||||
private lateinit var apiBaseUrl: String
|
||||
|
||||
private val baseUrl: String
|
||||
get() = "$apiBaseUrl/repos/$owner/$repo"
|
||||
|
||||
private val gson = Gson()
|
||||
private val client = OkHttpClient()
|
||||
private val jsonMediaType = "application/json; charset=utf-8".toMediaType()
|
||||
|
||||
companion object {
|
||||
private val log = LoggerFactory.getLogger(GiteaService::class.java)
|
||||
}
|
||||
|
||||
// Generic private functions
|
||||
private fun createAuthHeader(): String {
|
||||
return Credentials.basic(username, password)
|
||||
}
|
||||
|
||||
private fun executeRequest(request: Request): Response {
|
||||
return client.newCall(request).execute()
|
||||
}
|
||||
|
||||
private fun buildGetRequest(url: String): Request {
|
||||
return Request.Builder()
|
||||
.url(url)
|
||||
.addHeader("Authorization", createAuthHeader())
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun buildPostRequest(url: String, body: Any): Request {
|
||||
val jsonBody = gson.toJson(body)
|
||||
val requestBody = jsonBody.toRequestBody(jsonMediaType)
|
||||
|
||||
return Request.Builder()
|
||||
.url(url)
|
||||
.addHeader("Authorization", createAuthHeader())
|
||||
.post(requestBody)
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun buildPutRequest(url: String, body: Any): Request {
|
||||
val jsonBody = gson.toJson(body)
|
||||
val requestBody = jsonBody.toRequestBody(jsonMediaType)
|
||||
|
||||
return Request.Builder()
|
||||
.url(url)
|
||||
.addHeader("Authorization", createAuthHeader())
|
||||
.put(requestBody)
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun mapToIssue(giteaIssue: GiteaIssueResponse): Issue {
|
||||
log.info("Gitea issue: {}", giteaIssue.toString())
|
||||
return Issue(
|
||||
number = giteaIssue.number,
|
||||
title = giteaIssue.title,
|
||||
body = giteaIssue.body,
|
||||
assigned = giteaIssue.assignee?.let {
|
||||
if (it.fullName.isNotBlank()) it.fullName else it.login
|
||||
},
|
||||
labels = giteaIssue.labels.map { it.name }
|
||||
)
|
||||
}
|
||||
|
||||
private fun getIssueById(issueNumber: Int): Issue? {
|
||||
val url = "$baseUrl/issues/$issueNumber"
|
||||
val request = buildGetRequest(url)
|
||||
|
||||
executeRequest(request).use { response ->
|
||||
if (!response.isSuccessful) {
|
||||
println("Failed to get issue: $response")
|
||||
return null
|
||||
}
|
||||
|
||||
val json = response.body?.string() ?: return null
|
||||
val giteaIssue = gson.fromJson(json, GiteaIssueResponse::class.java)
|
||||
return mapToIssue(giteaIssue)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAvailableLabels(): List<Label> {
|
||||
val url = "$baseUrl/labels"
|
||||
val request = buildGetRequest(url)
|
||||
|
||||
executeRequest(request).use { response ->
|
||||
if (!response.isSuccessful) {
|
||||
println("Failed to get labels: $response")
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
val json = response.body?.string() ?: return emptyList()
|
||||
return gson.fromJson(json, Array<Label>::class.java).toList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getLabelIdsByNames(labelNames: List<String>): List<Int> {
|
||||
val availableLabels = getAvailableLabels()
|
||||
return labelNames.mapNotNull { name ->
|
||||
availableLabels.find { it.name.equals(name, ignoreCase = true) }?.id
|
||||
}
|
||||
}
|
||||
|
||||
fun getIssues(): List<Issue> {
|
||||
val url = "$baseUrl/issues"
|
||||
val request = buildGetRequest(url)
|
||||
|
||||
executeRequest(request).use { response ->
|
||||
if (!response.isSuccessful) {
|
||||
println("Unexpected code $response")
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
val json = response.body?.string() ?: return emptyList()
|
||||
val giteaIssues = gson.fromJson(json, Array<GiteaIssueResponse>::class.java)
|
||||
return giteaIssues.map { mapToIssue(it) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun createIssueLabelIds(
|
||||
title: String,
|
||||
body: String,
|
||||
assignee: String? = null,
|
||||
labelIds: List<Int>? = null
|
||||
): Issue? {
|
||||
val url = "$baseUrl/issues"
|
||||
val createRequest = CreateIssueRequest(
|
||||
title = title,
|
||||
body = body,
|
||||
assignee = assignee,
|
||||
labels = labelIds
|
||||
)
|
||||
|
||||
val request = buildPostRequest(url, createRequest)
|
||||
|
||||
executeRequest(request).use { response ->
|
||||
if (!response.isSuccessful) {
|
||||
println("Failed to create issue: $response")
|
||||
println("Response body: ${response.body?.string()}")
|
||||
return null
|
||||
}
|
||||
|
||||
val json = response.body?.string() ?: return null
|
||||
val giteaIssue = gson.fromJson(json, GiteaIssueResponse::class.java)
|
||||
return mapToIssue(giteaIssue)
|
||||
}
|
||||
}
|
||||
|
||||
fun createIssue(
|
||||
title: String,
|
||||
body: String,
|
||||
assignee: String? = null,
|
||||
labelNames: List<String>? = null
|
||||
): Issue? {
|
||||
val labelIds = labelNames?.let { getLabelIdsByNames(it) }
|
||||
return createIssueLabelIds(title, body, assignee, labelIds)
|
||||
}
|
||||
|
||||
private fun updateIssueLabelsIds(
|
||||
issueNumber: Int,
|
||||
labelIds: List<Int>
|
||||
): Issue? {
|
||||
val url = "$baseUrl/issues/$issueNumber/labels"
|
||||
log.info("url: {}", url)
|
||||
val updateRequest = UpdateLabelsRequest(labels = labelIds)
|
||||
|
||||
val request = buildPutRequest(url, updateRequest)
|
||||
|
||||
executeRequest(request).use { response ->
|
||||
if (!response.isSuccessful) {
|
||||
println("Failed to update labels: $response")
|
||||
println("Response body: ${response.body?.string()}")
|
||||
return null
|
||||
}
|
||||
|
||||
return getIssueById(issueNumber)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateIssueLabels(
|
||||
issueNumber: Int,
|
||||
labelNames: List<String>
|
||||
): Issue? {
|
||||
val labelIds = getLabelIdsByNames(labelNames)
|
||||
return updateIssueLabelsIds(issueNumber, labelIds)
|
||||
}
|
||||
}
|
||||
@@ -5,37 +5,62 @@ import ai.koog.agents.core.tools.annotations.Tool
|
||||
import ai.koog.agents.core.tools.reflect.ToolSet
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import java.io.File
|
||||
|
||||
val username: String? = System.getenv("GIT_USERNAME")
|
||||
val password: String? = System.getenv("GIT_PASSWORD")
|
||||
//val username: String? = System.getenv("GIT_USERNAME")
|
||||
//val password: String? = System.getenv("GIT_PASSWORD")
|
||||
//val workspace: String? = System.getenv("SF_WORKSPACE")
|
||||
|
||||
// Implement a simple calculator tool that can add two numbers
|
||||
@LLMDescription("Tools for performing basic git operations")
|
||||
class GitTools : ToolSet {
|
||||
|
||||
companion object {
|
||||
private val log = LoggerFactory.getLogger(GitTools::class.java)
|
||||
}
|
||||
|
||||
val username = "developer-ai"
|
||||
val password = "XCO1bsNyhyIzk2"
|
||||
val workspace = "/Users/erik/projecten/workspace"
|
||||
|
||||
@Tool
|
||||
@LLMDescription("Clone een git repository")
|
||||
fun cloneRepository(
|
||||
@LLMDescription("The remote url from the git repository")
|
||||
remoteUrl: String,
|
||||
@LLMDescription("The local path to clone the repository to")
|
||||
localPath: File) {
|
||||
@LLMDescription("The name of the project to clone")
|
||||
projectName: String): String {
|
||||
|
||||
Git.cloneRepository()
|
||||
.setURI(remoteUrl)
|
||||
.setDirectory(localPath)
|
||||
.call()
|
||||
}
|
||||
val localPath = workspace + File.separatorChar + projectName
|
||||
log.info("localPath: {}", localPath)
|
||||
|
||||
if (File(localPath).exists()) {
|
||||
return "\"$projectName\" already cloned"
|
||||
}
|
||||
|
||||
try {
|
||||
Git.cloneRepository()
|
||||
.setURI(remoteUrl)
|
||||
.setDirectory(File(localPath))
|
||||
.call()
|
||||
} catch (e: Exception) {
|
||||
log.error("Error during clone $projectName", e)
|
||||
return "Error found: ${e.message}"
|
||||
}
|
||||
return "Repository $projectName successfully cloned"
|
||||
}
|
||||
|
||||
@Tool
|
||||
@LLMDescription("Pull a git repository")
|
||||
fun pull(
|
||||
@LLMDescription("The local path from the local git repository")
|
||||
localPath: String,
|
||||
projectName: String,
|
||||
@LLMDescription("The branch to pull")
|
||||
branch: String) {
|
||||
|
||||
val localPath = workspace + File.pathSeparator + projectName
|
||||
Git.open(File(localPath)).use { git ->
|
||||
git.pull()
|
||||
.setRemote("origin")
|
||||
|
||||
5
src/main/resources/application-test.properties
Normal file
5
src/main/resources/application-test.properties
Normal file
@@ -0,0 +1,5 @@
|
||||
gitea.username=developer-ai
|
||||
gitea.password=XCO1bsNyhyIzk2
|
||||
gitea.owner=Trivion
|
||||
gitea.repo=tasklist
|
||||
gitea.base-url=http://dixienas:3001/api/v1
|
||||
7
src/main/resources/application.properties
Normal file
7
src/main/resources/application.properties
Normal file
@@ -0,0 +1,7 @@
|
||||
gitea.username=developer-ai
|
||||
gitea.password=XCO1bsNyhyIzk2
|
||||
gitea.owner=Trivion
|
||||
gitea.repo=tasklist
|
||||
gitea.base-url=http://dixienas:3001/api/v1
|
||||
|
||||
workspace=/Users/erik/projecten/workspace
|
||||
Reference in New Issue
Block a user