Skip to content

Commit fb8234b

Browse files
leehagoodjamescopybara-github
authored andcommitted
No public description
PiperOrigin-RevId: 945106852 Change-Id: I8b3a1e978ce1f3af3a203308f611409ee2a08324
1 parent 0004367 commit fb8234b

2 files changed

Lines changed: 151 additions & 0 deletions

File tree

google/antigravity/connections/local/event_processor.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,8 +498,15 @@ async def process_event(self, event: localharness_pb2.OutputEvent) -> None:
498498
tsu.state
499499
== localharness_pb2.TrajectoryStateUpdate.State.STATE_RUNNING
500500
):
501+
# If any trajectory is running, the connection is not idle.
502+
if self.is_idle.is_set():
503+
self.is_idle.clear()
501504
if is_subagent:
502505
self.active_subagent_ids.add(tsu.trajectory_id)
506+
else:
507+
# Note: the main trajectory seems to switch from RUNNING -> IDLE ->
508+
# RUNNING as it invokes subagents.
509+
self.parent_idle = False
503510

504511
elif tsu.state == localharness_pb2.TrajectoryStateUpdate.State.STATE_IDLE:
505512
if is_subagent:

google/antigravity/connections/local/event_processor_test.py

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,20 @@
1414

1515
"""Tests for event_processor that translates wire events to SDK events."""
1616

17+
import unittest
18+
from unittest import mock
19+
1720
from absl.testing import absltest
1821

1922
from google.antigravity.connections.local import localharness_pb2
2023
from google.antigravity import types
2124
from google.antigravity.connections.local import event_processor
2225

2326

27+
MAIN_TRAJECTORY_ID = "cbb3a5135a32671ae8152a25a857c4bc"
28+
SUBAGENT_TRAJECTORY_ID = "9121f3e9937e263b74a4a43ff6fb0117"
29+
30+
2431
class EventProcessorHelperTest(absltest.TestCase):
2532
"""Tests for standalone helper functions in event_processor."""
2633

@@ -257,5 +264,142 @@ def test_step_from_dict_normalizes_cns_uri_arguments(self):
257264
)
258265

259266

267+
class LocalHarnessEventProcessorTest(unittest.IsolatedAsyncioTestCase):
268+
"""Tests for LocalHarnessEventProcessor."""
269+
270+
async def test_main_agent_trajectory_step_update_resets_idle_state(self):
271+
"""Verifies that when a main agent transitions to RUNNING, idleness resets.
272+
273+
Why: The main agent can go in and out of the idle state as it waits on
274+
subagents. When it exits the idle state to STATE_RUNNING, we should record
275+
that so that the SDK does not terminate the agent process early.
276+
"""
277+
processor = event_processor.LocalHarnessEventProcessor(
278+
send_input_event_fn=mock.AsyncMock()
279+
)
280+
processor.main_trajectory_id = MAIN_TRAJECTORY_ID
281+
processor.parent_idle = True
282+
processor.is_idle.set()
283+
284+
event = localharness_pb2.OutputEvent(
285+
trajectory_state_update=localharness_pb2.TrajectoryStateUpdate(
286+
state=localharness_pb2.TrajectoryStateUpdate.State.STATE_RUNNING,
287+
trajectory_id=MAIN_TRAJECTORY_ID,
288+
)
289+
)
290+
await processor.process_event(event)
291+
292+
self.assertFalse(processor.parent_idle)
293+
self.assertFalse(processor.is_idle.is_set())
294+
295+
async def test_subagent_trajectory_step_update_resets_idle_state(self):
296+
"""Verifies that when a subagent transitions to RUNNING, idleness resets.
297+
298+
Why: A subagent transitioning to STATE_RUNNING should reset idleness, but
299+
not the state of the parent.
300+
"""
301+
processor = event_processor.LocalHarnessEventProcessor(
302+
send_input_event_fn=mock.AsyncMock()
303+
)
304+
processor.main_trajectory_id = MAIN_TRAJECTORY_ID
305+
processor.parent_idle = True
306+
processor.is_idle.set()
307+
308+
event = localharness_pb2.OutputEvent(
309+
trajectory_state_update=localharness_pb2.TrajectoryStateUpdate(
310+
state=localharness_pb2.TrajectoryStateUpdate.State.STATE_RUNNING,
311+
trajectory_id=SUBAGENT_TRAJECTORY_ID,
312+
)
313+
)
314+
await processor.process_event(event)
315+
316+
self.assertTrue(processor.parent_idle) # The parent remains idle
317+
self.assertFalse(processor.is_idle.is_set())
318+
self.assertIn(SUBAGENT_TRAJECTORY_ID, processor.active_subagent_ids)
319+
320+
async def test_trajectory_remains_active_if_any_agent_is_running(self):
321+
"""Verifies that when any agent is RUNNING, the trajectory is not idle.
322+
323+
Why: As agents transistion from IDLE to RUNNING, the trajectory should be
324+
considered active.
325+
"""
326+
327+
processor = event_processor.LocalHarnessEventProcessor(
328+
send_input_event_fn=mock.AsyncMock()
329+
)
330+
processor.main_trajectory_id = MAIN_TRAJECTORY_ID
331+
332+
# 1) Main agent starts, assert trajectory is active
333+
event = localharness_pb2.OutputEvent(
334+
trajectory_state_update=localharness_pb2.TrajectoryStateUpdate(
335+
state=localharness_pb2.TrajectoryStateUpdate.State.STATE_RUNNING,
336+
trajectory_id=MAIN_TRAJECTORY_ID,
337+
)
338+
)
339+
await processor.process_event(event)
340+
self.assertFalse(processor.parent_idle)
341+
self.assertFalse(processor.is_idle.is_set())
342+
343+
# 2) Subagent starts, assert trajectory is still active
344+
event = localharness_pb2.OutputEvent(
345+
trajectory_state_update=localharness_pb2.TrajectoryStateUpdate(
346+
state=localharness_pb2.TrajectoryStateUpdate.State.STATE_RUNNING,
347+
trajectory_id=SUBAGENT_TRAJECTORY_ID,
348+
)
349+
)
350+
await processor.process_event(event)
351+
self.assertFalse(processor.parent_idle)
352+
self.assertFalse(processor.is_idle.is_set())
353+
self.assertIn(SUBAGENT_TRAJECTORY_ID, processor.active_subagent_ids)
354+
355+
# 3) Main agent goes idle, assert trajectory is still active
356+
event = localharness_pb2.OutputEvent(
357+
trajectory_state_update=localharness_pb2.TrajectoryStateUpdate(
358+
state=localharness_pb2.TrajectoryStateUpdate.State.STATE_IDLE,
359+
trajectory_id=MAIN_TRAJECTORY_ID,
360+
)
361+
)
362+
await processor.process_event(event)
363+
self.assertTrue(processor.parent_idle)
364+
self.assertFalse(processor.is_idle.is_set())
365+
self.assertIn(SUBAGENT_TRAJECTORY_ID, processor.active_subagent_ids)
366+
367+
# 4) Main agent starts again, assert trajectory is still active
368+
event = localharness_pb2.OutputEvent(
369+
trajectory_state_update=localharness_pb2.TrajectoryStateUpdate(
370+
state=localharness_pb2.TrajectoryStateUpdate.State.STATE_RUNNING,
371+
trajectory_id=MAIN_TRAJECTORY_ID,
372+
)
373+
)
374+
await processor.process_event(event)
375+
self.assertFalse(processor.parent_idle)
376+
self.assertFalse(processor.is_idle.is_set())
377+
self.assertIn(SUBAGENT_TRAJECTORY_ID, processor.active_subagent_ids)
378+
379+
# 5) Subagent goes idle, assert trajectory is still active
380+
event = localharness_pb2.OutputEvent(
381+
trajectory_state_update=localharness_pb2.TrajectoryStateUpdate(
382+
state=localharness_pb2.TrajectoryStateUpdate.State.STATE_IDLE,
383+
trajectory_id=SUBAGENT_TRAJECTORY_ID,
384+
)
385+
)
386+
await processor.process_event(event)
387+
self.assertFalse(processor.parent_idle)
388+
self.assertFalse(processor.is_idle.is_set())
389+
self.assertNotIn(SUBAGENT_TRAJECTORY_ID, processor.active_subagent_ids)
390+
391+
# 6) Main agent goes idle, assert trajectory is now idle
392+
# (since all agents are idle)
393+
event = localharness_pb2.OutputEvent(
394+
trajectory_state_update=localharness_pb2.TrajectoryStateUpdate(
395+
state=localharness_pb2.TrajectoryStateUpdate.State.STATE_IDLE,
396+
trajectory_id=MAIN_TRAJECTORY_ID,
397+
)
398+
)
399+
await processor.process_event(event)
400+
self.assertTrue(processor.parent_idle)
401+
self.assertTrue(processor.is_idle.is_set())
402+
403+
260404
if __name__ == "__main__":
261405
absltest.main()

0 commit comments

Comments
 (0)