superbrowser-sdk 2.4.0__tar.gz → 2.5.0__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.
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/CHANGELOG.md +45 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/PKG-INFO +1 -1
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/mcp.md +40 -6
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/pyproject.toml +1 -1
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/__init__.py +1 -1
- superbrowser_sdk-2.5.0/src/super_browser/agent/diagnostics.py +287 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/agent/facade.py +28 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/mcp_server.py +114 -2
- superbrowser_sdk-2.5.0/tests/test_diagnostics.py +760 -0
- superbrowser_sdk-2.5.0/tests/test_mcp_diagnostics.py +271 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_mcp_navigation.py +19 -16
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_mcp_server.py +18 -11
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_mcp_server_smoke.py +57 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/.env.example +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/.github/workflows/adversarial-v3.yml +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/.github/workflows/adversarial.yml +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/.github/workflows/benchmark.yml +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/.github/workflows/dco.yml +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/.github/workflows/e2e.yml +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/.github/workflows/publish.yml +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/.github/workflows/smoke.yml +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/.github/workflows/stress.yml +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/.github/workflows/test.yml +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/.gitignore +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/.pre-commit-config.yaml +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/CONTRIBUTING.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/Dockerfile +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/LICENSE +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/README.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/Super-Browser.png +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/benchmarks/fixtures/behavioral.html +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/benchmarks/fixtures/dom-heavy.html +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/benchmarks/fixtures/form.html +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/benchmarks/fixtures/simple.html +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/benchmarks/v1.11.0-baseline-patchright.json +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/benchmarks/v1.11.0-baseline-patchright.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/conftest.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docker-compose.yml +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/agent-reliability.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/aiv/AIV_FRAMEWORK_v5.3.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/anti-detection-ejecta.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/api-ergonomics-audit.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/api-reference.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/api-stability.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/architecture.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/behavioral-synthesis.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/browser-networking.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/cloak-integration.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/consistency-engine.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/discovery/DISCOVERY-REPORT.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/error-catalog.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/fingerprint-scoring.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/fingerprint-validation.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/gap-analysis.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/human-behavior.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/memory.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/migration/v1-to-v2.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/migration/v1.8-to-v1.9.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/operating-doctrine.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/platform-abstraction.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/plugins.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/quickstart.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/recording.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/rfcs/README.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/rfcs/v2-decomposition.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/rfcs/v2-track-a-api-simplification.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/rfcs/v2-track-b-network-stealth.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/rfcs/v2-track-c-behavioral-realism.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/rfcs/v2-track-d-challenge-infrastructure.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/rfcs/v2-track-e-e2e-harness.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/stealth-coverage.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/docs/stealth-evidence.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/examples/backend_selection.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/examples/basic_usage.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/examples/budget_tracking.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/examples/cloak_stealth.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/examples/error_handling.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/examples/fingerprint_scan.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/examples/human_behavior.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/examples/multi_tab_workflow.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/examples/session_persistence.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/examples/stealth_mode.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/scripts/adversarial_run.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/scripts/agent_efficiency_benchmark.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/scripts/browser_benchmark.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/scripts/e2e_trend.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/scripts/run_stealth_gauntlet.sh +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/scripts/smoke_published.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/scripts/stress_real_world.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/scripts/validate_e2e_report.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/scripts/verify_release_artifact.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/__main__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/agent/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/agent/config.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/agent/debug.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/agent/delegator.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/agent/llm/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/agent/llm/anthropic_client.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/agent/llm/browser_transport.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/agent/llm/budget_aware.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/agent/llm/factory.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/agent/llm/openai_client.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/agent/llm/protocol.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/agent/loop.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/agent/loop_detector.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/agent/plugins.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/agent/registry.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/agent/router.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/agent/structured_logging.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/agent/types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/behavioral/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/behavioral/bezier.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/behavioral/dwell.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/behavioral/fitts.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/behavioral/gauss.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/behavioral/keyboard.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/behavioral/mouse.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/behavioral/navigation.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/behavioral/orchestrator.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/behavioral/prng.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/behavioral/qwerty.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/behavioral/scroll.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/behavioral/session_seed.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/behavioral/types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/browser/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/browser/backends/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/browser/backends/cdp_backend.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/browser/backends/patchright_backend.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/browser/backends/playwright_backend.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/browser/backends/selenium_backend.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/browser/cdp.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/browser/cloak_backend.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/browser/cloud.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/browser/config.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/browser/discovery.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/browser/engine.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/browser/fetch.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/browser/injectors/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/browser/injectors/bidi_injector.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/browser/injectors/cdp_injector.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/browser/injectors/page_injector.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/browser/page.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/browser/session.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/browser/shutdown.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/browser/tabs.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/budget/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/budget/cascade.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/budget/client.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/budget/compressor.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/budget/cost_estimator.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/budget/credential_pool.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/budget/governor.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/budget/types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/cli/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/cli/commands.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/cli/interactive.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/cli/script.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/config.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/events/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/events/bus.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/events/types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/interaction/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/interaction/cache.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/interaction/controller.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/interaction/decorator.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/interaction/presets.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/interaction/recovery.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/interaction/snapshot.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/interaction/types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/interaction/vision.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/memory/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/memory/integration.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/memory/store.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/memory/types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/plugins/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/plugins/decorators.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/plugins/hooks.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/py.typed +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/recording/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/recording/persistence.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/recording/recorder.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/recording/replayer.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/recording/report.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/recording/types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/recovery/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/recovery/checkpoint.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/recovery/classifier.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/recovery/coordinator.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/recovery/event_bus.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/recovery/format_validator.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/recovery/reflection.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/recovery/retry_tracker.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/recovery/session_recovery.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/recovery/types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/recovery/watchdogs.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/results/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/results/output.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/results/typed.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/results/types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/results/validation.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/security/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/security/action_redaction.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/security/approval.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/security/credential_vault.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/security/domain_filter.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/security/gate.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/security/injection.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/security/manager.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/security/policy.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/security/redactor.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/security/types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/session/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/session/proxy.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/skills/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/skills/activation.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/skills/markdown.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/skills/registry.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/skills/types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/action_policy.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/captcha.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/challenges/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/challenges/cache.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/challenges/pow.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/challenges/turnstile.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/consistency/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/consistency/dag.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/consistency/derive.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/consistency/errors.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/consistency/inject.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/consistency/inject_delivery.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/consistency/matrix.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/consistency/prng.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/consistency/rule.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/consistency/rules/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/consistency/rules/audio.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/consistency/rules/behavior.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/consistency/rules/fonts.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/consistency/rules/gpu.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/consistency/rules/locale.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/consistency/rules/navigator.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/consistency/rules/screen.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/consistency/rules/user_agent.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/diagnostics.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/ejecta/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/ejecta/audio.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/ejecta/browser_apis.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/ejecta/canvas.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/ejecta/config.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/ejecta/registry.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/ejecta/timing.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/ejecta/types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/ejecta/webrtc.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/fingerprint_scanner.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/fingerprint_score.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/headers.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/human.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/human_config.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/ip_reputation.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/manager.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/profiles/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/profiles/data/linux-chrome-stable.json +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/profiles/data/macos-chrome-stable.json +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/profiles/data/macos-m4-chrome-stable.json +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/profiles/data/windows-chrome-stable.json +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/profiles/host_detect.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/profiles/schema.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/proxy.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/proxy_pool.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/report.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/scoring.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/tls_baselines.json +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/tls_fingerprint.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/user_agent_pool.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/validation/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/validation/checks.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/validation/harness.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/validation/report.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/stealth/validation/suite.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/testing.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/tracing/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/tracing/cost_analytics.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/tracing/flow_logger.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/tracing/middleware.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/tracing/session_db.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/tracing/sinks.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/tracing/types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/verification/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/verification/ax_diff.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/verification/hasher.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/verification/types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/verification/verifier.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/vision/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/vision/cache.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/vision/controller.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/vision/coords.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/vision/factory.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/vision/ocr.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/vision/providers.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/src/super_browser/vision/types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/stress/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/stress/server.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial/conftest.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial/controlled_server.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial/report.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial/scoring.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial/targets.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial/test_controlled_server.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial/test_targets_unit.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial/test_tier1_scanners.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial/test_tier2_vendors.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial/test_tier3_controlled.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/README.md +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/adversarial3/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/adversarial3/backends.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/adversarial3/behavioral_telemetry.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/adversarial3/core.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/adversarial3/engines/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/adversarial3/engines/scoring.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/adversarial3/harness.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/adversarial3/reporters/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/adversarial3/reporters/history.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/adversarial3/reporters/json_reporter.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/adversarial3/reporters/markdown_reporter.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/adversarial3/server.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/adversarial3/vectors/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/adversarial3/vectors/automation.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/adversarial3/vectors/behavioral.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/adversarial3/vectors/controlled.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/adversarial3/vectors/ejector.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/adversarial3/vectors/external.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/adversarial3/vectors/fingerprint.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/adversarial3/vectors/network.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/pytest.ini +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/run.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/tests/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/tests/conftest.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/tests/test_backends.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/tests/test_behavioral_telemetry.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/tests/test_behavioral_telemetry_smoke.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/tests/test_behavioral_vectors.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/tests/test_core.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/tests/test_external.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/tests/test_harness_smoke.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/tests/test_header_ordering.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/tests/test_reporters.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/tests/test_scoring.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/tests/test_server.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/tests/test_superbrowser_backend.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/adversarial_v3/tests/test_vectors.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/conftest.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/discovery/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/discovery/conftest.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/discovery/test_task_01_example_nav.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/discovery/test_task_02_google_search.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/discovery/test_task_03_github_login.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/discovery/test_task_04_amazon_search.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/discovery/test_task_05_google_forms.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/discovery/test_task_06_google_flights.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/discovery/test_task_07_wikipedia_extract.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/discovery/test_task_08_reddit_spa.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/discovery/test_task_09_form_complex.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/discovery/test_task_10_signup_flow.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/e2e/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/e2e/conftest.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/e2e/test_behavioral_realism.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/e2e/test_challenge_detection.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/e2e/test_interaction.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/e2e/test_live_navigation.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/e2e/test_multi_tab.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/e2e/test_navigation.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/e2e/test_session_persistence.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/e2e/test_stealth_overhead.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/e2e_v1_3_journey.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/conftest.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_config_composition.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_engine_backends.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_error_paths.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_facade_smoke.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_full_lifecycle.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_multi_backend.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_performance_smoke.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_playwright_integration.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_public_api.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_session_persistence.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_stealth_abstraction.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_v1100_features.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_v150_features.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_v160_features.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_v170_features.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_v180_features.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_v190_features.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_v191_features.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_v192_features.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_v193_features.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_v194_features.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_v195_features.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_v1_3_features.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/integration/test_v1_4_features.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/pattern_validation.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/stealth_detection/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/stealth_detection/conftest.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/stealth_detection/test_chrome_runtime.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/stealth_detection/test_cli_switches.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/stealth_detection/test_headless_indicators.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/stealth_detection/test_live_sites.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/stealth_detection/test_runtime_enable.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/stealth_detection/test_tls_fingerprint.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/stealth_detection/test_webdriver.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_action_timeout.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_browser_transport.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_controller_rebinding.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_debug_mode.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_default_tooling.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_delegator.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_error_screenshots.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_facade.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_facade_security.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_facade_security_control.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_facade_security_file_tab.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_facade_security_network.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_facade_security_session.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_fail_fast.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_llm.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_llm_budget.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_llm_production.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_llm_streaming.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_loop.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_loop_detector.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_prompt_isolation.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_registry.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_retry_budget.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_streaming.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_structured_logging.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_tab_cap.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_task_02.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_agent/test_types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_behavioral/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_behavioral/test_behavioral.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_behavioral/test_dwell.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_behavioral/test_hardening.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_behavioral/test_human_config_dwell.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_behavioral/test_navigation.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_behavioral/test_orchestrator.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_behavioral/test_session_seed.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_benchmark/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_benchmark/test_efficiency.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_benchmarks/test_browser_benchmark.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_benchmarks/test_stress_real_world.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_browser/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_browser/test_cdp.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_browser/test_cdp_backend.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_browser/test_cloak_backend.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_browser/test_cloak_docs.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_browser/test_cloak_integration.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_browser/test_config.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_browser/test_discovery.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_browser/test_engine_protocol.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_browser/test_fetch.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_browser/test_injectors.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_browser/test_page.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_browser/test_patchright_backend.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_browser/test_playwright_backend.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_browser/test_selenium_backend.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_browser/test_session.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_browser/test_shutdown.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_budget/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_budget/test_cascade.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_budget/test_cascade_governor.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_budget/test_circuit_breaker.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_budget/test_client.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_budget/test_compressor.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_budget/test_cost_estimator.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_budget/test_credential_pool.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_budget/test_governor.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_budget/test_types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_cli/test_interactive.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_cli/test_script.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_cli/test_stealth_check.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_cli/test_stealth_validate.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_cli/test_unified_cli.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_config.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_e2e/test_report_schema.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_e2e/test_trend.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_ejecta/test_audio.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_ejecta/test_batch37_integration.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_ejecta/test_batch38_integration.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_ejecta/test_browser_apis.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_ejecta/test_canvas.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_ejecta/test_integration.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_ejecta/test_timing.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_ejecta/test_webrtc.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_events/test_event_bus.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_events/test_lifecycle_hooks.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_governance_docs.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_interaction/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_interaction/test_cache.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_interaction/test_controller.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_interaction/test_decorator.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_interaction/test_injection.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_interaction/test_page_change.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_interaction/test_presets.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_interaction/test_recovery.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_interaction/test_snapshot.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_interaction/test_types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_interaction/test_vision.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_mcp_entrypoint.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_mcp_permissions.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_mcp_write_tools.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_mcp_write_tools_wave2.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_memory/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_memory/test_cli_config.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_memory/test_integration.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_memory/test_store.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_recording/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_recording/test_persistence.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_recording/test_recorder.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_recording/test_replayer.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_recovery/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_recovery/test_checkpoint.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_recovery/test_classifier.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_recovery/test_coordinator.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_recovery/test_event_bus.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_recovery/test_format_validator.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_recovery/test_reflection.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_recovery/test_retry_tracker.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_recovery/test_session_recovery.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_recovery/test_types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_recovery/test_watchdogs.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_release/test_naming_consistency.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_release/test_smoke_published.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_release/test_verify_artifact.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_results/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_results/test_batch40_integration.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_results/test_categories.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_results/test_output.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_results/test_typed.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_results/test_types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_results/test_validation.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_runtime_correctness/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_runtime_correctness/test_runtime_fixes.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_security/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_security/test_approval.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_security/test_credential_vault.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_security/test_domain_filter.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_security/test_injection.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_security/test_manager.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_security/test_policy.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_security/test_redaction_pipeline.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_security/test_redactor.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_security/test_types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_session/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_session/test_locale.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_session/test_proxy.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_skills/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_skills/test_activation.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_skills/test_integration.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_skills/test_markdown.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_skills/test_registry.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_skills/test_types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_action_policy.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_captcha.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_captcha_resolution.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_challenge_cache.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_challenge_config.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_consistency/test_consistency.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_consistency_inject.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_diagnostics.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_e2e_lifecycle.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_e2e_reporting.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_fingerprint_scanner.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_fingerprint_score.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_headers.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_human.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_human_behavior_v2.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_ip_reputation.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_kasada_detection.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_manager.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_network_stealth_config.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_profiles.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_proxy.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_proxy_pool.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_stealth_bridge.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_tls_fingerprint.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_turnstile_detection.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_user_agent_pool.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_stealth/test_validation.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_tracing/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_tracing/test_cost_analytics.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_tracing/test_flow_logger.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_tracing/test_middleware.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_tracing/test_session_db.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_tracing/test_sinks.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_tracing/test_types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_verification/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_verification/test_ax_diff.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_verification/test_hasher.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_verification/test_types.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_verification/test_verifier.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_vision/__init__.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_vision/test_cache.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_vision/test_controller.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_vision/test_coords.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_vision/test_factory.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_vision/test_ocr.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_vision/test_providers.py +0 -0
- {superbrowser_sdk-2.4.0 → superbrowser_sdk-2.5.0}/tests/test_vision/test_types.py +0 -0
|
@@ -5,6 +5,51 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.5.0] — 2026-06-25
|
|
9
|
+
|
|
10
|
+
### Added — MCP Server P2: Diagnostics Pack
|
|
11
|
+
|
|
12
|
+
An explainability layer for failed reads/rendering. Five new inspect-tier
|
|
13
|
+
tools let an agent inspect browser/page/network evidence when
|
|
14
|
+
`navigate → wait_for → extract_text` returns unexpected content — without
|
|
15
|
+
expanding the action surface. No `--allow-actions`, no action budget, no audit
|
|
16
|
+
entry, no side effects.
|
|
17
|
+
|
|
18
|
+
- `get_console_messages` — buffered browser console messages, filterable by
|
|
19
|
+
level.
|
|
20
|
+
- `get_page_errors` — buffered uncaught page errors with stack traces.
|
|
21
|
+
- `get_network_errors` — requests that failed (status ≥ 400, no response, or
|
|
22
|
+
net error).
|
|
23
|
+
- `list_requests` — all buffered request summaries; returns `request_id` for
|
|
24
|
+
`get_request` follow-up.
|
|
25
|
+
- `get_request` — one request's metadata by `request_id`.
|
|
26
|
+
|
|
27
|
+
New `DiagnosticsBuffer` (`super_browser.agent.diagnostics`): session-wide ring
|
|
28
|
+
buffers for console / page-error / network events, wired into the facade
|
|
29
|
+
lifecycle (`start()` + `_attach_page()`). Survives tab switches. Exposed as
|
|
30
|
+
`SuperBrowser.diagnostics`. Reads are snapshots (non-destructive); bounded
|
|
31
|
+
deques (default 500, via `config.event_buffer_size`).
|
|
32
|
+
|
|
33
|
+
### Design constraints (P2)
|
|
34
|
+
|
|
35
|
+
- Diagnostics entries carry a monotonic `seq`, `timestamp_ms`, and `page_url`.
|
|
36
|
+
- Request records use a stable `request_id` (assigned by the buffer). A URL can
|
|
37
|
+
have multiple requests (redirects, retries), so retrieval is always by
|
|
38
|
+
`request_id`, never by URL.
|
|
39
|
+
- **No response bodies** and **no raw header values** are returned. `get_request`
|
|
40
|
+
exposes `header_names` (keys) only. Console text, page errors, and URLs are
|
|
41
|
+
returned as-is, matching the existing inspect-tool posture.
|
|
42
|
+
- `get_request` returns a structured `{ok: false, reason: "not_found"}` when the
|
|
43
|
+
request was never buffered or evicted; it never raises.
|
|
44
|
+
|
|
45
|
+
### Compatibility notes
|
|
46
|
+
|
|
47
|
+
- The default stdio server now advertises **13 tools** (was 8): the 5
|
|
48
|
+
diagnostics tools are inspect-tier and always advertised. Clients asserting
|
|
49
|
+
on the advertised count should update. This is additive — no tools were
|
|
50
|
+
removed and no refusal strings changed.
|
|
51
|
+
- Action mode advertises **19 tools** (was 14).
|
|
52
|
+
|
|
8
53
|
## [2.4.0] — 2026-06-23
|
|
9
54
|
|
|
10
55
|
### Added — MCP Server P1: Navigation Workflows
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: superbrowser-sdk
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.5.0
|
|
4
4
|
Summary: Anti-detection agent browser SDK — stealth, budget governance, security guardrails, and structured error recovery behind one async facade
|
|
5
5
|
Project-URL: Homepage, https://github.com/Octo-Lex/Super-Browser
|
|
6
6
|
Project-URL: Documentation, https://github.com/Octo-Lex/Super-Browser#readme
|
|
@@ -5,9 +5,10 @@ Super Browser exposes its browser inspection and control surface over the
|
|
|
5
5
|
agents (Claude, Cursor, etc.) can observe and interact with a page without
|
|
6
6
|
scripting Python.
|
|
7
7
|
|
|
8
|
-
The stdio server advertises **
|
|
9
|
-
navigation) — enough to read a URL end-to-end
|
|
10
|
-
|
|
8
|
+
The stdio server advertises **thirteen tools by default** (six inspect + five
|
|
9
|
+
diagnostics + two navigation) — enough to read a URL end-to-end and explain
|
|
10
|
+
why a read failed. When action mode is enabled, it advertises **six additional
|
|
11
|
+
action tools**; every action call is checked by
|
|
11
12
|
`MCPSessionPolicy` and `SecurityManager` before it can reach the browser.
|
|
12
13
|
|
|
13
14
|
See [RFC #178](https://github.com/Octo-Lex/Super-Browser/issues/178) for the
|
|
@@ -30,12 +31,12 @@ python -m patchright install chromium
|
|
|
30
31
|
Either of:
|
|
31
32
|
|
|
32
33
|
```bash
|
|
33
|
-
superbrowser-mcp # default:
|
|
34
|
+
superbrowser-mcp # default: 13 tools (inspect + diagnostics + navigation)
|
|
34
35
|
superbrowser-mcp --allow-actions # 14 tools (adds the action tier)
|
|
35
36
|
python -m super_browser.mcp_server
|
|
36
37
|
```
|
|
37
38
|
|
|
38
|
-
Both start a **stdio** server. The default server advertises
|
|
39
|
+
Both start a **stdio** server. The default server advertises 13 tools and
|
|
39
40
|
recognizes (but refuses) action-tool calls with a structured policy refusal.
|
|
40
41
|
|
|
41
42
|
Action mode can also be enabled via the environment:
|
|
@@ -118,6 +119,21 @@ advertised; the third requires action mode; the fourth is not implemented.
|
|
|
118
119
|
| `extract_text` | `query` (required), `selector` (optional) | Text content, optionally scoped to a CSS selector. | Yes |
|
|
119
120
|
| `screenshot` | `full_page` (optional, default `false`) | Base64 PNG of the viewport or full page. | Yes |
|
|
120
121
|
| `list_tabs` | none | Snapshot of open tabs. | Yes |
|
|
122
|
+
| `get_console_messages` | `level` (optional), `limit` (optional, default 100) | Buffered browser console messages (snapshot, non-destructive). | Yes |
|
|
123
|
+
| `get_page_errors` | `limit` (optional, default 100) | Buffered uncaught page errors with stack traces. | Yes |
|
|
124
|
+
| `get_network_errors` | `url_filter` (optional), `limit` (optional, default 100) | Requests that failed (status ≥ 400, no response, or net error). | Yes |
|
|
125
|
+
| `list_requests` | `url_filter` (optional), `resource_type` (optional), `limit` (optional, default 100) | All buffered request summaries; returns `request_id` for `get_request`. | Yes |
|
|
126
|
+
| `get_request` | `request_id` (required) | One request's metadata (method, url, status, `header_names` — keys only, no values, no body). | Yes |
|
|
127
|
+
|
|
128
|
+
The five diagnostics tools read from a session-wide ring buffer that captures
|
|
129
|
+
console messages, page errors, and network requests via page-event listeners.
|
|
130
|
+
Reads are **snapshots** (non-destructive): the buffer is not cleared on read.
|
|
131
|
+
Diagnostics entries carry a monotonic `seq`, a `timestamp_ms`, and the
|
|
132
|
+
`page_url` at the time of the event. Request records use a stable `request_id`
|
|
133
|
+
(assigned by the buffer); a URL can have multiple requests, so always retrieve
|
|
134
|
+
via `request_id` from `list_requests`, not by URL. **No response bodies and no
|
|
135
|
+
raw header values** are returned — `get_request` exposes `header_names` (keys)
|
|
136
|
+
only.
|
|
121
137
|
|
|
122
138
|
### Navigation tier (always advertised)
|
|
123
139
|
|
|
@@ -142,6 +158,24 @@ navigate → wait_for → observe / extract_text / screenshot
|
|
|
142
158
|
|
|
143
159
|
This is the default-mode loop an agent uses to read a page.
|
|
144
160
|
|
|
161
|
+
#### Debugging workflow
|
|
162
|
+
|
|
163
|
+
When a read returns unexpected or empty content, the diagnostics tools explain
|
|
164
|
+
why — without expanding the action surface:
|
|
165
|
+
|
|
166
|
+
```text
|
|
167
|
+
navigate → wait_for → extract_text / observe
|
|
168
|
+
↓ (unexpected / empty / errored)
|
|
169
|
+
get_console_messages → get_page_errors → get_network_errors
|
|
170
|
+
↓ (inspect the evidence)
|
|
171
|
+
list_requests → get_request(request_id=...) (drill into one request)
|
|
172
|
+
↓
|
|
173
|
+
adjust selector / report failure / retry
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Diagnostics are inspect-tier: no `--allow-actions`, no action budget, no audit
|
|
177
|
+
entry, no side effects.
|
|
178
|
+
|
|
145
179
|
### Action tier (advertised when action mode is enabled)
|
|
146
180
|
|
|
147
181
|
| Tool | Args | Security level |
|
|
@@ -193,7 +227,7 @@ restricts the survivors.
|
|
|
193
227
|
|
|
194
228
|
The default server behavior partitions the surface by risk:
|
|
195
229
|
|
|
196
|
-
- **`list_tools()`** advertises only the Inspect + Navigation tiers (
|
|
230
|
+
- **`list_tools()`** advertises only the Inspect + Navigation tiers (13 tools).
|
|
197
231
|
- **`call_tool()`** still recognizes action-tool names and returns a structured
|
|
198
232
|
policy refusal (`refusal.reason = "actions are disabled"`), not an "Unknown
|
|
199
233
|
tool" error.
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "superbrowser-sdk"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.5.0"
|
|
8
8
|
description = "Anti-detection agent browser SDK — stealth, budget governance, security guardrails, and structured error recovery behind one async facade"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "Apache-2.0" }
|
|
@@ -6,7 +6,7 @@ from super_browser.agent.types import StreamEvent as StreamEvent # noqa: F401
|
|
|
6
6
|
from super_browser.config import Config as Config # noqa: F401
|
|
7
7
|
from super_browser.results.types import ActionResult as ActionResult # noqa: F401
|
|
8
8
|
|
|
9
|
-
__version__ = "2.
|
|
9
|
+
__version__ = "2.5.0"
|
|
10
10
|
|
|
11
11
|
__all__ = [
|
|
12
12
|
"SuperBrowser",
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
"""Session-wide diagnostics capture for page events.
|
|
2
|
+
|
|
3
|
+
Wires Playwright/Patchright page-event listeners (console, pageerror, request,
|
|
4
|
+
response) into bounded ring buffers that survive tab switches. Read semantics
|
|
5
|
+
are snapshots (non-destructive): callers get list-copies; the bounded deques
|
|
6
|
+
naturally drop the oldest entries.
|
|
7
|
+
|
|
8
|
+
Designed for the MCP diagnostics tool pack — an inspect-tier explainability
|
|
9
|
+
layer for failed reads/rendering. No action gate, no side effects, no response
|
|
10
|
+
bodies, no raw header values (header keys only).
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import time
|
|
16
|
+
import weakref
|
|
17
|
+
from collections import deque
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
_DEFAULT_MAX_SIZE = 500
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _safe_call(obj: Any, attr: str, *, default: Any = None) -> Any:
|
|
24
|
+
"""Call a sync attr/method on a Playwright object, swallowing errors.
|
|
25
|
+
|
|
26
|
+
Many Playwright surfaces expose properties that are sometimes methods,
|
|
27
|
+
sometimes attributes, and can raise if the underlying handle is gone.
|
|
28
|
+
Used only in the sync event handlers.
|
|
29
|
+
"""
|
|
30
|
+
fn = getattr(obj, attr, None)
|
|
31
|
+
if fn is None:
|
|
32
|
+
return default
|
|
33
|
+
try:
|
|
34
|
+
return fn() if callable(fn) else fn
|
|
35
|
+
except Exception: # noqa: BLE001
|
|
36
|
+
return default
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# Internal record keys that are never exposed in public snapshots/details.
|
|
40
|
+
_INTERNAL_KEYS = frozenset({"_request_obj_id"})
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _strip(record: dict) -> dict:
|
|
44
|
+
"""Return a copy of ``record`` with internal plumbing keys removed."""
|
|
45
|
+
return {k: v for k, v in record.items() if k not in _INTERNAL_KEYS}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class DiagnosticsBuffer:
|
|
49
|
+
"""Session-wide ring buffers for page diagnostic events.
|
|
50
|
+
|
|
51
|
+
Three bounded deques (console / errors / requests) plus a monotonic seq
|
|
52
|
+
counter. Reads are snapshots (non-destructive). ``attach()`` is idempotent
|
|
53
|
+
by raw-page identity (tracked via a ``WeakSet``), so it is safe to call
|
|
54
|
+
across repeated tab switches on the same underlying page.
|
|
55
|
+
|
|
56
|
+
Event handlers are intentionally sync-safe — they never ``await`` inside
|
|
57
|
+
``page.on(...)`` callbacks. All Playwright/Patchright properties read in
|
|
58
|
+
the handlers (``ConsoleMessage.type/.text``, ``Request.method/.url/...``,
|
|
59
|
+
``Request.failure``, ``Request.timing``) are sync.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def __init__(self, max_size: int = _DEFAULT_MAX_SIZE) -> None:
|
|
63
|
+
self.max_size = max_size
|
|
64
|
+
self._console: deque[dict] = deque(maxlen=max_size)
|
|
65
|
+
self._errors: deque[dict] = deque(maxlen=max_size)
|
|
66
|
+
self._requests: deque[dict] = deque(maxlen=max_size)
|
|
67
|
+
self._seq = 0
|
|
68
|
+
self._request_counter = 0
|
|
69
|
+
# request_id -> record, for O(1) request_detail lookup.
|
|
70
|
+
self._req_index: dict[str, dict] = {}
|
|
71
|
+
# id(Playwright Request obj) -> request_id, for response correlation
|
|
72
|
+
# via response.request back-reference. (Request objects are hashable by
|
|
73
|
+
# identity; we key by id() to avoid holding strong refs in the dict.)
|
|
74
|
+
self._req_obj_index: dict[int, str] = {}
|
|
75
|
+
# Idempotent-attach tracking by weak page identity. A WeakSet (rather
|
|
76
|
+
# than a set[int] of id() values) ensures a page that is GC'd drops
|
|
77
|
+
# out automatically, eliminating the id()-reuse window in which a
|
|
78
|
+
# newly-allocated page reusing a freed page's address would be wrongly
|
|
79
|
+
# treated as already-attached.
|
|
80
|
+
self._attached: "weakref.WeakSet[Any]" = weakref.WeakSet()
|
|
81
|
+
|
|
82
|
+
# --- internal helpers ---
|
|
83
|
+
|
|
84
|
+
def _next_seq(self) -> int:
|
|
85
|
+
self._seq += 1
|
|
86
|
+
return self._seq
|
|
87
|
+
|
|
88
|
+
@staticmethod
|
|
89
|
+
def _now_ms() -> float:
|
|
90
|
+
return time.time() * 1000.0
|
|
91
|
+
|
|
92
|
+
def _on_console(self, raw_page: Any, message: Any) -> None:
|
|
93
|
+
self._console.append({
|
|
94
|
+
"seq": self._next_seq(),
|
|
95
|
+
"timestamp_ms": self._now_ms(),
|
|
96
|
+
"type": getattr(message, "type", None),
|
|
97
|
+
"text": getattr(message, "text", None),
|
|
98
|
+
"page_url": getattr(raw_page, "url", None),
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
# --- attach / detach ---
|
|
102
|
+
|
|
103
|
+
def attach(self, raw_page: Any) -> None:
|
|
104
|
+
"""Wire console/pageerror/request/response listeners onto ``raw_page``.
|
|
105
|
+
|
|
106
|
+
Idempotent by weak page identity: a second call with the same page
|
|
107
|
+
object is a no-op. The weak reference means a page that is GC'd
|
|
108
|
+
drops out of the tracking set automatically, so a later page that
|
|
109
|
+
happens to reuse a freed page's memory address is NOT wrongly treated
|
|
110
|
+
as already-attached. Safe across repeated tab switches.
|
|
111
|
+
"""
|
|
112
|
+
if raw_page in self._attached:
|
|
113
|
+
return
|
|
114
|
+
self._attached.add(raw_page)
|
|
115
|
+
|
|
116
|
+
raw_page.on("console", lambda msg: self._on_console(raw_page, msg))
|
|
117
|
+
raw_page.on("pageerror", lambda err: self._on_pageerror(raw_page, err))
|
|
118
|
+
raw_page.on("request", lambda req: self._on_request(raw_page, req))
|
|
119
|
+
raw_page.on("response", lambda resp: self._on_response(raw_page, resp))
|
|
120
|
+
|
|
121
|
+
def detach(self, raw_page: Any) -> None:
|
|
122
|
+
"""Remove a page from the attached set so it can be re-attached.
|
|
123
|
+
|
|
124
|
+
Note: Playwright/Patchright does not expose listener removal on the
|
|
125
|
+
Page object, so this only clears the idempotency guard. Listeners on
|
|
126
|
+
a page that is being closed are harmless (the page is GC'd, and the
|
|
127
|
+
WeakSet entry drops out automatically).
|
|
128
|
+
"""
|
|
129
|
+
self._attached.discard(raw_page)
|
|
130
|
+
|
|
131
|
+
# --- placeholders for later tasks ---
|
|
132
|
+
|
|
133
|
+
def _on_pageerror(self, raw_page: Any, error: Any) -> None:
|
|
134
|
+
# Real page errors may carry only .message; .name/.stack are optional.
|
|
135
|
+
# getattr-with-default keeps the handler robust without swallowing the
|
|
136
|
+
# event on a missing attribute.
|
|
137
|
+
self._errors.append({
|
|
138
|
+
"seq": self._next_seq(),
|
|
139
|
+
"timestamp_ms": self._now_ms(),
|
|
140
|
+
"message": getattr(error, "message", str(error)),
|
|
141
|
+
"name": getattr(error, "name", None),
|
|
142
|
+
"stack": getattr(error, "stack", None),
|
|
143
|
+
"page_url": getattr(raw_page, "url", None),
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
def _on_request(self, raw_page: Any, request: Any) -> None:
|
|
147
|
+
# Assign a stable request_id and capture the request-side fields.
|
|
148
|
+
# Response-side fields (status/status_text/ok) are filled in by
|
|
149
|
+
# _on_response via the correlation index. Failure/header enrichment is
|
|
150
|
+
# captured here (sync) since the Request object is available.
|
|
151
|
+
self._request_counter += 1
|
|
152
|
+
request_id = f"r-{self._request_counter}"
|
|
153
|
+
seq = self._next_seq()
|
|
154
|
+
|
|
155
|
+
# redirected_from: a Playwright Request or None. Correlate to our
|
|
156
|
+
# request_id if we've seen it; else record None.
|
|
157
|
+
redirected_from_obj = _safe_call(request, "redirected_from", default=None)
|
|
158
|
+
redirected_from_id = (
|
|
159
|
+
self._req_obj_index.get(id(redirected_from_obj))
|
|
160
|
+
if redirected_from_obj is not None else None
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
# Failure text: Request.failure() returns a string or None for net errors.
|
|
164
|
+
failure_text = _safe_call(request, "failure", default=None)
|
|
165
|
+
|
|
166
|
+
# Header NAMES only (keys), never values — sensitivity control.
|
|
167
|
+
headers = _safe_call(request, "headers", default={}) or {}
|
|
168
|
+
try:
|
|
169
|
+
header_names = list(headers.keys())
|
|
170
|
+
except Exception: # noqa: BLE001
|
|
171
|
+
header_names = []
|
|
172
|
+
|
|
173
|
+
record = {
|
|
174
|
+
"seq": seq,
|
|
175
|
+
"request_id": request_id,
|
|
176
|
+
"timestamp_ms": self._now_ms(),
|
|
177
|
+
"method": getattr(request, "method", None),
|
|
178
|
+
"url": getattr(request, "url", None),
|
|
179
|
+
"resource_type": getattr(request, "resource_type", None),
|
|
180
|
+
"is_navigation": bool(_safe_call(request, "is_navigation_request", default=False)),
|
|
181
|
+
"redirected_from": redirected_from_id,
|
|
182
|
+
"status": None,
|
|
183
|
+
"status_text": None,
|
|
184
|
+
"ok": None,
|
|
185
|
+
"failed": failure_text is not None,
|
|
186
|
+
"failure_text": failure_text,
|
|
187
|
+
"header_names": header_names,
|
|
188
|
+
"page_url": getattr(raw_page, "url", None),
|
|
189
|
+
# Internal plumbing key — stripped from public output by _strip().
|
|
190
|
+
# Stored so the eviction path can prune _req_obj_index.
|
|
191
|
+
"_request_obj_id": id(request),
|
|
192
|
+
}
|
|
193
|
+
# Prune both indexes BEFORE appending if this append will evict the
|
|
194
|
+
# oldest deque entry. Without this, _req_index/_req_obj_index grow
|
|
195
|
+
# unbounded for the session and request_detail() returns records that
|
|
196
|
+
# list_requests() can no longer see (eviction inconsistency).
|
|
197
|
+
if len(self._requests) == self.max_size:
|
|
198
|
+
evicted = self._requests[0]
|
|
199
|
+
evicted_rid = evicted.get("request_id")
|
|
200
|
+
if evicted_rid is not None:
|
|
201
|
+
self._req_index.pop(evicted_rid, None)
|
|
202
|
+
evicted_oid = evicted.get("_request_obj_id")
|
|
203
|
+
if evicted_oid is not None:
|
|
204
|
+
self._req_obj_index.pop(evicted_oid, None)
|
|
205
|
+
self._requests.append(record)
|
|
206
|
+
self._req_index[request_id] = record
|
|
207
|
+
self._req_obj_index[id(request)] = request_id
|
|
208
|
+
|
|
209
|
+
def _on_response(self, raw_page: Any, response: Any) -> None:
|
|
210
|
+
# Correlate back to the originating request via response.request, then
|
|
211
|
+
# enrich the record with status/status_text/ok. If we never buffered
|
|
212
|
+
# the request (e.g. started mid-session), silently drop.
|
|
213
|
+
origin = getattr(response, "request", None)
|
|
214
|
+
if origin is None:
|
|
215
|
+
return
|
|
216
|
+
request_id = self._req_obj_index.get(id(origin))
|
|
217
|
+
if request_id is None:
|
|
218
|
+
return
|
|
219
|
+
record = self._req_index.get(request_id)
|
|
220
|
+
if record is None:
|
|
221
|
+
return
|
|
222
|
+
status = _safe_call(response, "status", default=None)
|
|
223
|
+
record["status"] = status
|
|
224
|
+
record["status_text"] = _safe_call(response, "status_text", default=None)
|
|
225
|
+
record["ok"] = _safe_call(response, "ok", default=None)
|
|
226
|
+
# A response with status>=400 is a failure even if the request had no
|
|
227
|
+
# net-level failure_text.
|
|
228
|
+
if status is not None and status >= 400:
|
|
229
|
+
record["failed"] = True
|
|
230
|
+
|
|
231
|
+
# --- snapshot accessors ---
|
|
232
|
+
|
|
233
|
+
def last_seq(self) -> int:
|
|
234
|
+
"""The highest seq assigned so far (0 before any event)."""
|
|
235
|
+
return self._seq
|
|
236
|
+
|
|
237
|
+
def console_messages(
|
|
238
|
+
self, *, level: str | None = None, limit: int = 100,
|
|
239
|
+
) -> list[dict]:
|
|
240
|
+
"""Snapshot of console entries (newest-last), optionally filtered by level."""
|
|
241
|
+
items = list(self._console)
|
|
242
|
+
if level is not None:
|
|
243
|
+
items = [e for e in items if e.get("type") == level]
|
|
244
|
+
return items[-limit:] if limit is not None else items
|
|
245
|
+
|
|
246
|
+
def page_errors(self, *, limit: int = 100) -> list[dict]:
|
|
247
|
+
"""Snapshot of uncaught page errors (newest-last)."""
|
|
248
|
+
items = list(self._errors)
|
|
249
|
+
return items[-limit:] if limit is not None else items
|
|
250
|
+
|
|
251
|
+
def requests(
|
|
252
|
+
self,
|
|
253
|
+
*,
|
|
254
|
+
url_filter: str | None = None,
|
|
255
|
+
resource_type: str | None = None,
|
|
256
|
+
failed_only: bool = False,
|
|
257
|
+
limit: int = 100,
|
|
258
|
+
) -> list[dict]:
|
|
259
|
+
"""Snapshot of request records (newest-last).
|
|
260
|
+
|
|
261
|
+
- ``url_filter``: substring match against the request URL.
|
|
262
|
+
- ``resource_type``: exact match (e.g. "fetch", "xhr", "image").
|
|
263
|
+
- ``failed_only``: requests where failed OR status>=400 OR status is None.
|
|
264
|
+
- ``limit``: return the last N (None = all).
|
|
265
|
+
"""
|
|
266
|
+
items = [_strip(r) for r in self._requests]
|
|
267
|
+
if url_filter is not None:
|
|
268
|
+
items = [r for r in items if r.get("url") and url_filter in r["url"]]
|
|
269
|
+
if resource_type is not None:
|
|
270
|
+
items = [r for r in items if r.get("resource_type") == resource_type]
|
|
271
|
+
if failed_only:
|
|
272
|
+
items = [
|
|
273
|
+
r for r in items
|
|
274
|
+
if r.get("failed") or (r.get("status") is not None and r["status"] >= 400)
|
|
275
|
+
or r.get("status") is None
|
|
276
|
+
]
|
|
277
|
+
return items[-limit:] if limit is not None else items
|
|
278
|
+
|
|
279
|
+
def request_detail(self, request_id: str) -> dict | None:
|
|
280
|
+
"""One record by request_id, or None if not buffered/evicted.
|
|
281
|
+
|
|
282
|
+
Returns the live record (reflects response enrichment that arrived
|
|
283
|
+
after the request event). The MCP tool layer turns None into a
|
|
284
|
+
structured ``{ok: false, reason: "not_found"}`` response.
|
|
285
|
+
"""
|
|
286
|
+
rec = self._req_index.get(request_id)
|
|
287
|
+
return _strip(rec) if rec is not None else None
|
|
@@ -80,9 +80,33 @@ class SuperBrowser:
|
|
|
80
80
|
self._recorder: Any = None # Optional[SessionRecorder]
|
|
81
81
|
self._event_bus: Any = None # Optional[EventBus]
|
|
82
82
|
self._memory_store: Optional[MemoryStore] = None # Set via enable_memory()
|
|
83
|
+
# Diagnostics: session-wide page-event capture (console/errors/network).
|
|
84
|
+
# Attached to every raw page via start()/_attach_page(); survives tab
|
|
85
|
+
# switches because listener closures bind to the raw Page, not PageHandle.
|
|
86
|
+
from super_browser.agent.diagnostics import DiagnosticsBuffer
|
|
87
|
+
buf_size = getattr(self._config, "event_buffer_size", 500) if self._config else 500
|
|
88
|
+
self._diagnostics = DiagnosticsBuffer(max_size=buf_size)
|
|
83
89
|
|
|
84
90
|
# -- Lifecycle --
|
|
85
91
|
|
|
92
|
+
@property
|
|
93
|
+
def diagnostics(self) -> Any:
|
|
94
|
+
"""Session-wide diagnostics buffer (console/page-errors/network).
|
|
95
|
+
|
|
96
|
+
Exposed for the MCP diagnostics tools and direct SDK consumers. Reads
|
|
97
|
+
are snapshots (non-destructive); see :class:`DiagnosticsBuffer`.
|
|
98
|
+
"""
|
|
99
|
+
return self._diagnostics
|
|
100
|
+
|
|
101
|
+
def _attach_diagnostics(self, raw_page: Any) -> None:
|
|
102
|
+
"""Wire diagnostics listeners onto a raw page.
|
|
103
|
+
|
|
104
|
+
Called from :meth:`start` (initial page) and :meth:`_attach_page`
|
|
105
|
+
(tab open/switch). Idempotent by raw-page identity inside the buffer,
|
|
106
|
+
so it is safe to call on every tab switch.
|
|
107
|
+
"""
|
|
108
|
+
self._diagnostics.attach(raw_page)
|
|
109
|
+
|
|
86
110
|
async def start(self) -> None:
|
|
87
111
|
cfg = self._config
|
|
88
112
|
# -- Determine backend & session config from composition root --
|
|
@@ -99,6 +123,8 @@ class SuperBrowser:
|
|
|
99
123
|
await self._session.start()
|
|
100
124
|
self._page = await self._session.new_page()
|
|
101
125
|
self._controller = MultimodalController(self._page, self._page.engine_page.cdp)
|
|
126
|
+
# Wire diagnostics listeners onto the initial page.
|
|
127
|
+
self._attach_diagnostics(self._page.backend_page)
|
|
102
128
|
self._running = True
|
|
103
129
|
self._register_builtin_tools()
|
|
104
130
|
self._configure_verification()
|
|
@@ -425,6 +451,8 @@ class SuperBrowser:
|
|
|
425
451
|
cdp = CDPBridge(cdp_session, _SC())
|
|
426
452
|
self._page = PageHandle(page_obj, cdp)
|
|
427
453
|
self._controller = MultimodalController(self._page, self._page.engine_page.cdp)
|
|
454
|
+
# Wire diagnostics listeners onto the new tab/switched page.
|
|
455
|
+
self._attach_diagnostics(self._page.backend_page)
|
|
428
456
|
|
|
429
457
|
# -- Multi-Tab --
|
|
430
458
|
|
|
@@ -242,8 +242,75 @@ _PHASE2B_WAVE2_TOOL_NAMES = frozenset(t.name for t in PHASE2B_WAVE2_TOOLS)
|
|
|
242
242
|
# redaction, domain policy when configured) but NOT action-gated and does NOT
|
|
243
243
|
# consume the action budget.
|
|
244
244
|
|
|
245
|
-
#
|
|
246
|
-
|
|
245
|
+
# Diagnostics inspect-tier tools (P2): explainability layer for failed
|
|
246
|
+
# reads/rendering. Read-only snapshots of console/page-error/network buffers.
|
|
247
|
+
# No action gate, no audit, no budget. No response bodies, no raw header
|
|
248
|
+
# values (header NAMES only).
|
|
249
|
+
DIAGNOSTICS_TOOLS: list[types.Tool] = [
|
|
250
|
+
types.Tool(
|
|
251
|
+
name="get_console_messages",
|
|
252
|
+
description="Return buffered browser console messages (snapshot, non-destructive). Inspect-tier.",
|
|
253
|
+
inputSchema={
|
|
254
|
+
"type": "object",
|
|
255
|
+
"properties": {
|
|
256
|
+
"level": {"type": "string", "description": "Filter by console type: log, error, warning, info, debug."},
|
|
257
|
+
"limit": {"type": "integer", "default": 100, "description": "Return the last N entries."},
|
|
258
|
+
},
|
|
259
|
+
"required": [],
|
|
260
|
+
},
|
|
261
|
+
),
|
|
262
|
+
types.Tool(
|
|
263
|
+
name="get_page_errors",
|
|
264
|
+
description="Return buffered uncaught page errors with stack traces (snapshot). Inspect-tier.",
|
|
265
|
+
inputSchema={
|
|
266
|
+
"type": "object",
|
|
267
|
+
"properties": {
|
|
268
|
+
"limit": {"type": "integer", "default": 100, "description": "Return the last N entries."},
|
|
269
|
+
},
|
|
270
|
+
"required": [],
|
|
271
|
+
},
|
|
272
|
+
),
|
|
273
|
+
types.Tool(
|
|
274
|
+
name="get_network_errors",
|
|
275
|
+
description="Return buffered network requests that failed (status>=400, no response, or net error). Inspect-tier.",
|
|
276
|
+
inputSchema={
|
|
277
|
+
"type": "object",
|
|
278
|
+
"properties": {
|
|
279
|
+
"url_filter": {"type": "string", "description": "Substring filter on URL."},
|
|
280
|
+
"limit": {"type": "integer", "default": 100, "description": "Return the last N entries."},
|
|
281
|
+
},
|
|
282
|
+
"required": [],
|
|
283
|
+
},
|
|
284
|
+
),
|
|
285
|
+
types.Tool(
|
|
286
|
+
name="list_requests",
|
|
287
|
+
description="Return buffered network request summaries (request_id, method, url, status). Use request_id with get_request for detail. Inspect-tier.",
|
|
288
|
+
inputSchema={
|
|
289
|
+
"type": "object",
|
|
290
|
+
"properties": {
|
|
291
|
+
"url_filter": {"type": "string", "description": "Substring filter on URL."},
|
|
292
|
+
"resource_type": {"type": "string", "description": "Exact resource type: fetch, xhr, document, image, ..."},
|
|
293
|
+
"limit": {"type": "integer", "default": 100, "description": "Return the last N entries."},
|
|
294
|
+
},
|
|
295
|
+
"required": [],
|
|
296
|
+
},
|
|
297
|
+
),
|
|
298
|
+
types.Tool(
|
|
299
|
+
name="get_request",
|
|
300
|
+
description="Return one network request's metadata by request_id (from list_requests). No response body, header names only. Inspect-tier.",
|
|
301
|
+
inputSchema={
|
|
302
|
+
"type": "object",
|
|
303
|
+
"properties": {
|
|
304
|
+
"request_id": {"type": "string", "description": "The request_id returned by list_requests."},
|
|
305
|
+
},
|
|
306
|
+
"required": ["request_id"],
|
|
307
|
+
},
|
|
308
|
+
),
|
|
309
|
+
]
|
|
310
|
+
_DIAGNOSTICS_TOOL_NAMES = frozenset(t.name for t in DIAGNOSTICS_TOOLS)
|
|
311
|
+
|
|
312
|
+
# Inspect-tier tools: the existing read-only set + diagnostics.
|
|
313
|
+
INSPECT_TOOLS: list[types.Tool] = [*PHASE1_TOOLS, *DIAGNOSTICS_TOOLS]
|
|
247
314
|
INSPECT_TOOL_NAMES = frozenset(t.name for t in INSPECT_TOOLS)
|
|
248
315
|
|
|
249
316
|
# Navigation-tier tools: page acquisition (navigate) + read condition (wait_for).
|
|
@@ -1057,6 +1124,51 @@ class ToolDispatcher:
|
|
|
1057
1124
|
result = await self.runtime.current_url()
|
|
1058
1125
|
return _text_content({"ok": True, **result})
|
|
1059
1126
|
|
|
1127
|
+
# --- Diagnostics handlers (inspect-tier; read from sb.diagnostics) ---
|
|
1128
|
+
|
|
1129
|
+
async def _tool_get_console_messages(self, arguments: dict[str, Any]) -> list[types.TextContent]:
|
|
1130
|
+
sb = await self.runtime.get_browser()
|
|
1131
|
+
level = arguments.get("level")
|
|
1132
|
+
limit = arguments.get("limit", 100)
|
|
1133
|
+
messages = sb.diagnostics.console_messages(level=level, limit=limit)
|
|
1134
|
+
return _text_content({"ok": True, "messages": messages, "count": len(messages)})
|
|
1135
|
+
|
|
1136
|
+
async def _tool_get_page_errors(self, arguments: dict[str, Any]) -> list[types.TextContent]:
|
|
1137
|
+
sb = await self.runtime.get_browser()
|
|
1138
|
+
limit = arguments.get("limit", 100)
|
|
1139
|
+
errors = sb.diagnostics.page_errors(limit=limit)
|
|
1140
|
+
return _text_content({"ok": True, "errors": errors, "count": len(errors)})
|
|
1141
|
+
|
|
1142
|
+
async def _tool_get_network_errors(self, arguments: dict[str, Any]) -> list[types.TextContent]:
|
|
1143
|
+
sb = await self.runtime.get_browser()
|
|
1144
|
+
url_filter = arguments.get("url_filter")
|
|
1145
|
+
limit = arguments.get("limit", 100)
|
|
1146
|
+
reqs = sb.diagnostics.requests(url_filter=url_filter, failed_only=True, limit=limit)
|
|
1147
|
+
return _text_content({"ok": True, "requests": reqs, "count": len(reqs)})
|
|
1148
|
+
|
|
1149
|
+
async def _tool_list_requests(self, arguments: dict[str, Any]) -> list[types.TextContent]:
|
|
1150
|
+
sb = await self.runtime.get_browser()
|
|
1151
|
+
url_filter = arguments.get("url_filter")
|
|
1152
|
+
resource_type = arguments.get("resource_type")
|
|
1153
|
+
limit = arguments.get("limit", 100)
|
|
1154
|
+
reqs = sb.diagnostics.requests(
|
|
1155
|
+
url_filter=url_filter, resource_type=resource_type, failed_only=False, limit=limit,
|
|
1156
|
+
)
|
|
1157
|
+
return _text_content({"ok": True, "requests": reqs, "count": len(reqs)})
|
|
1158
|
+
|
|
1159
|
+
async def _tool_get_request(self, arguments: dict[str, Any]) -> list[types.TextContent]:
|
|
1160
|
+
request_id = arguments.get("request_id")
|
|
1161
|
+
if not isinstance(request_id, str) or not request_id.strip():
|
|
1162
|
+
return _error_content(
|
|
1163
|
+
"'request_id' is required and must be a non-empty string",
|
|
1164
|
+
kind="invalid_arguments",
|
|
1165
|
+
)
|
|
1166
|
+
sb = await self.runtime.get_browser()
|
|
1167
|
+
detail = sb.diagnostics.request_detail(request_id)
|
|
1168
|
+
if detail is None:
|
|
1169
|
+
return _text_content({"ok": False, "reason": "not_found", "request_id": request_id})
|
|
1170
|
+
return _text_content({"ok": True, "request": detail})
|
|
1171
|
+
|
|
1060
1172
|
async def _tool_observe(self, arguments: dict[str, Any]) -> list[types.TextContent]:
|
|
1061
1173
|
_require_no_args(arguments)
|
|
1062
1174
|
sb = await self.runtime.get_browser()
|