-
Notifications
You must be signed in to change notification settings - Fork 359
Conversation
hemasekhar-p
commented
Jun 10, 2026
Hi @DABH, thank you for your contribution! We appreciate you taking the time to submit this pull request. As per contribution policy, please ensure your PR consists of a single commit and i have noticed inconsistency code formatting. Could you please change your commits accordingly and address the code formatting issue?
hemasekhar-p
commented
Jun 11, 2026
@DABH, thank you for your quick response. when running a Maven build, some files are modifying due to incorrect formatting. so, use the Maven build to ensure your changes are properly aligned and please make sure your PR contains a single commit.
...d IDs ADK generates timestamps and IDs by calling Instant.now() and UUID.randomUUID() directly, leaving callers no way to control them. This blocks integrations that need to supply their own timestamps and IDs. adk-python and adk-go already expose an equivalent seam. Add a leaf com.google.adk.platform package with TimeProvider and UuidProvider functional interfaces, each with a SYSTEM default that preserves today's wall-clock/random behavior. Rather than an ambient ThreadLocal (which would silently fall back to the system providers once the RxJava flow hops onto a Schedulers worker thread), the providers are threaded as data through InvocationContext, so they are visible on whatever thread builds an event. Callers configure them once on the Runner, which also injects them into the default InMemorySessionService it constructs. Event ids and timestamps, the invocation id, function-call ids, the event compaction summarizer, and the InMemorySessionService session id and lastUpdateTime now derive from the in-scope providers. Event.generateEventId() and the Event.Builder timestamp default delegate to the SYSTEM providers, so the platform interfaces are the single source for generated ids and times while the public Event API stays unchanged.
d92d033 to
742e700
Compare
DABH
commented
Jun 11, 2026
Thanks @hemasekhar-p — addressed both. I rebased onto the latest main and ran the full Maven build (which runs the bound fmt:format goal); mvn fmt:check now reports 0 non-complying files across all modules. I've also squashed the change into a single commit. Let me know if you still see any files being reformatted on your end.
DABH
commented
Jun 11, 2026
Also @hemasekhar-p I made a few improvements to the design/implementation based on @xumaple's feedback (updated the PR description accordingly). Thanks again for the fast review and please just let me know what else I can do to help make this PR mergeable. I appreciate your help and look forward to hearing from you!
Uh oh!
There was an error while loading. Please reload this page.
Link to Issue or Description of Change
Problem:
ADK generates timestamps and IDs by calling
Instant.now()andUUID.randomUUID()directly. There are use cases where it's useful to have custom clock and UUID providers, such as when you want to make runs reproducible/deterministic.adk-pythonalready solves this withplatform.time/platform.uuid- see google/adk-python#4200. Closely inspired by that, we propose adding similar functionality foradk-java. Note that a similar PR is open right now foradk-go: google/adk-go#964.Solution:
Introduce a leaf package
com.google.adk.platformwith two functional interfaces:TimeProvider—Instant now(), defaultSYSTEMbacked byInstant::now.UuidProvider—String newUuid(), defaultSYSTEMbacked byUUID.randomUUID().Both default to today's wall-clock / random behavior, so this change is fully backwards-compatible.
The providers are threaded as data through
InvocationContextrather than stored in an ambientThreadLocal. ADK's core flow hops threads viaRxJava(e.g.BaseLlmFlowobserves onSchedulers.io()/ the agent executor), and events are built downstream on those worker threads. We considered using aThreadLocalbut that would silently fall back to the system providers after a thread hop, failing open with no error. So the proposed solution here, carrying the providers on theInvocationContext(which is already captured in the RxJava lambdas and passed down the chain) makes them visible on whatever thread builds an event, so this is thread-safe. This mirrors the proposed changes toadk-go, which diverged fromadk-python's contextvar mechanism for the same concurrency reason.Users configure the providers once on the
Runner(Runner.builder().timeProvider(...).uuidProvider(...)); no knowledge of ADK's internal threads is required.The other files edited in this PR are just call sites updated to derive from the in-scope providers:
InvocationContext— invocation ID, plusnow()/newUuid()accessors.BaseLlmFlow,Functions,OutputSchema— event IDs + timestamps, function-call IDs.Runner— invocation ID + event builds.InMemorySessionService— auto session ID +lastUpdateTime(constructor injection; default constructor keepsSYSTEMbehavior).Event.generateEventId()and theEvent.Builder.build()timestamp default now delegate toUuidProvider.SYSTEM/TimeProvider.SYSTEM, so the platform interfaces are the single source for generated IDs and timestamps while theEventAPI stays unchanged.Testing Plan
Unit Tests:
New/updated tests:
platform/TimeProviderTest,platform/UuidProviderTest—SYSTEMdefaults + custom-provider behavior.InvocationContextTest— providers default toSYSTEM, are carried by the builder/toBuilder(), and drivenow()/newUuid().FunctionsTest— function-call ID derives from the injected provider.InMemorySessionServiceTest— injected providers produce a deterministic session ID andlastUpdateTime.RunnerTest.runAsync_withDeterministicProviders_producesIdenticalEvents— the headline guarantee: running the same input twice through the full flow yields byte-identical event IDs, timestamps, and invocation IDs.Local results (
./mvnw -pl core test, openjdk@17), all green:./mvnw -pl core fmt:check— 0 non-complying files.Manual End-to-End (E2E) Tests:
This is an in-process library seam with no runtime/config surface to exercise manually. The guarantee is verified by the unit test above, which asserts two independent runs of the same invocation produce identical IDs and timestamps.
Checklist
Additional context
Motivated by maintaining feature parity with
adk-pythonand the proposed changes toadk-go.