append_event is the method that persists events to the session storage (database, in-memory, etc.). It's called by the Runner class during agent execution to save events as they are generated.
User Request
↓
runner.run_async()
↓
_exec_with_plugin()
↓
Agent generates events
↓
append_event() ← Called for each non-partial event
↓
Event persisted to session storage
Location: src/google/adk/runners.py:656
This is the main entry point where events are appended during agent execution.
When:
- During normal agent execution flow
- For each non-partial event generated by the agent
- After early exit events from plugins
Code:
async for event in agen:
if not event.partial: # Only append complete events
if self._should_append_event(event, is_live_call):
await self.session_service.append_event(
session=session, event=event
)Called for:
- Model responses (text, function calls)
- Tool execution results
- Agent state changes
- Any complete event from the agent
Location: src/google/adk/runners.py:739
When:
- When a new user message is added to the session
- Called at the start of
run_async()to save the user's input
Code:
event = Event(
invocation_id=invocation_context.invocation_id,
author='user',
content=new_message,
)
await self.session_service.append_event(session=session, event=event)Location: src/google/adk/runners.py:494
When:
- When rewinding a session to a previous point
- Creates a rewind event that marks the rollback point
Code:
rewind_event = Event(
invocation_id=new_invocation_context_id(),
author='user',
actions=EventActions(rewind_before_invocation_id=...),
)
await self.session_service.append_event(session=session, event=rewind_event)Location: src/google/adk/runners.py:645
When:
- When a plugin's
before_runcallback returns early exit content - Allows plugins to short-circuit agent execution
Code:
if isinstance(early_exit_result, types.Content):
early_exit_event = Event(...)
if self._should_append_event(early_exit_event, is_live_call):
await self.session_service.append_event(
session=session, event=early_exit_event
)Location: src/google/adk/runners.py:601 (via compaction plugins)
When:
- After an invocation completes
- When compaction plugins merge/compress events
Code:
compaction_event = await compactor.maybe_compact_events(events=session.events)
if compaction_event:
await self.session_service.append_event(
session=session, event=compaction_event
)- Complete (non-partial) events from the agent
- User messages when they're added to the session
- Model responses (text, function calls)
- Tool execution results
- Rewind events when sessions are rolled back
- Compaction events after invocation completes
- Early exit events from plugins
-
Partial events (
event.partial == True)- These are streaming chunks that haven't completed yet
- Only the final complete event is appended
-
Live audio responses (in live mode)
- Filtered out by
_should_append_event() - Audio data is stored in artifacts instead
- Filtered out by
# 1. User sends request to /chat endpoint
POST /chat {"message": "Hi", "orderItemUUID": "..."}
# 2. Runner.run_async() is called
async for event in runner.run_async(
user_id=user_id,
session_id=session.id,
new_message=new_message,
):
# 3. Inside run_async():
# a. _append_new_message_to_session() is called
# → append_event() saves user message ✓
#
# b. Agent processes and generates events
# → _exec_with_plugin() processes each event
#
# c. For each non-partial event:
# → append_event() saves model response ✓
# → append_event() saves tool results ✓
# → append_event() saves state changes ✓
#
# 4. Event is yielded to client (SSE stream)
yield f'data: {event.model_dump_json()}\n\n'In PostgresSessionService (src/google/adk/sessions/postgres_session_service.py:197):
- Validates the event and session are not null
- Skips if event is partial
- Retrieves the session from database
- Adds the event to the session's events list
- Updates the session's
last_update_time - Saves the updated session back to PostgreSQL
- Calls parent class
append_event()for additional processing
append_eventis called by the Runner, not directly by your code- Only complete (non-partial) events are persisted
- Called automatically during agent execution flow
- Thread-safe - each request has its own session context
- Idempotent - can be called multiple times safely
- Who: The
Runnerclass callsappend_event - When:
- During agent execution (for each complete event)
- When user messages are added
- During session rewinds
- After compaction runs
- Where: Inside
Runner._exec_with_plugin()and related methods - Why: To persist the conversation history to the session storage