connectonion 0.6.1__py3-none-any.whl → 0.6.3__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 (413) hide show
  1. connectonion/__init__.py +46 -9
  2. connectonion/cli/__init__.py +11 -1
  3. connectonion/cli/browser_agent/__init__.py +11 -1
  4. connectonion/cli/browser_agent/browser.py +95 -142
  5. connectonion/cli/browser_agent/element_finder.py +147 -0
  6. connectonion/cli/browser_agent/highlight_screenshot.py +182 -0
  7. connectonion/cli/browser_agent/prompt.md +188 -105
  8. connectonion/cli/browser_agent/prompts/element_matcher.md +59 -0
  9. connectonion/cli/browser_agent/prompts/form_filler.md +19 -0
  10. connectonion/cli/browser_agent/prompts/scroll_strategy.md +36 -0
  11. connectonion/cli/browser_agent/scripts/extract_elements.js +126 -0
  12. connectonion/cli/browser_agent/scroll.py +145 -0
  13. connectonion/cli/co_ai/__init__.py +6 -0
  14. connectonion/cli/co_ai/agent.py +87 -0
  15. connectonion/cli/co_ai/agents/__init__.py +5 -0
  16. connectonion/cli/co_ai/agents/registry.py +57 -0
  17. connectonion/cli/co_ai/commands/__init__.py +45 -0
  18. connectonion/cli/co_ai/commands/compact.py +173 -0
  19. connectonion/cli/co_ai/commands/cost.py +77 -0
  20. connectonion/cli/co_ai/commands/export.py +60 -0
  21. connectonion/cli/co_ai/commands/help.py +80 -0
  22. connectonion/cli/co_ai/commands/init.py +101 -0
  23. connectonion/cli/co_ai/commands/sessions.py +55 -0
  24. connectonion/cli/co_ai/commands/tasks.py +63 -0
  25. connectonion/cli/co_ai/commands/undo.py +103 -0
  26. connectonion/cli/co_ai/context.py +127 -0
  27. connectonion/cli/co_ai/main.py +52 -0
  28. connectonion/cli/co_ai/plugins/__init__.py +6 -0
  29. connectonion/cli/co_ai/plugins/reminder.py +76 -0
  30. connectonion/cli/co_ai/plugins/shell_approval.py +105 -0
  31. connectonion/cli/co_ai/prompts/agents/explore.md +79 -0
  32. connectonion/cli/co_ai/prompts/agents/plan.md +60 -0
  33. connectonion/cli/co_ai/prompts/assembler.py +303 -0
  34. connectonion/cli/{docs/co-vibecoding-principles-docs-contexts-all-in-one.md → co_ai/prompts/connectonion/README.md} +26 -0
  35. connectonion/cli/co_ai/prompts/connectonion/api.md +457 -0
  36. connectonion/cli/co_ai/prompts/connectonion/cli/README.md +805 -0
  37. connectonion/cli/co_ai/prompts/connectonion/cli/auth.md +46 -0
  38. connectonion/cli/co_ai/prompts/connectonion/cli/browser.md +235 -0
  39. connectonion/cli/co_ai/prompts/connectonion/cli/copy.md +184 -0
  40. connectonion/cli/co_ai/prompts/connectonion/cli/create.md +335 -0
  41. connectonion/cli/co_ai/prompts/connectonion/cli/init.md +431 -0
  42. connectonion/cli/co_ai/prompts/connectonion/co-directory-structure.md +214 -0
  43. connectonion/cli/co_ai/prompts/connectonion/concepts/agent.md +1078 -0
  44. connectonion/cli/co_ai/prompts/connectonion/concepts/events.md +816 -0
  45. connectonion/cli/co_ai/prompts/connectonion/concepts/llm_do.md +256 -0
  46. connectonion/cli/co_ai/prompts/connectonion/concepts/max_iterations.md +362 -0
  47. connectonion/cli/co_ai/prompts/connectonion/concepts/models.md +641 -0
  48. connectonion/cli/co_ai/prompts/connectonion/concepts/plugins.md +100 -0
  49. connectonion/cli/co_ai/prompts/connectonion/concepts/prompts.md +122 -0
  50. connectonion/cli/co_ai/prompts/connectonion/concepts/tools.md +512 -0
  51. connectonion/cli/co_ai/prompts/connectonion/concepts/transcribe.md +156 -0
  52. connectonion/cli/co_ai/prompts/connectonion/concepts/trust.md +291 -0
  53. connectonion/cli/co_ai/prompts/connectonion/debug/README.md +18 -0
  54. connectonion/cli/co_ai/prompts/connectonion/debug/auto_debug.md +1026 -0
  55. connectonion/cli/co_ai/prompts/connectonion/debug/console.md +129 -0
  56. connectonion/cli/co_ai/prompts/connectonion/debug/eval-format.md +178 -0
  57. connectonion/cli/co_ai/prompts/connectonion/debug/eval.md +230 -0
  58. connectonion/cli/co_ai/prompts/connectonion/debug/exceptions.md +307 -0
  59. connectonion/cli/co_ai/prompts/connectonion/debug/log.md +117 -0
  60. connectonion/cli/co_ai/prompts/connectonion/debug/xray.md +215 -0
  61. connectonion/cli/co_ai/prompts/connectonion/design-decisions/001-choosing-input-method.md +202 -0
  62. connectonion/cli/co_ai/prompts/connectonion/design-decisions/002-choosing-llm-function-name.md +202 -0
  63. connectonion/cli/co_ai/prompts/connectonion/design-decisions/003-choosing-trust-keyword.md +141 -0
  64. connectonion/cli/co_ai/prompts/connectonion/design-decisions/004-cli-create-flow.md +117 -0
  65. connectonion/cli/co_ai/prompts/connectonion/design-decisions/005-designing-agent-network-protocol.md +503 -0
  66. connectonion/cli/co_ai/prompts/connectonion/design-decisions/006-agent-address-format.md +305 -0
  67. connectonion/cli/co_ai/prompts/connectonion/design-decisions/007-authentication-backend-design.md +240 -0
  68. connectonion/cli/co_ai/prompts/connectonion/design-decisions/008-naming-is-hard.md +228 -0
  69. connectonion/cli/co_ai/prompts/connectonion/design-decisions/009-why-connect-function.md +167 -0
  70. connectonion/cli/co_ai/prompts/connectonion/design-decisions/010-cli-ux-progressive-disclosure.md +176 -0
  71. connectonion/cli/co_ai/prompts/connectonion/design-decisions/011-global-config-identity-management.md +357 -0
  72. connectonion/cli/co_ai/prompts/connectonion/design-decisions/012-tool-execution-separation.md +259 -0
  73. connectonion/cli/co_ai/prompts/connectonion/design-decisions/013-debug-and-logging-design.md +253 -0
  74. connectonion/cli/co_ai/prompts/connectonion/design-decisions/014-hook-system-design.md +510 -0
  75. connectonion/cli/co_ai/prompts/connectonion/design-decisions/015-interactive-auto-debug-design.md +837 -0
  76. connectonion/cli/co_ai/prompts/connectonion/design-decisions/016-why-no-zero-knowledge-proofs.md +358 -0
  77. connectonion/cli/co_ai/prompts/connectonion/design-decisions/017-session-logging-and-eval-format.md +120 -0
  78. connectonion/cli/co_ai/prompts/connectonion/design-decisions/018-event-api-naming.md +274 -0
  79. connectonion/cli/co_ai/prompts/connectonion/design-decisions/019-agent-lifecycle-design.md +655 -0
  80. connectonion/cli/co_ai/prompts/connectonion/design-decisions/020-trust-system-and-network-architecture.md +503 -0
  81. connectonion/cli/co_ai/prompts/connectonion/design-decisions/021-task-storage-jsonl-design.md +496 -0
  82. connectonion/cli/co_ai/prompts/connectonion/design-decisions/022-raw-asgi-implementation.md +273 -0
  83. connectonion/cli/co_ai/prompts/connectonion/examples/agent_reasoning.md +62 -0
  84. connectonion/cli/co_ai/prompts/connectonion/examples/atomic_tools.md +24 -0
  85. connectonion/cli/co_ai/prompts/connectonion/examples/load_guide.md +18 -0
  86. connectonion/cli/co_ai/prompts/connectonion/examples.md +0 -0
  87. connectonion/cli/co_ai/prompts/connectonion/hook-system-options.md +364 -0
  88. connectonion/cli/co_ai/prompts/connectonion/index.md +162 -0
  89. connectonion/cli/co_ai/prompts/connectonion/integrations/README.md +12 -0
  90. connectonion/cli/co_ai/prompts/connectonion/integrations/auth.md +450 -0
  91. connectonion/cli/co_ai/prompts/connectonion/integrations/google.md +431 -0
  92. connectonion/cli/co_ai/prompts/connectonion/integrations/microsoft.md +370 -0
  93. connectonion/cli/co_ai/prompts/connectonion/network/README.md +14 -0
  94. connectonion/cli/co_ai/prompts/connectonion/network/connect.md +543 -0
  95. connectonion/cli/co_ai/prompts/connectonion/network/connection.md +538 -0
  96. connectonion/cli/co_ai/prompts/connectonion/network/deploy.md +123 -0
  97. connectonion/cli/co_ai/prompts/connectonion/network/host.md +1049 -0
  98. connectonion/cli/co_ai/prompts/connectonion/network/protocol/agent-relay-protocol.md +495 -0
  99. connectonion/cli/co_ai/prompts/connectonion/network/protocol/announce-message.md +115 -0
  100. connectonion/cli/co_ai/prompts/connectonion/principles.md +124 -0
  101. connectonion/cli/co_ai/prompts/connectonion/quickstart.md +261 -0
  102. connectonion/cli/co_ai/prompts/connectonion/roadmap.md +81 -0
  103. connectonion/cli/co_ai/prompts/connectonion/templates/README.md +77 -0
  104. connectonion/cli/co_ai/prompts/connectonion/templates/meta-agent.md +152 -0
  105. connectonion/cli/co_ai/prompts/connectonion/templates/minimal.md +105 -0
  106. connectonion/cli/co_ai/prompts/connectonion/templates/playwright.md +130 -0
  107. connectonion/cli/co_ai/prompts/connectonion/templates/web-research.md +144 -0
  108. connectonion/cli/co_ai/prompts/connectonion/tui/README.md +95 -0
  109. connectonion/cli/co_ai/prompts/connectonion/tui/chat.md +181 -0
  110. connectonion/cli/co_ai/prompts/connectonion/tui/divider.md +63 -0
  111. connectonion/cli/co_ai/prompts/connectonion/tui/dropdown.md +83 -0
  112. connectonion/cli/co_ai/prompts/connectonion/tui/footer.md +44 -0
  113. connectonion/cli/co_ai/prompts/connectonion/tui/fuzzy.md +68 -0
  114. connectonion/cli/co_ai/prompts/connectonion/tui/input.md +84 -0
  115. connectonion/cli/co_ai/prompts/connectonion/tui/keys.md +77 -0
  116. connectonion/cli/co_ai/prompts/connectonion/tui/pick.md +71 -0
  117. connectonion/cli/co_ai/prompts/connectonion/tui/providers.md +89 -0
  118. connectonion/cli/co_ai/prompts/connectonion/tui/status_bar.md +67 -0
  119. connectonion/cli/co_ai/prompts/connectonion/useful_plugins/README.md +156 -0
  120. connectonion/cli/co_ai/prompts/connectonion/useful_plugins/calendar_plugin.md +68 -0
  121. connectonion/cli/co_ai/prompts/connectonion/useful_plugins/eval.md +89 -0
  122. connectonion/cli/co_ai/prompts/connectonion/useful_plugins/gmail_plugin.md +68 -0
  123. connectonion/cli/co_ai/prompts/connectonion/useful_plugins/image_result_formatter.md +74 -0
  124. connectonion/cli/co_ai/prompts/connectonion/useful_plugins/re_act.md +86 -0
  125. connectonion/cli/co_ai/prompts/connectonion/useful_plugins/shell_approval.md +69 -0
  126. connectonion/cli/co_ai/prompts/connectonion/useful_tools/README.md +81 -0
  127. connectonion/cli/co_ai/prompts/connectonion/useful_tools/diff_writer.md +138 -0
  128. connectonion/cli/co_ai/prompts/connectonion/useful_tools/get_emails.md +499 -0
  129. connectonion/cli/co_ai/prompts/connectonion/useful_tools/gmail.md +135 -0
  130. connectonion/cli/co_ai/prompts/connectonion/useful_tools/google_calendar.md +106 -0
  131. connectonion/cli/co_ai/prompts/connectonion/useful_tools/memory.md +486 -0
  132. connectonion/cli/co_ai/prompts/connectonion/useful_tools/microsoft_calendar.md +106 -0
  133. connectonion/cli/co_ai/prompts/connectonion/useful_tools/outlook.md +120 -0
  134. connectonion/cli/co_ai/prompts/connectonion/useful_tools/send_email.md +403 -0
  135. connectonion/cli/co_ai/prompts/connectonion/useful_tools/shell.md +95 -0
  136. connectonion/cli/co_ai/prompts/connectonion/useful_tools/slash_command.md +96 -0
  137. connectonion/cli/co_ai/prompts/connectonion/useful_tools/terminal.md +97 -0
  138. connectonion/cli/co_ai/prompts/connectonion/useful_tools/todo_list.md +252 -0
  139. connectonion/cli/co_ai/prompts/connectonion/useful_tools/web_fetch.md +130 -0
  140. connectonion/cli/co_ai/prompts/connectonion/vibe-coding-guide.md +97 -0
  141. connectonion/cli/co_ai/prompts/connectonion/windows-support.md +258 -0
  142. connectonion/cli/co_ai/prompts/main.md +247 -0
  143. connectonion/cli/co_ai/prompts/reminders/plan_mode.md +34 -0
  144. connectonion/cli/co_ai/prompts/summarization.md +55 -0
  145. connectonion/cli/co_ai/prompts/tools/ask_user.md +61 -0
  146. connectonion/cli/co_ai/prompts/tools/background.md +57 -0
  147. connectonion/cli/co_ai/prompts/tools/edit.md +90 -0
  148. connectonion/cli/co_ai/prompts/tools/glob.md +52 -0
  149. connectonion/cli/co_ai/prompts/tools/grep.md +55 -0
  150. connectonion/cli/co_ai/prompts/tools/plan_mode.md +80 -0
  151. connectonion/cli/co_ai/prompts/tools/read.md +40 -0
  152. connectonion/cli/co_ai/prompts/tools/shell.md +67 -0
  153. connectonion/cli/co_ai/prompts/tools/task.md +51 -0
  154. connectonion/cli/co_ai/prompts/tools/todo.md +139 -0
  155. connectonion/cli/co_ai/prompts/tools/write.md +47 -0
  156. connectonion/cli/co_ai/prompts/workflow.md +89 -0
  157. connectonion/cli/co_ai/reminders.py +159 -0
  158. connectonion/cli/co_ai/sessions.py +110 -0
  159. connectonion/cli/co_ai/skills/__init__.py +37 -0
  160. connectonion/cli/co_ai/skills/builtin/commit/SKILL.md +63 -0
  161. connectonion/cli/co_ai/skills/builtin/review-pr/SKILL.md +76 -0
  162. connectonion/cli/co_ai/skills/loader.py +166 -0
  163. connectonion/cli/co_ai/skills/tool.py +46 -0
  164. connectonion/cli/co_ai/tools/__init__.py +92 -0
  165. connectonion/cli/co_ai/tools/ask_user.py +35 -0
  166. connectonion/cli/co_ai/tools/background.py +201 -0
  167. connectonion/cli/co_ai/tools/diff_writer.py +291 -0
  168. connectonion/cli/co_ai/tools/edit.py +89 -0
  169. connectonion/cli/co_ai/tools/glob.py +84 -0
  170. connectonion/cli/co_ai/tools/grep.py +158 -0
  171. connectonion/cli/co_ai/tools/load_guide.py +23 -0
  172. connectonion/cli/co_ai/tools/multi_edit.py +116 -0
  173. connectonion/cli/co_ai/tools/plan_mode.py +172 -0
  174. connectonion/cli/co_ai/tools/read.py +67 -0
  175. connectonion/cli/co_ai/tools/task.py +59 -0
  176. connectonion/cli/co_ai/tools/todo_list.py +159 -0
  177. connectonion/cli/co_ai/tools/write.py +126 -0
  178. connectonion/cli/commands/__init__.py +11 -1
  179. connectonion/cli/commands/ai_commands.py +34 -0
  180. connectonion/cli/commands/copy_commands.py +55 -6
  181. connectonion/cli/commands/create.py +20 -17
  182. connectonion/cli/commands/init.py +19 -22
  183. connectonion/cli/commands/project_cmd_lib.py +15 -0
  184. connectonion/cli/main.py +11 -0
  185. connectonion/console.py +15 -1
  186. connectonion/core/__init__.py +10 -1
  187. connectonion/core/agent.py +37 -16
  188. connectonion/core/exceptions.py +74 -0
  189. connectonion/core/llm.py +54 -6
  190. connectonion/core/tool_executor.py +32 -31
  191. connectonion/core/tool_factory.py +47 -10
  192. connectonion/debug/__init__.py +10 -1
  193. connectonion/debug/debug_explainer/__init__.py +10 -1
  194. connectonion/debug/execution_analyzer/__init__.py +10 -1
  195. connectonion/debug/execution_analyzer/execution_analysis.py +5 -2
  196. connectonion/debug/runtime_inspector/__init__.py +10 -1
  197. connectonion/docs/.package-ignore +6 -0
  198. connectonion/docs/README.md +2036 -0
  199. connectonion/docs/api.md +457 -0
  200. connectonion/docs/archive/001-ai-agent-is-just-prompt-plus-function.md +249 -0
  201. connectonion/docs/archive/README.md +53 -0
  202. connectonion/docs/archive/archive/consolidation-plan.md +72 -0
  203. connectonion/docs/archive/archive/core-principles-extracted.md +239 -0
  204. connectonion/docs/archive/archive/master-principles.md +222 -0
  205. connectonion/docs/archive/archive/principles.md +293 -0
  206. connectonion/docs/archive/archive/simplicity-principles.md +221 -0
  207. connectonion/docs/archive/attack-defense-insights.md +410 -0
  208. connectonion/docs/archive/business-model.md +305 -0
  209. connectonion/docs/archive/core-principles-unified.md +190 -0
  210. connectonion/docs/archive/discussion-journey.md +178 -0
  211. connectonion/docs/archive/economic-analysis.md +323 -0
  212. connectonion/docs/archive/features/01-share-and-find.md +256 -0
  213. connectonion/docs/archive/features/02-agent-authentication.md +93 -0
  214. connectonion/docs/archive/features/03-test-before-trust.md +71 -0
  215. connectonion/docs/archive/features/06-reliability-and-offline.md +197 -0
  216. connectonion/docs/archive/features/README.md +46 -0
  217. connectonion/docs/archive/features-roadmap.md +247 -0
  218. connectonion/docs/archive/mcp-comparison-insights.md +215 -0
  219. connectonion/docs/archive/migration-strategy.md +571 -0
  220. connectonion/docs/archive/mini-whitepaper.md +293 -0
  221. connectonion/docs/archive/network-protocol.md +394 -0
  222. connectonion/docs/archive/semantic-revolution.md +367 -0
  223. connectonion/docs/archive/technical-architecture.md +453 -0
  224. connectonion/docs/archive/the-semantic-insight.md +207 -0
  225. connectonion/docs/archive/threat-model.md +164 -0
  226. connectonion/docs/cli/README.md +805 -0
  227. connectonion/docs/cli/auth.md +46 -0
  228. connectonion/docs/cli/browser.md +235 -0
  229. connectonion/docs/cli/copy.md +232 -0
  230. connectonion/docs/cli/create.md +335 -0
  231. connectonion/docs/cli/init.md +431 -0
  232. connectonion/docs/co-directory-structure.md +214 -0
  233. connectonion/docs/concepts/agent.md +1078 -0
  234. connectonion/docs/concepts/events.md +699 -0
  235. connectonion/docs/concepts/llm_do.md +256 -0
  236. connectonion/docs/concepts/max_iterations.md +362 -0
  237. connectonion/docs/concepts/models.md +641 -0
  238. connectonion/docs/concepts/plugins.md +100 -0
  239. connectonion/docs/concepts/prompts.md +122 -0
  240. connectonion/docs/concepts/session.md +428 -0
  241. connectonion/docs/concepts/tools.md +512 -0
  242. connectonion/docs/concepts/transcribe.md +156 -0
  243. connectonion/docs/concepts/trust.md +291 -0
  244. connectonion/docs/connectonion.md +1256 -0
  245. connectonion/docs/debug/README.md +18 -0
  246. connectonion/docs/debug/auto_debug.md +1026 -0
  247. connectonion/docs/debug/console.md +129 -0
  248. connectonion/docs/debug/eval-format.md +178 -0
  249. connectonion/docs/debug/eval.md +230 -0
  250. connectonion/docs/debug/exceptions.md +307 -0
  251. connectonion/docs/debug/log.md +117 -0
  252. connectonion/docs/debug/xray.md +215 -0
  253. connectonion/docs/design-decisions/001-choosing-input-method.md +202 -0
  254. connectonion/docs/design-decisions/002-choosing-llm-function-name.md +202 -0
  255. connectonion/docs/design-decisions/003-choosing-trust-keyword.md +141 -0
  256. connectonion/docs/design-decisions/004-cli-create-flow.md +117 -0
  257. connectonion/docs/design-decisions/005-designing-agent-network-protocol.md +503 -0
  258. connectonion/docs/design-decisions/006-agent-address-format.md +305 -0
  259. connectonion/docs/design-decisions/007-authentication-backend-design.md +240 -0
  260. connectonion/docs/design-decisions/008-naming-is-hard.md +228 -0
  261. connectonion/docs/design-decisions/009-why-connect-function.md +167 -0
  262. connectonion/docs/design-decisions/010-cli-ux-progressive-disclosure.md +176 -0
  263. connectonion/docs/design-decisions/011-global-config-identity-management.md +357 -0
  264. connectonion/docs/design-decisions/012-tool-execution-separation.md +259 -0
  265. connectonion/docs/design-decisions/013-debug-and-logging-design.md +253 -0
  266. connectonion/docs/design-decisions/014-hook-system-design.md +510 -0
  267. connectonion/docs/design-decisions/015-interactive-auto-debug-design.md +837 -0
  268. connectonion/docs/design-decisions/016-why-no-zero-knowledge-proofs.md +358 -0
  269. connectonion/docs/design-decisions/017-session-logging-and-eval-format.md +120 -0
  270. connectonion/docs/design-decisions/018-event-api-naming.md +274 -0
  271. connectonion/docs/design-decisions/019-agent-lifecycle-design.md +655 -0
  272. connectonion/docs/design-decisions/020-trust-system-and-network-architecture.md +503 -0
  273. connectonion/docs/design-decisions/021-task-storage-jsonl-design.md +496 -0
  274. connectonion/docs/design-decisions/022-raw-asgi-implementation.md +273 -0
  275. connectonion/docs/examples.md +0 -0
  276. connectonion/docs/hook-system-options.md +364 -0
  277. connectonion/docs/integrations/README.md +12 -0
  278. connectonion/docs/integrations/auth.md +450 -0
  279. connectonion/docs/integrations/google.md +431 -0
  280. connectonion/docs/integrations/microsoft.md +370 -0
  281. connectonion/docs/network/README.md +14 -0
  282. connectonion/docs/network/connect.md +629 -0
  283. connectonion/docs/network/deploy.md +124 -0
  284. connectonion/docs/network/host.md +1087 -0
  285. connectonion/docs/network/io.md +538 -0
  286. connectonion/docs/network/protocol/agent-relay-protocol.md +495 -0
  287. connectonion/docs/network/protocol/announce-message.md +115 -0
  288. connectonion/docs/principles.md +124 -0
  289. connectonion/docs/quickstart.md +261 -0
  290. connectonion/docs/roadmap.md +81 -0
  291. connectonion/docs/templates/README.md +77 -0
  292. connectonion/docs/templates/meta-agent.md +152 -0
  293. connectonion/docs/templates/minimal.md +105 -0
  294. connectonion/docs/templates/playwright.md +130 -0
  295. connectonion/docs/templates/web-research.md +144 -0
  296. connectonion/docs/tui/README.md +95 -0
  297. connectonion/docs/tui/chat.md +181 -0
  298. connectonion/docs/tui/divider.md +63 -0
  299. connectonion/docs/tui/dropdown.md +83 -0
  300. connectonion/docs/tui/footer.md +44 -0
  301. connectonion/docs/tui/fuzzy.md +68 -0
  302. connectonion/docs/tui/input.md +84 -0
  303. connectonion/docs/tui/keys.md +77 -0
  304. connectonion/docs/tui/pick.md +71 -0
  305. connectonion/docs/tui/providers.md +89 -0
  306. connectonion/docs/tui/status_bar.md +67 -0
  307. connectonion/docs/useful_plugins/README.md +160 -0
  308. connectonion/docs/useful_plugins/calendar_plugin.md +68 -0
  309. connectonion/docs/useful_plugins/eval.md +89 -0
  310. connectonion/docs/useful_plugins/gmail_plugin.md +68 -0
  311. connectonion/docs/useful_plugins/image_result_formatter.md +74 -0
  312. connectonion/docs/useful_plugins/re_act.md +86 -0
  313. connectonion/docs/useful_plugins/shell_approval.md +69 -0
  314. connectonion/docs/useful_plugins/system_reminder.md +210 -0
  315. connectonion/docs/useful_prompts/README.md +127 -0
  316. connectonion/docs/useful_prompts/coding_agent.md +214 -0
  317. connectonion/docs/useful_tools/README.md +81 -0
  318. connectonion/docs/useful_tools/ask_user.md +103 -0
  319. connectonion/docs/useful_tools/diff_writer.md +158 -0
  320. connectonion/docs/useful_tools/get_emails.md +519 -0
  321. connectonion/docs/useful_tools/gmail.md +155 -0
  322. connectonion/docs/useful_tools/google_calendar.md +126 -0
  323. connectonion/docs/useful_tools/memory.md +506 -0
  324. connectonion/docs/useful_tools/microsoft_calendar.md +126 -0
  325. connectonion/docs/useful_tools/outlook.md +140 -0
  326. connectonion/docs/useful_tools/send_email.md +423 -0
  327. connectonion/docs/useful_tools/shell.md +115 -0
  328. connectonion/docs/useful_tools/slash_command.md +116 -0
  329. connectonion/docs/useful_tools/terminal.md +115 -0
  330. connectonion/docs/useful_tools/todo_list.md +272 -0
  331. connectonion/docs/useful_tools/web_fetch.md +150 -0
  332. connectonion/docs/vibe-coding-guide.md +97 -0
  333. connectonion/docs/windows-support.md +258 -0
  334. connectonion/logger.py +3 -3
  335. connectonion/network/__init__.py +19 -6
  336. connectonion/network/asgi/__init__.py +81 -0
  337. connectonion/network/asgi/http.py +205 -0
  338. connectonion/network/asgi/websocket.py +217 -0
  339. connectonion/network/connect.py +232 -185
  340. connectonion/network/host/__init__.py +59 -0
  341. connectonion/network/host/auth.py +191 -0
  342. connectonion/network/host/routes.py +135 -0
  343. connectonion/network/host/server.py +289 -0
  344. connectonion/network/host/session.py +78 -0
  345. connectonion/network/io/__init__.py +21 -0
  346. connectonion/network/{connection.py → io/base.py} +17 -42
  347. connectonion/network/io/websocket.py +55 -0
  348. connectonion/network/relay.py +37 -16
  349. connectonion/network/trust/__init__.py +30 -0
  350. connectonion/network/trust/factory.py +138 -0
  351. connectonion/network/{trust_agents.py → trust/prompts.py} +3 -3
  352. connectonion/network/{trust_functions.py → trust/tools.py} +2 -2
  353. connectonion/prompt_files/__init__.py +11 -1
  354. connectonion/prompt_files/react_acknowledge.md +26 -0
  355. connectonion/prompts.py +10 -1
  356. connectonion/tui/chat.py +10 -1
  357. connectonion/tui/divider.py +10 -1
  358. connectonion/tui/dropdown.py +10 -1
  359. connectonion/tui/footer.py +8 -0
  360. connectonion/tui/fuzzy.py +11 -1
  361. connectonion/tui/input.py +118 -70
  362. connectonion/tui/keys.py +133 -6
  363. connectonion/tui/providers.py +11 -1
  364. connectonion/tui/status_bar.py +10 -1
  365. connectonion/useful_events_handlers/__init__.py +8 -0
  366. connectonion/useful_events_handlers/reflect.py +19 -4
  367. connectonion/useful_plugins/__init__.py +2 -1
  368. connectonion/useful_plugins/eval.py +2 -2
  369. connectonion/useful_plugins/gmail_plugin.py +3 -3
  370. connectonion/useful_plugins/image_result_formatter.py +3 -3
  371. connectonion/useful_plugins/re_act.py +114 -28
  372. connectonion/useful_plugins/shell_approval.py +2 -2
  373. connectonion/useful_plugins/system_reminder.py +103 -0
  374. connectonion/useful_plugins/ui_stream.py +18 -133
  375. connectonion/useful_prompts/README.md +61 -0
  376. connectonion/useful_prompts/__init__.py +45 -0
  377. connectonion/useful_prompts/coding_agent/README.md +106 -0
  378. connectonion/useful_prompts/coding_agent/assembler.py +123 -0
  379. connectonion/useful_prompts/coding_agent/prompts/main.md +227 -0
  380. connectonion/useful_prompts/coding_agent/prompts/tools/ask_user.md +61 -0
  381. connectonion/useful_prompts/coding_agent/prompts/tools/background.md +57 -0
  382. connectonion/useful_prompts/coding_agent/prompts/tools/edit.md +90 -0
  383. connectonion/useful_prompts/coding_agent/prompts/tools/glob.md +52 -0
  384. connectonion/useful_prompts/coding_agent/prompts/tools/grep.md +55 -0
  385. connectonion/useful_prompts/coding_agent/prompts/tools/plan_mode.md +80 -0
  386. connectonion/useful_prompts/coding_agent/prompts/tools/read.md +40 -0
  387. connectonion/useful_prompts/coding_agent/prompts/tools/shell.md +67 -0
  388. connectonion/useful_prompts/coding_agent/prompts/tools/task.md +51 -0
  389. connectonion/useful_prompts/coding_agent/prompts/tools/todo.md +139 -0
  390. connectonion/useful_prompts/coding_agent/prompts/tools/write.md +48 -0
  391. connectonion/useful_prompts/system-reminders/security-warning.md +14 -0
  392. connectonion/useful_prompts/system-reminders/test-reminder.md +11 -0
  393. connectonion/useful_tools/__init__.py +31 -4
  394. connectonion/useful_tools/ask_user.py +35 -0
  395. connectonion/useful_tools/bash.py +69 -0
  396. connectonion/useful_tools/diff_writer.py +186 -94
  397. connectonion/useful_tools/edit.py +102 -0
  398. connectonion/useful_tools/glob_files.py +97 -0
  399. connectonion/useful_tools/grep_files.py +171 -0
  400. connectonion/useful_tools/multi_edit.py +116 -0
  401. connectonion/useful_tools/read_file.py +73 -0
  402. connectonion/useful_tools/shell.py +50 -45
  403. connectonion/useful_tools/write_file.py +129 -0
  404. {connectonion-0.6.1.dist-info → connectonion-0.6.3.dist-info}/METADATA +10 -3
  405. connectonion-0.6.3.dist-info/RECORD +469 -0
  406. connectonion/cli/browser_agent/scroll_strategies.py +0 -276
  407. connectonion/network/asgi.py +0 -407
  408. connectonion/network/host.py +0 -616
  409. connectonion/network/trust.py +0 -166
  410. connectonion-0.6.1.dist-info/RECORD +0 -123
  411. /connectonion/cli/{docs → co_ai/prompts/connectonion}/connectonion.md +0 -0
  412. {connectonion-0.6.1.dist-info → connectonion-0.6.3.dist-info}/WHEEL +0 -0
  413. {connectonion-0.6.1.dist-info → connectonion-0.6.3.dist-info}/entry_points.txt +0 -0
connectonion/__init__.py CHANGED
@@ -1,13 +1,23 @@
1
- """ConnectOnion - A simple agent framework with behavior tracking."""
1
+ """
2
+ Purpose: Main package entry point exposing public API for ConnectOnion framework
3
+ LLM-Note:
4
+ Dependencies: imports from [core/, logger.py, llm_do.py, transcribe.py, prompts.py, debug/, useful_tools/, network/, address.py] | imported by [user code, tests/, examples/] | no direct tests (integration tests import from here)
5
+ Data flow: loads .env from cwd via load_dotenv() → exports all public API symbols → user imports `from connectonion import Agent, llm_do, ...`
6
+ State/Effects: auto-loads .env file from current working directory (NOT module directory) at import time
7
+ Integration: exposes complete public API: Agent, LLM, Logger, create_tool_from_function, llm_do, transcribe, xray, event decorators, built-in tools, networking functions | __all__ defines explicit public exports
8
+ Performance: .env loading happens once at first import (dotenv caches)
9
+ Errors: none (import errors bubble from submodules)
10
+ ConnectOnion - A simple agent framework with behavior tracking.
11
+ """
2
12
 
3
- __version__ = "0.6.1"
13
+ __version__ = "0.6.3"
4
14
 
5
15
  # Auto-load .env files for the entire framework
6
16
  from dotenv import load_dotenv
7
17
  from pathlib import Path as _Path
8
18
 
9
- # Load from current working directory (where user runs their script)
10
- # NOT from the module's location (framework directory)
19
+ # SDK only loads from current working directory (where user runs their script)
20
+ # CLI commands (co ai, co browser, etc.) handle global fallback separately
11
21
  load_dotenv(_Path.cwd() / ".env")
12
22
 
13
23
  from .core import Agent, LLM, create_tool_from_function
@@ -27,12 +37,20 @@ from .llm_do import llm_do
27
37
  from .transcribe import transcribe
28
38
  from .prompts import load_system_prompt
29
39
  from .debug import xray, auto_debug_exception, replay, xray_replay
30
- from .useful_tools import send_email, get_emails, mark_read, mark_unread, Memory, Gmail, GoogleCalendar, Outlook, MicrosoftCalendar, WebFetch, Shell, DiffWriter, pick, yes_no, autocomplete, TodoList, SlashCommand
31
- from .network import connect, RemoteAgent, host, create_app, Connection
40
+ from .useful_tools import (
41
+ send_email, get_emails, mark_read, mark_unread,
42
+ Memory, Gmail, GoogleCalendar, Outlook, MicrosoftCalendar,
43
+ WebFetch, Shell, bash, DiffWriter, MODE_NORMAL, MODE_AUTO, MODE_PLAN,
44
+ pick, yes_no, autocomplete, TodoList, SlashCommand,
45
+ # Claude Code-style file tools
46
+ read_file, edit, multi_edit, glob, grep, write, FileWriter,
47
+ )
48
+ from .network import connect, RemoteAgent, Response, host, create_app, IO
32
49
  from .network import relay, announce
33
50
  from . import address
34
51
 
35
52
  __all__ = [
53
+ # Core
36
54
  "Agent",
37
55
  "LLM",
38
56
  "Logger",
@@ -43,10 +61,13 @@ __all__ = [
43
61
  "xray",
44
62
  "replay",
45
63
  "xray_replay",
64
+ "auto_debug_exception",
65
+ # Email tools
46
66
  "send_email",
47
67
  "get_emails",
48
68
  "mark_read",
49
69
  "mark_unread",
70
+ # Class-based tools
50
71
  "Memory",
51
72
  "Gmail",
52
73
  "GoogleCalendar",
@@ -54,21 +75,37 @@ __all__ = [
54
75
  "MicrosoftCalendar",
55
76
  "WebFetch",
56
77
  "Shell",
78
+ "bash",
57
79
  "DiffWriter",
80
+ "MODE_NORMAL",
81
+ "MODE_AUTO",
82
+ "MODE_PLAN",
83
+ # TUI helpers
58
84
  "pick",
59
85
  "yes_no",
60
86
  "autocomplete",
87
+ # Task management
61
88
  "TodoList",
62
89
  "SlashCommand",
63
- "auto_debug_exception",
90
+ # Claude Code-style file tools
91
+ "read_file",
92
+ "edit",
93
+ "multi_edit",
94
+ "glob",
95
+ "grep",
96
+ "write",
97
+ "FileWriter",
98
+ # Networking
64
99
  "connect",
65
100
  "RemoteAgent",
101
+ "Response",
66
102
  "host",
67
103
  "create_app",
68
- "Connection",
104
+ "IO",
69
105
  "relay",
70
106
  "announce",
71
107
  "address",
108
+ # Event decorators
72
109
  "after_user_input",
73
110
  "before_llm",
74
111
  "after_llm",
@@ -77,5 +114,5 @@ __all__ = [
77
114
  "after_each_tool",
78
115
  "after_tools",
79
116
  "on_error",
80
- "on_complete"
117
+ "on_complete",
81
118
  ]
@@ -1,3 +1,13 @@
1
- """ConnectOnion CLI module."""
1
+ """
2
+ Purpose: CLI module entry point with version metadata
3
+ LLM-Note:
4
+ Dependencies: none | imported by [cli/main.py, setup.py] | no direct tests
5
+ Data flow: pure metadata (version string)
6
+ State/Effects: no state
7
+ Integration: exposes __version__ for CLI about/version commands
8
+ Performance: trivial
9
+ Errors: none
10
+ ConnectOnion CLI module.
11
+ """
2
12
 
3
13
  __version__ = "0.0.1b5"
@@ -1,4 +1,14 @@
1
- """Browser agent module for ConnectOnion CLI."""
1
+ """
2
+ Purpose: Browser agent module exports for CLI browser automation
3
+ LLM-Note:
4
+ Dependencies: imports from [browser.py] | imported by [cli/commands/browser_commands.py] | no direct tests
5
+ Data flow: re-exports execute_browser_command and BrowserAutomation
6
+ State/Effects: no state
7
+ Integration: exposes execute_browser_command(), BrowserAutomation class for `co browser` command
8
+ Performance: trivial
9
+ Errors: none
10
+ Browser agent module for ConnectOnion CLI.
11
+ """
2
12
 
3
13
  from .browser import execute_browser_command, BrowserAutomation
4
14
 
@@ -1,4 +1,13 @@
1
- """Browser Agent for CLI - Natural language browser automation.
1
+ """
2
+ Purpose: Natural language browser automation via Playwright with Chrome profile support
3
+ LLM-Note:
4
+ Dependencies: imports from [playwright.sync_api, connectonion Agent/llm_do, cli/browser_agent/element_finder, pydantic, pathlib, dotenv] | imported by [cli/commands/browser_commands.py] | tested by [tests/cli/test_browser_agent.py]
5
+ Data flow: BrowserAutomation() initializes Playwright → copies Chrome profile to .browser_agent_profile/ → opens browser with context → provides tools (navigate, find_element, fill_form, screenshot, scroll, wait_for_login) → Agent uses these tools via natural language → element_finder.py uses vision LLM to locate elements | screenshots saved to .tmp/ directory
6
+ State/Effects: maintains browser/page/context state | copies Chrome profile on first run | writes screenshots to .tmp/{timestamp}.png | modifies form_data dict for form fills | auto-closes browser in __del__
7
+ Integration: exposes BrowserAutomation(use_chrome_profile, headless) with methods: navigate(url), find_element(description), fill_form(field_values), screenshot(viewport), scroll(direction, description), click(description), type_text(description, text), wait_for_login(seconds) | FormField Pydantic model for form parsing | used by `co browser` CLI command
8
+ Performance: headless by default (faster) | Chrome profile copy (one-time, slow first run) | vision model for element finding (slower but accurate) | screenshots base64-encoded for LLM analysis
9
+ Errors: returns error string if Playwright not installed | returns "Browser already open" if reinitializing | element not found returns descriptive error | Chrome must be closed when using profile
10
+ Browser Agent for CLI - Natural language browser automation.
2
11
 
3
12
  This module provides a browser automation agent that understands natural language
4
13
  requests for browser operations via the ConnectOnion CLI.
@@ -20,6 +29,7 @@ from typing import Optional, List, Dict, Any
20
29
  from connectonion import Agent, llm_do
21
30
  from dotenv import load_dotenv
22
31
  from pydantic import BaseModel, Field
32
+ from . import element_finder
23
33
 
24
34
  # Default screenshots directory
25
35
  SCREENSHOTS_DIR = Path.cwd() / ".tmp"
@@ -53,7 +63,7 @@ class BrowserAutomation:
53
63
  Supports Chrome profile for persistent sessions.
54
64
  """
55
65
 
56
- def __init__(self, use_chrome_profile: bool = False, headless: bool = True):
66
+ def __init__(self, use_chrome_profile: bool = True, headless: bool = True):
57
67
  """Initialize browser automation.
58
68
 
59
69
  Args:
@@ -95,8 +105,9 @@ class BrowserAutomation:
95
105
  self.playwright = sync_playwright().start()
96
106
 
97
107
  if self.use_chrome_profile:
98
- # Use Chromium with Chrome profile copy
99
- chromium_profile = Path.cwd() / "chromium_automation_profile"
108
+ # Use Chromium with Chrome profile copy in global ~/.co/ folder
109
+ chromium_profile = Path.home() / ".co" / "browser_profile"
110
+ chromium_profile.parent.mkdir(parents=True, exist_ok=True)
100
111
 
101
112
  if not chromium_profile.exists():
102
113
  import shutil
@@ -109,17 +120,28 @@ class BrowserAutomation:
109
120
  source_profile = home / ".config/google-chrome"
110
121
 
111
122
  if source_profile.exists():
123
+ def safe_copy(src, dst):
124
+ try:
125
+ shutil.copy2(src, dst)
126
+ except:
127
+ pass # Skip any file that can't be copied
128
+
112
129
  shutil.copytree(
113
130
  source_profile,
114
131
  chromium_profile,
115
- ignore=shutil.ignore_patterns('*Cache*', '*cache*', 'Service Worker', 'ShaderCache'),
132
+ ignore=shutil.ignore_patterns(
133
+ '*Cache*', '*cache*', 'Service Worker', 'ShaderCache',
134
+ 'Singleton*', '*lock*', '*Lock*', '*.tmp', 'GPUCache',
135
+ 'Code Cache', 'DawnCache', 'GrShaderCache', 'blob_storage'
136
+ ),
137
+ copy_function=safe_copy,
116
138
  dirs_exist_ok=True
117
139
  )
118
140
 
119
141
  self.browser = self.playwright.chromium.launch_persistent_context(
120
142
  str(chromium_profile),
121
143
  headless=headless,
122
- args=['--disable-blink-features=AutomationControlled'],
144
+ args=['--no-sandbox', '--disable-setuid-sandbox', '--disable-blink-features=AutomationControlled'],
123
145
  ignore_default_args=['--enable-automation'],
124
146
  timeout=120000,
125
147
  )
@@ -127,10 +149,12 @@ class BrowserAutomation:
127
149
  self.page.add_init_script("""
128
150
  Object.defineProperty(navigator, 'webdriver', { get: () => undefined });
129
151
  """)
152
+ self.page.set_viewport_size({"width": 1920, "height": 1080})
130
153
  return f"Browser opened with Chrome profile: {chromium_profile}"
131
154
  else:
132
155
  self.browser = self.playwright.chromium.launch(headless=headless)
133
156
  self.page = self.browser.new_page()
157
+ self.page.set_viewport_size({"width": 1920, "height": 1080})
134
158
  return "Browser opened successfully"
135
159
 
136
160
  def go_to(self, url: str) -> str:
@@ -149,88 +173,94 @@ class BrowserAutomation:
149
173
  def find_element_by_description(self, description: str) -> str:
150
174
  """Find element using natural language description.
151
175
 
152
- Uses AI to analyze HTML and find the best matching element.
176
+ Uses element_finder: LLM selects from indexed list, never generates CSS.
153
177
 
154
178
  Args:
155
179
  description: e.g., "the submit button", "email input field"
156
180
 
157
181
  Returns:
158
- CSS selector for the element, or error message
182
+ Pre-built locator string, or error message
159
183
  """
160
184
  if not self.page:
161
185
  return "Browser not open"
162
186
 
163
- html = self.page.content()
164
-
165
- class ElementSelector(BaseModel):
166
- selector: str = Field(..., description="CSS selector for the element")
167
- confidence: float = Field(..., description="Confidence score 0-1")
168
- explanation: str = Field(..., description="Why this element matches")
169
-
170
- result = llm_do(
171
- f"""Analyze this HTML and find the CSS selector for: "{description}"
172
-
173
- HTML (first 15000 chars): {html[:15000]}
174
-
175
- Return the most specific CSS selector that uniquely identifies this element.
176
- """,
177
- output=ElementSelector,
178
- model="gpt-4o",
179
- temperature=0.1
180
- )
181
-
182
- if self.page.locator(result.selector).count() > 0:
183
- return result.selector
184
- else:
185
- return f"Found selector {result.selector} but element not on page"
187
+ element = element_finder.find_element(self.page, description)
188
+ if element:
189
+ return element.locator
190
+ return f"Could not find element matching: {description}"
186
191
 
187
192
  def click(self, description: str) -> str:
188
193
  """Click on an element using natural language description.
189
194
 
190
- Args:
191
- description: e.g., "the blue submit button", "link to contact page"
195
+ Uses element_finder: LLM selects from pre-built locators, never generates CSS.
192
196
  """
193
197
  if not self.page:
194
198
  return "Browser not open"
195
199
 
196
- selector = self.find_element_by_description(description)
200
+ element = element_finder.find_element(self.page, description)
197
201
 
198
- if selector.startswith("Could not") or selector.startswith("Found selector"):
199
- if self.page.locator(f"text='{description}'").count() > 0:
200
- self.page.click(f"text='{description}'")
201
- return f"Clicked on '{description}' (by text)"
202
- return selector
202
+ if not element:
203
+ # Fallback to simple text matching
204
+ text_locator = self.page.get_by_text(description)
205
+ if text_locator.count() > 0:
206
+ text_locator.first.click()
207
+ return f"Clicked on '{description}' (by text fallback)"
208
+ return f"Could not find element matching: {description}"
203
209
 
204
- self.page.click(selector)
205
- return f"Clicked on '{description}'"
210
+ # Try the locator with fresh bounding box
211
+ locator = self.page.locator(element.locator)
212
+
213
+ if locator.count() > 0:
214
+ box = locator.first.bounding_box()
215
+ if box:
216
+ x = box['x'] + box['width'] / 2
217
+ y = box['y'] + box['height'] / 2
218
+ self.page.mouse.click(x, y)
219
+ return f"Clicked [{element.index}] {element.tag} '{element.text}'"
220
+
221
+ locator.first.click(force=True)
222
+ return f"Clicked [{element.index}] {element.tag} '{element.text}' (force)"
223
+
224
+ # Fallback: use original coordinates
225
+ x = element.x + element.width // 2
226
+ y = element.y + element.height // 2
227
+ self.page.mouse.click(x, y)
228
+ return f"Clicked [{element.index}] '{element.text}' at ({x}, {y})"
206
229
 
207
230
  def type_text(self, field_description: str, text: str) -> str:
208
231
  """Type text into a form field.
209
232
 
210
- Args:
211
- field_description: e.g., "email field", "password input"
212
- text: The text to type
233
+ Uses element_finder: LLM selects from pre-built locators, never generates CSS.
213
234
  """
214
235
  if not self.page:
215
236
  return "Browser not open"
216
237
 
217
- selector = self.find_element_by_description(field_description)
218
-
219
- if selector.startswith("Could not") or selector.startswith("Found selector"):
220
- for fallback in [
221
- f"input[placeholder*='{field_description}' i]",
222
- f"[aria-label*='{field_description}' i]",
223
- f"input[name*='{field_description}' i]"
224
- ]:
225
- if self.page.locator(fallback).count() > 0:
226
- self.page.fill(fallback, text)
227
- self.form_data[field_description] = text
228
- return f"Typed into {field_description}"
229
- return f"Could not find field '{field_description}'"
230
-
231
- self.page.fill(selector, text)
238
+ element = element_finder.find_element(self.page, field_description)
239
+
240
+ if not element:
241
+ # Fallback to placeholder matching
242
+ placeholder_locator = self.page.get_by_placeholder(field_description)
243
+ if placeholder_locator.count() > 0:
244
+ placeholder_locator.first.fill(text)
245
+ self.form_data[field_description] = text
246
+ return f"Typed into '{field_description}'"
247
+ return f"Could not find field: {field_description}"
248
+
249
+ # Try the pre-built locator
250
+ locator = self.page.locator(element.locator)
251
+
252
+ if locator.count() > 0:
253
+ locator.first.fill(text)
254
+ self.form_data[field_description] = text
255
+ return f"Typed into [{element.index}] {element.tag}"
256
+
257
+ # Fallback: click then type
258
+ x = element.x + element.width // 2
259
+ y = element.y + element.height // 2
260
+ self.page.mouse.click(x, y)
261
+ self.page.keyboard.type(text)
232
262
  self.form_data[field_description] = text
233
- return f"Typed into {field_description}"
263
+ return f"Typed into [{element.index}] at ({x}, {y})"
234
264
 
235
265
  def get_text(self) -> str:
236
266
  """Get all visible text from the page."""
@@ -306,27 +336,6 @@ class BrowserAutomation:
306
336
  self.page.set_viewport_size({"width": width, "height": height})
307
337
  return f"Viewport set to {width}x{height}"
308
338
 
309
- def screenshot_mobile(self, url: str = None) -> str:
310
- """Take screenshot with iPhone viewport (390x844)."""
311
- if url:
312
- self.go_to(url)
313
- self.set_viewport(390, 844)
314
- return self.take_screenshot()
315
-
316
- def screenshot_tablet(self, url: str = None) -> str:
317
- """Take screenshot with iPad viewport (768x1024)."""
318
- if url:
319
- self.go_to(url)
320
- self.set_viewport(768, 1024)
321
- return self.take_screenshot()
322
-
323
- def screenshot_desktop(self, url: str = None) -> str:
324
- """Take screenshot with desktop viewport (1920x1080)."""
325
- if url:
326
- self.go_to(url)
327
- self.set_viewport(1920, 1080)
328
- return self.take_screenshot()
329
-
330
339
  def find_forms(self) -> List[FormField]:
331
340
  """Find all form fields on the current page."""
332
341
  if not self.page:
@@ -440,69 +449,13 @@ class BrowserAutomation:
440
449
  return f"Waited for {seconds} seconds"
441
450
 
442
451
  def scroll(self, times: int = 5, description: str = "the main content area") -> str:
443
- """Universal scroll with automatic strategy selection.
444
-
445
- Tries multiple strategies until one works:
446
- 1. AI-generated strategy (analyzes page structure)
447
- 2. Element scrolling
448
- 3. Page scrolling
452
+ """Universal scroll with AI strategy and fallback.
449
453
 
450
- Args:
451
- times: Number of scroll iterations
452
- description: What to scroll (e.g., "the email list")
453
-
454
- Returns:
455
- Status message with successful strategy
454
+ Tries: AI-generated → Element scroll → Page scroll
455
+ Verifies success with screenshot comparison.
456
456
  """
457
- from . import scroll_strategies
458
- return scroll_strategies.scroll_with_verification(
459
- page=self.page,
460
- take_screenshot=self.take_screenshot,
461
- times=times,
462
- description=description
463
- )
464
-
465
- def scroll_page(self, direction: str = "down", amount: int = 1000) -> str:
466
- """Scroll the page in a direction.
467
-
468
- Args:
469
- direction: "down", "up", "top", or "bottom"
470
- amount: Pixels to scroll (ignored for "bottom"/"top")
471
- """
472
- if not self.page:
473
- return "Browser not open"
474
-
475
- if direction == "bottom":
476
- self.page.evaluate("window.scrollTo(0, document.body.scrollHeight)")
477
- return "Scrolled to bottom of page"
478
- elif direction == "top":
479
- self.page.evaluate("window.scrollTo(0, 0)")
480
- return "Scrolled to top of page"
481
- elif direction == "down":
482
- self.page.evaluate(f"window.scrollBy(0, {amount})")
483
- return f"Scrolled down {amount} pixels"
484
- elif direction == "up":
485
- self.page.evaluate(f"window.scrollBy(0, -{amount})")
486
- return f"Scrolled up {amount} pixels"
487
- else:
488
- return f"Unknown direction: {direction}"
489
-
490
- def scroll_element(self, selector: str, amount: int = 1000) -> str:
491
- """Scroll a specific element by CSS selector."""
492
- if not self.page:
493
- return "Browser not open"
494
-
495
- result = self.page.evaluate(f"""
496
- (() => {{
497
- const element = document.querySelector('{selector}');
498
- if (!element) return 'Element not found: {selector}';
499
- const beforeScroll = element.scrollTop;
500
- element.scrollTop += {amount};
501
- const afterScroll = element.scrollTop;
502
- return `Scrolled from ${{beforeScroll}}px to ${{afterScroll}}px`;
503
- }})()
504
- """)
505
- return result
457
+ from . import scroll
458
+ return scroll.scroll(self.page, self.take_screenshot, times, description)
506
459
 
507
460
  def wait_for_manual_login(self, site_name: str = "the website") -> str:
508
461
  """Pause automation for user to login manually.
@@ -0,0 +1,147 @@
1
+ """
2
+ Purpose: Find interactive elements on web pages using natural language descriptions via vision LLM
3
+ LLM-Note:
4
+ Dependencies: imports from [playwright.sync_api Page, connectonion llm_do, pydantic, pathlib] | imported by [cli/browser_agent/browser.py] | tested by [tests/cli/test_element_finder.py]
5
+ Data flow: extract_elements(page) → evaluates extract_elements.js → injects data-browser-agent-id on all interactive elements → returns list[InteractiveElement] with locators | find_element(page, description, elements) → formats elements for LLM → calls llm_do with vision model + screenshot → LLM selects matching element by index → returns InteractiveElement with pre-built locator
6
+ State/Effects: modifies DOM by injecting data-browser-agent-id attributes (temporary, removed on navigation) | takes screenshot for vision analysis | no persistent state
7
+ Integration: exposes extract_elements(page) → list[InteractiveElement], find_element(page, description, elements, screenshot) → InteractiveElement|None, highlight_element(page, element) for visual feedback | InteractiveElement model has tag, text, role, aria_label, placeholder, x, y, width, height, locator | ElementMatch model for LLM response
8
+ Performance: JavaScript extraction is fast | LLM matching uses vision model (slower) | limits to 150 elements for context window | pre-built locators (no retry needed)
9
+ Errors: returns None if no matching element found | raises if Playwright page not available | element may be stale if page navigates
10
+ Element Finder - Find interactive elements by natural language description.
11
+
12
+ Inspired by browser-use (https://github.com/browser-use/browser-use).
13
+
14
+ Architecture:
15
+ 1. JavaScript injects `data-browser-agent-id` into each interactive element
16
+ 2. LLM SELECTS from indexed element list, never GENERATES CSS selectors
17
+ 3. Pre-built locators are guaranteed to work
18
+
19
+ Usage:
20
+ elements = extract_elements(page)
21
+ element = find_element(page, "the login button", elements)
22
+ page.locator(element.locator).click()
23
+ """
24
+
25
+ from typing import List, Optional
26
+ from pathlib import Path
27
+ from pydantic import BaseModel, Field
28
+ from connectonion import llm_do
29
+
30
+
31
+ # Load JavaScript and prompt from files
32
+ _BASE_DIR = Path(__file__).parent
33
+ _EXTRACT_JS = (_BASE_DIR / "scripts" / "extract_elements.js").read_text()
34
+ _ELEMENT_MATCHER_PROMPT = (_BASE_DIR / "prompts" / "element_matcher.md").read_text()
35
+
36
+
37
+ class InteractiveElement(BaseModel):
38
+ """An interactive element on the page with pre-built locator."""
39
+ index: int
40
+ tag: str
41
+ text: str = ""
42
+ role: Optional[str] = None
43
+ aria_label: Optional[str] = None
44
+ placeholder: Optional[str] = None
45
+ input_type: Optional[str] = None
46
+ href: Optional[str] = None
47
+ x: int = 0
48
+ y: int = 0
49
+ width: int = 0
50
+ height: int = 0
51
+ locator: str = ""
52
+
53
+
54
+ class ElementMatch(BaseModel):
55
+ """LLM's element selection result."""
56
+ index: int = Field(..., description="Index of the matching element")
57
+ confidence: float = Field(..., description="Confidence 0-1")
58
+ reasoning: str = Field(..., description="Why this element matches")
59
+
60
+
61
+ def extract_elements(page) -> List[InteractiveElement]:
62
+ """Extract all interactive elements from the page.
63
+
64
+ Returns elements with:
65
+ - Bounding boxes (for position matching with screenshot)
66
+ - Pre-built Playwright locators (guaranteed to work)
67
+ - Text/aria/placeholder for LLM matching
68
+ """
69
+ raw = page.evaluate(_EXTRACT_JS)
70
+ return [InteractiveElement(**el) for el in raw]
71
+
72
+
73
+ def format_elements_for_llm(elements: List[InteractiveElement], max_count: int = 150) -> str:
74
+ """Format elements as compact list for LLM context.
75
+
76
+ Format: [index] tag "text" pos=(x,y) {extra info}
77
+ """
78
+ lines = []
79
+ for el in elements[:max_count]:
80
+ parts = [f"[{el.index}]", el.tag]
81
+
82
+ if el.text:
83
+ parts.append(f'"{el.text}"')
84
+ elif el.placeholder:
85
+ parts.append(f'placeholder="{el.placeholder}"')
86
+ elif el.aria_label:
87
+ parts.append(f'aria="{el.aria_label}"')
88
+
89
+ parts.append(f"pos=({el.x},{el.y})")
90
+
91
+ if el.input_type and el.tag == 'input':
92
+ parts.append(f"type={el.input_type}")
93
+
94
+ if el.role:
95
+ parts.append(f"role={el.role}")
96
+
97
+ if el.href:
98
+ href_short = el.href.split('?')[0][-30:]
99
+ parts.append(f"href=...{href_short}")
100
+
101
+ lines.append(' '.join(parts))
102
+
103
+ return '\n'.join(lines)
104
+
105
+
106
+ def find_element(
107
+ page,
108
+ description: str,
109
+ elements: List[InteractiveElement] = None
110
+ ) -> Optional[InteractiveElement]:
111
+ """Find an interactive element by natural language description.
112
+
113
+ This is the core function. LLM SELECTS from pre-built options.
114
+
115
+ Args:
116
+ page: Playwright page
117
+ description: Natural language like "the login button" or "email field"
118
+ elements: Pre-extracted elements (will extract if not provided)
119
+
120
+ Returns:
121
+ Matching InteractiveElement with pre-built locator, or None
122
+ """
123
+ if elements is None:
124
+ elements = extract_elements(page)
125
+
126
+ if not elements:
127
+ return None
128
+
129
+ element_list = format_elements_for_llm(elements)
130
+
131
+ # Build prompt from template
132
+ prompt = _ELEMENT_MATCHER_PROMPT.format(
133
+ description=description,
134
+ element_list=element_list
135
+ )
136
+
137
+ result = llm_do(
138
+ prompt,
139
+ output=ElementMatch,
140
+ model="co/gemini-2.5-flash",
141
+ temperature=0.1
142
+ )
143
+
144
+ if 0 <= result.index < len(elements):
145
+ return elements[result.index]
146
+
147
+ return None