|
39 | 39 | NavigateResponse, |
40 | 40 | SnapshotRequest, |
41 | 41 | SnapshotResponse, |
| 42 | + ViewFrameResponse, |
42 | 43 | ) |
43 | 44 | from agent_browser.runtime import ( |
44 | 45 | BrowserLaunchError, |
|
56 | 57 | SessionExpiredError, |
57 | 58 | SessionManager, |
58 | 59 | SessionNotFoundError, |
| 60 | + ViewFrameRateLimitedError, |
59 | 61 | VisionBudgetExhaustedError, |
60 | 62 | ) |
61 | 63 |
|
@@ -575,6 +577,17 @@ async def snapshot(payload: SnapshotRequest, request: Request) -> SnapshotRespon |
575 | 577 | vision_steps_remaining=result.vision_steps_remaining, |
576 | 578 | ) |
577 | 579 |
|
| 580 | + @application.post("/browser/view-frame", response_model=ViewFrameResponse) |
| 581 | + async def view_frame(payload: SnapshotRequest, request: Request) -> ViewFrameResponse: |
| 582 | + await require(request, RequiredAuthority.OBSERVER) |
| 583 | + result = await session_manager.capture_view_frame(payload.session_id) |
| 584 | + return ViewFrameResponse( |
| 585 | + session_id=result.session_id, |
| 586 | + screenshot_base64=result.frame.screenshot_base64, |
| 587 | + viewport=result.frame.viewport, |
| 588 | + captured_at=result.captured_at, |
| 589 | + ) |
| 590 | + |
578 | 591 | @application.post("/browser/interact", response_model=InteractResponse) |
579 | 592 | async def interact(payload: InteractRequest, request: Request) -> InteractResponse: |
580 | 593 | await require(request, RequiredAuthority.CONTROLLER) |
@@ -617,6 +630,8 @@ def _known_fault(error: Exception) -> _ApiFault | None: |
617 | 630 | return _ApiFault(ErrorCode.SESSION_EXPIRED, 410) |
618 | 631 | if isinstance(error, VisionBudgetExhaustedError): |
619 | 632 | return _ApiFault(ErrorCode.VISION_BUDGET_EXHAUSTED, 409) |
| 633 | + if isinstance(error, ViewFrameRateLimitedError): |
| 634 | + return _ApiFault(ErrorCode.VIEW_FRAME_RATE_LIMITED, 429, retry_after_seconds=1) |
620 | 635 | if isinstance(error, InvalidBrowserInteractionError): |
621 | 636 | return _ApiFault(ErrorCode.INVALID_INTERACTION, 400) |
622 | 637 | if isinstance(error, (BrowserLaunchError, BrowserNotReadyError)): |
@@ -661,6 +676,7 @@ def _external_security_fault(error: BaseException) -> _ApiFault | None: |
661 | 676 | ErrorCode.SESSION_NOT_FOUND: "Session was not found.", |
662 | 677 | ErrorCode.SESSION_EXPIRED: "Session expired.", |
663 | 678 | ErrorCode.VISION_BUDGET_EXHAUSTED: "The snapshot budget is exhausted.", |
| 679 | + ErrorCode.VIEW_FRAME_RATE_LIMITED: "View frame capture is rate limited.", |
664 | 680 | ErrorCode.INVALID_URL: "The navigation URL is invalid.", |
665 | 681 | ErrorCode.DESTINATION_BLOCKED: "The navigation destination is blocked.", |
666 | 682 | ErrorCode.INVALID_INTERACTION: "The request or interaction is invalid.", |
|
0 commit comments