upstream) {
+ return upstream.lift(observer -> TracingObserver.wrap(context, observer));
+ }
+
+ @Override
+ public CompletableSource apply(Completable upstream) {
+ return upstream.lift(observer -> TracingObserver.wrap(context, observer));
+ }
+ }
+
+ /**
+ * An observer that wraps another observer and ensures that the OpenTelemetry context is active
+ * during all callback methods.
+ *
+ * This implementation only wraps the data-flow callbacks (`onNext`, `onSuccess`, etc.). The
+ * `Subscription.request/cancel` and `Disposable.dispose` calls are not wrapped in the context. If
+ * the upstream logic depends on the context during these signals, they might lose trace
+ * information. Given this is a manual `withContext` utility, this might be an acceptable
+ * trade-off for simplicity/performance, but worth keeping in mind.
+ *
+ * @param The type of the items emitted by the stream.
+ */
+ private static final class TracingObserver
+ implements Subscriber, SingleObserver, MaybeObserver, CompletableObserver {
+ private final Context context;
+ private final Subscriber super T> subscriber;
+ private final SingleObserver super T> singleObserver;
+ private final MaybeObserver super T> maybeObserver;
+ private final CompletableObserver completableObserver;
+
+ private TracingObserver(
+ Context context,
+ Subscriber super T> subscriber,
+ SingleObserver super T> singleObserver,
+ MaybeObserver super T> maybeObserver,
+ CompletableObserver completableObserver) {
+ this.context = context;
+ this.subscriber = subscriber;
+ this.singleObserver = singleObserver;
+ this.maybeObserver = maybeObserver;
+ this.completableObserver = completableObserver;
+ }
+
+ static TracingObserver wrap(Context context, Subscriber super T> subscriber) {
+ return new TracingObserver<>(context, subscriber, null, null, null);
+ }
+
+ static TracingObserver wrap(Context context, SingleObserver super T> observer) {
+ return new TracingObserver<>(context, null, observer, null, null);
+ }
+
+ static TracingObserver wrap(Context context, MaybeObserver super T> observer) {
+ return new TracingObserver<>(context, null, null, observer, null);
+ }
+
+ static TracingObserver wrap(Context context, CompletableObserver observer) {
+ return new TracingObserver<>(context, null, null, null, observer);
+ }
+
+ private void runInContext(Runnable action) {
+ try (Scope scope = context.makeCurrent()) {
+ action.run();
+ }
+ }
+
+ @Override
+ public void onSubscribe(Subscription s) {
+ runInContext(
+ () -> {
+ if (subscriber != null) {
+ subscriber.onSubscribe(s);
+ }
+ });
+ }
+
+ @Override
+ public void onSubscribe(Disposable d) {
+ runInContext(
+ () -> {
+ if (singleObserver != null) {
+ singleObserver.onSubscribe(d);
+ } else if (maybeObserver != null) {
+ maybeObserver.onSubscribe(d);
+ } else if (completableObserver != null) {
+ completableObserver.onSubscribe(d);
+ }
+ });
+ }
+
+ @Override
+ public void onNext(T t) {
+ runInContext(
+ () -> {
+ if (subscriber != null) {
+ subscriber.onNext(t);
+ }
+ });
+ }
+
+ @Override
+ public void onSuccess(T t) {
+ runInContext(
+ () -> {
+ if (singleObserver != null) {
+ singleObserver.onSuccess(t);
+ } else if (maybeObserver != null) {
+ maybeObserver.onSuccess(t);
+ }
+ });
+ }
+
+ @Override
+ public void onError(Throwable t) {
+ runInContext(
+ () -> {
+ if (subscriber != null) {
+ subscriber.onError(t);
+ } else if (singleObserver != null) {
+ singleObserver.onError(t);
+ } else if (maybeObserver != null) {
+ maybeObserver.onError(t);
+ } else if (completableObserver != null) {
+ completableObserver.onError(t);
+ }
+ });
+ }
+
+ @Override
+ public void onComplete() {
+ runInContext(
+ () -> {
+ if (subscriber != null) {
+ subscriber.onComplete();
+ } else if (maybeObserver != null) {
+ maybeObserver.onComplete();
+ } else if (completableObserver != null) {
+ completableObserver.onComplete();
+ }
+ });
+ }
+ }
}
diff --git a/core/src/main/java/com/google/adk/utils/InstructionUtils.java b/core/src/main/java/com/google/adk/utils/InstructionUtils.java
index ea118b362..ff2a7b8bd 100644
--- a/core/src/main/java/com/google/adk/utils/InstructionUtils.java
+++ b/core/src/main/java/com/google/adk/utils/InstructionUtils.java
@@ -25,7 +25,6 @@
import io.reactivex.rxjava3.core.Single;
import java.util.ArrayList;
import java.util.List;
-import java.util.Optional;
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -167,12 +166,7 @@ private static Single resolveMatchAsync(InvocationContext context, Match
Maybe artifactMaybe =
context
.artifactService()
- .loadArtifact(
- session.appName(),
- session.userId(),
- session.id(),
- artifactName,
- Optional.empty());
+ .loadArtifact(session.appName(), session.userId(), session.id(), artifactName);
return artifactMaybe
.map(Part::toJson)
diff --git a/core/src/test/java/com/google/adk/artifacts/GcsArtifactServiceTest.java b/core/src/test/java/com/google/adk/artifacts/GcsArtifactServiceTest.java
index 88abd60c4..3b3c8c402 100644
--- a/core/src/test/java/com/google/adk/artifacts/GcsArtifactServiceTest.java
+++ b/core/src/test/java/com/google/adk/artifacts/GcsArtifactServiceTest.java
@@ -158,7 +158,7 @@ public void load_latestVersion_loadsCorrectly() {
when(mockStorage.get(blobIdV1)).thenReturn(blobV1);
Optional loadedArtifact =
- asOptional(service.loadArtifact(APP_NAME, USER_ID, SESSION_ID, FILENAME, Optional.empty()));
+ asOptional(service.loadArtifact(APP_NAME, USER_ID, SESSION_ID, FILENAME));
assertThat(loadedArtifact).isPresent();
Optional actualDataOptional = loadedArtifact.get().inlineData().get().data();
@@ -177,7 +177,7 @@ public void load_specificVersion_loadsCorrectly() {
when(mockStorage.get(blobIdV0)).thenReturn(blobV0);
Optional loadedArtifact =
- asOptional(service.loadArtifact(APP_NAME, USER_ID, SESSION_ID, FILENAME, Optional.of(0)));
+ asOptional(service.loadArtifact(APP_NAME, USER_ID, SESSION_ID, FILENAME, 0));
assertThat(loadedArtifact).isPresent();
Optional actualDataOptional = loadedArtifact.get().inlineData().get().data();
@@ -197,8 +197,7 @@ public void load_userNamespace_loadsCorrectly() {
when(mockStorage.get(blobIdV0)).thenReturn(blobV0);
Optional loadedArtifact =
- asOptional(
- service.loadArtifact(APP_NAME, USER_ID, SESSION_ID, USER_FILENAME, Optional.empty()));
+ asOptional(service.loadArtifact(APP_NAME, USER_ID, SESSION_ID, USER_FILENAME));
assertThat(loadedArtifact).isPresent();
Optional actualDataOptional = loadedArtifact.get().inlineData().get().data();
@@ -216,7 +215,7 @@ public void load_versionNotFound_returnsEmpty() {
when(mockStorage.get(blobIdV0)).thenReturn(null);
Optional loadedArtifact =
- asOptional(service.loadArtifact(APP_NAME, USER_ID, SESSION_ID, FILENAME, Optional.of(0)));
+ asOptional(service.loadArtifact(APP_NAME, USER_ID, SESSION_ID, FILENAME, 0));
assertThat(loadedArtifact).isEmpty();
verify(mockStorage).get(blobIdV0);
@@ -227,7 +226,7 @@ public void load_noVersionsExist_returnsEmpty() {
when(mockBlobPage.iterateAll()).thenReturn(ImmutableList.of());
Optional loadedArtifact =
- asOptional(service.loadArtifact(APP_NAME, USER_ID, SESSION_ID, FILENAME, Optional.empty()));
+ asOptional(service.loadArtifact(APP_NAME, USER_ID, SESSION_ID, FILENAME));
assertThat(loadedArtifact).isEmpty();
}
@@ -400,7 +399,7 @@ public void load_storageException_returnsEmpty() {
when(mockStorage.get(blobIdV0)).thenThrow(new StorageException(500, "Induced error"));
Optional loadedArtifact =
- asOptional(service.loadArtifact(APP_NAME, USER_ID, SESSION_ID, FILENAME, Optional.of(0)));
+ asOptional(service.loadArtifact(APP_NAME, USER_ID, SESSION_ID, FILENAME, 0));
assertThat(loadedArtifact).isEmpty();
}
diff --git a/core/src/test/java/com/google/adk/artifacts/InMemoryArtifactServiceTest.java b/core/src/test/java/com/google/adk/artifacts/InMemoryArtifactServiceTest.java
index 4cb493277..124a5e9d8 100644
--- a/core/src/test/java/com/google/adk/artifacts/InMemoryArtifactServiceTest.java
+++ b/core/src/test/java/com/google/adk/artifacts/InMemoryArtifactServiceTest.java
@@ -59,7 +59,7 @@ public void loadArtifact_loadsLatest() {
var unused2 =
service.saveArtifact(APP_NAME, USER_ID, SESSION_ID, FILENAME, artifact2).blockingGet();
Optional result =
- asOptional(service.loadArtifact(APP_NAME, USER_ID, SESSION_ID, FILENAME, Optional.empty()));
+ asOptional(service.loadArtifact(APP_NAME, USER_ID, SESSION_ID, FILENAME));
assertThat(result).hasValue(artifact2);
}
diff --git a/core/src/test/java/com/google/adk/flows/llmflows/CodeExecutionTest.java b/core/src/test/java/com/google/adk/flows/llmflows/CodeExecutionTest.java
index 353504dac..1485ca2c4 100644
--- a/core/src/test/java/com/google/adk/flows/llmflows/CodeExecutionTest.java
+++ b/core/src/test/java/com/google/adk/flows/llmflows/CodeExecutionTest.java
@@ -20,6 +20,7 @@
import static com.google.adk.testing.TestUtils.createTestAgentBuilder;
import static com.google.adk.testing.TestUtils.createTestLlm;
import static com.google.common.truth.Truth.assertThat;
+import static java.nio.charset.StandardCharsets.UTF_8;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.verify;
@@ -32,14 +33,19 @@
import com.google.adk.codeexecutors.CodeExecutionUtils.CodeExecutionInput;
import com.google.adk.codeexecutors.CodeExecutionUtils.CodeExecutionResult;
import com.google.adk.events.Event;
+import com.google.adk.flows.llmflows.RequestProcessor.RequestProcessingResult;
+import com.google.adk.models.LlmRequest;
import com.google.adk.models.LlmResponse;
import com.google.adk.sessions.InMemorySessionService;
import com.google.adk.sessions.Session;
import com.google.adk.testing.TestLlm;
import com.google.common.collect.ImmutableList;
+import com.google.genai.types.Blob;
import com.google.genai.types.Content;
import com.google.genai.types.Part;
import io.reactivex.rxjava3.core.Single;
+import io.reactivex.rxjava3.observers.TestObserver;
+import java.util.ArrayList;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -115,4 +121,38 @@ public void testResponseProcessor_withCode_executesCode() {
assertThat(executionResultPart.codeExecutionResult().get().output())
.hasValue("Code execution result:\nhello\n\n");
}
+
+ @Test
+ public void testRequestProcessor_withCode_hasNoErrors() throws Exception {
+ // arrange
+ LlmRequest.Builder llmReqBuilder = LlmRequest.builder();
+ when(mockCodeExecutor.codeBlockDelimiters())
+ .thenReturn(ImmutableList.of(ImmutableList.of("```tool_code", "\n```")));
+ when(mockCodeExecutor.optimizeDataFile()).thenReturn(true);
+ when(mockCodeExecutor.errorRetryAttempts()).thenReturn(2);
+ CodeExecutionResult executionResult = CodeExecutionResult.builder().stdout("hello\n").build();
+ when(mockCodeExecutor.executeCode(any(), any())).thenReturn(executionResult);
+ llmReqBuilder.contents(
+ new ArrayList<>(
+ ImmutableList.of(
+ Content.builder()
+ .role("user")
+ .parts(
+ ImmutableList.of(
+ Part.builder()
+ .inlineData(
+ Blob.builder()
+ .mimeType("text/csv")
+ .data("1,2,3\n".getBytes(UTF_8)))
+ .build()))
+ .build())));
+
+ // act
+ Single result =
+ CodeExecution.requestProcessor.processRequest(invocationContext, llmReqBuilder.build());
+ TestObserver testObserver = result.test();
+
+ // assert
+ testObserver.assertNoErrors();
+ }
}
diff --git a/core/src/test/java/com/google/adk/flows/llmflows/InstructionsTest.java b/core/src/test/java/com/google/adk/flows/llmflows/InstructionsTest.java
index 2ac9e454d..90f710856 100644
--- a/core/src/test/java/com/google/adk/flows/llmflows/InstructionsTest.java
+++ b/core/src/test/java/com/google/adk/flows/llmflows/InstructionsTest.java
@@ -32,7 +32,6 @@
import com.google.genai.types.Part;
import io.reactivex.rxjava3.core.Maybe;
import io.reactivex.rxjava3.core.Single;
-import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import org.junit.Before;
import org.junit.Rule;
@@ -122,11 +121,7 @@ public void processRequest_agentInstructionString_noPlaceholders_appendsInstruct
Session session = createSession();
Part artifactPart = Part.fromText("Artifact content");
when(mockArtifactService.loadArtifact(
- eq(session.appName()),
- eq(session.userId()),
- eq(session.id()),
- eq("file.txt"),
- eq(Optional.empty())))
+ eq(session.appName()), eq(session.userId()), eq(session.id()), eq("file.txt")))
.thenReturn(Maybe.just(artifactPart));
LlmAgent agent =
LlmAgent.builder().name("agent").instruction("File content: {artifact.file.txt}").build();
diff --git a/core/src/test/java/com/google/adk/telemetry/ContextPropagationTest.java b/core/src/test/java/com/google/adk/telemetry/ContextPropagationTest.java
index f809193cf..e5795d61f 100644
--- a/core/src/test/java/com/google/adk/telemetry/ContextPropagationTest.java
+++ b/core/src/test/java/com/google/adk/telemetry/ContextPropagationTest.java
@@ -31,6 +31,7 @@
import com.google.adk.runner.Runner;
import com.google.adk.sessions.InMemorySessionService;
import com.google.adk.sessions.Session;
+import com.google.adk.sessions.SessionKey;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.genai.types.Content;
@@ -44,12 +45,17 @@
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Context;
+import io.opentelemetry.context.ContextKey;
import io.opentelemetry.context.Scope;
import io.opentelemetry.sdk.testing.junit4.OpenTelemetryRule;
import io.opentelemetry.sdk.trace.data.SpanData;
+import io.reactivex.rxjava3.core.Completable;
import io.reactivex.rxjava3.core.Flowable;
+import io.reactivex.rxjava3.core.Maybe;
+import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.schedulers.Schedulers;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import org.junit.After;
import org.junit.Before;
@@ -380,6 +386,70 @@ public void testTraceFlowable() throws InterruptedException {
assertTrue(flowableSpanData.hasEnded());
}
+ @Test
+ public void testWithContextFlowable() throws InterruptedException {
+ ContextKey testKey = ContextKey.named("test-key");
+ Context testContext = Context.root().with(testKey, "test-value");
+
+ Flowable flowable =
+ Flowable.just(1, 2, 3)
+ .compose(Tracing.withContext(testContext))
+ .subscribeOn(Schedulers.computation())
+ .doOnNext(
+ i -> {
+ assertEquals("test-value", Context.current().get(testKey));
+ });
+ flowable.test().await().assertComplete();
+ }
+
+ @Test
+ public void testWithContextSingle() throws InterruptedException {
+ ContextKey testKey = ContextKey.named("test-key");
+ Context testContext = Context.root().with(testKey, "test-value");
+
+ Single single =
+ Single.just(1)
+ .compose(Tracing.withContext(testContext))
+ .subscribeOn(Schedulers.computation())
+ .doOnSuccess(
+ i -> {
+ assertEquals("test-value", Context.current().get(testKey));
+ });
+ single.test().await().assertComplete();
+ }
+
+ @Test
+ public void testWithContextMaybe() throws InterruptedException {
+ ContextKey testKey = ContextKey.named("test-key");
+ Context testContext = Context.root().with(testKey, "test-value");
+
+ Maybe maybe =
+ Maybe.just(1)
+ .compose(Tracing.withContext(testContext))
+ .subscribeOn(Schedulers.computation())
+ .doOnSuccess(
+ i -> {
+ assertEquals("test-value", Context.current().get(testKey));
+ });
+ maybe.test().await().assertComplete();
+ }
+
+ @Test
+ public void testWithContextCompletable() throws InterruptedException {
+ ContextKey testKey = ContextKey.named("test-key");
+ Context testContext = Context.root().with(testKey, "test-value");
+
+ Completable completable =
+ Completable.complete()
+ .compose(Tracing.withContext(testContext))
+ .subscribeOn(Schedulers.computation())
+ .doOnComplete(
+ () -> {
+ assertEquals("test-value", Context.current().get(testKey));
+ });
+ completable.test().await().assertComplete();
+ }
+
@Test
public void testTraceTransformer() throws InterruptedException {
Span parentSpan = tracer.spanBuilder("parent").startSpan();
@@ -595,7 +665,7 @@ public void runnerRunAsync_propagatesContext() throws InterruptedException {
Session session =
runner
.sessionService()
- .createSession("test-app", "test-user", null, "test-session")
+ .createSession(new SessionKey("test-app", "test-user", "test-session"))
.blockingGet();
Content newMessage = Content.fromParts(Part.fromText("hi"));
RunConfig runConfig = RunConfig.builder().build();
@@ -623,13 +693,20 @@ public void runnerRunLive_propagatesContext() throws InterruptedException {
Span parentSpan = tracer.spanBuilder("parent").startSpan();
try (Scope s = parentSpan.makeCurrent()) {
Session session =
- Session.builder("test-session").userId("test-user").appName("test-app").build();
+ runner
+ .sessionService()
+ .createSession("test-app", "test-user", (Map) null, "test-session")
+ .blockingGet();
Content newMessage = Content.fromParts(Part.fromText("hi"));
RunConfig runConfig = RunConfig.builder().build();
LiveRequestQueue liveRequestQueue = new LiveRequestQueue();
liveRequestQueue.content(newMessage);
liveRequestQueue.close();
- runner.runLive(session, liveRequestQueue, runConfig).test().await().assertComplete();
+ runner
+ .runLive(session.userId(), session.id(), liveRequestQueue, runConfig)
+ .test()
+ .await()
+ .assertComplete();
} finally {
parentSpan.end();
}
diff --git a/core/src/test/java/com/google/adk/tools/LoadArtifactsToolTest.java b/core/src/test/java/com/google/adk/tools/LoadArtifactsToolTest.java
index 5ed7a1f40..8405cfc42 100644
--- a/core/src/test/java/com/google/adk/tools/LoadArtifactsToolTest.java
+++ b/core/src/test/java/com/google/adk/tools/LoadArtifactsToolTest.java
@@ -1,7 +1,7 @@
package com.google.adk.tools;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.mock;
@@ -105,7 +105,7 @@ public void processLlmRequest_noArtifactsInContext_completesWithoutLoading() {
assertThat(finalRequest.config()).isPresent();
assertThat(finalRequest.config().get().systemInstruction()).isEmpty();
verify(mockArtifactService, never())
- .loadArtifact(anyString(), anyString(), anyString(), anyString(), any());
+ .loadArtifact(anyString(), anyString(), anyString(), anyString(), anyInt());
}
@Test
@@ -130,7 +130,7 @@ public void processLlmRequest_artifactsInContext_noFunctionCall_appendsInstructi
assertThat(appendedInstruction).contains("call the `load_artifacts` function");
verify(mockArtifactService, never())
- .loadArtifact(anyString(), anyString(), anyString(), anyString(), any());
+ .loadArtifact(anyString(), anyString(), anyString(), anyString(), anyInt());
}
@Test
@@ -215,7 +215,7 @@ public void processLlmRequest_artifactsInContext_withOtherFunctionCall_doesNotLo
.contains("You have a list of artifacts:");
verify(mockArtifactService, never())
- .loadArtifact(anyString(), anyString(), anyString(), anyString(), any());
+ .loadArtifact(anyString(), anyString(), anyString(), anyString(), anyInt());
assertThat(finalRequest.contents()).containsExactly(functionCallContent);
}
}
diff --git a/dev/pom.xml b/dev/pom.xml
index 57aa808c2..6cabcba7c 100644
--- a/dev/pom.xml
+++ b/dev/pom.xml
@@ -18,7 +18,7 @@
com.google.adk
google-adk-parent
- 0.8.1-SNAPSHOT
+ 0.9.1-SNAPSHOT
google-adk-dev
diff --git a/dev/src/main/java/com/google/adk/plugins/ReplayPlugin.java b/dev/src/main/java/com/google/adk/plugins/ReplayPlugin.java
index 5571b8d57..89032082c 100644
--- a/dev/src/main/java/com/google/adk/plugins/ReplayPlugin.java
+++ b/dev/src/main/java/com/google/adk/plugins/ReplayPlugin.java
@@ -90,7 +90,11 @@ public Maybe beforeModelCallback(
logger.debug("Verified and replaying LLM response for agent {}", agentName);
// Return the recorded response
- return recording.llmResponse().map(Maybe::just).orElse(Maybe.empty());
+ return recording
+ .llmResponses()
+ .filter(responses -> !responses.isEmpty())
+ .map(responses -> Maybe.just(responses.get(0)))
+ .orElse(Maybe.empty());
}
@Override
diff --git a/dev/src/main/java/com/google/adk/plugins/recordings/LlmRecording.java b/dev/src/main/java/com/google/adk/plugins/recordings/LlmRecording.java
index fe17aac0d..701b1e7ae 100644
--- a/dev/src/main/java/com/google/adk/plugins/recordings/LlmRecording.java
+++ b/dev/src/main/java/com/google/adk/plugins/recordings/LlmRecording.java
@@ -20,6 +20,7 @@
import com.google.adk.models.LlmRequest;
import com.google.adk.models.LlmResponse;
import com.google.auto.value.AutoValue;
+import java.util.List;
import java.util.Optional;
import javax.annotation.Nullable;
@@ -31,8 +32,8 @@ public abstract class LlmRecording {
/** The LLM request. */
public abstract Optional llmRequest();
- /** The LLM response. */
- public abstract Optional llmResponse();
+ /** The LLM responses. */
+ public abstract Optional> llmResponses();
public static Builder builder() {
return new AutoValue_LlmRecording.Builder();
@@ -44,7 +45,7 @@ public static Builder builder() {
public abstract static class Builder {
public abstract Builder llmRequest(@Nullable LlmRequest llmRequest);
- public abstract Builder llmResponse(@Nullable LlmResponse llmResponse);
+ public abstract Builder llmResponses(@Nullable List llmResponses);
public abstract LlmRecording build();
}
diff --git a/dev/src/main/java/com/google/adk/web/controller/ArtifactController.java b/dev/src/main/java/com/google/adk/web/controller/ArtifactController.java
index 27164f216..c181ab558 100644
--- a/dev/src/main/java/com/google/adk/web/controller/ArtifactController.java
+++ b/dev/src/main/java/com/google/adk/web/controller/ArtifactController.java
@@ -24,7 +24,6 @@
import io.reactivex.rxjava3.core.Single;
import java.util.Collections;
import java.util.List;
-import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -78,8 +77,7 @@ public Part loadArtifact(
versionStr);
Maybe artifactMaybe =
- artifactService.loadArtifact(
- appName, userId, sessionId, artifactName, Optional.ofNullable(version));
+ artifactService.loadArtifact(appName, userId, sessionId, artifactName, version);
Part artifact = artifactMaybe.blockingGet();
@@ -126,8 +124,7 @@ public Part loadArtifactVersion(
versionId);
Maybe artifactMaybe =
- artifactService.loadArtifact(
- appName, userId, sessionId, artifactName, Optional.of(versionId));
+ artifactService.loadArtifact(appName, userId, sessionId, artifactName, versionId);
Part artifact = artifactMaybe.blockingGet();
diff --git a/dev/src/main/java/com/google/adk/web/service/RunnerService.java b/dev/src/main/java/com/google/adk/web/service/RunnerService.java
index 7297af833..480c68472 100644
--- a/dev/src/main/java/com/google/adk/web/service/RunnerService.java
+++ b/dev/src/main/java/com/google/adk/web/service/RunnerService.java
@@ -78,13 +78,14 @@ public Runner getRunner(String appName) {
"RunnerService: Creating Runner for appName: {}, using agent definition: {}",
appName,
agent.name());
- return new Runner(
- agent,
- appName,
- this.artifactService,
- this.sessionService,
- this.memoryService,
- this.extraPlugins);
+ return Runner.builder()
+ .agent(agent)
+ .appName(appName)
+ .artifactService(this.artifactService)
+ .sessionService(this.sessionService)
+ .memoryService(this.memoryService)
+ .plugins(this.extraPlugins)
+ .build();
} catch (java.util.NoSuchElementException e) {
log.error(
"Agent/App named '{}' not found in registry. Available apps: {}",
diff --git a/dev/src/test/java/com/google/adk/plugins/ReplayPluginTest.java b/dev/src/test/java/com/google/adk/plugins/ReplayPluginTest.java
index f29298bce..8e89c2567 100644
--- a/dev/src/test/java/com/google/adk/plugins/ReplayPluginTest.java
+++ b/dev/src/test/java/com/google/adk/plugins/ReplayPluginTest.java
@@ -83,11 +83,11 @@ void beforeModelCallback_withMatchingRecording_returnsRecordedResponse() throws
- role: "user"
parts:
- text: "Hello"
- llm_response:
- content:
- role: "model"
- parts:
- - text: "Recorded response"
+ llm_responses:
+ - content:
+ role: "model"
+ parts:
+ - text: "Recorded response"
""");
// Step 1: Setup replay config
diff --git a/dev/src/test/java/com/google/adk/plugins/recordings/RecordingsLoaderTest.java b/dev/src/test/java/com/google/adk/plugins/recordings/RecordingsLoaderTest.java
index 92d12bc6d..ee115644c 100644
--- a/dev/src/test/java/com/google/adk/plugins/recordings/RecordingsLoaderTest.java
+++ b/dev/src/test/java/com/google/adk/plugins/recordings/RecordingsLoaderTest.java
@@ -58,16 +58,16 @@ void testLoadCRecording() throws Exception {
- function_declarations:
- name: validate_email
description: Validates email format
- llm_response:
- content:
- parts:
- - thought_signature: Cq0EAR_MhbYyfIgI1M5KlVyG9HzjQ_CvZiHb_RQ2KR0H_UkDj-LDdxdVayqSpG8F6wPq4aGB6lZlqjZIGvA5H2zX2RQ_Iu8Wb8t_wKoEpW4XcwzzU9Org_ZvTNx4TZHll5cH5ebo1LPRWfTqVn7cC1N5KwDZtS2XLwCmitucAAKGzGH4c-tM0dgj57NoMFa63iaHizzi2zupKoGPBB-ZmakNHAHRspkl85hKaq8m4fELHNNMnyi596jcGRHxTDBiqHmNG8PyRiOXRM9VOkNnPU8l2DN7b6CvaBPmH84t0MaHxFMmrMjTQaNTBw92lXT7LZfwYJrDxf1ZpVHjztpbIhfZyYyZmxhIDNcVlb5i4Xoe8Rcva51NgBJN-UAm9cXWBSvr2_EdQbWs7Tz57niquyLpD6fhnTPOWBN6PU2Nz5nMgq-SUyM7srg2Ta6OV9uwOYFAFl0klSBouZ44YTM-T-voCin7EobkTzzXcllDPJ5TPretD_mpkeATlJ3Gi3nPfFLuU2DqFb8fLZjovY5oseSkEvf6NYnGt26r290QzG0cFsZbpJdtysBL-lH-yOwKEl-26IjiWztk0wAxnIdrmILlD9hgXRuyudXI0hx4gH1KTIH7njNNyLMNevUYVGC4cGxa1IpCh4EevhfCT9PQYM-QPyRT4dRBNzoG_y_lZERctUNHAfp80ObBClHEvDjElC2H6kWlO_jBeDiyJpezO7OeYjmDipvKFk3rQgNP87A=
- function_call:
- name: validate_email
- args:
- email: test@example.com
- role: model
- finish_reason: STOP
+ llm_responses:
+ - content:
+ parts:
+ - thought_signature: Cq0EAR_MhbYyfIgI1M5KlVyG9HzjQ_CvZiHb_RQ2KR0H_UkDj-LDdxdVayqSpG8F6wPq4aGB6lZlqjZIGvA5H2zX2RQ_Iu8Wb8t_wKoEpW4XcwzzU9Org_ZvTNx4TZHll5cH5ebo1LPRWfTqVn7cC1N5KwDZtS2XLwCmitucAAKGzGH4c-tM0dgj57NoMFa63iaHizzi2zupKoGPBB-ZmakNHAHRspkl85hKaq8m4fELHNNMnyi596jcGRHxTDBiqHmNG8PyRiOXRM9VOkNnPU8l2DN7b6CvaBPmH84t0MaHxFMmrMjTQaNTBw92lXT7LZfwYJrDxf1ZpVHjztpbIhfZyYyZmxhIDNcVlb5i4Xoe8Rcva51NgBJN-UAm9cXWBSvr2_EdQbWs7Tz57niquyLpD6fhnTPOWBN6PU2Nz5nMgq-SUyM7srg2Ta6OV9uwOYFAFl0klSBouZ44YTM-T-voCin7EobkTzzXcllDPJ5TPretD_mpkeATlJ3Gi3nPfFLuU2DqFb8fLZjovY5oseSkEvf6NYnGt26r290QzG0cFsZbpJdtysBL-lH-yOwKEl-26IjiWztk0wAxnIdrmILlD9hgXRuyudXI0hx4gH1KTIH7njNNyLMNevUYVGC4cGxa1IpCh4EevhfCT9PQYM-QPyRT4dRBNzoG_y_lZERctUNHAfp80ObBClHEvDjElC2H6kWlO_jBeDiyJpezO7OeYjmDipvKFk3rQgNP87A=
+ function_call:
+ name: validate_email
+ args:
+ email: test@example.com
+ role: model
+ finish_reason: STOP
- user_message_index: 0
agent_name: booking_assistant
tool_recording:
@@ -108,7 +108,8 @@ void testLoadCRecording() throws Exception {
assertThat(systemInstructionText.get()).contains("booking assistant");
// Verify URL-safe Base64 deserialization (thought_signature with '_' and '-' characters)
- var responseContent = firstRecording.llmRecording().get().llmResponse().get().content().get();
+ var responseContent =
+ firstRecording.llmRecording().get().llmResponses().get().get(0).content().get();
var thoughtSignature = getOnlyPart(responseContent).thoughtSignature();
assertThat(thoughtSignature).isPresent();
assertThat(thoughtSignature.get()).isNotEmpty();
diff --git a/maven_plugin/examples/custom_tools/pom.xml b/maven_plugin/examples/custom_tools/pom.xml
index abd3c60f2..f2118f9cc 100644
--- a/maven_plugin/examples/custom_tools/pom.xml
+++ b/maven_plugin/examples/custom_tools/pom.xml
@@ -4,7 +4,7 @@
com.example
custom-tools-example
- 0.8.1-SNAPSHOT
+ 0.9.1-SNAPSHOT
jar
ADK Custom Tools Example
diff --git a/maven_plugin/examples/simple-agent/pom.xml b/maven_plugin/examples/simple-agent/pom.xml
index 309fe9364..5c0f4462d 100644
--- a/maven_plugin/examples/simple-agent/pom.xml
+++ b/maven_plugin/examples/simple-agent/pom.xml
@@ -4,7 +4,7 @@
com.example
simple-adk-agent
- 0.8.1-SNAPSHOT
+ 0.9.1-SNAPSHOT
jar
Simple ADK Agent Example
diff --git a/maven_plugin/pom.xml b/maven_plugin/pom.xml
index 6ff3404f3..c48331f72 100644
--- a/maven_plugin/pom.xml
+++ b/maven_plugin/pom.xml
@@ -5,7 +5,7 @@
com.google.adk
google-adk-parent
- 0.8.1-SNAPSHOT
+ 0.9.1-SNAPSHOT
../pom.xml
diff --git a/pom.xml b/pom.xml
index ffe904d74..11696db73 100644
--- a/pom.xml
+++ b/pom.xml
@@ -17,7 +17,7 @@
com.google.adk
google-adk-parent
- 0.8.1-SNAPSHOT
+ 0.9.1-SNAPSHOT
pom
Google Agent Development Kit Maven Parent POM
diff --git a/tutorials/city-time-weather/pom.xml b/tutorials/city-time-weather/pom.xml
index f4e8bdb52..76b7331f3 100644
--- a/tutorials/city-time-weather/pom.xml
+++ b/tutorials/city-time-weather/pom.xml
@@ -20,7 +20,7 @@
com.google.adk
google-adk-parent
- 0.8.1-SNAPSHOT
+ 0.9.1-SNAPSHOT
../../pom.xml
diff --git a/tutorials/live-audio-single-agent/pom.xml b/tutorials/live-audio-single-agent/pom.xml
index b6e649222..a330cf4bd 100644
--- a/tutorials/live-audio-single-agent/pom.xml
+++ b/tutorials/live-audio-single-agent/pom.xml
@@ -20,7 +20,7 @@
com.google.adk
google-adk-parent
- 0.8.1-SNAPSHOT
+ 0.9.1-SNAPSHOT
../../pom.xml