[pierre]: ensuring the bridge is present or not before declaring

This commit is contained in:
SirKentut
2026-06-24 03:30:20 -07:00
parent 154b6fef68
commit 420263b71f
2 changed files with 25 additions and 11 deletions
+17 -5
View File
@@ -121,6 +121,7 @@ def _app_bridge_expression(tool_name: str, tool_input: dict) -> str:
# reads poll briefly for the bridge to come up instead of declaring it absent.
_BRIDGE_READY_WAIT_MS = 8000
_BRIDGE_POLL_INTERVAL_MS = 400
_bridge_known_absent: set[str] = set()
def _parse_bridge_result(result: dict) -> object:
@@ -320,11 +321,22 @@ async def execute_browser_tool(
# AppInvoke does not wait: its action either exists right now or it does
# not, and a missing action should surface immediately.
if tool_name in ("AppDescribe", "AppGetState"):
waited = 0
while waited < _BRIDGE_READY_WAIT_MS and not _bridge_ready(_parse_bridge_result(result)):
await asyncio.sleep(_BRIDGE_POLL_INTERVAL_MS / 1000)
waited += _BRIDGE_POLL_INTERVAL_MS
result = await _eval_once()
ready = _bridge_ready(_parse_bridge_result(result))
# Only the cold-boot read polls. Once a card is memoed bridge-absent,
# every later read takes the single eval above and skips the 8s sink;
# that single eval still detects a bridge that came up between reads.
if not ready and browser_id not in _bridge_known_absent:
waited = 0
while waited < _BRIDGE_READY_WAIT_MS and not ready:
await asyncio.sleep(_BRIDGE_POLL_INTERVAL_MS / 1000)
waited += _BRIDGE_POLL_INTERVAL_MS
result = await _eval_once()
ready = _bridge_ready(_parse_bridge_result(result))
# Record the verdict so the next read knows whether to pay the wait.
if ready:
_bridge_known_absent.discard(browser_id)
else:
_bridge_known_absent.add(browser_id)
if tool_name == "AppDescribe":
_persist_app_controls(browser_id, _parse_bridge_result(result))
return result
@@ -118,12 +118,14 @@ TOOLS = [
"name": "AppAgent",
"description": (
"Operate one of the user's OpenSwarm-built apps (a small web app they "
"created, e.g. a graphing or form app) that is open on the dashboard. A "
"dedicated app agent reads the app's own actions and state through its "
"native bridge and performs the task (no screenshots or DOM scraping), "
"then returns a summary plus a final screenshot. Use this for the apps "
"listed in the selected-app context, not for websites (use BrowserAgent "
"for those)."
"created, e.g. a graphing tool, a form, or a canvas game like Doom) that "
"is open on the dashboard. A dedicated app agent performs the task: it "
"drives the app through its native bridge when one is available (reading "
"the app's own state and calling its controls), and otherwise falls back "
"to native keyboard/mouse plus screenshots for canvas and game apps that "
"expose no bridge. It returns a summary plus a final screenshot. Works for "
"ANY app in the selected-app context, including games and canvas apps; use "
"BrowserAgent only for websites, not these apps."
),
"inputSchema": {
"type": "object",