E57D feat: add add_events_to_memory facade for event-delta · google/adk-python@59e8897 · GitHub
[go: up one dir, main page]

Skip to content

Commit 59e8897

Browse files
GWealecopybara-github
authored andcommitted
feat: add add_events_to_memory facade for event-delta
Adds BaseMemoryService.add_events_to_memory(session, events=..., custom_metadata=...) and CallbackContext.add_events_to_memory(events=..., custom_metadata=...) so callers can add memories from an explicit subset of ADK events. Co-authored-by: George Weale <gweale@google.com> PiperOrigin-RevId: 868261578
1 parent de79bf1 commit 59e8897

File tree

7 files changed

+661
-14
lines changed

7 files changed

+661
-14
lines changed

src/google/adk/agents/callback_context.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
from __future__ import annotations
1616

17+
from collections.abc import Mapping
18+
from collections.abc import Sequence
1719
from typing import Any
1820
from typing import Optional
1921
from typing import TYPE_CHECKING
@@ -28,6 +30,7 @@
2830
from ..artifacts.base_artifact_service import ArtifactVersion
2931
from ..auth.auth_credential import AuthCredential
3032
from ..auth.auth_tool import AuthConfig
33+
from ..events.event import Event
3134
from ..events.event_actions import EventActions
3235
from ..sessions.state import State
3336
from .invocation_context import InvocationContext
@@ -219,3 +222,32 @@ async def my_after_agent_callback(callback_context: CallbackContext):
219222
await self._invocation_context.memory_service.add_session_to_memory(
220223
self._invocation_context.session
221224
)
225+
226+
async def add_events_to_memory(
227+
self,
228+
*,
229+
events: Sequence[Event],
230+
custom_metadata: Mapping[str, object] | None = None,
231+
) -> None:
232+
"""Adds an explicit list of events to the memory service.
233+
234+
Uses this callback's current session identifiers as memory scope.
235+
236+
Args:
237+
events: Explicit events to add to memory.
238+
custom_metadata: Optional standard metadata for memory generation.
239+
240+
Raises:
241+
ValueError: If memory service is not available.
242+
"""
243+
if self._invocation_context.memory_service is None:
244+
raise ValueError(
245+
"Cannot add events to memory: memory service is not available."
246+
)
247+
await self._invocation_context.memory_service.add_events_to_memory(
248+
app_name=self._invocation_context.session.app_name,
249+
user_id=self._invocation_context.session.user_id,
250+
session_id=self._invocation_context.session.id,
251+
events=events,
252+
custom_metadata=custom_metadata,
253+
)

src/google/adk/memory/base_memory_service.py

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
from abc import ABC
1919
from abc import abstractmethod
20+
from collections.abc import Mapping
21+
from collections.abc import Sequence
2022
from typing import TYPE_CHECKING
2123

2224
from pydantic import BaseModel
@@ -25,6 +27,7 @@
2527
from .memory_entry import MemoryEntry
2628

2729
if TYPE_CHECKING:
30+
from ..events.event import Event
2831
from ..sessions.session import Session
2932

3033

@@ -41,15 +44,15 @@ class SearchMemoryResponse(BaseModel):
4144
class BaseMemoryService(ABC):
4245
"""Base class for memory services.
4346
44-
The service provides functionalities to ingest sessions into memory so that
45-
the memory can be used for user queries.
47+
The service provides functionality to ingest conversation history into memory
48+
so that it can be used for user queries.
4649
"""
4750

4851
@abstractmethod
4952
async def add_session_to_memory(
5053
self,
5154
session: Session,
52-
):
55+
) -> None:
5356
"""Adds a session to the memory service.
5457
5558
A session may be added multiple times during its lifetime.
@@ -58,6 +61,38 @@ async def add_session_to_memory(
5861
session: The session to add.
5962
"""
6063

64+
async def add_events_to_memory(
65+
self,
66+
*,
67+
app_name: str,
68+
user_id: str,
69+
events: Sequence[Event],
70+
session_id: str | None = None,
71+
custom_metadata: Mapping[str, object] | None = None,
72+
) -> None:
73+
"""Adds an explicit list of events to the memory service.
74+
75+
This is intended for cases where callers want to persist only a subset of
76+
events (e.g., the latest turn), rather than re-ingesting the full session.
77+
78+
Implementations should treat `events` as an incremental update (delta) and
79+
must not assume it represents the full session.
80+
Implementations may ignore `session_id` if it is not applicable.
81+
82+
Args:
83+
app_name: The application name for memory scope.
84+
user_id: The user ID for memory scope.
85+
events: The events to add to memory.
86+
session_id: Optional session ID for memory scope/partitioning.
87+
custom_metadata: Optional, portable metadata for memory generation. Prefer
88+
this for service-specific fields (e.g., TTL) that may later become
89+
first-class API parameters.
90+
"""
91+
raise NotImplementedError(
92+
"This memory service does not support adding event deltas. "
93+
"Call add_session_to_memory(session) to ingest the full session."
94+
)
95+
6196
@abstractmethod
6297
async def search_memory(
6398
self,

src/google/adk/memory/in_memory_memory_service.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
# limitations under the License.
1414
from __future__ import annotations
1515

16+
from collections.abc import Mapping
17+
from collections.abc import Sequence
1618
import re
1719
import threading
1820
from typing import TYPE_CHECKING
@@ -28,8 +30,10 @@
2830
from ..events.event import Event
2931
from ..sessions.session import Session
3032

33+
_UNKNOWN_SESSION_ID = '__unknown_session_id__'
3134

32-
def _user_key(app_name: str, user_id: str):
35+
36+
def _user_key(app_name: str, user_id: str) -> str:
3337
return f'{app_name}/{user_id}'
3438

3539

@@ -56,7 +60,7 @@ def __init__(self):
5660
"""
5761

5862
@override
59-
async def add_session_to_memory(self, session: Session):< 802E /div>
63+
async def add_session_to_memory(self, session: Session) -> None:
6064
user_key = _user_key(session.app_name, session.user_id)
6165

6266
with self._lock:
@@ -67,6 +71,35 @@ async def add_session_to_memory(self, session: Session):
6771
if event.content and event.content.parts
6872
]
6973

74+
@override
75+
async def add_events_to_memory(
76+
self,
77+
*,
78+
app_name: str,
79+
user_id: str,
80+
events: Sequence[Event],
81+
session_id: str | None = None,
82+
custom_metadata: Mapping[str, object] | None = None,
83+
) -> None:
84+
_ = custom_metadata
85+
user_key = _user_key(app_name, user_id)
86+
scoped_session_id = session_id or _UNKNOWN_SESSION_ID
87+
events_to_add = [
88+
event for event in events if event.content and event.content.parts
89+
]
90+
91+
with self._lock:
92+
self._session_events[user_key] = self._session_events.get(user_key, {})
93+
existing_events = self._session_events[user_key].get(
94+
scoped_session_id, []
95+
)
96+
existing_ids = {event.id for event in existing_events}
97+
for event in events_to_add:
98+
if event.id not in existing_ids:
99+
existing_events.append(event)
100+
existing_ids.add(event.id)
101+
self._session_events[user_key][scoped_session_id] = existing_events
102+
70103
@override
71104
async def search_memory(
72105
self, *, app_name: str, user_id: str, query: str

0 commit comments

Comments
 (0)
0