11package com.jetbrains.example.koog.compose.agents.weather
22
33import ai.koog.agents.core.tools.Tool
4- import ai.koog.agents.core.tools.ToolResult
5- import ai.koog.agents.core.tools.ToolResultUtils
64import ai.koog.agents.core.tools.annotations.LLMDescription
75import kotlinx.datetime.DateTimePeriod
86import kotlinx.datetime.LocalDate
@@ -12,7 +10,6 @@ import kotlinx.datetime.offsetAt
1210import kotlinx.datetime.plus
1311import kotlinx.datetime.toInstant
1412import kotlinx.datetime.toLocalDateTime
15- import kotlinx.serialization.KSerializer
1613import kotlinx.serialization.SerialName
1714import kotlinx.serialization.Serializable
1815import kotlin.time.Clock
@@ -46,7 +43,12 @@ sealed interface WeatherTools {
4643 class CurrentDatetimeTool (
4744 val defaultTimeZone : TimeZone = UTC_ZONE ,
4845 val clock : Clock = CLOCK ,
49- ) : Tool<CurrentDatetimeTool.Args, CurrentDatetimeTool.Result>() {
46+ ) : Tool<CurrentDatetimeTool.Args, CurrentDatetimeTool.Result>(
47+ argsSerializer = Args .serializer(),
48+ resultSerializer = Result .serializer(),
49+ name = " current_datetime" ,
50+ description = " Get the current date and time in the specified timezone"
51+ ) {
5052 @Serializable
5153 data class Args (
5254 @property:LLMDescription("The timezone to get the current date and time in (e.g., 'UTC ', 'America /New_York ', 'Europe /London '). Defaults to UTC .")
@@ -59,17 +61,7 @@ sealed interface WeatherTools {
5961 val date : String ,
6062 val time : String ,
6163 val timezone : String
62- ) : ToolResult.TextSerializable() {
63- override fun textForLLM (): String {
64- return " Current datetime: $datetime , Date: $date , Time: $time , Timezone: $timezone "
65- }
66- }
67-
68- override val argsSerializer = Args .serializer()
69- override val resultSerializer: KSerializer <Result > = ToolResultUtils .toTextSerializer<Result >()
70-
71- override val name = " current_datetime"
72- override val description = " Get the current date and time in the specified timezone"
64+ )
7365
7466 override suspend fun execute (args : Args ): Result {
7567 val zoneId = try {
@@ -94,6 +86,10 @@ sealed interface WeatherTools {
9486 timezone = zoneId.id
9587 )
9688 }
89+
90+ override fun encodeResultToString (result : Result ): String {
91+ return " Current datetime: ${result.datetime} , Date: ${result.date} , Time: ${result.time} , Timezone: ${result.timezone} "
92+ }
9793 }
9894
9995 /* *
@@ -102,7 +98,12 @@ sealed interface WeatherTools {
10298 class AddDatetimeTool (
10399 val defaultTimeZone : TimeZone = UTC_ZONE ,
104100 val clock : Clock = CLOCK ,
105- ) : Tool<AddDatetimeTool.Args, AddDatetimeTool.Result>() {
101+ ) : Tool<AddDatetimeTool.Args, AddDatetimeTool.Result>(
102+ argsSerializer = Args .serializer(),
103+ resultSerializer = Result .serializer(),
104+ name = " add_datetime" ,
105+ description = " Add a duration to a date. Use this tool when you need to calculate offsets, such as tomorrow, in two days, etc."
106+ ) {
106107 @Serializable
107108 data class Args (
108109 @property:LLMDescription("The date to add to in ISO format (e.g., '2023-05-20')")
@@ -122,43 +123,7 @@ sealed interface WeatherTools {
122123 val daysAdded : Int ,
123124 val hoursAdded : Int ,
124125 val minutesAdded : Int
125- ) : ToolResult.TextSerializable() {
126- override fun textForLLM (): String {
127- return buildString {
128- append(" Date: $date " )
129- if (originalDate.isBlank()) {
130- append(" (starting from today)" )
131- } else {
132- append(" (starting from $originalDate )" )
133- }
134-
135- if (daysAdded != 0 || hoursAdded != 0 || minutesAdded != 0 ) {
136- append(" after adding" )
137-
138- if (daysAdded != 0 ) {
139- append(" $daysAdded days" )
140- }
141-
142- if (hoursAdded != 0 ) {
143- if (daysAdded != 0 ) append(" ," )
144- append(" $hoursAdded hours" )
145- }
146-
147- if (minutesAdded != 0 ) {
148- if (daysAdded != 0 || hoursAdded != 0 ) append(" ," )
149- append(" $minutesAdded minutes" )
150- }
151- }
152- }
153- }
154- }
155-
156- override val argsSerializer = Args .serializer()
157- override val resultSerializer = ToolResultUtils .toTextSerializer<Result >()
158-
159- override val name = " add_datetime"
160- override val description =
161- " Add a duration to a date. Use this tool when you need to calculate offsets, such as tomorrow, in two days, etc."
126+ )
162127
163128 override suspend fun execute (args : Args ): Result {
164129 val baseDate = if (args.date.isNotBlank()) {
@@ -193,6 +158,35 @@ sealed interface WeatherTools {
193158 minutesAdded = args.minutes
194159 )
195160 }
161+
162+ override fun encodeResultToString (result : Result ): String {
163+ return buildString {
164+ append(" Date: ${result.date} " )
165+ if (result.originalDate.isBlank()) {
166+ append(" (starting from today)" )
167+ } else {
168+ append(" (starting from ${result.originalDate} )" )
169+ }
170+
171+ if (result.daysAdded != 0 || result.hoursAdded != 0 || result.minutesAdded != 0 ) {
172+ append(" after adding" )
173+
174+ if (result.daysAdded != 0 ) {
175+ append(" ${result.daysAdded} days" )
176+ }
177+
178+ if (result.hoursAdded != 0 ) {
179+ if (result.daysAdded != 0 ) append(" ," )
180+ append(" ${result.hoursAdded} hours" )
181+ }
182+
183+ if (result.minutesAdded != 0 ) {
184+ if (result.daysAdded != 0 || result.hoursAdded != 0 ) append(" ," )
185+ append(" ${result.minutesAdded} minutes" )
186+ }
187+ }
188+ }
189+ }
196190 }
197191
198192 /* *
@@ -201,7 +195,12 @@ sealed interface WeatherTools {
201195 class WeatherForecastTool (
202196 private val openMeteoClient : OpenMeteoClient = OpenMeteoClient (),
203197 val defaultTimeZone : TimeZone = UTC_ZONE
204- ) : Tool<WeatherForecastTool.Args, WeatherForecastTool.Result>() {
198+ ) : Tool<WeatherForecastTool.Args, WeatherForecastTool.Result>(
199+ argsSerializer = Args .serializer(),
200+ resultSerializer = Result .serializer(),
201+ name = " weather_forecast" ,
202+ description = " Get a weather forecast for a location with specified granularity (daily or hourly)"
203+ ) {
205204 @Serializable
206205 data class Args (
207206 @property:LLMDescription("The location to get the weather forecast for (e.g., 'New York ', 'London ', 'Paris ')")
@@ -221,28 +220,7 @@ sealed interface WeatherTools {
221220 val forecast : String ,
222221 val date : String ,
223222 val granularity : Granularity
224- ) : ToolResult.TextSerializable() {
225- override fun textForLLM (): String {
226- val granularityText = when (granularity) {
227- Granularity .DAILY -> " daily"
228- Granularity .HOURLY -> " hourly"
229- }
230- val dateInfo = if (date.isBlank()) " starting from today" else " for $date "
231- val formattedLocation = if (locationCountry.isNullOrBlank()) {
232- locationName
233- } else {
234- " $locationName , $locationCountry "
235- }.trim().trimEnd(' ,' )
236-
237- return " Weather forecast for $formattedLocation ($granularityText , $dateInfo ):\n $forecast "
238- }
239- }
240-
241- override val argsSerializer = Args .serializer()
242- override val resultSerializer = ToolResultUtils .toTextSerializer<Result >()
243-
244- override val name = " weather_forecast"
245- override val description = " Get a weather forecast for a location with specified granularity (daily or hourly)"
223+ )
246224
247225 override suspend fun execute (args : Args ): Result {
248226 // Search for the location
@@ -371,5 +349,20 @@ sealed interface WeatherTools {
371349 else -> " Unknown"
372350 }
373351 }
352+
353+ override fun encodeResultToString (result : Result ): String {
354+ val granularityText = when (result.granularity) {
355+ Granularity .DAILY -> " daily"
356+ Granularity .HOURLY -> " hourly"
357+ }
358+ val dateInfo = if (result.date.isBlank()) " starting from today" else " for ${result.date} "
359+ val formattedLocation = if (result.locationCountry.isNullOrBlank()) {
360+ result.locationName
361+ } else {
362+ " ${result.locationName} , ${result.locationCountry} "
363+ }.trim().trimEnd(' ,' )
364+
365+ return " Weather forecast for $formattedLocation ($granularityText , $dateInfo ):\n ${result.forecast} "
366+ }
374367 }
375368}
0 commit comments