Skip to content

Commit dab1855

Browse files
authored
Merge pull request #205 from joreilly/koog_updates
Koog 0.5.0 + related updates
2 parents a1ef71a + bdfe611 commit dab1855

File tree

13 files changed

+128
-86
lines changed

13 files changed

+128
-86
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package dev.johnoreilly.climatetrace.agent
2+
3+
import ai.koog.prompt.executor.clients.google.GoogleModels
4+
import ai.koog.prompt.executor.llms.all.simpleGoogleAIExecutor
5+
import ai.koog.prompt.executor.model.PromptExecutor
6+
import ai.koog.prompt.llm.LLModel
7+
8+
actual fun getLLModel() = GoogleModels.Gemini2_5Flash
9+
10+
actual fun getPromptExecutor(apiKey: String): PromptExecutor {
11+
return simpleGoogleAIExecutor(apiKey)
12+
}

composeApp/src/commonMain/kotlin/dev/johnoreilly/climatetrace/agent/ClimateTraceAgent.kt

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,21 @@ package dev.johnoreilly.climatetrace.agent
33
import ai.koog.agents.core.agent.AIAgent
44
import ai.koog.agents.core.tools.ToolRegistry
55
import ai.koog.agents.features.eventHandler.feature.handleEvents
6-
import ai.koog.prompt.executor.clients.google.GoogleModels
7-
import ai.koog.prompt.executor.llms.all.simpleGoogleAIExecutor
6+
import ai.koog.prompt.executor.model.PromptExecutor
7+
import ai.koog.prompt.llm.LLModel
88
import dev.johnoreilly.climatetrace.data.ClimateTraceRepository
99

1010

1111

12+
expect fun getLLModel(): LLModel
13+
expect fun getPromptExecutor(apiKey: String = ""): PromptExecutor
14+
1215
class ClimateTraceAgent(private val climateTraceRepository: ClimateTraceRepository) {
1316
private val apiKeyGoogle = ""
14-
private var agent: AIAgent<String, String>? = null
15-
16-
suspend fun createAgent() {
17-
//val executor = simpleOpenAIExecutor(openAiApiKey)
18-
val executor = simpleGoogleAIExecutor(apiKeyGoogle)
1917

20-
agent = AIAgent(
21-
promptExecutor = executor,
22-
llmModel = GoogleModels.Gemini2_5Flash,
23-
//llmModel = OpenAIModels.Chat.GPT4o,
18+
suspend fun createAgent() = AIAgent(
19+
promptExecutor = getPromptExecutor(apiKeyGoogle),
20+
llmModel = getLLModel(),
2421
toolRegistry = createToolSetRegistry(climateTraceRepository),
2522
systemPrompt =
2623
"""
@@ -46,7 +43,7 @@ class ClimateTraceAgent(private val climateTraceRepository: ClimateTraceReposito
4643
ctx.responses.forEach { println(" $it") }
4744
}
4845

49-
onToolExecutionStarting { eventContext ->
46+
onToolCallStarting { eventContext ->
5047
println("Tool called: ${eventContext.tool} with args ${eventContext.toolArgs}")
5148
}
5249
onAgentExecutionFailed { eventContext ->
@@ -62,18 +59,15 @@ class ClimateTraceAgent(private val climateTraceRepository: ClimateTraceReposito
6259
}
6360
}
6461
}
65-
}
6662

6763

68-
suspend fun runAgent(prompt: String): String {
69-
agent?.let { agent ->
70-
println("Running agent")
71-
val output = agent.run(prompt)
72-
println("Result = $output")
73-
return output
74-
}
7564

76-
return ""
65+
suspend fun runAgent(prompt: String): String {
66+
val agent = createAgent()
67+
println("Running agent")
68+
val output = agent.run(prompt)
69+
println("Result = $output")
70+
return output
7771
}
7872

7973
private suspend fun createToolSetRegistry(climateTraceRepository: ClimateTraceRepository): ToolRegistry {

composeApp/src/commonMain/kotlin/dev/johnoreilly/climatetrace/agent/ClimateTraceTool.kt

Lines changed: 12 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,27 @@
11
package dev.johnoreilly.climatetrace.agent
22

33
import ai.koog.agents.core.tools.SimpleTool
4-
import ai.koog.agents.core.tools.ToolArgs
54
import ai.koog.agents.core.tools.ToolDescriptor
65
import ai.koog.agents.core.tools.ToolParameterDescriptor
76
import ai.koog.agents.core.tools.ToolParameterType
7+
import ai.koog.agents.core.tools.annotations.LLMDescription
88
import dev.johnoreilly.climatetrace.data.ClimateTraceRepository
99
import dev.johnoreilly.climatetrace.remote.Country
1010
import kotlinx.serialization.Serializable
1111

1212

1313
class GetCountryTool(val climateTraceRepository: ClimateTraceRepository) : SimpleTool<GetCountryTool.Args>() {
1414
@Serializable
15-
data class Args(val countryName: String) : ToolArgs
15+
data class Args(
16+
@property:LLMDescription("Country name")
17+
val countryName: String
18+
)
1619

1720
override val argsSerializer = Args.serializer()
1821
override val description = "Look up country code using country name"
1922

20-
2123
private var countryList: List<Country>? = null
2224

23-
override val descriptor = ToolDescriptor(
24-
name = "GetCountryTool",
25-
description = "Look up country code using country name",
26-
requiredParameters = listOf(
27-
ToolParameterDescriptor(
28-
name = "country", description = "country name", type = ToolParameterType.String
29-
)
30-
),
31-
)
32-
3325
override suspend fun doExecute(args: Args): String {
3426
try {
3527
if (countryList == null) {
@@ -46,24 +38,16 @@ class GetCountryTool(val climateTraceRepository: ClimateTraceRepository) : Simpl
4638

4739
class GetEmissionsTool(val climateTraceRepository: ClimateTraceRepository) : SimpleTool<GetEmissionsTool.Args>() {
4840
@Serializable
49-
data class Args(val countryCodeList: List<String>, val year: String) : ToolArgs
41+
data class Args(
42+
@property:LLMDescription("ISO country code list (e.g., 'USA', 'GBR', 'FRA')")
43+
val countryCodeList: List<String>,
44+
@property:LLMDescription("Year for which emissions occurred")
45+
val year: String
46+
)
5047

5148
override val argsSerializer = Args.serializer()
5249
override val description = "Get the emission data for a country for a particular year."
5350

54-
override val descriptor = ToolDescriptor(
55-
name = "GetEmissionsTool",
56-
description = "Get the emission data for a country for a particular year.",
57-
requiredParameters = listOf(
58-
ToolParameterDescriptor(
59-
name = "countryCodeList", description = "country code list", type = ToolParameterType.List(ToolParameterType.String)
60-
),
61-
ToolParameterDescriptor(
62-
name = "year", description = "year", type = ToolParameterType.String
63-
)
64-
),
65-
)
66-
6751
override suspend fun doExecute(args: Args): String {
6852
try {
6953
return climateTraceRepository.fetchCountryEmissionsInfo(args.countryCodeList, args.year).joinToString {
@@ -79,7 +63,7 @@ class GetEmissionsTool(val climateTraceRepository: ClimateTraceRepository) : Sim
7963

8064
class GetPopulationTool(val climateTraceRepository: ClimateTraceRepository) : SimpleTool<GetPopulationTool.Args>() {
8165
@Serializable
82-
data class Args(val countryCode: String) : ToolArgs
66+
data class Args(val countryCode: String)
8367

8468
override val argsSerializer = Args.serializer()
8569
override val description = "Get population data for a country by its country code"

composeApp/src/commonMain/kotlin/dev/johnoreilly/climatetrace/ui/AgentsScreen.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,11 @@ import androidx.compose.foundation.background
44
import androidx.compose.foundation.layout.Column
55
import androidx.compose.foundation.layout.Row
66
import androidx.compose.foundation.layout.Spacer
7-
import androidx.compose.foundation.layout.fillMaxSize
87
import androidx.compose.foundation.layout.fillMaxWidth
98
import androidx.compose.foundation.layout.height
109
import androidx.compose.foundation.layout.padding
1110
import androidx.compose.foundation.layout.size
1211
import androidx.compose.foundation.layout.width
13-
import androidx.compose.foundation.lazy.rememberLazyListState
1412
import androidx.compose.foundation.rememberScrollState
1513
import androidx.compose.foundation.shape.CircleShape
1614
import androidx.compose.foundation.shape.RoundedCornerShape

composeApp/src/commonMain/kotlin/dev/johnoreilly/climatetrace/viewmodel/AgentViewModel.kt

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import app.cash.molecule.RecompositionMode
1010
import app.cash.molecule.launchMolecule
1111
import com.rickclephas.kmp.observableviewmodel.ViewModel
1212
import com.rickclephas.kmp.observableviewmodel.coroutineScope
13-
import com.rickclephas.kmp.observableviewmodel.launch
1413
import dev.johnoreilly.climatetrace.agent.ClimateTraceAgent
1514
import kotlinx.coroutines.flow.Flow
1615
import kotlinx.coroutines.flow.MutableSharedFlow
@@ -19,20 +18,9 @@ import org.koin.core.component.KoinComponent
1918
import org.koin.core.component.inject
2019

2120

22-
sealed class Message {
23-
data class UserMessage(val text: String) : Message()
24-
data class AgentMessage(val text: String) : Message()
25-
data class SystemMessage(val text: String) : Message()
26-
data class ErrorMessage(val text: String) : Message()
27-
data class ToolCallMessage(val text: String) : Message()
28-
data class ResultMessage(val text: String) : Message()
29-
}
30-
31-
3221
data class AgentUIState(
3322
val prompt: String = "",
3423
val result: String = "",
35-
val messages: List<Message> = emptyList(),
3624
val isInputEnabled: Boolean = true,
3725
val isLoading: Boolean = false,
3826

@@ -55,11 +43,6 @@ open class AgentViewModel : ViewModel(), KoinComponent {
5543
agentPresenter(events)
5644
}
5745

58-
init {
59-
viewModelScope.launch {
60-
climateTraceAgent.createAgent()
61-
}
62-
}
6346

6447
fun updatePrompt(prompt: String) = events.tryEmit(AgentEvents.SetPrompt(prompt))
6548
fun runAgent() = events.tryEmit(AgentEvents.RunAgent)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package dev.johnoreilly.climatetrace.agent
2+
3+
import ai.koog.prompt.executor.clients.google.GoogleModels
4+
import ai.koog.prompt.executor.llms.all.simpleGoogleAIExecutor
5+
import ai.koog.prompt.executor.model.PromptExecutor
6+
import ai.koog.prompt.llm.LLModel
7+
8+
actual fun getLLModel() = GoogleModels.Gemini2_5Flash
9+
10+
actual fun getPromptExecutor(apiKey: String): PromptExecutor {
11+
return simpleGoogleAIExecutor(apiKey)
12+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package dev.johnoreilly.climatetrace.agent
2+
3+
import ai.koog.prompt.executor.llms.all.simpleOllamaAIExecutor
4+
import ai.koog.prompt.executor.model.PromptExecutor
5+
import ai.koog.prompt.llm.LLMCapability
6+
import ai.koog.prompt.llm.LLMProvider
7+
import ai.koog.prompt.llm.LLModel
8+
9+
actual fun getLLModel(): LLModel {
10+
return LLModel(
11+
provider = LLMProvider.Ollama,
12+
id = "gpt-oss:20b",
13+
capabilities = listOf(
14+
LLMCapability.Temperature,
15+
LLMCapability.Schema.JSON.Standard,
16+
LLMCapability.Tools
17+
),
18+
contextLength = 128_000,
19+
)
20+
}
21+
22+
actual fun getPromptExecutor(apiKey: String): PromptExecutor {
23+
return simpleOllamaAIExecutor()
24+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package dev.johnoreilly.climatetrace.agent
2+
3+
import ai.koog.prompt.executor.clients.google.GoogleModels
4+
import ai.koog.prompt.executor.llms.all.simpleGoogleAIExecutor
5+
import ai.koog.prompt.executor.model.PromptExecutor
6+
7+
actual fun getLLModel() = GoogleModels.Gemini2_5Flash
8+
9+
actual fun getPromptExecutor(apiKey: String): PromptExecutor {
10+
return simpleGoogleAIExecutor(apiKey)
11+
}

gradle/libs.versions.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ mcp = "0.7.2"
2727
shadowPlugin = "9.2.2"
2828
jib = "3.4.5"
2929
googleAdk = "0.3.0"
30-
koogAgents = "0.4.3-develop-20250927-0204"
31-
#koogAgents = "0.4.2"
30+
#koogAgents = "0.4.3-develop-20250927-0204"
31+
koogAgents = "0.5.0"
3232
markdownRenderer = "0.37.0"
3333
buildkonfig = "0.17.1"
3434

0 commit comments

Comments
 (0)