connectonion 0.5.8__py3-none-any.whl

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.
Files changed (113) hide show
  1. connectonion/__init__.py +78 -0
  2. connectonion/address.py +320 -0
  3. connectonion/agent.py +450 -0
  4. connectonion/announce.py +84 -0
  5. connectonion/asgi.py +287 -0
  6. connectonion/auto_debug_exception.py +181 -0
  7. connectonion/cli/__init__.py +3 -0
  8. connectonion/cli/browser_agent/__init__.py +5 -0
  9. connectonion/cli/browser_agent/browser.py +243 -0
  10. connectonion/cli/browser_agent/prompt.md +107 -0
  11. connectonion/cli/commands/__init__.py +1 -0
  12. connectonion/cli/commands/auth_commands.py +527 -0
  13. connectonion/cli/commands/browser_commands.py +27 -0
  14. connectonion/cli/commands/create.py +511 -0
  15. connectonion/cli/commands/deploy_commands.py +220 -0
  16. connectonion/cli/commands/doctor_commands.py +173 -0
  17. connectonion/cli/commands/init.py +469 -0
  18. connectonion/cli/commands/project_cmd_lib.py +828 -0
  19. connectonion/cli/commands/reset_commands.py +149 -0
  20. connectonion/cli/commands/status_commands.py +168 -0
  21. connectonion/cli/docs/co-vibecoding-principles-docs-contexts-all-in-one.md +2010 -0
  22. connectonion/cli/docs/connectonion.md +1256 -0
  23. connectonion/cli/docs.md +123 -0
  24. connectonion/cli/main.py +148 -0
  25. connectonion/cli/templates/meta-agent/README.md +287 -0
  26. connectonion/cli/templates/meta-agent/agent.py +196 -0
  27. connectonion/cli/templates/meta-agent/prompts/answer_prompt.md +9 -0
  28. connectonion/cli/templates/meta-agent/prompts/docs_retrieve_prompt.md +15 -0
  29. connectonion/cli/templates/meta-agent/prompts/metagent.md +71 -0
  30. connectonion/cli/templates/meta-agent/prompts/think_prompt.md +18 -0
  31. connectonion/cli/templates/minimal/README.md +56 -0
  32. connectonion/cli/templates/minimal/agent.py +40 -0
  33. connectonion/cli/templates/playwright/README.md +118 -0
  34. connectonion/cli/templates/playwright/agent.py +336 -0
  35. connectonion/cli/templates/playwright/prompt.md +102 -0
  36. connectonion/cli/templates/playwright/requirements.txt +3 -0
  37. connectonion/cli/templates/web-research/agent.py +122 -0
  38. connectonion/connect.py +128 -0
  39. connectonion/console.py +539 -0
  40. connectonion/debug_agent/__init__.py +13 -0
  41. connectonion/debug_agent/agent.py +45 -0
  42. connectonion/debug_agent/prompts/debug_assistant.md +72 -0
  43. connectonion/debug_agent/runtime_inspector.py +406 -0
  44. connectonion/debug_explainer/__init__.py +10 -0
  45. connectonion/debug_explainer/explain_agent.py +114 -0
  46. connectonion/debug_explainer/explain_context.py +263 -0
  47. connectonion/debug_explainer/explainer_prompt.md +29 -0
  48. connectonion/debug_explainer/root_cause_analysis_prompt.md +43 -0
  49. connectonion/debugger_ui.py +1039 -0
  50. connectonion/decorators.py +208 -0
  51. connectonion/events.py +248 -0
  52. connectonion/execution_analyzer/__init__.py +9 -0
  53. connectonion/execution_analyzer/execution_analysis.py +93 -0
  54. connectonion/execution_analyzer/execution_analysis_prompt.md +47 -0
  55. connectonion/host.py +579 -0
  56. connectonion/interactive_debugger.py +342 -0
  57. connectonion/llm.py +801 -0
  58. connectonion/llm_do.py +307 -0
  59. connectonion/logger.py +300 -0
  60. connectonion/prompt_files/__init__.py +1 -0
  61. connectonion/prompt_files/analyze_contact.md +62 -0
  62. connectonion/prompt_files/eval_expected.md +12 -0
  63. connectonion/prompt_files/react_evaluate.md +11 -0
  64. connectonion/prompt_files/react_plan.md +16 -0
  65. connectonion/prompt_files/reflect.md +22 -0
  66. connectonion/prompts.py +144 -0
  67. connectonion/relay.py +200 -0
  68. connectonion/static/docs.html +688 -0
  69. connectonion/tool_executor.py +279 -0
  70. connectonion/tool_factory.py +186 -0
  71. connectonion/tool_registry.py +105 -0
  72. connectonion/trust.py +166 -0
  73. connectonion/trust_agents.py +71 -0
  74. connectonion/trust_functions.py +88 -0
  75. connectonion/tui/__init__.py +57 -0
  76. connectonion/tui/divider.py +39 -0
  77. connectonion/tui/dropdown.py +251 -0
  78. connectonion/tui/footer.py +31 -0
  79. connectonion/tui/fuzzy.py +56 -0
  80. connectonion/tui/input.py +278 -0
  81. connectonion/tui/keys.py +35 -0
  82. connectonion/tui/pick.py +130 -0
  83. connectonion/tui/providers.py +155 -0
  84. connectonion/tui/status_bar.py +163 -0
  85. connectonion/usage.py +161 -0
  86. connectonion/useful_events_handlers/__init__.py +16 -0
  87. connectonion/useful_events_handlers/reflect.py +116 -0
  88. connectonion/useful_plugins/__init__.py +20 -0
  89. connectonion/useful_plugins/calendar_plugin.py +163 -0
  90. connectonion/useful_plugins/eval.py +139 -0
  91. connectonion/useful_plugins/gmail_plugin.py +162 -0
  92. connectonion/useful_plugins/image_result_formatter.py +127 -0
  93. connectonion/useful_plugins/re_act.py +78 -0
  94. connectonion/useful_plugins/shell_approval.py +159 -0
  95. connectonion/useful_tools/__init__.py +44 -0
  96. connectonion/useful_tools/diff_writer.py +192 -0
  97. connectonion/useful_tools/get_emails.py +183 -0
  98. connectonion/useful_tools/gmail.py +1596 -0
  99. connectonion/useful_tools/google_calendar.py +613 -0
  100. connectonion/useful_tools/memory.py +380 -0
  101. connectonion/useful_tools/microsoft_calendar.py +604 -0
  102. connectonion/useful_tools/outlook.py +488 -0
  103. connectonion/useful_tools/send_email.py +205 -0
  104. connectonion/useful_tools/shell.py +97 -0
  105. connectonion/useful_tools/slash_command.py +201 -0
  106. connectonion/useful_tools/terminal.py +285 -0
  107. connectonion/useful_tools/todo_list.py +241 -0
  108. connectonion/useful_tools/web_fetch.py +216 -0
  109. connectonion/xray.py +467 -0
  110. connectonion-0.5.8.dist-info/METADATA +741 -0
  111. connectonion-0.5.8.dist-info/RECORD +113 -0
  112. connectonion-0.5.8.dist-info/WHEEL +4 -0
  113. connectonion-0.5.8.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,243 @@
1
+ """Browser Agent for CLI - Natural language browser automation.
2
+
3
+ This module provides a browser automation agent that understands natural language
4
+ requests for taking screenshots and other browser operations via the ConnectOnion CLI.
5
+ """
6
+
7
+ import os
8
+ from pathlib import Path
9
+ from datetime import datetime
10
+ from connectonion import Agent, llm_do, xray
11
+ from dotenv import load_dotenv
12
+ from pydantic import BaseModel
13
+
14
+ # Default screenshots directory in current working directory
15
+ SCREENSHOTS_DIR = Path.cwd() / ".tmp"
16
+
17
+ # Check Playwright availability
18
+ try:
19
+ from playwright.sync_api import sync_playwright
20
+ PLAYWRIGHT_AVAILABLE = True
21
+ except ImportError:
22
+ PLAYWRIGHT_AVAILABLE = False
23
+
24
+ # Path to the browser agent system prompt
25
+ PROMPT_PATH = Path(__file__).parent / "prompt.md"
26
+
27
+
28
+ class BrowserAutomation:
29
+ """Browser automation for screenshots and interactions."""
30
+
31
+ def __init__(self):
32
+ self._screenshots = []
33
+ self._playwright = None
34
+ self._browser = None
35
+ self._page = None
36
+ self._initialize_browser()
37
+
38
+ def _initialize_browser(self):
39
+ """Initialize the browser instance."""
40
+ if not PLAYWRIGHT_AVAILABLE:
41
+ return
42
+ from playwright.sync_api import sync_playwright
43
+ self._playwright = sync_playwright().start()
44
+ self._browser = self._playwright.chromium.launch(headless=True)
45
+ self._page = self._browser.new_page()
46
+
47
+ def navigate_to(self, url: str) -> str:
48
+ """Navigate to a URL."""
49
+ if not url.startswith(('http://', 'https://')):
50
+ url = f'https://{url}' if '.' in url else f'http://{url}'
51
+ self._page.goto(url, wait_until='networkidle', timeout=30000)
52
+ # Sleep for 2 seconds to ensure page is fully loaded
53
+ self._page.wait_for_timeout(2000)
54
+ return f"Navigated to {url}"
55
+
56
+ def set_viewport(self, width: int, height: int) -> str:
57
+ """Set the browser viewport size.
58
+
59
+ Args:
60
+ width: Viewport width in pixels
61
+ height: Viewport height in pixels
62
+
63
+ Returns:
64
+ Success message
65
+ """
66
+ if not PLAYWRIGHT_AVAILABLE:
67
+ return 'Browser tools not installed. Run: pip install playwright && playwright install chromium'
68
+ self._page.set_viewport_size({"width": width, "height": height})
69
+ return f"Viewport set to {width}x{height}"
70
+
71
+ def take_screenshot(self, url: str, path: str = "",
72
+ width: int = 1920, height: int = 1080,
73
+ full_page: bool = False) -> str:
74
+ """Take a screenshot of the specified URL.
75
+
76
+ Args:
77
+ url: The URL to screenshot (e.g., "localhost:3000", "example.com")
78
+ path: Optional path to save the screenshot (auto-generates if empty)
79
+ width: Viewport width in pixels (default 1920)
80
+ height: Viewport height in pixels (default 1080)
81
+ full_page: If True, captures entire page height
82
+
83
+ Returns:
84
+ Success or error message
85
+ """
86
+ if not PLAYWRIGHT_AVAILABLE:
87
+ return 'Browser tools not installed. Run: pip install playwright && playwright install chromium'
88
+
89
+ # Navigate to URL
90
+ self.navigate_to(url)
91
+
92
+ # Set viewport size
93
+ self._page.set_viewport_size({"width": width, "height": height})
94
+
95
+ # Generate filename if needed
96
+ if not path:
97
+ # Ensure screenshots directory exists
98
+ SCREENSHOTS_DIR.mkdir(parents=True, exist_ok=True)
99
+ timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
100
+ path = str(SCREENSHOTS_DIR / f'screenshot_{timestamp}.png')
101
+ elif not path.startswith('/'): # Relative path
102
+ # If relative path given, save to screenshots dir
103
+ SCREENSHOTS_DIR.mkdir(parents=True, exist_ok=True)
104
+ if not path.endswith(('.png', '.jpg', '.jpeg')):
105
+ path += '.png'
106
+ path = str(SCREENSHOTS_DIR / path)
107
+ elif not path.endswith(('.png', '.jpg', '.jpeg')):
108
+ # Absolute path without extension
109
+ path += '.png'
110
+
111
+ # Ensure directory exists
112
+ Path(path).parent.mkdir(parents=True, exist_ok=True)
113
+
114
+ # Take screenshot
115
+ self._page.screenshot(path=path, full_page=full_page)
116
+
117
+ self._screenshots.append(path)
118
+ return f'Screenshot saved: {path}'
119
+
120
+ def screenshot_with_iphone_viewport(self, url: str, path: str = "") -> str:
121
+ """Take a screenshot with iPhone viewport (390x844)."""
122
+ return self.take_screenshot(url, path, width=390, height=844)
123
+
124
+ def screenshot_with_ipad_viewport(self, url: str, path: str = "") -> str:
125
+ """Take a screenshot with iPad viewport (768x1024)."""
126
+ return self.take_screenshot(url, path, width=768, height=1024)
127
+
128
+ def screenshot_with_desktop_viewport(self, url: str, path: str = "") -> str:
129
+ """Take a screenshot with desktop viewport (1920x1080)."""
130
+ return self.take_screenshot(url, path, width=1920, height=1080)
131
+
132
+ def get_current_page_html(self) -> str:
133
+ """Get the HTML content of the current page.
134
+
135
+ Returns:
136
+ The HTML content of the current page
137
+ """
138
+ if not PLAYWRIGHT_AVAILABLE:
139
+ return 'Browser tools not installed. Run: pip install playwright && playwright install chromium'
140
+ return self._page.content()
141
+
142
+ def get_current_url(self) -> str:
143
+ """Get the current page URL.
144
+
145
+ Returns:
146
+ The current URL
147
+ """
148
+ if not PLAYWRIGHT_AVAILABLE:
149
+ return 'Browser tools not installed. Run: pip install playwright && playwright install chromium'
150
+ return self._page.url
151
+
152
+ def wait(self, seconds: float) -> str:
153
+ """Wait for a specified number of seconds.
154
+
155
+ Args:
156
+ seconds: Number of seconds to wait
157
+
158
+ Returns:
159
+ Success message
160
+ """
161
+ if not PLAYWRIGHT_AVAILABLE:
162
+ return 'Browser tools not installed. Run: pip install playwright && playwright install chromium'
163
+ self._page.wait_for_timeout(seconds * 1000) # Convert to milliseconds
164
+ return f"Waited for {seconds} seconds"
165
+
166
+ @xray
167
+ def get_debug_trace(self) -> str:
168
+ """Get execution trace for debugging.
169
+
170
+ Returns:
171
+ Execution trace showing what happened
172
+ """
173
+ if hasattr(xray, 'trace'):
174
+ return xray.trace()
175
+ return "No trace available"
176
+
177
+ def click_element_by_description(self, description: str) -> str:
178
+ """Click an element on the current page based on natural language description.
179
+
180
+ Args:
181
+ description: Natural language description of what to click
182
+
183
+ Returns:
184
+ Result message
185
+ """
186
+ if not PLAYWRIGHT_AVAILABLE:
187
+ return 'Browser tools not installed. Run: pip install playwright && playwright install chromium'
188
+
189
+ html_content = self._page.content()
190
+
191
+ # Use llm_do to determine the selector
192
+ class ElementSelector(BaseModel):
193
+ selector: str
194
+ method: str # "text" or "css"
195
+
196
+ result = llm_do(
197
+ f"Find selector for: {description}\n\nHTML:\n{html_content[:5000]}",
198
+ output=ElementSelector,
199
+ system_prompt="Return the best selector to click the element. Use method='text' for button text, method='css' for CSS selectors."
200
+ )
201
+
202
+ if result.method == "text":
203
+ self._page.get_by_text(result.selector).click()
204
+ else:
205
+ self._page.locator(result.selector).click()
206
+
207
+ self._page.wait_for_timeout(1000)
208
+ return f"Clicked: {result.selector}"
209
+
210
+
211
+
212
+
213
+
214
+ def execute_browser_command(command: str) -> str:
215
+ """Execute a browser command using natural language.
216
+
217
+ Returns the agent's natural language response directly.
218
+ """
219
+ # Framework auto-loads local .env, but CLI commands need global fallback
220
+ # Check for API key in environment first
221
+ api_key = os.getenv('OPENONION_API_KEY')
222
+
223
+ # If not found, try loading from global config
224
+ if not api_key:
225
+ global_env = Path.home() / ".co" / "keys.env"
226
+ if global_env.exists():
227
+ load_dotenv(global_env)
228
+ api_key = os.getenv('OPENONION_API_KEY')
229
+
230
+ if not api_key:
231
+ return '❌ Browser agent requires authentication. Run: co auth'
232
+
233
+ browser = BrowserAutomation()
234
+ agent = Agent(
235
+ name="browser_cli",
236
+ model="co/gemini-2.5-pro",
237
+ api_key=api_key,
238
+ system_prompt=PROMPT_PATH,
239
+ tools=[browser],
240
+ max_iterations=10
241
+ )
242
+ return agent.input(command)
243
+
@@ -0,0 +1,107 @@
1
+ # Browser CLI Assistant
2
+
3
+ You are a browser automation assistant that understands natural language requests for browser automation including navigation, interaction, screenshots, and debugging.
4
+
5
+ ## Your Available Functions
6
+
7
+ ### Navigation & State
8
+ - `navigate_to(url)` - Navigate to any website
9
+ - `get_current_url()` - Get the current page URL
10
+ - `get_current_page_html()` - Get HTML content of current page
11
+ - `wait(seconds)` - Wait for specified seconds (useful after navigation or clicks)
12
+
13
+ ### Viewport & Display
14
+ - `set_viewport(width, height)` - Set custom viewport dimensions
15
+ - `screenshot_with_iphone_viewport(url, path)` - Take screenshot with iPhone size (390x844)
16
+ - `screenshot_with_ipad_viewport(url, path)` - Take screenshot with iPad size (768x1024)
17
+ - `screenshot_with_desktop_viewport(url, path)` - Take screenshot with desktop size (1920x1080)
18
+ - `take_screenshot(url, path, width, height, full_page)` - Take screenshot with all options
19
+
20
+ ### Interaction
21
+ - `click_element_by_description(description)` - Click elements using natural language (e.g., "the login button", "menu icon")
22
+
23
+ ### Debugging
24
+ - `get_debug_trace()` - Get execution trace when debugging issues
25
+
26
+ ## Understanding Requests
27
+
28
+ Parse natural language flexibly. Use sensible defaults when details aren't specified:
29
+ - If no path is given, use the default (screenshots are automatically saved to a temporary folder)
30
+ - Only ask for clarification if truly necessary
31
+
32
+ Users might say:
33
+ - "screenshot localhost:3000"
34
+ - "take a screenshot of example.com"
35
+ - "capture google.com and save it to /tmp/test.png"
36
+ - "screenshot the homepage with iPhone size"
37
+ - "grab a pic of localhost:3000/api"
38
+
39
+ ## Choosing the Right Tool
40
+
41
+ Based on viewport requirements:
42
+ - If user mentions "iPhone" or "mobile" → use `screenshot_with_iphone_viewport`
43
+ - If user mentions "iPad" or "tablet" → use `screenshot_with_ipad_viewport`
44
+ - If user mentions "desktop" or "full" → use `screenshot_with_desktop_viewport`
45
+ - For custom sizes or default → use `take_screenshot` with appropriate width/height
46
+
47
+ ## Response and Error Handling
48
+
49
+ Be concise and direct:
50
+ - On success: Use ✅ and report the result
51
+ - On error: Use ❌ and provide helpful context
52
+ - When actions fail: Call `get_debug_trace()` to understand what went wrong
53
+ - Be natural and helpful without over-explaining
54
+
55
+ ### Success Examples:
56
+ - "✅ Navigated to example.com"
57
+ - "✅ Clicked the login button"
58
+ - "✅ Screenshot saved: .tmp/screenshot_20240101_120000.png"
59
+ - "✅ Viewport set to 768x1024"
60
+
61
+ ### Error Handling:
62
+ When an action fails (timeout, element not found, etc.):
63
+ 1. Report the error clearly
64
+ 2. Use `get_debug_trace()` if the issue is unclear
65
+ 3. Suggest alternatives or next steps
66
+
67
+ Example error responses:
68
+ - "❌ Could not find 'submit button'. The element may not be visible or loaded yet."
69
+ - "❌ Navigation timeout. The page took too long to load."
70
+ - "❌ Click failed. Let me check the debug trace... [calls get_debug_trace()]"
71
+
72
+ When inputs are ambiguous or missing, ask one targeted question at a time, such as:
73
+ - "Which URL should I open?"
74
+ - "Do you want full-page or just the current viewport?"
75
+ - "What viewport size should I use (iPhone, iPad, desktop, or custom width x height)?"
76
+
77
+ ## Examples
78
+
79
+ ### Basic Navigation
80
+ User: "go to example.com and get the HTML"
81
+ → navigate_to("example.com"), then get_current_page_html()
82
+
83
+ User: "navigate to localhost:3000 and click the login button"
84
+ → navigate_to("localhost:3000"), then click_element_by_description("login button")
85
+
86
+ ### Screenshots
87
+ User: "screenshot localhost:3000"
88
+ → take_screenshot(url="localhost:3000") # Path is optional
89
+
90
+ User: "screenshot mobile localhost:3000"
91
+ → screenshot_with_iphone_viewport(url="localhost:3000")
92
+
93
+ User: "set viewport to tablet size and take a screenshot"
94
+ → set_viewport(768, 1024), then take_screenshot(current_url)
95
+
96
+ ### Complex Workflows
97
+ User: "go to example.com, click more info link, check if URL changed"
98
+ → navigate_to("example.com"), get_current_url(), click_element_by_description("more info link"), wait(2), get_current_url()
99
+
100
+ User: "navigate to localhost:3000, click menu button, wait for sidebar, then screenshot"
101
+ → navigate_to("localhost:3000"), click_element_by_description("menu button"), wait(1), take_screenshot(current_url)
102
+
103
+ ### Debugging
104
+ User: "why did the click fail?"
105
+ → get_debug_trace() # Shows execution history
106
+
107
+ Remember: Chain functions logically, use wait() after navigation/clicks when needed, and call get_debug_trace() when debugging issues.
@@ -0,0 +1 @@
1
+ """Command modules for ConnectOnion CLI."""