Skip to content

Commit d1e05ca

Browse files
google-genai-botcopybara-github
authored andcommitted
fix: Ensure callbackContextData is preserved across session update
PiperOrigin-RevId: 889281595
1 parent 84dff10 commit d1e05ca

2 files changed

Lines changed: 44 additions & 18 deletions

File tree

core/src/main/java/com/google/adk/runner/Runner.java

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -477,13 +477,8 @@ protected Flowable<Event> runAsyncImpl(
477477
session.appName(), session.userId(), session.id(), Optional.empty())
478478
.flatMapPublisher(
479479
updatedSession ->
480-
runAgentWithFreshSession(
481-
session,
482-
updatedSession,
483-
event,
484-
invocationId,
485-
runConfig,
486-
rootAgent))
480+
runAgentWithUpdatedSession(
481+
initialContext, updatedSession, event, rootAgent))
487482
.compose(Tracing.<Event>withContext(capturedContext));
488483
});
489484
})
@@ -495,19 +490,27 @@ protected Flowable<Event> runAsyncImpl(
495490
});
496491
}
497492

498-
private Flowable<Event> runAgentWithFreshSession(
499-
Session session,
500-
Session updatedSession,
501-
Event event,
502-
String invocationId,
503-
RunConfig runConfig,
504-
BaseAgent rootAgent) {
493+
/**
494+
* Runs the agent with the updated session state.
495+
*
496+
* <p>This method is called after the user message has been persistent in the session. It creates
497+
* a final {@link InvocationContext} that inherits state from the {@code initialContext} but uses
498+
* the {@code updatedSession} to ensure the agent can access the latest conversation history.
499+
*
500+
* @param initialContext the context from the start of the invocation, used to preserve metadata
501+
* and callback data.
502+
* @param updatedSession the session object containing the latest message.
503+
* @param event the event representing the user message that was just appended.
504+
* @param rootAgent the agent to be executed.
505+
* @return a stream of events from the agent execution and subsequent plugin callbacks.
506+
*/
507+
private Flowable<Event> runAgentWithUpdatedSession(
508+
InvocationContext initialContext, Session updatedSession, Event event, BaseAgent rootAgent) {
505509
// Create context with updated session for beforeRunCallback
506510
InvocationContext contextWithUpdatedSession =
507-
newInvocationContextBuilder(updatedSession)
508-
.invocationId(invocationId)
511+
initialContext.toBuilder()
512+
.session(updatedSession)
509513
.agent(this.findAgentToRun(updatedSession, rootAgent))
510-
.runConfig(runConfig)
511514
.userContent(event.content().orElseGet(Content::fromParts))
512515
.build();
513516

@@ -536,7 +539,7 @@ private Flowable<Event> runAgentWithFreshSession(
536539
.flatMap(
537540
registeredEvent -> {
538541
// TODO: remove this hack after deprecating runAsync with Session.
539-
copySessionStates(updatedSession, session);
542+
copySessionStates(updatedSession, initialContext.session());
540543
return contextWithUpdatedSession
541544
.pluginManager()
542545
.onEventCallback(contextWithUpdatedSession, registeredEvent)

core/src/test/java/com/google/adk/runner/RunnerTest.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,29 @@ public void onEventCallback_success() {
591591
verify(plugin).onEventCallback(any(), any());
592592
}
593593

594+
@Test
595+
public void callbackContextData_preservedAcrossInvocation() {
596+
String testKey = "testKey";
597+
String testValue = "testValue";
598+
599+
when(plugin.onUserMessageCallback(any(), any()))
600+
.thenAnswer(
601+
invocation -> {
602+
InvocationContext context = invocation.getArgument(0);
603+
context.callbackContextData().put(testKey, testValue);
604+
return Maybe.empty();
605+
});
606+
607+
ArgumentCaptor<InvocationContext> contextCaptor =
608+
ArgumentCaptor.forClass(InvocationContext.class);
609+
when(plugin.afterRunCallback(contextCaptor.capture())).thenReturn(Completable.complete());
610+
611+
var unused =
612+
runner.runAsync("user", session.id(), createContent("test")).toList().blockingGet();
613+
614+
assertThat(contextCaptor.getValue().callbackContextData()).containsEntry(testKey, testValue);
615+
}
616+
594617
@Test
595618
public void runAsync_withSessionKey_success() {
596619
var events =

0 commit comments

Comments
 (0)