From 16c0f149d2922b85cd84862e66b1089c97df912f Mon Sep 17 00:00:00 2001 From: Shahin Saadati Date: Thu, 20 Aug 2026 09:17:19 -0700 Subject: [PATCH 1/2] Add Kotlin tabs to the tool confirmation page All three tab groups showed Python, TypeScript, Go and Java but not Kotlin, even though the API has existed since adk-kotlin v0.1.0. Kotlin turns out to sit closer to Python than to TypeScript here: the @Tool annotation carries a requireConfirmation flag, so the boolean case is a direct equivalent of FunctionTool(require_confirmation=True) rather than something callers hand-roll. The flag is a compile-time constant, though, so dynamic thresholds are evaluated inside the tool through ToolContext, the way ADK Java does it. The prose that previously singled out TypeScript for that now names Kotlin too. The advanced example reads the returned payload through Number rather than casting straight to Int, because the payload arrives decoded from JSON and its numeric type is not guaranteed - the same trap the Go tab calls out for float64. --- docs/tools-custom/confirmation.md | 34 +++++++-- .../confirmation/ToolConfirmationExample.kt | 74 +++++++++++++++++++ .../dynamic/ReimbursementTools.kt | 47 ++++++++++++ tools/kotlin-snippets/files_to_test.txt | 2 + 4 files changed, 152 insertions(+), 5 deletions(-) create mode 100644 examples/kotlin/snippets/tools/confirmation/ToolConfirmationExample.kt create mode 100644 examples/kotlin/snippets/tools/confirmation/dynamic/ReimbursementTools.kt diff --git a/docs/tools-custom/confirmation.md b/docs/tools-custom/confirmation.md index e69b6cf33d..c5a2709fd7 100644 --- a/docs/tools-custom/confirmation.md +++ b/docs/tools-custom/confirmation.md @@ -1,7 +1,7 @@ # Get action confirmation for ADK Tools
- Supported in ADKPython v1.14.0TypeScript v0.2.0Go v0.3.0Experimental + Supported in ADKPython v1.14.0TypeScript v0.2.0Go v0.3.0Kotlin v0.8.0Experimental
Some agent workflows require confirmation for decision making, verification, @@ -49,9 +49,10 @@ agent pattern. When your tool only requires a simple `yes` or `no` from the user, you can append a confirmation step. In Python, Go, and Java, you can enable this by wrapping the tool with the `FunctionTool` class and setting the -`require_confirmation` parameter (or equivalent) to `True`. In TypeScript, you -implement this logic manually within the `execute` function using the -`ToolContext`. +`require_confirmation` parameter (or equivalent) to `True`. In Kotlin, you set +`requireConfirmation = true` on the tool function's `@Tool` annotation. In +TypeScript, you implement this logic manually within the `execute` function +using the `ToolContext`. The following examples show how to enable boolean confirmation: @@ -118,9 +119,15 @@ The following examples show how to enable boolean confirmation: .build(); ``` +=== "Kotlin" + + ```kotlin + --8<-- "examples/kotlin/snippets/tools/confirmation/ToolConfirmationExample.kt:boolean_confirmation" + ``` + ### Require confirmation function -You can modify the behavior of the confirmation requirement by using a function that returns a boolean response based on the tool's input. In TypeScript, this is handled by adding conditional logic to your `execute` function. +You can modify the behavior of the confirmation requirement by using a function that returns a boolean response based on the tool's input. In TypeScript, this is handled by adding conditional logic to your `execute` function. In Kotlin, the `@Tool` annotation's flag is a compile-time constant, so the conditional logic goes inside the tool function. === "Python" @@ -198,6 +205,17 @@ You can modify the behavior of the confirmation requirement by using a function .build(); ``` +=== "Kotlin" + + !!! note + The `@Tool` annotation's `requireConfirmation` flag is a compile-time + constant, so a threshold is evaluated inside the tool using the + `ToolContext`, as in ADK Java. + + ```kotlin + --8<-- "examples/kotlin/snippets/tools/confirmation/dynamic/ReimbursementTools.kt:dynamic_confirmation" + ``` + ## Advanced confirmation {#advanced-confirmation} When a tool confirmation requires more details for the user or a more complex @@ -333,6 +351,12 @@ time off requests for an employee: } ``` +=== "Kotlin" + + ```kotlin + --8<-- "examples/kotlin/snippets/tools/confirmation/ToolConfirmationExample.kt:advanced_confirmation" + ``` + ## Remote confirmation with REST API {#remote-response} If there is no active user interface for a human confirmation of an agent diff --git a/examples/kotlin/snippets/tools/confirmation/ToolConfirmationExample.kt b/examples/kotlin/snippets/tools/confirmation/ToolConfirmationExample.kt new file mode 100644 index 0000000000..26395b1841 --- /dev/null +++ b/examples/kotlin/snippets/tools/confirmation/ToolConfirmationExample.kt @@ -0,0 +1,74 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.adk.kt.examples.tools.confirmation + +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.models.Gemini +import com.google.adk.kt.tools.ToolContext + +// --8<-- [start:boolean_confirmation] +class ReimbursementTools { + /** Reimburse an amount. */ + @Tool(requireConfirmation = true) // Pause for user confirmation before every call. + fun reimburse( + @Param("The amount to reimburse.") amount: Int, + ): Map = mapOf("status" to "ok", "reimbursedAmount" to amount) +} + +val reimbursementAgent = + LlmAgent( + name = "reimbursement_agent", + model = Gemini(name = "gemini-flash-latest"), + tools = ReimbursementTools().generatedTools(), + ) +// --8<-- [end:boolean_confirmation] + +// --8<-- [start:advanced_confirmation] +class TimeOffTools { + /** Request day off for the employee. */ + @Tool + fun requestTimeOff( + context: ToolContext, + @Param("The number of days requested.") days: Int, + ): Map { + val confirmation = context.toolConfirmation + if (confirmation == null) { + context.requestConfirmation( + hint = + "Please approve or reject the tool call requestTimeOff() by responding " + + "with a FunctionResponse with an expected ToolConfirmation payload.", + payload = mapOf("approved_days" to 0), + ) + // Return an intermediate status indicating that the tool is waiting for + // a confirmation response: + return mapOf("status" to "Manager approval is required.") + } + + // The payload comes back decoded from JSON, so the number may arrive as any + // Number subtype. Read it through Number rather than casting straight to Int. + val payload = confirmation.payload as? Map<*, *> + val approvedDays = + minOf((payload?.get("approved_days") as? Number)?.toInt() ?: 0, days) + if (approvedDays == 0) { + return mapOf("status" to "The time off request is rejected.", "approved_days" to 0) + } + return mapOf("status" to "ok", "approved_days" to approvedDays) + } +} +// --8<-- [end:advanced_confirmation] diff --git a/examples/kotlin/snippets/tools/confirmation/dynamic/ReimbursementTools.kt b/examples/kotlin/snippets/tools/confirmation/dynamic/ReimbursementTools.kt new file mode 100644 index 0000000000..62da167685 --- /dev/null +++ b/examples/kotlin/snippets/tools/confirmation/dynamic/ReimbursementTools.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.adk.kt.examples.tools.confirmation.dynamic + +import com.google.adk.kt.annotations.Param +import com.google.adk.kt.annotations.Tool +import com.google.adk.kt.tools.ToolContext + +// --8<-- [start:dynamic_confirmation] +class ReimbursementTools { + /** Reimburse an amount, requiring manager approval above a threshold. */ + @Tool + fun reimburse( + context: ToolContext, + @Param("The amount to reimburse.") amount: Int, + ): Map { + // The @Tool annotation's requireConfirmation flag is a compile-time constant, + // so the threshold is evaluated here using the ToolContext instead. + if (amount > 1000) { + val confirmation = context.toolConfirmation + if (confirmation == null) { + context.requestConfirmation(hint = "Amount > 1000 requires approval.") + // Return an intermediate status while the confirmation is pending. + return mapOf("status" to "Pending manager approval.") + } + if (!confirmation.confirmed) { + return mapOf("status" to "Reimbursement rejected.") + } + } + return mapOf("status" to "ok", "reimbursedAmount" to amount) + } +} +// --8<-- [end:dynamic_confirmation] diff --git a/tools/kotlin-snippets/files_to_test.txt b/tools/kotlin-snippets/files_to_test.txt index b1902c362c..b63293f4d1 100644 --- a/tools/kotlin-snippets/files_to_test.txt +++ b/tools/kotlin-snippets/files_to_test.txt @@ -40,3 +40,5 @@ snippets/tools/overview/UserPreferenceTools.kt snippets/tools/overview/CustomerSupport.kt snippets/tools/overview/DocAnalysisTools.kt snippets/tools/overview/OrderTools.kt +snippets/tools/confirmation/ToolConfirmationExample.kt +snippets/tools/confirmation/dynamic/ReimbursementTools.kt From d327559f682eaa64ff531cbd505a90d3b4930280 Mon Sep 17 00:00:00 2001 From: Shahin Saadati Date: Thu, 20 Aug 2026 11:21:43 -0700 Subject: [PATCH 2/2] Badge the confirmation page with the version the API shipped in The badge said Kotlin v0.8.0, the version adk-docs compiles against, rather than the introducing release. ToolConfirmation, ToolContext.requestConfirmation and the @Tool requireConfirmation flag were all present at v0.1.0. --- docs/tools-custom/confirmation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tools-custom/confirmation.md b/docs/tools-custom/confirmation.md index c5a2709fd7..ccd771515e 100644 --- a/docs/tools-custom/confirmation.md +++ b/docs/tools-custom/confirmation.md @@ -1,7 +1,7 @@ # Get action confirmation for ADK Tools
- Supported in ADKPython v1.14.0TypeScript v0.2.0Go v0.3.0Kotlin v0.8.0Experimental + Supported in ADKPython v1.14.0TypeScript v0.2.0Go v0.3.0Kotlin v0.1.0Experimental
Some agent workflows require confirmation for decision making, verification,