Skip to content

Add Kotlin snippets for Memory Bank and RAG memory - #2089

Open
happyhuman wants to merge 7 commits into
mainfrom
docs-kotlin-memory-services
Open

Add Kotlin snippets for Memory Bank and RAG memory#2089
happyhuman wants to merge 7 commits into
mainfrom
docs-kotlin-memory-services

Conversation

@happyhuman

@happyhuman happyhuman commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

docs/sessions/memory.md documented VertexAiMemoryBankService and
VertexAiRagMemoryService for Python only — the Kotlin tab stopped at the
in-memory service. Both have been available in adk-kotlin since 0.7.0, so this
adds the two missing tabs.

Stacked on #2088. Both services are 0.7.0-only, so this needs the pin
bump to compile.

CI note: kotlin-snippets-pr-check.yaml is gated on branches: [main],
which filters the base, so the Kotlin build/lint job has never run on this
PR. Retargeting after #2088 merges emits a pull_request: edited event,
which the workflow's default types don't include — so it still won't run.
Force-push this branch after #2088 lands to fire synchronize, and wait
for green before merging.

What's in it

  • memory.md: Kotlin tabs for the Memory Bank and RAG memory sections.
  • MemoryExample.kt: memory_bank and rag_memory snippet regions.

Notes for reviewers

  • ragCorpus takes a bare corpus id, not a full resource name.
    normalizeCorpusName does require(!ragCorpus.startsWith("projects/")) and
    throws on a full name, expanding the bare id itself. This diverges from the
    Python tab immediately above, which passes the full
    projects/.../ragCorpora/... name, so the snippet calls the difference out
    inline. (An earlier revision of this PR claimed the opposite; fixed.)
  • Both Vertex services declare an internal primary constructor. The
    snippets use the public secondary one taking project/location plus the engine
    or corpus id. Reading the primary signature alone yields a constructor
    callers cannot invoke — noting it here rather than in the rendered snippet,
    where a reader can't see the constructor anyway.
  • Both snippets build a Runner, matching the surrounding prose
    ("instantiating the service and passing it to the Runner") and the Python
    tab. They previously stopped at a factory function.
  • The language badge stays at Kotlin v0.1.0. It marks when Kotlin support
    for the page was introduced, not the newest API on it — the other six Kotlin
    snippets have worked since 0.1.0.
  • One rendering change outside the new sections: the
    [start:full_example] marker moved above the function's KDoc, so that KDoc
    now renders inside the code block at memory.md:229. ktlint forces this —
    "an EOL comment may not be preceded by a KDoc; reversed order is allowed when
    separated by a newline" — and the reversed order is the only compliant
    arrangement short of deleting the KDoc.

Verification

  • ./gradlew compileKotlin passes; ktlint clean on changed files.
  • Transclusion regions resolve; no orphaned tabs.
  • API surface checked against the adk-kotlin v0.7.0 sources.

The Kotlin examples were pinned to adk-kotlin 0.5.0, which predates the
context caching, Vertex AI memory, and RAG retrieval APIs. Bump the pin to
0.7.0 so snippets for those features can be added.

Three consequences of the bump are handled here:

- `ExperimentalResumabilityFeature` was removed in 0.7.0, so RunConfigExample
  no longer opts into it. The annotation class is gone, not merely deprecated,
  so this is a hard compile break rather than a warning that could be deferred.
- The Vertex AI session and memory services expose Ktor's `HttpClient` as a
  defaulted constructor parameter, so any snippet naming them needs Ktor on the
  compile classpath, not just at runtime.
- The `resolutionStrategy` block forcing kotlin-stdlib 2.1.20 is now dead. It
  worked around 0.5.0 publishing a stdlib newer than this project's compiler;
  0.6.0 fixed that upstream. Verified that the highest stdlib on the compile
  classpath is still 2.1.20 without it.

Also fixes two unrelated snags found while validating the above:

- `check_kotlin_snippets.sh` walked `examples/kotlin` without pruning build
  output, so after any local build it reported every generated KSP file as an
  unregistered snippet. CI only ever ran it against a clean checkout, so the
  bug was invisible there.
- A transclusion path in logging.md was split across two lines, so the include
  never resolved and the code block rendered empty.
@happyhuman
happyhuman force-pushed the kotlin-examples-adk-0.7.0 branch from 260a152 to d465c81 Compare August 7, 2026 17:19
@happyhuman
happyhuman force-pushed the docs-kotlin-memory-services branch from 7df4c6a to 673ad88 Compare August 7, 2026 17:19
@happyhuman happyhuman self-assigned this Aug 7, 2026
happyhuman and others added 3 commits August 7, 2026 17:21
The three plugin sample links 404. adk-python renamed
`contributing/samples/plugin/` to `contributing/samples/plugins/`; the
directory contents are otherwise unchanged, so only the path segment moves.

This is what the repo-wide `link-check` job has been failing on. It is
unrelated to the 0.7.0 upgrade in this PR, but the check gates the merge and
the fix is confined to the three URLs.

Verified all three targets return 200.
The memory page documented `VertexAiMemoryBankService` and
`VertexAiRagMemoryService` for Python and Java only; the Kotlin tab stopped at
the in-memory service. Both are available in adk-kotlin as of 0.7.0, so add
the two missing tabs.

Both services declare an `internal` primary constructor, so the snippets use
the public secondary one that takes project/location plus the engine or corpus
id -- reading the primary signature alone gives a constructor callers cannot
invoke.

The page's language-support badge stays at Kotlin v0.1.0: it marks when Kotlin
support for the page was introduced, and the other six Kotlin snippets on it
have worked since then.

The remaining diff in MemoryExample.kt is ktlint bringing pre-existing lines
into line with the repo style, which the linter now gates on because the file
is touched here.
@happyhuman
happyhuman force-pushed the docs-kotlin-memory-services branch from 673ad88 to d97ec91 Compare August 7, 2026 17:36
Three fixes from review:

- The `rag_memory` KDoc claimed `ragCorpus` accepts a bare id or a full
  resource name. It is the opposite: `normalizeCorpusName` does
  `require(!ragCorpus.startsWith("projects/"))` and throws on a full name. The
  Python tab directly above this snippet passes a full resource name, so a
  reader switching tabs would have hit an IllegalArgumentException with a
  comment telling them it was fine. The note now states the bare-id rule and
  calls out the divergence from Python explicitly.
- Dropped "the primary constructor is internal" from the rendered snippet. It
  is a note for reviewers, not for readers, who cannot see that constructor.
  It stays in the PR description.
- Both snippets stopped at a factory function while the surrounding prose says
  "instantiating the service and passing it to the Runner" and the Python tab
  shows exactly that. They now build the service and pass it to a Runner.
@happyhuman
happyhuman requested a review from wikaaaaa August 7, 2026 19:16
Base automatically changed from kotlin-examples-adk-0.7.0 to main August 7, 2026 20:24
@netlify

netlify Bot commented Aug 7, 2026

Copy link
Copy Markdown

Deploy Preview for adk-docs-preview ready!

Name Link
🔨 Latest commit 2e517d2
🔍 Latest deploy log https://app.netlify.com/projects/adk-docs-preview/deploys/6a7645cd8305340008d5e240
😎 Deploy Preview https://deploy-preview-2089--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.

@joefernandez

Copy link
Copy Markdown
Collaborator

Technical review report

adk-docs PR #2089 — Add Kotlin snippets for Memory Bank and RAG memory

Verdict: technically correct, with two accuracy issues to fix before merge. The API surface in both new snippets matches adk-kotlin v0.7.0 exactly. One placeholder value will throw at runtime, and one inline comment mischaracterizes the Python contract.

A note on scope: the PR adds Kotlin snippets, so the authoritative source is google/adk-kotlin (cited below, as requested). I used google/adk-python @ b333c85 only to check the cross-language claims the PR makes about the Python tab.


Verified correct

1. Memory Bank constructor — project / location / agentEngineId

The snippet's three named arguments match the public secondary constructor exactly, in declaration order:

VertexAiMemoryBankService.kt#L77-L90

The PR's reviewer note about the primary constructor being internal is also accurate — #L61-L62 declares internal constructor(private val client: VertexAiMemoryBankClient), so the secondary constructor is the only one callers can reach.

2. RAG constructor — all five arguments, including types

VertexAiRagMemoryService.kt#L85-L98

similarityTopK: Int? = null and vectorDistanceThreshold: Double confirm 5 and 0.6 are well-typed. Internal primary constructor at #L61-L67.

3. The headline fix — ragCorpus really does reject a full resource name

This is the substantive correction in commit 22f8d8d, and it is right:

VertexAiRagMemoryService.kt#L321-L329

internal fun normalizeCorpusName(ragCorpus: String, project: String, location: String): String {
  validateSegment(project, "project")
  validateSegment(location, "location")
  require(!ragCorpus.startsWith("projects/")) {
    "ragCorpus must be a bare corpus id, not a full resource name: '$ragCorpus'."
  }
  validateSegment(ragCorpus, "ragCorpus id")
  return "projects/$project/locations/$location/ragCorpora/$ragCorpus"
}

The KDoc agrees at #L76-L77. The earlier revision's claim was indeed backwards; the fix is correct.

4. Both types satisfy InMemoryRunner's memoryService

Both declare : MemoryService (memory bank #L62, RAG #L67), and the runner accepts memoryService: MemoryService?:

InMemoryRunner.kt#L46-L53

5. The "wire it to a Runner" change matches upstream's own examples

The new snippets are near-identical to adk-kotlin's canonical examples, which is strong corroboration:

Line 132 is literally InMemoryRunner(agent = agent, appName = APP_NAME, memoryService = memoryService) — the snippet's exact shape. This also settles that LlmAgent binds to the agent: BaseAgent parameter.

6. "Available since 0.7.0" is correct

Both paths return HTTP 404 at tag v0.6.0 and 200 at v0.7.0; v0.7.0 is the latest release (2026-08-03). The dependency on PR #2088's pin bump is real.


Issues to fix

Issue 1 (should fix): agentEngineId = "AGENT_ENGINE_ID" throws IllegalArgumentException.

adk-kotlin validates that the id is numeric:

VertexAiMemoryBankService.kt#L481-L488

internal fun validateAgentEngineId(agentEngineId: String): String {
  require(agentEngineId.isNotBlank()) { "agentEngineId must not be blank." }
  require(agentEngineId.all { it.isDigit() }) { ... }

Python has no such check — it only rejects empty and warns on / (vertex_ai_memory_bank_service.py#L199-L202, #L218-L220) — so the Python tab's identical "AGENT_ENGINE_ID" placeholder is fine there and fatal here.

Worth noting the asymmetry: the other three placeholders are safe, because PROJECT_ID, LOCATION and CORPUS_ID all match RESOURCE_SEGMENT_PATTERN = Regex("^[a-zA-Z0-9_-]+$") at #L495-L503. AGENT_ENGINE_ID is the single placeholder in the PR that is guaranteed to fail.

Suggest agentEngineId = "1234567890", which also matches the agentengine://1234567890 in the prose ~20 lines above, and mirrors upstream's own KDoc example at #L71-L72. This is the same class of Python/Kotlin divergence the PR carefully documented for ragCorpus — it just missed this one.

Issue 2 (minor accuracy): the ragCorpus comment overstates the Python divergence.

The snippet says "unlike the Python tab above, which takes the full name". Python accepts both forms:

vertex_ai_rag_memory_service.py#L107-L109

rag_corpus: The name of the Agent Platform RAG corpus to use. Format:
  ``projects/{project}/locations/{location}/ragCorpora/{rag_corpus_id}``
  or ``{rag_corpus_id}``

The startswith("projects/") branch at #L132-L138 is only a fallback for inferring project/location. So the statement is true of the tab (which does pass a full name) but reads as an API contrast, and as written implies Python requires the full form. Suggested rewording: "Python accepts either form; Kotlin accepts only the bare id."

Observation (no action required): both services live in jvmMain, not commonMain — unlike InMemoryMemoryService, which is in commonMain. These two snippets are therefore JVM-only while the other six Kotlin snippets on the page are multiplatform. Harmless for the docs build, but a KMP reader targeting Android or native cannot use them.


On the non-API claims

The [start:full_example] marker move and the ktlint reformatting of pre-existing lines are plausible and self-consistent, but they're properties of the docs repo's linter config, not of adk-kotlin — I did not run the build, so I'm taking ./gradlew compileKotlin passing on the author's word. The transclusion anchors (memory_bank, rag_memory) are correctly paired open/close and the two new === "Kotlin" tabs are indented consistently with the adjacent Python tabs.

The CI caveat in the description is worth heeding: the Kotlin build/lint job appears never to have run on this PR, and the two findings above are exactly the kind a compile alone wouldn't catch anyway — validateAgentEngineId fires at runtime, not compile time.

@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.

Thanks for the update.

Have a look at the Technical review report issues, particularly Issue 2 to see if it worth mentioning. I don't consider that a required change, thought.
#2089 (comment)

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.

2 participants