Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/tools-custom/function-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,12 @@ it's None) into the content of the `FunctionResponse` sent back to the LLM.
--8<-- "examples/java/snippets/src/main/java/tools/LongRunningFunctionExample.java:full_code"
```

=== "Kotlin"

```kotlin
--8<-- "examples/kotlin/snippets/tools/function-tools/LongRunningTool.kt:call_reimbursement_tool"
```

??? "Python complete example: File Processing Simulation"

```python
Expand Down
56 changes: 56 additions & 0 deletions examples/kotlin/snippets/tools/function-tools/LongRunningTool.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import com.google.adk.kt.agents.Instruction
import com.google.adk.kt.agents.LlmAgent
import com.google.adk.kt.annotations.Param
import com.google.adk.kt.annotations.Tool
import com.google.adk.kt.events.Event
import com.google.adk.kt.models.Gemini
import com.google.adk.kt.runners.InMemoryRunner
import com.google.adk.kt.types.Content
import com.google.adk.kt.types.FunctionResponse
import com.google.adk.kt.types.Part

// --8<-- [start:long_running_tool]
data class ReimbursementApproval(
Expand Down Expand Up @@ -47,3 +52,54 @@ fun main() {
)
}
// --8<-- [end:long_running_tool]

// --8<-- [start:call_reimbursement_tool]
private fun printText(event: Event) {
val text = event.content?.parts?.mapNotNull { it.text }?.joinToString("").orEmpty()
if (text.isNotEmpty()) println("[${event.author}]: $text")
}

suspend fun callReimbursementAgent(
runner: InMemoryRunner,
userId: String,
sessionId: String,
query: String,
) {
var pendingCallId: String? = null
var pendingResponse: FunctionResponse? = null

runner
.runAsync(
userId = userId,
sessionId = sessionId,
newMessage = Content(role = "user", parts = listOf(Part(text = query))),
).collect { event ->
val callId = pendingCallId
if (callId == null) {
// A long-running call is the one whose id the event lists in longRunningToolIds.
pendingCallId =
event
.functionCalls()
.firstOrNull { it.id != null && it.id in event.longRunningToolIds }
?.id
} else {
event
.functionResponses()
.firstOrNull { it.id == callId }
?.let { pendingResponse = it }
}
printText(event)
}

// The tool returned "pending" and the invocation paused. Resume it by sending the
// outcome back as a FunctionResponse carrying the same id.
val paused = pendingResponse ?: return
val updated = paused.copy(response = mapOf("status" to "approved"))
runner
.runAsync(
userId = userId,
sessionId = sessionId,
newMessage = Content(role = "user", parts = listOf(Part(functionResponse = updated))),
).collect(::printText)
}
// --8<-- [end:call_reimbursement_tool]
Loading