|
29 | 29 | logger = logging.getLogger('google_adk.' + __name__) |
30 | 30 |
|
31 | 31 |
|
| 32 | +def _is_event_in_branch(current_branch: Optional[str], event: Event) -> bool: |
| 33 | + """Return True if ``event`` belongs to ``current_branch`` (or the root).""" |
| 34 | + if not current_branch: |
| 35 | + # No branch means we're at the root; include all events without a branch. |
| 36 | + return not event.branch |
| 37 | + return event.branch == current_branch or not event.branch |
| 38 | + |
| 39 | + |
| 40 | +def _find_previous_interaction_id( |
| 41 | + events: list[Event], |
| 42 | + *, |
| 43 | + agent_name: str, |
| 44 | + current_branch: Optional[str], |
| 45 | +) -> Optional[str]: |
| 46 | + """Find the most recent interaction_id authored by ``agent_name``. |
| 47 | +
|
| 48 | + Scans ``events`` in reverse, skipping events outside ``current_branch``, and |
| 49 | + returns the first ``interaction_id`` from an event authored by this agent. |
| 50 | + """ |
| 51 | + logger.debug( |
| 52 | + 'Finding previous_interaction_id: agent=%s, branch=%s, num_events=%d', |
| 53 | + agent_name, |
| 54 | + current_branch, |
| 55 | + len(events), |
| 56 | + ) |
| 57 | + for event in reversed(events): |
| 58 | + if not _is_event_in_branch(current_branch, event): |
| 59 | + logger.debug( |
| 60 | + 'Skipping event not in branch: author=%s, branch=%s, current=%s', |
| 61 | + event.author, |
| 62 | + event.branch, |
| 63 | + current_branch, |
| 64 | + ) |
| 65 | + continue |
| 66 | + logger.debug( |
| 67 | + 'Checking event: author=%s, interaction_id=%s, branch=%s', |
| 68 | + event.author, |
| 69 | + event.interaction_id, |
| 70 | + event.branch, |
| 71 | + ) |
| 72 | + if event.author == agent_name and event.interaction_id: |
| 73 | + logger.debug( |
| 74 | + 'Found interaction_id from agent %s: %s', |
| 75 | + agent_name, |
| 76 | + event.interaction_id, |
| 77 | + ) |
| 78 | + return event.interaction_id |
| 79 | + return None |
| 80 | + |
| 81 | + |
32 | 82 | class InteractionsRequestProcessor(BaseLlmRequestProcessor): |
33 | 83 | """Request processor for Interactions API stateful conversations. |
34 | 84 | This processor extracts the previous_interaction_id from session events |
@@ -75,66 +125,12 @@ async def run_async( |
75 | 125 | def _find_previous_interaction_id( |
76 | 126 | self, invocation_context: 'InvocationContext' |
77 | 127 | ) -> Optional[str]: |
78 | | - """Find the previous interaction ID from session events. |
79 | | - For interactions API stateful mode, we need to find the most recent |
80 | | - interaction_id from model responses to chain interactions. |
81 | | - Args: |
82 | | - invocation_context: The invocation context containing session events. |
83 | | - Returns: |
84 | | - The previous interaction ID if found, None otherwise. |
85 | | - """ |
86 | | - events = invocation_context.session.events |
87 | | - current_branch = invocation_context.branch |
88 | | - agent_name = invocation_context.agent.name |
89 | | - logger.debug( |
90 | | - 'Finding previous_interaction_id: agent=%s, branch=%s, num_events=%d', |
91 | | - agent_name, |
92 | | - current_branch, |
93 | | - len(events), |
| 128 | + """Find the previous interaction ID from session events.""" |
| 129 | + return _find_previous_interaction_id( |
| 130 | + invocation_context.session.events, |
| 131 | + agent_name=invocation_context.agent.name, |
| 132 | + current_branch=invocation_context.branch, |
94 | 133 | ) |
95 | | - # Iterate backwards through events to find the most recent interaction_id |
96 | | - for event in reversed(events): |
97 | | - # Skip events not in current branch |
98 | | - if not self._is_event_in_branch(current_branch, event): |
99 | | - logger.debug( |
100 | | - 'Skipping event not in branch: author=%s, branch=%s, current=%s', |
101 | | - event.author, |
102 | | - event.branch, |
103 | | - current_branch, |
104 | | - ) |
105 | | - continue |
106 | | - # Look for model responses with interaction_id from this agent |
107 | | - logger.debug( |
108 | | - 'Checking event: author=%s, interaction_id=%s, branch=%s', |
109 | | - event.author, |
110 | | - event.interaction_id, |
111 | | - event.branch, |
112 | | - ) |
113 | | - # Only consider events from this agent (skip sub-agent events) |
114 | | - if event.author == agent_name and event.interaction_id: |
115 | | - logger.debug( |
116 | | - 'Found interaction_id from agent %s: %s', |
117 | | - agent_name, |
118 | | - event.interaction_id, |
119 | | - ) |
120 | | - return event.interaction_id |
121 | | - return None |
122 | | - |
123 | | - def _is_event_in_branch( |
124 | | - self, current_branch: Optional[str], event: Event |
125 | | - ) -> bool: |
126 | | - """Check if an event belongs to the current branch. |
127 | | - Args: |
128 | | - current_branch: The current branch name. |
129 | | - event: The event to check. |
130 | | - Returns: |
131 | | - True if the event belongs to the current branch. |
132 | | - """ |
133 | | - if not current_branch: |
134 | | - # No branch means we're at the root, include all events without branch |
135 | | - return not event.branch |
136 | | - # Event must be in the same branch or have no branch (root level) |
137 | | - return event.branch == current_branch or not event.branch |
138 | 134 |
|
139 | 135 |
|
140 | 136 | # Module-level processor instance for use in flow configuration |
|
0 commit comments