Skip to content

Add Kotlin snippets to the custom tools page, including toolset filtering - #2114

Merged
happyhuman merged 10 commits into
mainfrom
docs-kotlin-toolset-filter
Aug 19, 2026
Merged

Add Kotlin snippets to the custom tools page, including toolset filtering#2114
happyhuman merged 10 commits into
mainfrom
docs-kotlin-toolset-filter

Conversation

@happyhuman

@happyhuman happyhuman commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

docs/tools-custom/index.md had six language tab groups and not one carried
Kotlin. All six do now, plus a subsection on filtering a toolset's tools with
ToolFilter, which is genuinely new in adk-kotlin 0.7.0.

Section Snippet
Example (tools in instructions) WeatherSentiment.kt
State Management UserPreferenceTools.kt
Controlling Agent Flow CustomerSupport.kt
Artifacts / Memory DocAnalysisTools.kt
Defining Effective Tool Functions OrderTools.kt
Simple Math Toolset ToolsetExample.kt:init
Filter tools in toolsets (new subsection) ToolsetExample.kt:filter

All transcluded, so CI compiles and lints every one of them.

Corrections made during review

ToolFilter is not a Kotlin-only capability. An earlier version of this
description, and of the page, said Python and TypeScript had no equivalent. They
do — Python's BaseToolset takes tool_filter: Optional[Union[ToolPredicate, List[str]]] with readonly_context, and Java and TypeScript match it;
b/548652184 tracks the substance.
The subsection is still Kotlin-only in its code, but the heading is now the
plain "Filter tools in toolsets", the prose says outright that every SDK can do
this, and the badge's title scopes the version to the Kotlin API rather than to
filtering as a concept.

Badge versions were wrong. The page badge and the ## Toolsets badge both
claimed Kotlin v0.7.0; @Tool, ToolContext and Toolset all exist at the
v0.1.0 tag, so both now read v0.1.0 — matching function-tools.md. Only the
filtering subsection keeps v0.7.0, which is the release ToolFilter landed in.
The ## Toolsets badge also had a bare Java span with no version; it now reads
v0.3.0, the first adk-java release containing BaseToolset.

The ## Toolsets badge is rewritten by this PR — an earlier revision of this
description said it was untouched, which was wrong: commit 098bf00b replaced
its stale title="…available for Python and TypeScript" (stale because a Java
tab already existed) and added the Java and Kotlin spans.

One unrelated fix, carried because it blocks CI

MultiAgentExample.kt overrode BaseTool.run(context, args: Map<String, Any>).
adk-kotlin 0.8.0 widened that to Map<String, Any?>, so the override compiles
no more. The break came in with the 0.8.0 bump in #2143, not from this branch —
it surfaces here because the snippet runner builds the whole examples project,
while #2143 changed no .kt files and so compiled nothing. One character.

Notes for reviewers

  • Source-breaking upstream change, which the snippet quietly documents:
    McpToolsetConfig.toolFilter went List<String>? (v0.6.0) → ToolFilter?
    (v0.7.0).
  • The filter snippet is its own subsection, not a fourth tab on the Simple
    Math Toolset group. That group is one worked example explained by five bullets
    — agent, greet_tool, name prefixing, a tool_context.state write, close()
    — and a filtering snippet satisfies none of them. Kotlin cannot satisfy the
    prefix bullet at all: BaseTool.name is a val. A bullet now explains that
    deviation instead of leaving readers with prose that doesn't match the code.
  • Deliberately left out: search_memory in the artifacts snippet (not on
    Kotlin's ToolContext; it lives on MemoryService, and the Java tab omits it
    too).

Verification

  • ./gradlew compileKotlin clean; ktlint clean; check_kotlin_snippets.sh
    passes.
  • Tool bodies are execution-verified, not just compiled — run through a harness
    with a real ToolContext:
unfiltered    : [addNumbers, subtractNumbers]
allowList     : [addNumbers]
predicate off : [addNumbers]
predicate on  : [addNumbers, subtractNumbers]
INVOKED addNumbers(a=7, b=3)      -> {result=10}
INVOKED subtractNumbers(a=7, b=3) -> {result=4}
  • Not exercised: no LLM call — the two main() entry points need credentials, so
    they are compile-verified only.

The Toolsets section had no Kotlin. ToolFilter and ToolPredicate arrived in
adk-kotlin 0.7.0 and give Kotlin something the other languages do not have: a
filter that receives the ReadonlyContext, so a toolset's tool list can depend on
session state or the current user.

The Python tab in the Simple Math Toolset example only gestures at this, in a
commented-out branch inside get_tools(). This snippet implements it, showing all
three states: no filter selects everything, allowList selects by name, and a
Predicate decides per invocation.

Placed in its own subsection rather than as a fourth tab on the Simple Math
Toolset example. That group is one worked example explained by five bullets --
an agent, a greet tool, name prefixing, a tool_context.state write and close() --
and a filtering snippet satisfies none of them. Kotlin cannot satisfy the prefix
bullet at all, since BaseTool.name is a val and adk-kotlin has no prefix
mechanism. A tab there would have left readers with four bullets that do not
describe the code above them.

Transcluded, so CI compiles and lints it. Verified beyond compiling: the tools
are generated by KSP, filtering returns the expected sets for all three cases,
and the tool bodies run -- addNumbers(7,3) -> {result=10}.
@netlify

netlify Bot commented Aug 11, 2026

Copy link
Copy Markdown

Deploy Preview for adk-docs-preview ready!

Name Link
🔨 Latest commit de751d8
🔍 Latest deploy log https://app.netlify.com/projects/adk-docs-preview/deploys/6a85e7117d0f6f0008d4adcb
😎 Deploy Preview https://deploy-preview-2114--adk-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@happyhuman happyhuman self-assigned this Aug 11, 2026

@wikaaaaa wikaaaaa left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I checked the snippet against adk-kotlin v0.7.0 and the code is correct.

Just a comment to the PRs justification -- "gives Kotlin a capability the other languages don't have" isn't accurate. Context-aware tool filtering exists in other languages, ex. Python

Out of scope for this PR, but none of the other snippets in this file include Kotlin — should we add them?

@happyhuman

Copy link
Copy Markdown
Collaborator Author

Thanks @wikaaaaa — both points addressed, and you were right on the first one.

On "a capability the other languages don't have"

Wrong, and I've corrected it. Python's BaseToolset takes tool_filter: Optional[Union[ToolPredicate, List[str]]], and ToolPredicate.__call__ receives readonly_context — that's the same context-aware filtering and the allow-list-by-name form I claimed was Kotlin's alone.

More importantly, that claim had leaked into the page, not just the description. A single-language badge asserts exclusivity in this repo — the Python-only precedent I cited in the description (docs/agents/llm-agents.md:426) sits on set_default_model, which genuinely is Python-only. So Supported in ADK | Kotlin v0.7.0 under the conceptual heading "Filtering which tools a toolset exposes" was telling readers Python can't do this.

Fixed by scoping the heading to the API rather than the concept: "Filtering which tools a toolset exposes with ToolFilter". ToolFilter really is Kotlin v0.7.0, so the badge is now true, and the title attribute notes other languages have their own mechanisms.

On the other snippets — done, all of them

The page had six language tab groups and not one had Kotlin. All six do now:

Section Snippet
Example (tools in instructions) WeatherSentiment.kt
State Management UserPreferenceTools.kt
Controlling Agent Flow CustomerSupport.kt
Artifacts / Memory DocAnalysisTools.kt
Defining Effective Tool Functions OrderTools.kt
Simple Math Toolset ToolsetExample.kt:init

All transcluded, so CI compiles and lints them. Also fixed the ## Toolsets section badge, which claimed "Python and TypeScript" despite the Java tab that was already there.

These are execution-verified, not just compiled. I wired a temporary harness with a real ToolContext and ran every tool: filtering, transferToAgent, artifact load/save, and state deltas all behave as documented. Two things that caught real bugs:

  • The toolset example originally had no greet_tool, so bullets 2 and 3 of "In this example" described code that wasn't in the Kotlin tab. Added greetUser.
  • The state snippet wrote a nested map to stateDelta while reading committed state. Unlike Python's layered tool_context.state, Kotlin's view doesn't include deltas written earlier in the same invocation, so a second call in one turn silently dropped the first. Now one flat key per preference — the same shape the Java tab uses.

What I deliberately left out

  • search_memory in the artifacts/memory snippet. Not available on Kotlin's ToolContext; it lives on MemoryService. The Kotlin tab covers artifacts only, which is exactly what the Java tab already does, and the bullet above it already scopes search_memory to "Python, Go and TypeScript". The KDoc points at LoadMemoryTool/PreloadMemoryTool as the Kotlin route.
  • Tool-name prefixing in the toolset example. adk-kotlin 0.7.0 has no prefix mechanism and BaseTool.name is a val. Rather than leave a bullet describing absent code, I added one explaining the deviation.
  • Live-model execution for the two main() entry points — they need credentials, same as the Python originals. Every tool body is execution-verified; those two entry points are compile-verified only.

Heads up that this outgrew the PR title, which I'll update along with the description. Happy to split the five backfilled snippets into their own PR if you'd rather review them separately from the ToolFilter change you already approved.

@happyhuman
happyhuman requested a review from wikaaaaa August 14, 2026 20:17
…ilter

# Conflicts:
#	tools/kotlin-snippets/files_to_test.txt

@wikaaaaa wikaaaaa left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for filling in the other snippets!

Comment thread examples/kotlin/snippets/tools/overview/CustomerSupport.kt Outdated
Comment thread examples/kotlin/snippets/tools/overview/OrderTools.kt Outdated
Comment thread examples/kotlin/snippets/tools/overview/ToolsetExample.kt Outdated
@joefernandez

Copy link
Copy Markdown
Collaborator

Technical review report

Verification method — the PR is entirely Kotlin, so verified against google/adk-kotlin v0.7.0 (the version examples/kotlin/build.gradle.kts pins), not adk-python. Checked out the PR head, ran ./gradlew compileKotlin (BUILD SUCCESSFUL, KSP + compile), ran the toolset logic for real, and reproduced the PR's claimed output exactly:

unfiltered    : [addNumbers, subtractNumbers]
allowList     : [addNumbers]
predicate off : [addNumbers]
predicate on  : [addNumbers, subtractNumbers]

Code: technically correct. Every API the six snippets use exists with the signature used — cited with line numbers in the artifact. Key ones:

[] Also flagged: the Kotlin v0.7.0 badges overstate the requirement (@Tool/ToolContext/Toolset all ship in v0.1.0, and function-tools.md already says v0.1.0); the new Java span has no version; and the PR description describes only one of its two commits (it says the Toolsets badge is untouched — commit 098bf00b rewrote it).

@joefernandez

Copy link
Copy Markdown
Collaborator

Follow up item from technical review: filed b/548652184

PR claims ToolFilter gives Kotlin "a capability the other languages don't have" and that "Python and TypeScript have no ToolFilter equivalent". All three other SDKs have it, context parameter and all — Kotlin's naming is a direct port of Java's:

That undercuts the reason given for making it a Kotlin-only subsection instead of a four-tab one.

@joefernandez joefernandez left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved with comments

Comment thread docs/tools-custom/index.md Outdated
happyhuman and others added 4 commits August 18, 2026 21:40
Conflict in tools/kotlin-snippets/files_to_test.txt: main appended
snippets/a2a/A2AConsumer.kt (#2118) while this branch appended its six
snippets/tools/overview/ registrations at the same spot. Kept both, main's
line first.

Checked the merged tree for silent breakage as well, since main moved to
adk-kotlin 0.8.0 (#2143) under this branch's snippets: ToolFilter,
isToolSelected and Toolset are byte-identical between 0.7.0 and 0.8.0, and
these snippets use BaseTool only as a return type, not as a supertype.
adk-kotlin 0.8.0 widened `BaseTool.run`'s args from `Map<String, Any>` to
`Map<String, Any?>`, so the override in this snippet overrides nothing and the
class no longer implements its abstract member. `compileKotlin` fails with
"'run' overrides nothing" at MultiAgentExample.kt:61.

The break arrived on main with the 0.8.0 bump in #2143, not from this branch.
It surfaces here because the snippet runner builds the whole examples project,
while that PR's own check only compiled the files it changed - and it changed
no .kt files at all. Fixing it here because it blocks this PR; it is one
character and unrelated to the toolset filtering content.
Four things from joefernandez's review:

- Heading shortened to "Filter tools in toolsets" as suggested.
- That shorter heading is conceptual, and the subsection carries a Kotlin-only
  badge, which would repeat the exclusivity claim his b/548652184 is about.
  Python, Java and TypeScript all filter toolsets by name or by a
  context-aware predicate on BaseToolset, so the section now says so in a
  sentence and the badge's title scopes the version to the Kotlin ToolFilter
  API rather than to filtering as a concept.
- Page badge Kotlin v0.7.0 -> v0.1.0, and the Toolsets badge likewise. @tool,
  ToolContext and Toolset all exist at the v0.1.0 tag; only ToolFilter is new
  in v0.7.0, and function-tools.md already carries v0.1.0.
- The Toolsets badge's bare "Java" span now reads v0.3.0, the first adk-java
  release containing BaseToolset (added in a211ac4c, tagged v0.3.0).
@happyhuman happyhuman changed the title Add Kotlin snippet for filtering a toolset's tools Add Kotlin snippets to the custom tools page, including toolset filtering Aug 19, 2026
@happyhuman

happyhuman commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator Author

All four addressed in 840b9b0: heading shortened, badges corrected to v0.1.0 (Java v0.3.0), exclusivity claim dropped, description rewritten. Thanks for the catch.

@happyhuman
happyhuman merged commit 8da5856 into main Aug 19, 2026
12 checks passed
@happyhuman
happyhuman deleted the docs-kotlin-toolset-filter branch August 19, 2026 17:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants