Skip to content

Commit

Permalink
Added Ktlint to spotless (#8)
Browse files Browse the repository at this point in the history
* Added Ktlint to spotless

* Formatting

* trimMargin instead of trimIndent

---------

Co-authored-by: Niels Simonides <[email protected]>
  • Loading branch information
nsmnds and Niels Simonides authored May 3, 2024
1 parent 3072093 commit 5f3c9af
Show file tree
Hide file tree
Showing 37 changed files with 1,405 additions and 1,098 deletions.
45 changes: 45 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# https://editorconfig.org
root = true

[*]
indent_style = space
indent_size = 2
max_line_length = 140

end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.{java,kt,kts,scala,rs,xml,kt.spec,kts.spec}]
indent_size = 4

[*.{kt,kts}]
ktlint_code_style = ktlint_official
ktlint_ignore_back_ticked_identifier = true

ktlint_standard = enabled
ktlint_standard_property-naming = disabled

# Experimental rules run by default run on the ktlint code base itself. Experimental rules should not be released if
# we are not pleased ourselves with the results on the ktlint code base.
ktlint_experimental = enabled

# Don't allow any wildcard imports
ij_kotlin_packages_to_use_import_on_demand = unset

# Prevent wildcard imports
ij_kotlin_name_count_to_use_star_import = 99
ij_kotlin_name_count_to_use_star_import_for_members = 99



[*.md]
trim_trailing_whitespace = false
max_line_length = unset

[gradle/verification-metadata.xml]
indent_size = 3

[*.yml]
ij_yaml_spaces_within_brackets = false
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ subprojects {
target("**/*.kt")
trimTrailingWhitespace()
endWithNewline()
ktlint()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ package community.flock.aigentic.core.agent

import community.flock.aigentic.core.agent.prompt.SystemPromptBuilder
import community.flock.aigentic.core.message.Message
import community.flock.aigentic.core.tool.ToolName
import community.flock.aigentic.core.model.Model
import community.flock.aigentic.core.tool.InternalTool
import community.flock.aigentic.core.tool.Tool
import community.flock.aigentic.core.tool.ToolName
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
Expand All @@ -15,13 +15,14 @@ import kotlinx.datetime.Instant

data class Task(
val description: String,
val instructions: List<Instruction>
val instructions: List<Instruction>,
)

data class Instruction(val text: String)

sealed interface Context {
data class Text(val text: String) : Context

data class Image(val base64: String) : Context
}

Expand Down Expand Up @@ -54,4 +55,5 @@ data class Agent(
}

fun Agent.getMessages() = messages.asSharedFlow()

fun Agent.getStatus() = status.asStateFlow()
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,43 @@ import community.flock.aigentic.core.agent.events.toEvents
import community.flock.aigentic.core.agent.tool.FinishReason
import community.flock.aigentic.core.agent.tool.FinishedOrStuck
import community.flock.aigentic.core.agent.tool.finishOrStuckTool
import community.flock.aigentic.core.message.*
import community.flock.aigentic.core.tool.ToolName
import community.flock.aigentic.core.message.Message
import community.flock.aigentic.core.message.Sender
import community.flock.aigentic.core.message.ToolCall
import community.flock.aigentic.core.message.ToolResultContent
import community.flock.aigentic.core.message.argumentsAsJson
import community.flock.aigentic.core.model.ModelResponse
import community.flock.aigentic.core.tool.Tool
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.MutableSharedFlow
import community.flock.aigentic.core.tool.ToolName
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.flatMapConcat
import kotlinx.coroutines.flow.map
import kotlinx.datetime.Clock

data class ToolInterceptorResult(val cancelExecution: Boolean, val reason: String?)

interface ToolInterceptor {
suspend fun intercept(agent: Agent, tool: Tool, toolCall: ToolCall): ToolInterceptorResult
suspend fun intercept(
agent: Agent,
tool: Tool,
toolCall: ToolCall,
): ToolInterceptorResult
}

suspend fun Agent.run(): FinishedOrStuck = coroutineScope {

async {
getMessages().flatMapConcat{ it.toEvents().asFlow() }.collect{
println(it.text)
suspend fun Agent.run(): FinishedOrStuck =
coroutineScope {
async {
getMessages().flatMapConcat { it.toEvents().asFlow() }.collect {
println(it.text)
}
}
}

AgentExecutor().runAgent(this@run)
}
AgentExecutor().runAgent(this@run)
}

class AgentExecutor(private val toolInterceptors: List<ToolInterceptor> = emptyList()) {

suspend fun runAgent(agent: Agent): FinishedOrStuck {
agent.setRunningState(AgentRunningState.RUNNING)

Expand All @@ -45,14 +52,15 @@ class AgentExecutor(private val toolInterceptors: List<ToolInterceptor> = emptyL
val resultState = result.await()

agent.updateStatus {
val endRunningState = if (resultState.reason is FinishReason.ImStuck) {
AgentRunningState.STUCK
} else {
AgentRunningState.COMPLETED
}
val endRunningState =
if (resultState.reason is FinishReason.ImStuck) {
AgentRunningState.STUCK
} else {
AgentRunningState.COMPLETED
}
it.copy(
runningState = endRunningState,
endTimestamp = Clock.System.now()
endTimestamp = Clock.System.now(),
)
}
return resultState
Expand All @@ -69,29 +77,34 @@ class AgentExecutor(private val toolInterceptors: List<ToolInterceptor> = emptyL
}.forEach { messages.emit(it) }
}

private suspend fun processResponse(agent: Agent, response: ModelResponse, onFinished: (FinishedOrStuck) -> Unit) {
private suspend fun processResponse(
agent: Agent,
response: ModelResponse,
onFinished: (FinishedOrStuck) -> Unit,
) {
val message = response.message
agent.messages.emit(message)

when (message) {
is Message.ToolCalls -> {
val shouldSendNextRequest = message.toolCalls
.map { toolCall ->
when (toolCall.name) {
finishOrStuckTool.name.value -> {
val finishedOrStuck = finishOrStuckTool.handler(toolCall.argumentsAsJson())
onFinished(finishedOrStuck)
false
}

else -> {
val toolResult = agent.execute(toolCall)
agent.messages.emit(toolResult)
true
val shouldSendNextRequest =
message.toolCalls
.map { toolCall ->
when (toolCall.name) {
finishOrStuckTool.name.value -> {
val finishedOrStuck = finishOrStuckTool.handler(toolCall.argumentsAsJson())
onFinished(finishedOrStuck)
false
}

else -> {
val toolResult = agent.execute(toolCall)
agent.messages.emit(toolResult)
true
}
}
}
}
.contains(true)
.contains(true)

if (shouldSendNextRequest) {
sendToolResponse(agent, onFinished)
Expand Down Expand Up @@ -121,18 +134,22 @@ class AgentExecutor(private val toolInterceptors: List<ToolInterceptor> = emptyL
private suspend fun runInterceptors(
agent: Agent,
tool: Tool,
toolCall: ToolCall
): Message.ToolResult? = toolInterceptors
.map { it.intercept(agent, tool, toolCall) }
.firstOrNull { it.cancelExecution }?.let {
Message.ToolResult(
toolCall.id,
toolCall.name,
ToolResultContent(it.reason ?: "Tool execution blocked by interceptor")
)
}
toolCall: ToolCall,
): Message.ToolResult? =
toolInterceptors
.map { it.intercept(agent, tool, toolCall) }
.firstOrNull { it.cancelExecution }?.let {
Message.ToolResult(
toolCall.id,
toolCall.name,
ToolResultContent(it.reason ?: "Tool execution blocked by interceptor"),
)
}

private suspend fun sendToolResponse(agent: Agent, onFinished: (FinishedOrStuck) -> Unit) {
private suspend fun sendToolResponse(
agent: Agent,
onFinished: (FinishedOrStuck) -> Unit,
) {
val response = agent.sendModelRequest()
processResponse(agent, response, onFinished)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package community.flock.aigentic.core.agent.events

import community.flock.aigentic.core.agent.tool.FinishReason
import community.flock.aigentic.core.agent.tool.finishOrStuckTool
import community.flock.aigentic.core.message.Message
import community.flock.aigentic.core.message.ToolCall
import community.flock.aigentic.core.message.argumentsAsJson
import community.flock.aigentic.core.agent.tool.FinishReason
import community.flock.aigentic.core.agent.tool.finishOrStuckTool

sealed interface AgentEvent {

val text: String

data object Started : AgentEvent {
Expand All @@ -31,25 +30,27 @@ sealed interface AgentEvent {
}

data object SendingResponse : AgentEvent {
override val text = """
📡 Sending response to model
override val text =
"""
|📡 Sending response to model
-----------------------------------
""".trimIndent()
""".trimMargin()
}

}

suspend fun Message.toEvents(): List<AgentEvent> = when (this) {
is Message.SystemPrompt -> listOf(AgentEvent.Started)
is Message.Text, is Message.Image -> emptyList()
is Message.ToolCalls -> this.toolCalls.map {
when(it.name) {
finishOrStuckTool.name.value -> getFinishEvent(it)
else -> AgentEvent.ExecuteTool(it)
}
suspend fun Message.toEvents(): List<AgentEvent> =
when (this) {
is Message.SystemPrompt -> listOf(AgentEvent.Started)
is Message.Text, is Message.Image -> emptyList()
is Message.ToolCalls ->
this.toolCalls.map {
when (it.name) {
finishOrStuckTool.name.value -> getFinishEvent(it)
else -> AgentEvent.ExecuteTool(it)
}
}
is Message.ToolResult -> listOf(AgentEvent.ToolResult(this))
}
is Message.ToolResult -> listOf(AgentEvent.ToolResult(this))
}

suspend fun getFinishEvent(it: ToolCall): AgentEvent {
val finishedOrStuck = finishOrStuckTool.handler(it.argumentsAsJson())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,42 +1,42 @@
package community.flock.aigentic.core.agent.prompt

import community.flock.aigentic.core.message.Message
import community.flock.aigentic.core.agent.Agent
import community.flock.aigentic.core.agent.tool.finishOrStuckTool
import community.flock.aigentic.core.message.Message

interface SystemPromptBuilder {
fun buildSystemPrompt(agent: Agent): Message.SystemPrompt
}

data object DefaultSystemPromptBuilder : SystemPromptBuilder {

override fun buildSystemPrompt(agent: Agent): Message.SystemPrompt =
agent.createSystemPrompt()
override fun buildSystemPrompt(agent: Agent): Message.SystemPrompt = agent.createSystemPrompt()
}

private fun Agent.createSystemPrompt(): Message.SystemPrompt {

val baseInstruction =
"You are an agent which helps the user to accomplish different tasks. These tasks are outlined by the user below. The user has defined a set of tools which are available to achieve those tasks. The user also gives you information which gives you context, these are the first messages. Please execute one of these tools and the given context to fulfil these tasks. Don't send any text messages only use tools"
"""
|You are an agent which helps the user to accomplish different tasks. These tasks are outlined by the user below.
|The user also gives you information which gives you context, these are the first messages.
|Please execute one of these tools and the given context to fulfil these tasks. Don't send any text messages only use tools
""".trimMargin()

val instructions = task.instructions.joinToString(separator = "\n\n")

val finishConditionDescription =
"""You are finished when the task is executed successfully: ${task.description}
If you meet this condition, call the ${finishOrStuckTool.name} tool to indicate that you are done and have finished all tasks.
When you don't know what to do also call the ${finishOrStuckTool.name} tool to indicate that you are stuck and need help.
""".trimIndent()
"""
|You are finished when the task is executed successfully: ${task.description}
|If you meet this condition, call the ${finishOrStuckTool.name.value} tool to indicate that you are done and have finished all tasks.
|When you don't know what to do also call the ${finishOrStuckTool.name.value} tool to indicate that you are stuck and need help.
""".trimMargin()

return Message.SystemPrompt(
"""
$baseInstruction
|$baseInstruction
Instructions:
$instructions
|Instructions:
|$instructions
$finishConditionDescription
""".trimIndent()
|$finishConditionDescription
""".trimMargin(),
)
}
Loading

0 comments on commit 5f3c9af

Please sign in to comment.