agentenv-framework-protocol 0.1.438__tar.gz → 0.1.440__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/PKG-INFO +5 -3
  2. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/README.md +4 -2
  3. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/pyproject.toml +1 -1
  4. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/website_browser.py +21 -2
  5. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_website_browser.py +36 -1
  6. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/.gitignore +0 -0
  7. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/LICENSE +0 -0
  8. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/NOTICE +0 -0
  9. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/THIRD_PARTY_NOTICES.md +0 -0
  10. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/examples/__init__.py +0 -0
  11. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/examples/advanced_agent.py +0 -0
  12. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/examples/basic_agent.py +0 -0
  13. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/examples/custom_extensions_agent.py +0 -0
  14. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/examples/multimodal_agent.py +0 -0
  15. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/examples/reference_model.py +0 -0
  16. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/examples/streaming_agent.py +0 -0
  17. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/__init__.py +0 -0
  18. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/a2a_agent/__init__.py +0 -0
  19. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/a2a_agent/_trajectory_log.py +0 -0
  20. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/a2a_agent/_triggers.py +0 -0
  21. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/a2a_agent/extensions.py +0 -0
  22. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/a2a_agent/framework.py +0 -0
  23. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/a2a_agent/peer_agents.py +0 -0
  24. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/a2a_agent/proxy.py +0 -0
  25. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/a2a_agent/registry.py +0 -0
  26. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/a2a_agent/staging.py +0 -0
  27. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/a2a_agent/tasks/__init__.py +0 -0
  28. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/a2a_agent/tasks/v1.py +0 -0
  29. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/agent_env_environment.py +0 -0
  30. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/client.py +0 -0
  31. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/__init__.py +0 -0
  32. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/_declare.py +0 -0
  33. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/_linux.py +0 -0
  34. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/_load.py +0 -0
  35. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/_with_fds.py +0 -0
  36. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/app.py +0 -0
  37. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/app_data.py +0 -0
  38. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/app_runtime.py +0 -0
  39. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/apps.py +0 -0
  40. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/card.py +0 -0
  41. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/checks.py +0 -0
  42. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/conformance/__init__.py +0 -0
  43. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/conformance/__main__.py +0 -0
  44. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/conformance/checks.py +0 -0
  45. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/conformance/client.py +0 -0
  46. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/conformance/fixture.py +0 -0
  47. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/conformance/mp4.py +0 -0
  48. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/conformance/report.py +0 -0
  49. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/dataplane.py +0 -0
  50. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/driver.py +0 -0
  51. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/errors.py +0 -0
  52. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/extensions.py +0 -0
  53. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/frames.py +0 -0
  54. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/keys.py +0 -0
  55. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/launch.py +0 -0
  56. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/manifest.py +0 -0
  57. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/operations.py +0 -0
  58. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/platform.py +0 -0
  59. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/queue.py +0 -0
  60. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/recording.py +0 -0
  61. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/results.py +0 -0
  62. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/run_install_step.py +0 -0
  63. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/runtime.py +0 -0
  64. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/serve.py +0 -0
  65. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/serve_app.py +0 -0
  66. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/session.py +0 -0
  67. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/settings.py +0 -0
  68. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/skill.py +0 -0
  69. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/spaces.py +0 -0
  70. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/computer/tools.py +0 -0
  71. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/errors.py +0 -0
  72. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/manifest.py +0 -0
  73. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/preflight.py +0 -0
  74. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/tool_access.py +0 -0
  75. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/tool_client.py +0 -0
  76. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/tool_context.py +0 -0
  77. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/transfers.py +0 -0
  78. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/src/agentenv_protocol/types.py +0 -0
  79. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/computer_fake.py +0 -0
  80. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/probe_fake.py +0 -0
  81. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_a2a_agent.py +0 -0
  82. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_a2a_agent_examples.py +0 -0
  83. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_a2a_cdp_config.py +0 -0
  84. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_a2a_object_transfers.py +0 -0
  85. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_a2a_peer_agents.py +0 -0
  86. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_a2a_proxy.py +0 -0
  87. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_a2a_staging.py +0 -0
  88. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_a2a_trajectory_log.py +0 -0
  89. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_agent_env_environment.py +0 -0
  90. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_client.py +0 -0
  91. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_computer_app_data.py +0 -0
  92. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_computer_app_server.py +0 -0
  93. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_computer_conformance.py +0 -0
  94. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_computer_conformance_checks.py +0 -0
  95. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_computer_conformance_recording.py +0 -0
  96. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_computer_dataplane.py +0 -0
  97. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_computer_declare.py +0 -0
  98. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_computer_driver.py +0 -0
  99. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_computer_extensions.py +0 -0
  100. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_computer_frames.py +0 -0
  101. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_computer_queue.py +0 -0
  102. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_computer_recording.py +0 -0
  103. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_computer_serve.py +0 -0
  104. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_computer_spaces.py +0 -0
  105. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_control_token.py +0 -0
  106. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_data_objects.py +0 -0
  107. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_errors.py +0 -0
  108. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_extension_methods.py +0 -0
  109. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_intake.py +0 -0
  110. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_manifest.py +0 -0
  111. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_preflight.py +0 -0
  112. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_tool_access.py +0 -0
  113. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_tool_annotations.py +0 -0
  114. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_tool_client.py +0 -0
  115. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_tool_context.py +0 -0
  116. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_tool_context_fastmcp.py +0 -0
  117. {agentenv_framework_protocol-0.1.438 → agentenv_framework_protocol-0.1.440}/tests/test_tool_context_injection.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: agentenv-framework-protocol
3
- Version: 0.1.438
3
+ Version: 0.1.440
4
4
  Summary: Open data-plane protocol and server SDK for agent environments.
5
5
  Project-URL: Homepage, https://www.agentenvframework.com
6
6
  Project-URL: Documentation, https://www.agentenvframework.com/docs
@@ -846,8 +846,10 @@ are the profile's template. The base class adds:
846
846
  the pipe rather than a second copy, which would hand its window to the first and exit. The ready check
847
847
  `devtools_answers` asks `Browser.getVersion` over the pipe.
848
848
  - **Its control connection**, `self.control`, a `BrowserControl` over the pipe. At each launch it attaches
849
- to every page with flattened sessions and keeps a record, `since` its server started: open tabs in
850
- opened order, the one whose page has focus `active`; `closed_tabs`, each with `closed_at` and
849
+ to every page with flattened sessions, telling each page it attached to as it opened, a popup say, to run, and keeps a
850
+ record, `since` its server started: open tabs in opened order, each with its URL and title as the browser has them
851
+ when the record is read (Chrome sends no event for a title), the one whose page has focus `active`; `closed_tabs`,
852
+ each as of its page's last load, with `closed_at` and
851
853
  `closed_by` (`agentenv`, over this connection; `unknown`, anyone else; `exit` or `stop`, when the browser
852
854
  ended on its own or its server stopped it); `downloads`, into `~/Downloads`, each with its state
853
855
  and, completed, its size and sha256; and `dialogs`, each with its type, message, answer and who gave it.
@@ -790,8 +790,10 @@ are the profile's template. The base class adds:
790
790
  the pipe rather than a second copy, which would hand its window to the first and exit. The ready check
791
791
  `devtools_answers` asks `Browser.getVersion` over the pipe.
792
792
  - **Its control connection**, `self.control`, a `BrowserControl` over the pipe. At each launch it attaches
793
- to every page with flattened sessions and keeps a record, `since` its server started: open tabs in
794
- opened order, the one whose page has focus `active`; `closed_tabs`, each with `closed_at` and
793
+ to every page with flattened sessions, telling each page it attached to as it opened, a popup say, to run, and keeps a
794
+ record, `since` its server started: open tabs in opened order, each with its URL and title as the browser has them
795
+ when the record is read (Chrome sends no event for a title), the one whose page has focus `active`; `closed_tabs`,
796
+ each as of its page's last load, with `closed_at` and
795
797
  `closed_by` (`agentenv`, over this connection; `unknown`, anyone else; `exit` or `stop`, when the browser
796
798
  ended on its own or its server stopped it); `downloads`, into `~/Downloads`, each with its state
797
799
  and, completed, its size and sha256; and `dialogs`, each with its type, message, answer and who gave it.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agentenv-framework-protocol"
3
- version = "0.1.438"
3
+ version = "0.1.440"
4
4
  description = "Open data-plane protocol and server SDK for agent environments."
5
5
  readme = "README.md"
6
6
  license = "Apache-2.0"
@@ -260,13 +260,26 @@ class BrowserControl:
260
260
  return visible
261
261
 
262
262
  async def record(self) -> dict:
263
- """The record ``since`` it started: open ``tabs``, each with whether it's ``active``, ``closed_tabs``,
264
- ``downloads`` and ``dialogs``."""
263
+ """The record ``since`` it started: open ``tabs``, each with its URL and title now and whether it's ``active``,
264
+ ``closed_tabs``, ``downloads`` and ``dialogs``."""
265
+ await self._refresh()
265
266
  active = await self.active_tab()
266
267
  return {"since": self.since, "tabs": [{**tab, "active": tab["id"] == active} for tab in self.tabs.values()],
267
268
  "closed_tabs": list(self.closed_tabs), "downloads": list(self.downloads.values()),
268
269
  "dialogs": list(self.dialog_log)}
269
270
 
271
+ async def _refresh(self, target: Optional[str] = None) -> None:
272
+ """The URL and title of the tab ``target``, or of every open tab, as the browser has them now: it sends no
273
+ event when a page's title changes."""
274
+ try:
275
+ infos = (await self.devtools.call("Target.getTargets", {"filter": PAGES},
276
+ timeout_s=ACTIVE_CHECK_TIMEOUT_S))["targetInfos"]
277
+ except (ConnectionError, DevToolsError, asyncio.TimeoutError, KeyError):
278
+ return
279
+ for info in infos:
280
+ if target in (None, info["targetId"]) and (tab := self.tabs.get(info["targetId"])) is not None:
281
+ tab.update(url=info.get("url", tab["url"]), title=info.get("title", tab["title"]))
282
+
270
283
  def _event(self, message: dict) -> None:
271
284
  handler = getattr(self, "_on_" + message.get("method", "").replace(".", "_"), None)
272
285
  if handler is not None:
@@ -295,10 +308,16 @@ class BrowserControl:
295
308
  if params["targetInfo"].get("type") == "page":
296
309
  self._sessions[params["sessionId"]] = params["targetInfo"]["targetId"]
297
310
  self._spawn(self.devtools.call("Page.enable", session_id=params["sessionId"]))
311
+ # A page attached as it opens, a popup say, waits for this before it navigates.
312
+ self._spawn(self.devtools.call("Runtime.runIfWaitingForDebugger", session_id=params["sessionId"]))
298
313
 
299
314
  def _on_Target_detachedFromTarget(self, params: dict, session: Optional[str]) -> None:
300
315
  self._sessions.pop(params["sessionId"], None)
301
316
 
317
+ def _on_Page_loadEventFired(self, params: dict, session: Optional[str]) -> None:
318
+ if (target := self._sessions.get(session)) is not None:
319
+ self._spawn(self._refresh(target))
320
+
302
321
  def _on_Page_javascriptDialogOpening(self, params: dict, session: Optional[str]) -> None:
303
322
  dialog = {"tab": self._sessions.get(session), "type": params.get("type"), "message": params.get("message", ""),
304
323
  "url": params.get("url", ""), "opened_at": _now(), "answer": None, "by": None}
@@ -3,7 +3,8 @@ for each; a subclass refused for carrying one of them; the start tabs, the time
3
3
  its launch run with no desktop when alone; a CDP connection over a new debugging pipe at each launch, which its ready
4
4
  check asks, and a browser launched again when its server restarts; its shared memory in files only on a small
5
5
  /dev/shm; an empty cache and the deploy's prompt answers in its profile at each launch; its policies, card params and
6
- skill; and an app that isn't a browser launched and declared as before."""
6
+ skill; its record's titles read from the browser, which sends no event for a page's; and an app that isn't a browser
7
+ launched and declared as before."""
7
8
  from __future__ import annotations
8
9
 
9
10
  import asyncio
@@ -492,6 +493,40 @@ async def test_its_control_records_tabs_in_opened_order_and_who_closed_each_and_
492
493
  assert devtools.calls[2][1] == {"behavior": "default", "eventsEnabled": True}
493
494
 
494
495
 
496
+ @pytest.mark.asyncio
497
+ async def test_each_page_it_attaches_to_is_told_to_run_so_a_popup_it_attached_to_as_it_opened_navigates(tmp_path):
498
+ devtools = StubDevTools()
499
+ control = BrowserControl(devtools, "agent")
500
+ await control.attach()
501
+ devtools.send("Target.attachedToTarget", {"sessionId": "s-popup", "waitingForDebugger": True, **_page("popup")})
502
+ await asyncio.sleep(0)
503
+
504
+ assert ("Page.enable", {}, "s-popup") in devtools.calls
505
+ assert ("Runtime.runIfWaitingForDebugger", {}, "s-popup") in devtools.calls
506
+
507
+
508
+ @pytest.mark.asyncio
509
+ async def test_its_record_reads_each_tabs_title_when_read_and_when_its_page_loads_since_no_event_says(tmp_path):
510
+ now = {"a": "Inbox", "b": "Draft"}
511
+ devtools = StubDevTools({"Target.getTargets": lambda params, session: {"targetInfos": [
512
+ _page(target, f"https://mail.test/{target}", title)["targetInfo"] for target, title in now.items()]}})
513
+ control = BrowserControl(devtools, "agent")
514
+ await control.attach()
515
+ for target in ("a", "b"):
516
+ devtools.send("Target.targetCreated", _page(target, f"https://mail.test/{target}", f"mail.test/{target}"))
517
+ devtools.send("Target.attachedToTarget", {"sessionId": f"s-{target}", **_page(target)})
518
+ devtools.send("Page.loadEventFired", {"timestamp": 1}, session="s-b")
519
+ await asyncio.sleep(0)
520
+ del now["b"]
521
+ devtools.send("Target.targetDestroyed", {"targetId": "b"})
522
+ now["a"] = "Inbox (1)"
523
+ record = await control.record()
524
+
525
+ assert [(tab["id"], tab["title"]) for tab in record["tabs"]] == [("a", "Inbox (1)")]
526
+ assert [(tab["id"], tab["title"]) for tab in record["closed_tabs"]] == [("b", "Draft")]
527
+ assert ("Target.getTargets", {"filter": [{"type": "page"}]}, None) in devtools.calls
528
+
529
+
495
530
  @pytest.mark.asyncio
496
531
  @pytest.mark.parametrize("dialogs, kind, sent, answer, by", [
497
532
  ("accept", "prompt", {"accept": True, "promptText": "yes"}, "accepted", "agentenv"),