patchpal 0.23.1__tar.gz → 0.24.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.
- {patchpal-0.23.1/patchpal.egg-info → patchpal-0.24.0}/PKG-INFO +6 -1
- {patchpal-0.23.1 → patchpal-0.24.0}/README.md +2 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/__init__.py +1 -1
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/agent/function_calling.py +86 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/cli/interactive.py +45 -1
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/config.py +10 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/permissions.py +17 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/tools/__init__.py +52 -0
- patchpal-0.24.0/patchpal/tools/browser_tools.py +1171 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/tools/definitions.py +275 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/tools/web_tools.py +59 -16
- {patchpal-0.23.1 → patchpal-0.24.0/patchpal.egg-info}/PKG-INFO +6 -1
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal.egg-info/SOURCES.txt +1 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal.egg-info/requires.txt +4 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/pyproject.toml +4 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/tests/test_agent.py +40 -6
- {patchpal-0.23.1 → patchpal-0.24.0}/LICENSE +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/MANIFEST.in +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/agent/__init__.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/agent/bedrock_profile_utils.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/agent/react.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/cli/__init__.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/cli/autopilot.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/cli/mcp.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/cli/sandbox.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/cli/streaming.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/context.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/prompts/react_prompt.md +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/prompts/system_prompt.md +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/skills.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/tools/audit.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/tools/code_analysis.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/tools/common.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/tools/file_reading.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/tools/file_writing.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/tools/find_tool.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/tools/grep_tool.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/tools/image_handler.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/tools/mcp.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/tools/repo_map.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/tools/shell_tools.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/tools/todo_tools.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/tools/tool_schema.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal/tools/user_interaction.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal.egg-info/dependency_links.txt +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal.egg-info/entry_points.txt +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/patchpal.egg-info/top_level.txt +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/setup.cfg +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/tests/test_cli.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/tests/test_config_dynamic.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/tests/test_context.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/tests/test_custom_tools.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/tests/test_enabled_tools.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/tests/test_find_tool.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/tests/test_guardrails.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/tests/test_image_blocking.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/tests/test_maximum_security.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/tests/test_mcp_config.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/tests/test_memory.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/tests/test_memory_locations.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/tests/test_operational_safety.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/tests/test_optional_tools.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/tests/test_permissions.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/tests/test_react.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/tests/test_reasoning_content.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/tests/test_repo_map.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/tests/test_simplified_prompt.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/tests/test_skills.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/tests/test_streaming.py +0 -0
- {patchpal-0.23.1 → patchpal-0.24.0}/tests/test_tools.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: patchpal
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.24.0
|
|
4
4
|
Summary: An agentic coding and automation assistant, supporting both local and cloud LLMs
|
|
5
5
|
Author: PatchPal Contributors
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -38,6 +38,9 @@ Requires-Dist: ruff==0.14.13; extra == "dev"
|
|
|
38
38
|
Requires-Dist: pre-commit>=3.0.0; extra == "dev"
|
|
39
39
|
Provides-Extra: mcp
|
|
40
40
|
Requires-Dist: mcp>=0.9.0; extra == "mcp"
|
|
41
|
+
Provides-Extra: browser
|
|
42
|
+
Requires-Dist: playwright>=1.40.0; extra == "browser"
|
|
43
|
+
Requires-Dist: nest-asyncio>=1.5.0; extra == "browser"
|
|
41
44
|
Provides-Extra: docs
|
|
42
45
|
Requires-Dist: mkdocs<2.0,>=1.5.0; extra == "docs"
|
|
43
46
|
Requires-Dist: mkdocs-material>=9.5.0; extra == "docs"
|
|
@@ -62,6 +65,7 @@ Most agent frameworks are [built in TypeScript](https://news.ycombinator.com/ite
|
|
|
62
65
|
- [Sandbox Mode](https://amaiya.github.io/patchpal/usage/sandbox/) for secure container isolation
|
|
63
66
|
- [Python SDK](https://amaiya.github.io/patchpal/usage/python-api/) for flexibility and extensibility
|
|
64
67
|
- [Built-In](https://amaiya.github.io/patchpal/features/tools/) and [Custom Tools](https://amaiya.github.io/patchpal/features/custom-tools/)
|
|
68
|
+
- [Browser Automation](https://amaiya.github.io/patchpal/features/tools/#browser-automation-14-tools-optional) for interactive web tasks, form filling, and JavaScript-heavy sites
|
|
65
69
|
- [Skills System](https://amaiya.github.io/patchpal/features/skills/) and [MCP Integration](https://amaiya.github.io/patchpal/features/mcp/)
|
|
66
70
|
- [Autopilot Mode](https://amaiya.github.io/patchpal/usage/autopilot/) using [Ralph Wiggum loops](https://github.com/amaiya/patchpal/tree/main/examples/ralph/)
|
|
67
71
|
- [Project Memory](https://amaiya.github.io/patchpal/features/memory/) automatically loads project context from `MEMORY.md` (repository root or `~/.patchpal/repos/<repo-name>/MEMORY.md`) at startup.
|
|
@@ -108,6 +112,7 @@ docker run -it --rm \
|
|
|
108
112
|
|
|
109
113
|
## Setup
|
|
110
114
|
0. **Install**: `pip install patchpal`
|
|
115
|
+
- **Optional**: For browser automation (13 additional tools): `pip install patchpal[browser] && python -m playwright install chromium`
|
|
111
116
|
1. **Get an API key or a Local LLM Engine**:
|
|
112
117
|
- **[Cloud]** For Anthropic models (default): Sign up at https://console.anthropic.com/
|
|
113
118
|
- **[Cloud]** For OpenAI models: Get a key from https://platform.openai.com/
|
|
@@ -14,6 +14,7 @@ Most agent frameworks are [built in TypeScript](https://news.ycombinator.com/ite
|
|
|
14
14
|
- [Sandbox Mode](https://amaiya.github.io/patchpal/usage/sandbox/) for secure container isolation
|
|
15
15
|
- [Python SDK](https://amaiya.github.io/patchpal/usage/python-api/) for flexibility and extensibility
|
|
16
16
|
- [Built-In](https://amaiya.github.io/patchpal/features/tools/) and [Custom Tools](https://amaiya.github.io/patchpal/features/custom-tools/)
|
|
17
|
+
- [Browser Automation](https://amaiya.github.io/patchpal/features/tools/#browser-automation-14-tools-optional) for interactive web tasks, form filling, and JavaScript-heavy sites
|
|
17
18
|
- [Skills System](https://amaiya.github.io/patchpal/features/skills/) and [MCP Integration](https://amaiya.github.io/patchpal/features/mcp/)
|
|
18
19
|
- [Autopilot Mode](https://amaiya.github.io/patchpal/usage/autopilot/) using [Ralph Wiggum loops](https://github.com/amaiya/patchpal/tree/main/examples/ralph/)
|
|
19
20
|
- [Project Memory](https://amaiya.github.io/patchpal/features/memory/) automatically loads project context from `MEMORY.md` (repository root or `~/.patchpal/repos/<repo-name>/MEMORY.md`) at startup.
|
|
@@ -60,6 +61,7 @@ docker run -it --rm \
|
|
|
60
61
|
|
|
61
62
|
## Setup
|
|
62
63
|
0. **Install**: `pip install patchpal`
|
|
64
|
+
- **Optional**: For browser automation (13 additional tools): `pip install patchpal[browser] && python -m playwright install chromium`
|
|
63
65
|
1. **Get an API key or a Local LLM Engine**:
|
|
64
66
|
- **[Cloud]** For Anthropic models (default): Sign up at https://console.anthropic.com/
|
|
65
67
|
- **[Cloud]** For OpenAI models: Get a key from https://platform.openai.com/
|
|
@@ -1496,6 +1496,92 @@ Repository root takes priority if both exist."""
|
|
|
1496
1496
|
"\033[2m❓ Asking user a question...\033[0m",
|
|
1497
1497
|
flush=True,
|
|
1498
1498
|
)
|
|
1499
|
+
elif tool_name == "browser_navigate":
|
|
1500
|
+
print(
|
|
1501
|
+
f"\033[2m🌐 Browser navigating: {tool_args.get('url', '')}\033[0m",
|
|
1502
|
+
flush=True,
|
|
1503
|
+
)
|
|
1504
|
+
elif tool_name == "browser_click":
|
|
1505
|
+
print(
|
|
1506
|
+
f"\033[2m🖱️ Browser clicking: {tool_args.get('selector', '')}\033[0m",
|
|
1507
|
+
flush=True,
|
|
1508
|
+
)
|
|
1509
|
+
elif tool_name == "browser_fill":
|
|
1510
|
+
print(
|
|
1511
|
+
f"\033[2m⌨️ Browser filling: {tool_args.get('selector', '')}\033[0m",
|
|
1512
|
+
flush=True,
|
|
1513
|
+
)
|
|
1514
|
+
elif tool_name == "browser_screenshot":
|
|
1515
|
+
print(
|
|
1516
|
+
f"\033[2m📸 Browser screenshot: {tool_args.get('path', '') or 'default path'}\033[0m",
|
|
1517
|
+
flush=True,
|
|
1518
|
+
)
|
|
1519
|
+
elif tool_name == "browser_get_text":
|
|
1520
|
+
print(
|
|
1521
|
+
"\033[2m📄 Browser extracting page text...\033[0m",
|
|
1522
|
+
flush=True,
|
|
1523
|
+
)
|
|
1524
|
+
elif tool_name == "browser_get_html":
|
|
1525
|
+
print(
|
|
1526
|
+
"\033[2m📋 Browser extracting HTML source...\033[0m",
|
|
1527
|
+
flush=True,
|
|
1528
|
+
)
|
|
1529
|
+
elif tool_name == "browser_scroll":
|
|
1530
|
+
direction = tool_args.get("direction", "down")
|
|
1531
|
+
selector = tool_args.get("selector", "")
|
|
1532
|
+
if selector:
|
|
1533
|
+
scroll_desc = f"to '{selector}'"
|
|
1534
|
+
else:
|
|
1535
|
+
scroll_desc = direction
|
|
1536
|
+
print(
|
|
1537
|
+
f"\033[2m📜 Browser scrolling {scroll_desc}...\033[0m",
|
|
1538
|
+
flush=True,
|
|
1539
|
+
)
|
|
1540
|
+
elif tool_name == "browser_execute_script":
|
|
1541
|
+
script_preview = tool_args.get("script", "")[:50]
|
|
1542
|
+
if len(tool_args.get("script", "")) > 50:
|
|
1543
|
+
script_preview += "..."
|
|
1544
|
+
print(
|
|
1545
|
+
f"\033[2m⚡ Browser executing script: {script_preview}\033[0m",
|
|
1546
|
+
flush=True,
|
|
1547
|
+
)
|
|
1548
|
+
elif tool_name == "browser_wait":
|
|
1549
|
+
selector = tool_args.get("selector", "")
|
|
1550
|
+
if selector:
|
|
1551
|
+
wait_desc = f"for '{selector}'"
|
|
1552
|
+
else:
|
|
1553
|
+
wait_desc = f"{tool_args.get('milliseconds', 1000)}ms"
|
|
1554
|
+
print(
|
|
1555
|
+
f"\033[2m⏳ Browser waiting {wait_desc}...\033[0m",
|
|
1556
|
+
flush=True,
|
|
1557
|
+
)
|
|
1558
|
+
elif tool_name == "browser_close":
|
|
1559
|
+
print(
|
|
1560
|
+
"\033[2m🚪 Closing browser...\033[0m",
|
|
1561
|
+
flush=True,
|
|
1562
|
+
)
|
|
1563
|
+
elif tool_name == "browser_list_frames":
|
|
1564
|
+
print(
|
|
1565
|
+
"\033[2m🖼️ Browser listing frames...\033[0m",
|
|
1566
|
+
flush=True,
|
|
1567
|
+
)
|
|
1568
|
+
elif tool_name == "browser_switch_frame":
|
|
1569
|
+
frame_info = ""
|
|
1570
|
+
if "index" in tool_args and tool_args["index"] is not None:
|
|
1571
|
+
frame_info = f"index {tool_args['index']}"
|
|
1572
|
+
elif "name" in tool_args and tool_args["name"] is not None:
|
|
1573
|
+
frame_info = f"'{tool_args['name']}'"
|
|
1574
|
+
else:
|
|
1575
|
+
frame_info = "main page"
|
|
1576
|
+
print(
|
|
1577
|
+
f"\033[2m🖼️ Browser switching to frame: {frame_info}\033[0m",
|
|
1578
|
+
flush=True,
|
|
1579
|
+
)
|
|
1580
|
+
elif tool_name == "browser_dismiss_modals":
|
|
1581
|
+
print(
|
|
1582
|
+
"\033[2m🚫 Browser dismissing modals...\033[0m",
|
|
1583
|
+
flush=True,
|
|
1584
|
+
)
|
|
1499
1585
|
else:
|
|
1500
1586
|
# Check if this is an MCP tool by looking for __mcp_server__ attribute
|
|
1501
1587
|
if hasattr(tool_func, "__mcp_server__"):
|
|
@@ -575,6 +575,32 @@ Supported models: Any LiteLLM-supported model
|
|
|
575
575
|
pass # Don't fail if audit logging fails
|
|
576
576
|
|
|
577
577
|
print("\nGoodbye!")
|
|
578
|
+
|
|
579
|
+
# Clean up the browser if it was opened during the session.
|
|
580
|
+
# An open Playwright browser keeps its own asyncio machinery
|
|
581
|
+
# alive; closing it here releases the browser process/loop so
|
|
582
|
+
# they don't linger into interpreter shutdown.
|
|
583
|
+
try:
|
|
584
|
+
from patchpal.tools.browser_tools import _BrowserState
|
|
585
|
+
|
|
586
|
+
if _BrowserState.is_open():
|
|
587
|
+
_BrowserState.close(silent=True)
|
|
588
|
+
except Exception:
|
|
589
|
+
pass # Browser tools optional / already closed
|
|
590
|
+
|
|
591
|
+
# Suppress the benign "Task exception was never retrieved"
|
|
592
|
+
# warning that asyncio emits at shutdown: prompt_toolkit's
|
|
593
|
+
# pending Application.run_async() task gets cancelled with a
|
|
594
|
+
# KeyboardInterrupt during teardown, and nobody retrieves it.
|
|
595
|
+
# This is cosmetic and happens AFTER all work is done.
|
|
596
|
+
try:
|
|
597
|
+
import asyncio
|
|
598
|
+
|
|
599
|
+
_loop = asyncio.get_event_loop()
|
|
600
|
+
_loop.set_exception_handler(lambda loop, context: None)
|
|
601
|
+
except Exception:
|
|
602
|
+
pass
|
|
603
|
+
|
|
578
604
|
break
|
|
579
605
|
|
|
580
606
|
# Handle /help command - show available commands
|
|
@@ -1633,7 +1659,25 @@ Supported models: Any LiteLLM-supported model
|
|
|
1633
1659
|
)
|
|
1634
1660
|
continue
|
|
1635
1661
|
except Exception as e:
|
|
1636
|
-
|
|
1662
|
+
# Debug: Print full exception info to help diagnose asyncio errors
|
|
1663
|
+
import traceback
|
|
1664
|
+
|
|
1665
|
+
error_str = str(e)
|
|
1666
|
+
print(f"\n\033[1;31mError:\033[0m {error_str}")
|
|
1667
|
+
|
|
1668
|
+
# If it's the asyncio error, print more debug info
|
|
1669
|
+
if "asyncio.run() cannot be called from a running event loop" in error_str:
|
|
1670
|
+
print("\n\033[1;33m[DEBUG] AsyncIO Error Details:\033[0m")
|
|
1671
|
+
print(
|
|
1672
|
+
"This error occurs when asyncio.run() is called while an event loop is already running."
|
|
1673
|
+
)
|
|
1674
|
+
print("Stack trace:")
|
|
1675
|
+
traceback.print_exc()
|
|
1676
|
+
print(
|
|
1677
|
+
"\n\033[1;33m[DEBUG] If browser tools were just used, this may be a Playwright cleanup issue.\033[0m"
|
|
1678
|
+
)
|
|
1679
|
+
print("Try: Close any open browser windows and type 'exit' to restart PatchPal.\n")
|
|
1680
|
+
|
|
1637
1681
|
print("Please try again or type 'exit' to quit.")
|
|
1638
1682
|
|
|
1639
1683
|
|
|
@@ -79,6 +79,16 @@ class Config:
|
|
|
79
79
|
"""Enable web search and fetch tools (default: true)."""
|
|
80
80
|
return _get_env_bool("PATCHPAL_ENABLE_WEB", "true")
|
|
81
81
|
|
|
82
|
+
@property
|
|
83
|
+
def ENABLE_BROWSER(self) -> bool:
|
|
84
|
+
"""Enable browser automation tools (default: true).
|
|
85
|
+
|
|
86
|
+
Browser tools require web access, so they are only available when
|
|
87
|
+
ENABLE_WEB is also true (and Playwright is installed). Set this to
|
|
88
|
+
false to disable the browser tools while keeping web_search/web_fetch.
|
|
89
|
+
"""
|
|
90
|
+
return _get_env_bool("PATCHPAL_ENABLE_BROWSER", "true")
|
|
91
|
+
|
|
82
92
|
@property
|
|
83
93
|
def ENABLE_MCP(self) -> bool:
|
|
84
94
|
"""Enable Model Context Protocol tools (default: true)."""
|
|
@@ -358,6 +358,23 @@ class PermissionManager:
|
|
|
358
358
|
if self._check_grant_list(self.persistent_grants, tool_name, pattern, full_command):
|
|
359
359
|
return True
|
|
360
360
|
|
|
361
|
+
# Special case: "browser" pattern applies across all browser tools
|
|
362
|
+
# If browser pattern was granted to ANY browser tool, apply to all
|
|
363
|
+
if pattern == "browser":
|
|
364
|
+
browser_tools = [
|
|
365
|
+
"browser_navigate",
|
|
366
|
+
"browser_click",
|
|
367
|
+
"browser_fill",
|
|
368
|
+
"browser_execute_script",
|
|
369
|
+
]
|
|
370
|
+
for browser_tool in browser_tools:
|
|
371
|
+
if self._check_grant_list(self.session_grants, browser_tool, pattern, full_command):
|
|
372
|
+
return True
|
|
373
|
+
if self._check_grant_list(
|
|
374
|
+
self.persistent_grants, browser_tool, pattern, full_command
|
|
375
|
+
):
|
|
376
|
+
return True
|
|
377
|
+
|
|
361
378
|
return False
|
|
362
379
|
|
|
363
380
|
def _grant_permission(
|
|
@@ -67,6 +67,42 @@ from patchpal.tools.web_tools import (
|
|
|
67
67
|
web_search,
|
|
68
68
|
)
|
|
69
69
|
|
|
70
|
+
# Browser tools (optional - only available if Playwright installed)
|
|
71
|
+
try:
|
|
72
|
+
from patchpal.tools.browser_tools import (
|
|
73
|
+
PLAYWRIGHT_AVAILABLE,
|
|
74
|
+
browser_click,
|
|
75
|
+
browser_close,
|
|
76
|
+
browser_dismiss_modals,
|
|
77
|
+
browser_execute_script,
|
|
78
|
+
browser_fill,
|
|
79
|
+
browser_get_html,
|
|
80
|
+
browser_get_text,
|
|
81
|
+
browser_list_frames,
|
|
82
|
+
browser_navigate,
|
|
83
|
+
browser_press_key,
|
|
84
|
+
browser_screenshot,
|
|
85
|
+
browser_scroll,
|
|
86
|
+
browser_switch_frame,
|
|
87
|
+
browser_wait,
|
|
88
|
+
)
|
|
89
|
+
except ImportError:
|
|
90
|
+
PLAYWRIGHT_AVAILABLE = False
|
|
91
|
+
browser_navigate = None
|
|
92
|
+
browser_click = None
|
|
93
|
+
browser_fill = None
|
|
94
|
+
browser_screenshot = None
|
|
95
|
+
browser_get_text = None
|
|
96
|
+
browser_get_html = None
|
|
97
|
+
browser_scroll = None
|
|
98
|
+
browser_execute_script = None
|
|
99
|
+
browser_press_key = None
|
|
100
|
+
browser_wait = None
|
|
101
|
+
browser_close = None
|
|
102
|
+
browser_dismiss_modals = None
|
|
103
|
+
browser_list_frames = None
|
|
104
|
+
browser_switch_frame = None
|
|
105
|
+
|
|
70
106
|
__all__ = [
|
|
71
107
|
# File operations
|
|
72
108
|
"read_file",
|
|
@@ -96,6 +132,22 @@ __all__ = [
|
|
|
96
132
|
"web_fetch",
|
|
97
133
|
"web_search",
|
|
98
134
|
"get_url_tracker",
|
|
135
|
+
# Browser tools (optional)
|
|
136
|
+
"PLAYWRIGHT_AVAILABLE",
|
|
137
|
+
"browser_navigate",
|
|
138
|
+
"browser_click",
|
|
139
|
+
"browser_fill",
|
|
140
|
+
"browser_screenshot",
|
|
141
|
+
"browser_get_text",
|
|
142
|
+
"browser_get_html",
|
|
143
|
+
"browser_scroll",
|
|
144
|
+
"browser_execute_script",
|
|
145
|
+
"browser_press_key",
|
|
146
|
+
"browser_wait",
|
|
147
|
+
"browser_close",
|
|
148
|
+
"browser_dismiss_modals",
|
|
149
|
+
"browser_list_frames",
|
|
150
|
+
"browser_switch_frame",
|
|
99
151
|
# Shell tools
|
|
100
152
|
"run_shell",
|
|
101
153
|
# User interaction
|