Spaces:
Sleeping
Sleeping
Download web_tools.py from ifroyou/chat-browser-bridge: direct link, hf CLI and curl.
- Browser
- Download file 11.2 kB
-
https://huggingface.co/spaces/ifroyou/chat-browser-bridge/resolve/main/web_tools.py
- Command line
-
hf download hf://spaces/ifroyou/chat-browser-bridge/web_tools.py
-
curl -L -o web_tools.py https://huggingface.co/spaces/ifroyou/chat-browser-bridge/resolve/main/web_tools.py
11.2 kB
| """Same explicit MCP schemas for Bridge and NEXUS Gateway. | |
| No generic JS, arbitrary RPC operation, raw URL request or secret field is exposed. | |
| """ | |
| from __future__ import annotations | |
| import json | |
| from typing import Any | |
| from web_guarded import GuardError, Scope, parse_spec | |
| WEB_OPERATIONS = frozenset({ | |
| 'browser_web_observe','browser_web_action','browser_web_wait','browser_web_receipt', | |
| 'browser_web_cancel','browser_web_download_read', | |
| }) | |
| _SCOPE_FIELDS = {'task_id','worker_id','generation','session_id','lease_id'} | |
| _FIELDS = { | |
| 'browser_web_observe': _SCOPE_FIELDS | {'page_id','frame_id','max_nodes','offset'}, | |
| 'browser_web_action': _SCOPE_FIELDS | {'observation_id','ref_id','request_id','action','spec_json','user_confirmed','sensitive_confirmed'}, | |
| 'browser_web_wait': _SCOPE_FIELDS | {'observation_id','ref_id','condition','expected_json','timeout_ms'}, | |
| 'browser_web_receipt': _SCOPE_FIELDS | {'request_id'}, | |
| 'browser_web_cancel': _SCOPE_FIELDS | {'request_id','user_confirmed'}, | |
| 'browser_web_download_read': _SCOPE_FIELDS | {'download_id','offset','max_bytes'}, | |
| } | |
| def _build_upload_spec(files, inline_file_name: str, inline_content_base64: str, inline_expected_sha256: str) -> dict: | |
| inline_supplied = any(value != '' for value in (inline_file_name, inline_content_base64, inline_expected_sha256)) | |
| fileparam_supplied = files is not None | |
| if int(fileparam_supplied) + int(inline_supplied) != 1: | |
| raise GuardError('UPLOAD_ROUTE_EXCLUSIVITY_REQUIRED') | |
| if fileparam_supplied: | |
| return {'files': files} | |
| if not all(isinstance(value, str) and value for value in | |
| (inline_file_name, inline_content_base64, inline_expected_sha256)): | |
| raise GuardError('UPLOAD_INLINE_FIELDS_REQUIRED') | |
| return {'inline_file': { | |
| 'file_name': inline_file_name, | |
| 'content_base64': inline_content_base64, | |
| 'expected_sha256': inline_expected_sha256, | |
| }} | |
| async def dispatch_bridge_web(service, owner: str, operation: str, payload: dict) -> dict: | |
| if operation not in WEB_OPERATIONS: | |
| raise GuardError('WEB_OPERATION_NOT_ALLOWED') | |
| if not isinstance(payload,dict) or set(payload) - _FIELDS[operation] or _SCOPE_FIELDS - set(payload): | |
| raise GuardError('WEB_PAYLOAD_FIELDS_INVALID') | |
| scope=Scope(owner=owner,**{k:payload[k] for k in _SCOPE_FIELDS}) | |
| scope.validate() | |
| if operation=='browser_web_observe': | |
| return await service.observe(scope,page_id=payload.get('page_id',''), | |
| frame_id=payload.get('frame_id',''),max_nodes=payload.get('max_nodes',60),offset=payload.get('offset',0)) | |
| if operation=='browser_web_action': | |
| return await service.action(scope,observation_id=payload['observation_id'],ref_id=payload.get('ref_id',''), | |
| request_id=payload['request_id'],action=payload['action'],spec=parse_spec(payload.get('spec_json','{}')), | |
| user_confirmed=payload.get('user_confirmed',False),sensitive_confirmed=payload.get('sensitive_confirmed',False)) | |
| if operation=='browser_web_wait': | |
| spec=parse_spec(payload.get('expected_json','{}')) | |
| if set(spec)!={'expected'}: | |
| raise GuardError('WAIT_EXPECTED_OBJECT_REQUIRED') | |
| return await service.wait(scope,observation_id=payload['observation_id'],ref_id=payload['ref_id'], | |
| condition=payload['condition'],expected=spec['expected'],timeout_ms=payload.get('timeout_ms',1500)) | |
| if operation=='browser_web_receipt': | |
| return service.receipt(scope,payload['request_id']) | |
| if operation=='browser_web_cancel': | |
| return await service.cancel(scope,request_id=payload['request_id'], | |
| user_confirmed=payload.get('user_confirmed',False)) | |
| return await service.download_read(scope,download_id=payload['download_id'], | |
| offset=payload.get('offset',0),max_bytes=payload.get('max_bytes',65536)) | |
| def _register(server, call, prefix: str): | |
| # Lazy import keeps pure safety tests independent of an installed MCP runtime. | |
| from mcp.types import ToolAnnotations | |
| read=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=False, openWorldHint=True) | |
| write=ToolAnnotations(readOnlyHint=False, destructiveHint=False, idempotentHint=False, openWorldHint=True) | |
| async def observe(session_id: str,lease_id: str,task_id: str,worker_id: str,generation: int, | |
| page_id: str='',frame_id: str='',max_nodes: int=60,offset: int=0): | |
| return await call('browser_web_observe',dict(session_id=session_id,lease_id=lease_id,task_id=task_id, | |
| worker_id=worker_id,generation=generation,page_id=page_id,frame_id=frame_id,max_nodes=max_nodes,offset=offset)) | |
| async def action(session_id: str,lease_id: str,task_id: str,worker_id: str,generation: int, | |
| request_id: str,observation_id: str,action: str,ref_id: str='',spec_json: str='{}', | |
| user_confirmed: bool=False,sensitive_confirmed: bool=False): | |
| return await call('browser_web_action',dict(session_id=session_id,lease_id=lease_id,task_id=task_id, | |
| worker_id=worker_id,generation=generation,request_id=request_id,observation_id=observation_id, | |
| action=action,ref_id=ref_id,spec_json=spec_json,user_confirmed=user_confirmed, | |
| sensitive_confirmed=sensitive_confirmed)) | |
| async def wait(session_id: str,lease_id: str,task_id: str,worker_id: str,generation: int, | |
| observation_id: str,ref_id: str,condition: str,expected_json: str,timeout_ms: int=1500): | |
| return await call('browser_web_wait',dict(session_id=session_id,lease_id=lease_id,task_id=task_id, | |
| worker_id=worker_id,generation=generation,observation_id=observation_id,ref_id=ref_id, | |
| condition=condition,expected_json=expected_json,timeout_ms=timeout_ms)) | |
| async def receipt(session_id: str,lease_id: str,task_id: str,worker_id: str,generation: int,request_id: str): | |
| return await call('browser_web_receipt',dict(session_id=session_id,lease_id=lease_id,task_id=task_id, | |
| worker_id=worker_id,generation=generation,request_id=request_id)) | |
| async def cancel(session_id: str,lease_id: str,task_id: str,worker_id: str,generation: int, | |
| request_id: str,user_confirmed: bool=False): | |
| return await call('browser_web_cancel',dict(session_id=session_id,lease_id=lease_id,task_id=task_id, | |
| worker_id=worker_id,generation=generation,request_id=request_id,user_confirmed=user_confirmed)) | |
| async def download_read(session_id: str,lease_id: str,task_id: str,worker_id: str,generation: int, | |
| download_id: str,offset: int=0,max_bytes: int=65536): | |
| return await call('browser_web_download_read',dict(session_id=session_id,lease_id=lease_id, | |
| task_id=task_id,worker_id=worker_id,generation=generation,download_id=download_id, | |
| offset=offset,max_bytes=max_bytes)) | |
| async def upload(session_id: str,lease_id: str,task_id: str,worker_id: str,generation: int, | |
| request_id: str,observation_id: str,ref_id: str, | |
| files: list[dict[str,str]] | None=None,inline_file_name: str='', | |
| inline_content_base64: str='',inline_expected_sha256: str='', | |
| user_confirmed: bool=False): | |
| spec=_build_upload_spec(files,inline_file_name,inline_content_base64,inline_expected_sha256) | |
| spec_json=json.dumps(spec,ensure_ascii=True,separators=(',',':'),allow_nan=False) | |
| return await call('browser_web_action',dict(session_id=session_id,lease_id=lease_id,task_id=task_id, | |
| worker_id=worker_id,generation=generation,request_id=request_id,observation_id=observation_id, | |
| action='upload',ref_id=ref_id,spec_json=spec_json,user_confirmed=user_confirmed, | |
| sensitive_confirmed=True)) | |
| def register_bridge_web_tools(server, service, owner_get): | |
| async def call(operation,payload): | |
| # Do not catch authentication errors or substitute another owner's session. | |
| owner=owner_get() | |
| return await dispatch_bridge_web(service,owner,operation,payload) | |
| _register(server,call,'browser_web_') | |
| def register_gateway_web_tools(server, relay, render): | |
| async def call(operation,payload): | |
| # Existing relay owns auth, 429, cooldown and transport uncertainty. | |
| # No retry loop, alternate route or low-level browser fallback here. | |
| return render(await relay(operation,payload)) | |
| _register(server,call,'nexus_browser_web_') | |