diff --git a/core/src/main/java/com/google/adk/sessions/InMemorySessionService.java b/core/src/main/java/com/google/adk/sessions/InMemorySessionService.java index b2a584b11..d9bb047a3 100644 --- a/core/src/main/java/com/google/adk/sessions/InMemorySessionService.java +++ b/core/src/main/java/com/google/adk/sessions/InMemorySessionService.java @@ -154,19 +154,13 @@ public Maybe getSession( if (config.numRecentEvents().isEmpty() && config.afterTimestamp().isPresent()) { Instant threshold = config.afterTimestamp().get(); - eventsInCopy.removeIf( - event -> getEventTimestampEpochSeconds(event) < threshold.getEpochSecond()); + eventsInCopy.removeIf(event -> getInstantFromEvent(event).isBefore(threshold)); } // Merge state into the potentially filtered copy and return return Maybe.just(mergeWithGlobalState(appName, userId, sessionCopy)); } - // Helper to get event timestamp as epoch seconds - private long getEventTimestampEpochSeconds(Event event) { - return event.timestamp() / 1000L; - } - @Override public Single listSessions(String appName, String userId) { Objects.requireNonNull(appName, "appName cannot be null"); @@ -294,10 +288,7 @@ public Single appendEvent(Session session, Event event) { /** Converts an event's timestamp to an Instant. Adapt based on actual Event structure. */ // TODO: have Event.timestamp() return Instant directly private Instant getInstantFromEvent(Event event) { - double epochSeconds = getEventTimestampEpochSeconds(event); - long seconds = (long) epochSeconds; - long nanos = (long) ((epochSeconds % 1.0) * 1_000_000_000L); - return Instant.ofEpochSecond(seconds, nanos); + return Instant.ofEpochMilli(event.timestamp()); } /** diff --git a/core/src/test/java/com/google/adk/sessions/InMemorySessionServiceTest.java b/core/src/test/java/com/google/adk/sessions/InMemorySessionServiceTest.java index 41e156ffd..0d9235b1b 100644 --- a/core/src/test/java/com/google/adk/sessions/InMemorySessionServiceTest.java +++ b/core/src/test/java/com/google/adk/sessions/InMemorySessionServiceTest.java @@ -20,6 +20,7 @@ import com.google.adk.events.Event; import com.google.adk.events.EventActions; import io.reactivex.rxjava3.core.Single; +import java.time.Instant; import java.util.HashMap; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; @@ -214,6 +215,24 @@ public void appendEvent_removesState() { assertThat(retrievedSessionRemove.state()).doesNotContainKey("temp:tempKey"); } + @Test + public void appendEvent_updatesSessionTimestampWithFractionalSeconds() { + InMemorySessionService sessionService = new InMemorySessionService(); + Session session = + sessionService.createSession("app", "user", new HashMap<>(), "session1").blockingGet(); + + // Add an event with a timestamp that contains a fractional second + Event eventAdd = Event.builder().timestamp(5500).build(); + var unused = sessionService.appendEvent(session, eventAdd).blockingGet(); + + // Verify the last modified timestamp contains a fractional second + Session retrievedSession = + sessionService + .getSession(session.appName(), session.userId(), session.id(), Optional.empty()) + .blockingGet(); + assertThat(retrievedSession.lastUpdateTime()).isEqualTo(Instant.ofEpochSecond(5, 500000000L)); + } + @Test public void sequentialAgents_shareTempState() { InMemorySessionService sessionService = new InMemorySessionService();