connectonion 0.6.2__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 (407) 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 +13 -3
  5. connectonion/cli/browser_agent/element_finder.py +8 -0
  6. connectonion/cli/browser_agent/highlight_screenshot.py +9 -1
  7. connectonion/cli/browser_agent/scroll.py +8 -0
  8. connectonion/cli/co_ai/__init__.py +6 -0
  9. connectonion/cli/co_ai/agent.py +87 -0
  10. connectonion/cli/co_ai/agents/__init__.py +5 -0
  11. connectonion/cli/co_ai/agents/registry.py +57 -0
  12. connectonion/cli/co_ai/commands/__init__.py +45 -0
  13. connectonion/cli/co_ai/commands/compact.py +173 -0
  14. connectonion/cli/co_ai/commands/cost.py +77 -0
  15. connectonion/cli/co_ai/commands/export.py +60 -0
  16. connectonion/cli/co_ai/commands/help.py +80 -0
  17. connectonion/cli/co_ai/commands/init.py +101 -0
  18. connectonion/cli/co_ai/commands/sessions.py +55 -0
  19. connectonion/cli/co_ai/commands/tasks.py +63 -0
  20. connectonion/cli/co_ai/commands/undo.py +103 -0
  21. connectonion/cli/co_ai/context.py +127 -0
  22. connectonion/cli/co_ai/main.py +52 -0
  23. connectonion/cli/co_ai/plugins/__init__.py +6 -0
  24. connectonion/cli/co_ai/plugins/reminder.py +76 -0
  25. connectonion/cli/co_ai/plugins/shell_approval.py +105 -0
  26. connectonion/cli/co_ai/prompts/agents/explore.md +79 -0
  27. connectonion/cli/co_ai/prompts/agents/plan.md +60 -0
  28. connectonion/cli/co_ai/prompts/assembler.py +303 -0
  29. connectonion/cli/{docs/co-vibecoding-principles-docs-contexts-all-in-one.md → co_ai/prompts/connectonion/README.md} +26 -0
  30. connectonion/cli/co_ai/prompts/connectonion/api.md +457 -0
  31. connectonion/cli/co_ai/prompts/connectonion/cli/README.md +805 -0
  32. connectonion/cli/co_ai/prompts/connectonion/cli/auth.md +46 -0
  33. connectonion/cli/co_ai/prompts/connectonion/cli/browser.md +235 -0
  34. connectonion/cli/co_ai/prompts/connectonion/cli/copy.md +184 -0
  35. connectonion/cli/co_ai/prompts/connectonion/cli/create.md +335 -0
  36. connectonion/cli/co_ai/prompts/connectonion/cli/init.md +431 -0
  37. connectonion/cli/co_ai/prompts/connectonion/co-directory-structure.md +214 -0
  38. connectonion/cli/co_ai/prompts/connectonion/concepts/agent.md +1078 -0
  39. connectonion/cli/co_ai/prompts/connectonion/concepts/events.md +816 -0
  40. connectonion/cli/co_ai/prompts/connectonion/concepts/llm_do.md +256 -0
  41. connectonion/cli/co_ai/prompts/connectonion/concepts/max_iterations.md +362 -0
  42. connectonion/cli/co_ai/prompts/connectonion/concepts/models.md +641 -0
  43. connectonion/cli/co_ai/prompts/connectonion/concepts/plugins.md +100 -0
  44. connectonion/cli/co_ai/prompts/connectonion/concepts/prompts.md +122 -0
  45. connectonion/cli/co_ai/prompts/connectonion/concepts/tools.md +512 -0
  46. connectonion/cli/co_ai/prompts/connectonion/concepts/transcribe.md +156 -0
  47. connectonion/cli/co_ai/prompts/connectonion/concepts/trust.md +291 -0
  48. connectonion/cli/co_ai/prompts/connectonion/debug/README.md +18 -0
  49. connectonion/cli/co_ai/prompts/connectonion/debug/auto_debug.md +1026 -0
  50. connectonion/cli/co_ai/prompts/connectonion/debug/console.md +129 -0
  51. connectonion/cli/co_ai/prompts/connectonion/debug/eval-format.md +178 -0
  52. connectonion/cli/co_ai/prompts/connectonion/debug/eval.md +230 -0
  53. connectonion/cli/co_ai/prompts/connectonion/debug/exceptions.md +307 -0
  54. connectonion/cli/co_ai/prompts/connectonion/debug/log.md +117 -0
  55. connectonion/cli/co_ai/prompts/connectonion/debug/xray.md +215 -0
  56. connectonion/cli/co_ai/prompts/connectonion/design-decisions/001-choosing-input-method.md +202 -0
  57. connectonion/cli/co_ai/prompts/connectonion/design-decisions/002-choosing-llm-function-name.md +202 -0
  58. connectonion/cli/co_ai/prompts/connectonion/design-decisions/003-choosing-trust-keyword.md +141 -0
  59. connectonion/cli/co_ai/prompts/connectonion/design-decisions/004-cli-create-flow.md +117 -0
  60. connectonion/cli/co_ai/prompts/connectonion/design-decisions/005-designing-agent-network-protocol.md +503 -0
  61. connectonion/cli/co_ai/prompts/connectonion/design-decisions/006-agent-address-format.md +305 -0
  62. connectonion/cli/co_ai/prompts/connectonion/design-decisions/007-authentication-backend-design.md +240 -0
  63. connectonion/cli/co_ai/prompts/connectonion/design-decisions/008-naming-is-hard.md +228 -0
  64. connectonion/cli/co_ai/prompts/connectonion/design-decisions/009-why-connect-function.md +167 -0
  65. connectonion/cli/co_ai/prompts/connectonion/design-decisions/010-cli-ux-progressive-disclosure.md +176 -0
  66. connectonion/cli/co_ai/prompts/connectonion/design-decisions/011-global-config-identity-management.md +357 -0
  67. connectonion/cli/co_ai/prompts/connectonion/design-decisions/012-tool-execution-separation.md +259 -0
  68. connectonion/cli/co_ai/prompts/connectonion/design-decisions/013-debug-and-logging-design.md +253 -0
  69. connectonion/cli/co_ai/prompts/connectonion/design-decisions/014-hook-system-design.md +510 -0
  70. connectonion/cli/co_ai/prompts/connectonion/design-decisions/015-interactive-auto-debug-design.md +837 -0
  71. connectonion/cli/co_ai/prompts/connectonion/design-decisions/016-why-no-zero-knowledge-proofs.md +358 -0
  72. connectonion/cli/co_ai/prompts/connectonion/design-decisions/017-session-logging-and-eval-format.md +120 -0
  73. connectonion/cli/co_ai/prompts/connectonion/design-decisions/018-event-api-naming.md +274 -0
  74. connectonion/cli/co_ai/prompts/connectonion/design-decisions/019-agent-lifecycle-design.md +655 -0
  75. connectonion/cli/co_ai/prompts/connectonion/design-decisions/020-trust-system-and-network-architecture.md +503 -0
  76. connectonion/cli/co_ai/prompts/connectonion/design-decisions/021-task-storage-jsonl-design.md +496 -0
  77. connectonion/cli/co_ai/prompts/connectonion/design-decisions/022-raw-asgi-implementation.md +273 -0
  78. connectonion/cli/co_ai/prompts/connectonion/examples/agent_reasoning.md +62 -0
  79. connectonion/cli/co_ai/prompts/connectonion/examples/atomic_tools.md +24 -0
  80. connectonion/cli/co_ai/prompts/connectonion/examples/load_guide.md +18 -0
  81. connectonion/cli/co_ai/prompts/connectonion/examples.md +0 -0
  82. connectonion/cli/co_ai/prompts/connectonion/hook-system-options.md +364 -0
  83. connectonion/cli/co_ai/prompts/connectonion/index.md +162 -0
  84. connectonion/cli/co_ai/prompts/connectonion/integrations/README.md +12 -0
  85. connectonion/cli/co_ai/prompts/connectonion/integrations/auth.md +450 -0
  86. connectonion/cli/co_ai/prompts/connectonion/integrations/google.md +431 -0
  87. connectonion/cli/co_ai/prompts/connectonion/integrations/microsoft.md +370 -0
  88. connectonion/cli/co_ai/prompts/connectonion/network/README.md +14 -0
  89. connectonion/cli/co_ai/prompts/connectonion/network/connect.md +543 -0
  90. connectonion/cli/co_ai/prompts/connectonion/network/connection.md +538 -0
  91. connectonion/cli/co_ai/prompts/connectonion/network/deploy.md +123 -0
  92. connectonion/cli/co_ai/prompts/connectonion/network/host.md +1049 -0
  93. connectonion/cli/co_ai/prompts/connectonion/network/protocol/agent-relay-protocol.md +495 -0
  94. connectonion/cli/co_ai/prompts/connectonion/network/protocol/announce-message.md +115 -0
  95. connectonion/cli/co_ai/prompts/connectonion/principles.md +124 -0
  96. connectonion/cli/co_ai/prompts/connectonion/quickstart.md +261 -0
  97. connectonion/cli/co_ai/prompts/connectonion/roadmap.md +81 -0
  98. connectonion/cli/co_ai/prompts/connectonion/templates/README.md +77 -0
  99. connectonion/cli/co_ai/prompts/connectonion/templates/meta-agent.md +152 -0
  100. connectonion/cli/co_ai/prompts/connectonion/templates/minimal.md +105 -0
  101. connectonion/cli/co_ai/prompts/connectonion/templates/playwright.md +130 -0
  102. connectonion/cli/co_ai/prompts/connectonion/templates/web-research.md +144 -0
  103. connectonion/cli/co_ai/prompts/connectonion/tui/README.md +95 -0
  104. connectonion/cli/co_ai/prompts/connectonion/tui/chat.md +181 -0
  105. connectonion/cli/co_ai/prompts/connectonion/tui/divider.md +63 -0
  106. connectonion/cli/co_ai/prompts/connectonion/tui/dropdown.md +83 -0
  107. connectonion/cli/co_ai/prompts/connectonion/tui/footer.md +44 -0
  108. connectonion/cli/co_ai/prompts/connectonion/tui/fuzzy.md +68 -0
  109. connectonion/cli/co_ai/prompts/connectonion/tui/input.md +84 -0
  110. connectonion/cli/co_ai/prompts/connectonion/tui/keys.md +77 -0
  111. connectonion/cli/co_ai/prompts/connectonion/tui/pick.md +71 -0
  112. connectonion/cli/co_ai/prompts/connectonion/tui/providers.md +89 -0
  113. connectonion/cli/co_ai/prompts/connectonion/tui/status_bar.md +67 -0
  114. connectonion/cli/co_ai/prompts/connectonion/useful_plugins/README.md +156 -0
  115. connectonion/cli/co_ai/prompts/connectonion/useful_plugins/calendar_plugin.md +68 -0
  116. connectonion/cli/co_ai/prompts/connectonion/useful_plugins/eval.md +89 -0
  117. connectonion/cli/co_ai/prompts/connectonion/useful_plugins/gmail_plugin.md +68 -0
  118. connectonion/cli/co_ai/prompts/connectonion/useful_plugins/image_result_formatter.md +74 -0
  119. connectonion/cli/co_ai/prompts/connectonion/useful_plugins/re_act.md +86 -0
  120. connectonion/cli/co_ai/prompts/connectonion/useful_plugins/shell_approval.md +69 -0
  121. connectonion/cli/co_ai/prompts/connectonion/useful_tools/README.md +81 -0
  122. connectonion/cli/co_ai/prompts/connectonion/useful_tools/diff_writer.md +138 -0
  123. connectonion/cli/co_ai/prompts/connectonion/useful_tools/get_emails.md +499 -0
  124. connectonion/cli/co_ai/prompts/connectonion/useful_tools/gmail.md +135 -0
  125. connectonion/cli/co_ai/prompts/connectonion/useful_tools/google_calendar.md +106 -0
  126. connectonion/cli/co_ai/prompts/connectonion/useful_tools/memory.md +486 -0
  127. connectonion/cli/co_ai/prompts/connectonion/useful_tools/microsoft_calendar.md +106 -0
  128. connectonion/cli/co_ai/prompts/connectonion/useful_tools/outlook.md +120 -0
  129. connectonion/cli/co_ai/prompts/connectonion/useful_tools/send_email.md +403 -0
  130. connectonion/cli/co_ai/prompts/connectonion/useful_tools/shell.md +95 -0
  131. connectonion/cli/co_ai/prompts/connectonion/useful_tools/slash_command.md +96 -0
  132. connectonion/cli/co_ai/prompts/connectonion/useful_tools/terminal.md +97 -0
  133. connectonion/cli/co_ai/prompts/connectonion/useful_tools/todo_list.md +252 -0
  134. connectonion/cli/co_ai/prompts/connectonion/useful_tools/web_fetch.md +130 -0
  135. connectonion/cli/co_ai/prompts/connectonion/vibe-coding-guide.md +97 -0
  136. connectonion/cli/co_ai/prompts/connectonion/windows-support.md +258 -0
  137. connectonion/cli/co_ai/prompts/main.md +247 -0
  138. connectonion/cli/co_ai/prompts/reminders/plan_mode.md +34 -0
  139. connectonion/cli/co_ai/prompts/summarization.md +55 -0
  140. connectonion/cli/co_ai/prompts/tools/ask_user.md +61 -0
  141. connectonion/cli/co_ai/prompts/tools/background.md +57 -0
  142. connectonion/cli/co_ai/prompts/tools/edit.md +90 -0
  143. connectonion/cli/co_ai/prompts/tools/glob.md +52 -0
  144. connectonion/cli/co_ai/prompts/tools/grep.md +55 -0
  145. connectonion/cli/co_ai/prompts/tools/plan_mode.md +80 -0
  146. connectonion/cli/co_ai/prompts/tools/read.md +40 -0
  147. connectonion/cli/co_ai/prompts/tools/shell.md +67 -0
  148. connectonion/cli/co_ai/prompts/tools/task.md +51 -0
  149. connectonion/cli/co_ai/prompts/tools/todo.md +139 -0
  150. connectonion/cli/co_ai/prompts/tools/write.md +47 -0
  151. connectonion/cli/co_ai/prompts/workflow.md +89 -0
  152. connectonion/cli/co_ai/reminders.py +159 -0
  153. connectonion/cli/co_ai/sessions.py +110 -0
  154. connectonion/cli/co_ai/skills/__init__.py +37 -0
  155. connectonion/cli/co_ai/skills/builtin/commit/SKILL.md +63 -0
  156. connectonion/cli/co_ai/skills/builtin/review-pr/SKILL.md +76 -0
  157. connectonion/cli/co_ai/skills/loader.py +166 -0
  158. connectonion/cli/co_ai/skills/tool.py +46 -0
  159. connectonion/cli/co_ai/tools/__init__.py +92 -0
  160. connectonion/cli/co_ai/tools/ask_user.py +35 -0
  161. connectonion/cli/co_ai/tools/background.py +201 -0
  162. connectonion/cli/co_ai/tools/diff_writer.py +291 -0
  163. connectonion/cli/co_ai/tools/edit.py +89 -0
  164. connectonion/cli/co_ai/tools/glob.py +84 -0
  165. connectonion/cli/co_ai/tools/grep.py +158 -0
  166. connectonion/cli/co_ai/tools/load_guide.py +23 -0
  167. connectonion/cli/co_ai/tools/multi_edit.py +116 -0
  168. connectonion/cli/co_ai/tools/plan_mode.py +172 -0
  169. connectonion/cli/co_ai/tools/read.py +67 -0
  170. connectonion/cli/co_ai/tools/task.py +59 -0
  171. connectonion/cli/co_ai/tools/todo_list.py +159 -0
  172. connectonion/cli/co_ai/tools/write.py +126 -0
  173. connectonion/cli/commands/__init__.py +11 -1
  174. connectonion/cli/commands/ai_commands.py +34 -0
  175. connectonion/cli/commands/copy_commands.py +55 -6
  176. connectonion/cli/commands/create.py +20 -17
  177. connectonion/cli/commands/init.py +19 -22
  178. connectonion/cli/commands/project_cmd_lib.py +15 -0
  179. connectonion/cli/main.py +11 -0
  180. connectonion/console.py +15 -1
  181. connectonion/core/__init__.py +10 -1
  182. connectonion/core/agent.py +37 -16
  183. connectonion/core/exceptions.py +74 -0
  184. connectonion/core/llm.py +54 -6
  185. connectonion/core/tool_executor.py +32 -31
  186. connectonion/core/tool_factory.py +47 -10
  187. connectonion/debug/__init__.py +10 -1
  188. connectonion/debug/debug_explainer/__init__.py +10 -1
  189. connectonion/debug/execution_analyzer/__init__.py +10 -1
  190. connectonion/debug/execution_analyzer/execution_analysis.py +5 -2
  191. connectonion/debug/runtime_inspector/__init__.py +10 -1
  192. connectonion/docs/.package-ignore +6 -0
  193. connectonion/docs/README.md +2036 -0
  194. connectonion/docs/api.md +457 -0
  195. connectonion/docs/archive/001-ai-agent-is-just-prompt-plus-function.md +249 -0
  196. connectonion/docs/archive/README.md +53 -0
  197. connectonion/docs/archive/archive/consolidation-plan.md +72 -0
  198. connectonion/docs/archive/archive/core-principles-extracted.md +239 -0
  199. connectonion/docs/archive/archive/master-principles.md +222 -0
  200. connectonion/docs/archive/archive/principles.md +293 -0
  201. connectonion/docs/archive/archive/simplicity-principles.md +221 -0
  202. connectonion/docs/archive/attack-defense-insights.md +410 -0
  203. connectonion/docs/archive/business-model.md +305 -0
  204. connectonion/docs/archive/core-principles-unified.md +190 -0
  205. connectonion/docs/archive/discussion-journey.md +178 -0
  206. connectonion/docs/archive/economic-analysis.md +323 -0
  207. connectonion/docs/archive/features/01-share-and-find.md +256 -0
  208. connectonion/docs/archive/features/02-agent-authentication.md +93 -0
  209. connectonion/docs/archive/features/03-test-before-trust.md +71 -0
  210. connectonion/docs/archive/features/06-reliability-and-offline.md +197 -0
  211. connectonion/docs/archive/features/README.md +46 -0
  212. connectonion/docs/archive/features-roadmap.md +247 -0
  213. connectonion/docs/archive/mcp-comparison-insights.md +215 -0
  214. connectonion/docs/archive/migration-strategy.md +571 -0
  215. connectonion/docs/archive/mini-whitepaper.md +293 -0
  216. connectonion/docs/archive/network-protocol.md +394 -0
  217. connectonion/docs/archive/semantic-revolution.md +367 -0
  218. connectonion/docs/archive/technical-architecture.md +453 -0
  219. connectonion/docs/archive/the-semantic-insight.md +207 -0
  220. connectonion/docs/archive/threat-model.md +164 -0
  221. connectonion/docs/cli/README.md +805 -0
  222. connectonion/docs/cli/auth.md +46 -0
  223. connectonion/docs/cli/browser.md +235 -0
  224. connectonion/docs/cli/copy.md +232 -0
  225. connectonion/docs/cli/create.md +335 -0
  226. connectonion/docs/cli/init.md +431 -0
  227. connectonion/docs/co-directory-structure.md +214 -0
  228. connectonion/docs/concepts/agent.md +1078 -0
  229. connectonion/docs/concepts/events.md +699 -0
  230. connectonion/docs/concepts/llm_do.md +256 -0
  231. connectonion/docs/concepts/max_iterations.md +362 -0
  232. connectonion/docs/concepts/models.md +641 -0
  233. connectonion/docs/concepts/plugins.md +100 -0
  234. connectonion/docs/concepts/prompts.md +122 -0
  235. connectonion/docs/concepts/session.md +428 -0
  236. connectonion/docs/concepts/tools.md +512 -0
  237. connectonion/docs/concepts/transcribe.md +156 -0
  238. connectonion/docs/concepts/trust.md +291 -0
  239. connectonion/docs/connectonion.md +1256 -0
  240. connectonion/docs/debug/README.md +18 -0
  241. connectonion/docs/debug/auto_debug.md +1026 -0
  242. connectonion/docs/debug/console.md +129 -0
  243. connectonion/docs/debug/eval-format.md +178 -0
  244. connectonion/docs/debug/eval.md +230 -0
  245. connectonion/docs/debug/exceptions.md +307 -0
  246. connectonion/docs/debug/log.md +117 -0
  247. connectonion/docs/debug/xray.md +215 -0
  248. connectonion/docs/design-decisions/001-choosing-input-method.md +202 -0
  249. connectonion/docs/design-decisions/002-choosing-llm-function-name.md +202 -0
  250. connectonion/docs/design-decisions/003-choosing-trust-keyword.md +141 -0
  251. connectonion/docs/design-decisions/004-cli-create-flow.md +117 -0
  252. connectonion/docs/design-decisions/005-designing-agent-network-protocol.md +503 -0
  253. connectonion/docs/design-decisions/006-agent-address-format.md +305 -0
  254. connectonion/docs/design-decisions/007-authentication-backend-design.md +240 -0
  255. connectonion/docs/design-decisions/008-naming-is-hard.md +228 -0
  256. connectonion/docs/design-decisions/009-why-connect-function.md +167 -0
  257. connectonion/docs/design-decisions/010-cli-ux-progressive-disclosure.md +176 -0
  258. connectonion/docs/design-decisions/011-global-config-identity-management.md +357 -0
  259. connectonion/docs/design-decisions/012-tool-execution-separation.md +259 -0
  260. connectonion/docs/design-decisions/013-debug-and-logging-design.md +253 -0
  261. connectonion/docs/design-decisions/014-hook-system-design.md +510 -0
  262. connectonion/docs/design-decisions/015-interactive-auto-debug-design.md +837 -0
  263. connectonion/docs/design-decisions/016-why-no-zero-knowledge-proofs.md +358 -0
  264. connectonion/docs/design-decisions/017-session-logging-and-eval-format.md +120 -0
  265. connectonion/docs/design-decisions/018-event-api-naming.md +274 -0
  266. connectonion/docs/design-decisions/019-agent-lifecycle-design.md +655 -0
  267. connectonion/docs/design-decisions/020-trust-system-and-network-architecture.md +503 -0
  268. connectonion/docs/design-decisions/021-task-storage-jsonl-design.md +496 -0
  269. connectonion/docs/design-decisions/022-raw-asgi-implementation.md +273 -0
  270. connectonion/docs/examples.md +0 -0
  271. connectonion/docs/hook-system-options.md +364 -0
  272. connectonion/docs/integrations/README.md +12 -0
  273. connectonion/docs/integrations/auth.md +450 -0
  274. connectonion/docs/integrations/google.md +431 -0
  275. connectonion/docs/integrations/microsoft.md +370 -0
  276. connectonion/docs/network/README.md +14 -0
  277. connectonion/docs/network/connect.md +629 -0
  278. connectonion/docs/network/deploy.md +124 -0
  279. connectonion/docs/network/host.md +1087 -0
  280. connectonion/docs/network/io.md +538 -0
  281. connectonion/docs/network/protocol/agent-relay-protocol.md +495 -0
  282. connectonion/docs/network/protocol/announce-message.md +115 -0
  283. connectonion/docs/principles.md +124 -0
  284. connectonion/docs/quickstart.md +261 -0
  285. connectonion/docs/roadmap.md +81 -0
  286. connectonion/docs/templates/README.md +77 -0
  287. connectonion/docs/templates/meta-agent.md +152 -0
  288. connectonion/docs/templates/minimal.md +105 -0
  289. connectonion/docs/templates/playwright.md +130 -0
  290. connectonion/docs/templates/web-research.md +144 -0
  291. connectonion/docs/tui/README.md +95 -0
  292. connectonion/docs/tui/chat.md +181 -0
  293. connectonion/docs/tui/divider.md +63 -0
  294. connectonion/docs/tui/dropdown.md +83 -0
  295. connectonion/docs/tui/footer.md +44 -0
  296. connectonion/docs/tui/fuzzy.md +68 -0
  297. connectonion/docs/tui/input.md +84 -0
  298. connectonion/docs/tui/keys.md +77 -0
  299. connectonion/docs/tui/pick.md +71 -0
  300. connectonion/docs/tui/providers.md +89 -0
  301. connectonion/docs/tui/status_bar.md +67 -0
  302. connectonion/docs/useful_plugins/README.md +160 -0
  303. connectonion/docs/useful_plugins/calendar_plugin.md +68 -0
  304. connectonion/docs/useful_plugins/eval.md +89 -0
  305. connectonion/docs/useful_plugins/gmail_plugin.md +68 -0
  306. connectonion/docs/useful_plugins/image_result_formatter.md +74 -0
  307. connectonion/docs/useful_plugins/re_act.md +86 -0
  308. connectonion/docs/useful_plugins/shell_approval.md +69 -0
  309. connectonion/docs/useful_plugins/system_reminder.md +210 -0
  310. connectonion/docs/useful_prompts/README.md +127 -0
  311. connectonion/docs/useful_prompts/coding_agent.md +214 -0
  312. connectonion/docs/useful_tools/README.md +81 -0
  313. connectonion/docs/useful_tools/ask_user.md +103 -0
  314. connectonion/docs/useful_tools/diff_writer.md +158 -0
  315. connectonion/docs/useful_tools/get_emails.md +519 -0
  316. connectonion/docs/useful_tools/gmail.md +155 -0
  317. connectonion/docs/useful_tools/google_calendar.md +126 -0
  318. connectonion/docs/useful_tools/memory.md +506 -0
  319. connectonion/docs/useful_tools/microsoft_calendar.md +126 -0
  320. connectonion/docs/useful_tools/outlook.md +140 -0
  321. connectonion/docs/useful_tools/send_email.md +423 -0
  322. connectonion/docs/useful_tools/shell.md +115 -0
  323. connectonion/docs/useful_tools/slash_command.md +116 -0
  324. connectonion/docs/useful_tools/terminal.md +115 -0
  325. connectonion/docs/useful_tools/todo_list.md +272 -0
  326. connectonion/docs/useful_tools/web_fetch.md +150 -0
  327. connectonion/docs/vibe-coding-guide.md +97 -0
  328. connectonion/docs/windows-support.md +258 -0
  329. connectonion/logger.py +3 -3
  330. connectonion/network/__init__.py +19 -6
  331. connectonion/network/asgi/__init__.py +81 -0
  332. connectonion/network/asgi/http.py +205 -0
  333. connectonion/network/asgi/websocket.py +217 -0
  334. connectonion/network/connect.py +232 -185
  335. connectonion/network/host/__init__.py +59 -0
  336. connectonion/network/host/auth.py +191 -0
  337. connectonion/network/host/routes.py +135 -0
  338. connectonion/network/host/server.py +289 -0
  339. connectonion/network/host/session.py +78 -0
  340. connectonion/network/io/__init__.py +21 -0
  341. connectonion/network/{connection.py → io/base.py} +17 -42
  342. connectonion/network/io/websocket.py +55 -0
  343. connectonion/network/relay.py +37 -16
  344. connectonion/network/trust/__init__.py +30 -0
  345. connectonion/network/trust/factory.py +138 -0
  346. connectonion/network/{trust_agents.py → trust/prompts.py} +3 -3
  347. connectonion/network/{trust_functions.py → trust/tools.py} +2 -2
  348. connectonion/prompt_files/__init__.py +11 -1
  349. connectonion/prompt_files/react_acknowledge.md +26 -0
  350. connectonion/prompts.py +10 -1
  351. connectonion/tui/chat.py +10 -1
  352. connectonion/tui/divider.py +10 -1
  353. connectonion/tui/dropdown.py +10 -1
  354. connectonion/tui/footer.py +8 -0
  355. connectonion/tui/fuzzy.py +11 -1
  356. connectonion/tui/input.py +118 -70
  357. connectonion/tui/keys.py +133 -6
  358. connectonion/tui/providers.py +11 -1
  359. connectonion/tui/status_bar.py +10 -1
  360. connectonion/useful_events_handlers/__init__.py +8 -0
  361. connectonion/useful_events_handlers/reflect.py +19 -4
  362. connectonion/useful_plugins/__init__.py +2 -1
  363. connectonion/useful_plugins/eval.py +2 -2
  364. connectonion/useful_plugins/gmail_plugin.py +3 -3
  365. connectonion/useful_plugins/image_result_formatter.py +3 -3
  366. connectonion/useful_plugins/re_act.py +114 -28
  367. connectonion/useful_plugins/shell_approval.py +2 -2
  368. connectonion/useful_plugins/system_reminder.py +103 -0
  369. connectonion/useful_plugins/ui_stream.py +18 -133
  370. connectonion/useful_prompts/README.md +61 -0
  371. connectonion/useful_prompts/__init__.py +45 -0
  372. connectonion/useful_prompts/coding_agent/README.md +106 -0
  373. connectonion/useful_prompts/coding_agent/assembler.py +123 -0
  374. connectonion/useful_prompts/coding_agent/prompts/main.md +227 -0
  375. connectonion/useful_prompts/coding_agent/prompts/tools/ask_user.md +61 -0
  376. connectonion/useful_prompts/coding_agent/prompts/tools/background.md +57 -0
  377. connectonion/useful_prompts/coding_agent/prompts/tools/edit.md +90 -0
  378. connectonion/useful_prompts/coding_agent/prompts/tools/glob.md +52 -0
  379. connectonion/useful_prompts/coding_agent/prompts/tools/grep.md +55 -0
  380. connectonion/useful_prompts/coding_agent/prompts/tools/plan_mode.md +80 -0
  381. connectonion/useful_prompts/coding_agent/prompts/tools/read.md +40 -0
  382. connectonion/useful_prompts/coding_agent/prompts/tools/shell.md +67 -0
  383. connectonion/useful_prompts/coding_agent/prompts/tools/task.md +51 -0
  384. connectonion/useful_prompts/coding_agent/prompts/tools/todo.md +139 -0
  385. connectonion/useful_prompts/coding_agent/prompts/tools/write.md +48 -0
  386. connectonion/useful_prompts/system-reminders/security-warning.md +14 -0
  387. connectonion/useful_prompts/system-reminders/test-reminder.md +11 -0
  388. connectonion/useful_tools/__init__.py +31 -4
  389. connectonion/useful_tools/ask_user.py +35 -0
  390. connectonion/useful_tools/bash.py +69 -0
  391. connectonion/useful_tools/diff_writer.py +186 -94
  392. connectonion/useful_tools/edit.py +102 -0
  393. connectonion/useful_tools/glob_files.py +97 -0
  394. connectonion/useful_tools/grep_files.py +171 -0
  395. connectonion/useful_tools/multi_edit.py +116 -0
  396. connectonion/useful_tools/read_file.py +73 -0
  397. connectonion/useful_tools/shell.py +50 -45
  398. connectonion/useful_tools/write_file.py +129 -0
  399. {connectonion-0.6.2.dist-info → connectonion-0.6.3.dist-info}/METADATA +10 -3
  400. connectonion-0.6.3.dist-info/RECORD +469 -0
  401. connectonion/network/asgi.py +0 -407
  402. connectonion/network/host.py +0 -616
  403. connectonion/network/trust.py +0 -166
  404. connectonion-0.6.2.dist-info/RECORD +0 -129
  405. /connectonion/cli/{docs → co_ai/prompts/connectonion}/connectonion.md +0 -0
  406. {connectonion-0.6.2.dist-info → connectonion-0.6.3.dist-info}/WHEEL +0 -0
  407. {connectonion-0.6.2.dist-info → connectonion-0.6.3.dist-info}/entry_points.txt +0 -0
@@ -37,7 +37,8 @@ from .project_cmd_lib import (
37
37
  interactive_menu,
38
38
  generate_custom_template,
39
39
  show_progress,
40
- configure_env_for_provider
40
+ configure_env_for_provider,
41
+ get_docs_source,
41
42
  )
42
43
 
43
44
  console = Console()
@@ -332,30 +333,28 @@ def handle_init(ai: Optional[bool], key: Optional[str], template: Optional[str],
332
333
  co_dir = Path(current_dir) / ".co"
333
334
  co_dir.mkdir(exist_ok=True)
334
335
 
335
- # Create docs directory and copy documentation (always overwrite for latest version)
336
+ # Create docs directory and copy ALL documentation (always overwrite for latest version)
336
337
  docs_dir = co_dir / "docs"
337
338
  if docs_dir.exists():
338
339
  shutil.rmtree(docs_dir)
339
340
  docs_dir.mkdir(exist_ok=True)
340
341
 
341
- # Copy ConnectOnion documentation
342
- cli_dir = Path(__file__).parent.parent
343
-
344
- # Always copy the vibe coding doc for all templates - it's the master reference doc
345
- master_doc = cli_dir / "docs" / "co-vibecoding-principles-docs-contexts-all-in-one.md"
346
-
347
- if master_doc.exists():
348
- # Copy to .co/docs/ (project metadata)
349
- target_doc = docs_dir / "co-vibecoding-principles-docs-contexts-all-in-one.md"
350
- shutil.copy2(master_doc, target_doc)
351
- files_created.append(".co/docs/co-vibecoding-principles-docs-contexts-all-in-one.md")
342
+ # Get docs source (works in both dev and installed package)
343
+ docs_source = get_docs_source()
352
344
 
353
- # ALSO copy to project root (always visible, easier to find)
354
- root_doc = Path(current_dir) / "co-vibecoding-principles-docs-contexts-all-in-one.md"
355
- shutil.copy2(master_doc, root_doc)
356
- files_created.append("co-vibecoding-principles-docs-contexts-all-in-one.md")
345
+ # Copy ALL docs to .co/docs/
346
+ if docs_source.exists() and docs_source.is_dir():
347
+ for item in docs_source.iterdir():
348
+ if item.name.startswith('.') or item.name == 'archive':
349
+ continue
350
+ dest = docs_dir / item.name
351
+ if item.is_dir():
352
+ shutil.copytree(item, dest, dirs_exist_ok=True)
353
+ else:
354
+ shutil.copy2(item, dest)
355
+ files_created.append(".co/docs/ (full documentation)")
357
356
  else:
358
- console.print(f"[yellow]⚠️ Warning: Vibe coding documentation not found at {master_doc}[/yellow]")
357
+ console.print(f"[yellow]⚠️ Warning: Documentation not found at {docs_source}[/yellow]")
359
358
 
360
359
  # Use global identity instead of generating project keys
361
360
  # NO PROJECT KEYS - we use global address/email
@@ -402,7 +401,6 @@ def handle_init(ai: Optional[bool], key: Optional[str], template: Optional[str],
402
401
  .co/cache/
403
402
  .co/logs/
404
403
  .co/history/
405
- co-vibecoding-principles-docs-contexts-all-in-one.md
406
404
  *.py[cod]
407
405
  __pycache__/
408
406
  todo.md
@@ -437,12 +435,11 @@ todo.md
437
435
 
438
436
  # Vibe Coding hint - clean formatting with proper spacing
439
437
  console.print("[bold yellow]💡 Vibe Coding:[/bold yellow] Use Claude/Cursor/Codex with")
440
- console.print(f" [cyan]co-vibecoding-principles-docs-contexts-all-in-one.md[/cyan]")
438
+ console.print(f" [cyan].co/docs/[/cyan] for full documentation")
441
439
  else:
442
440
  # Vibe Coding hint for building from scratch
443
441
  console.print("[bold yellow]💡 Vibe Coding:[/bold yellow] Use Claude/Cursor/Codex with")
444
- console.print(f" [cyan]co-vibecoding-principles-docs-contexts-all-in-one.md[/cyan]")
445
- console.print(" to build your agent")
442
+ console.print(f" [cyan].co/docs/[/cyan] to build your agent")
446
443
 
447
444
  # Resources - clean format with arrows for better alignment
448
445
  console.print()
@@ -31,6 +31,20 @@ from ... import address
31
31
  console = Console()
32
32
 
33
33
 
34
+ def get_docs_source() -> Path:
35
+ """Get the docs directory path - works in both dev and installed package."""
36
+ # After pip install: connectonion/docs/ exists (via force-include)
37
+ package_dir = Path(__file__).parent.parent.parent # connectonion/cli/commands/ → connectonion/
38
+ docs_source = package_dir / "docs"
39
+
40
+ # Fallback for editable install: docs are at project root
41
+ if not docs_source.exists():
42
+ project_root = package_dir.parent
43
+ docs_source = project_root / "docs"
44
+
45
+ return docs_source
46
+
47
+
34
48
 
35
49
 
36
50
  def validate_project_name(name: str) -> Tuple[bool, str]:
@@ -822,6 +836,7 @@ __all__ = [
822
836
  'show_progress',
823
837
  'generate_custom_template',
824
838
  'generate_custom_template_with_name',
839
+ 'get_docs_source',
825
840
  ]
826
841
 
827
842
  # All the handle_init and handle_create code has been moved to init.py and create.py
connectonion/cli/main.py CHANGED
@@ -141,6 +141,17 @@ def browser(command: str = typer.Argument(..., help="Browser command")):
141
141
  handle_browser(command)
142
142
 
143
143
 
144
+ @app.command()
145
+ def ai(
146
+ port: int = typer.Option(8000, "--port", "-p", help="Port for web server"),
147
+ model: str = typer.Option("co/claude-opus-4-5", "--model", "-m", help="Model to use"),
148
+ max_iterations: int = typer.Option(20, "--max-iterations", "-i", help="Max iterations"),
149
+ ):
150
+ """Start AI coding agent web server."""
151
+ from .commands.ai_commands import handle_ai
152
+ handle_ai(port=port, model=model, max_iterations=max_iterations)
153
+
154
+
144
155
  @app.command()
145
156
  def copy(
146
157
  names: List[str] = typer.Argument(None, help="Tool or plugin names to copy"),
connectonion/console.py CHANGED
@@ -101,7 +101,8 @@ class Console:
101
101
  model: str = "",
102
102
  tools: Union[List[str], int] = 0,
103
103
  log_dir: Optional[str] = None,
104
- llm: Any = None
104
+ llm: Any = None,
105
+ balance: Optional[float] = None
105
106
  ) -> None:
106
107
  """Print the ConnectOnion banner (Onion Stack style).
107
108
 
@@ -110,6 +111,7 @@ class Console:
110
111
  ● ─────────────────────
111
112
  connectonion v0.5.1
112
113
  o4-mini · 3 tools
114
+ balance: $4.22
113
115
  .co/logs/ · .co/evals/
114
116
 
115
117
  Args:
@@ -118,6 +120,7 @@ class Console:
118
120
  tools: List of tool names or count of tools
119
121
  log_dir: Log directory path (e.g., ".co/")
120
122
  llm: LLM instance to check for free tier
123
+ balance: Optional account balance in USD (only for co/ models)
121
124
  """
122
125
  version = _get_version()
123
126
 
@@ -138,6 +141,11 @@ class Console:
138
141
  is_free_tier = type(llm).__name__ == "OpenOnionLLM"
139
142
  aaron_message = "credits on me, go build —aaron" if is_free_tier else None
140
143
 
144
+ # Fetch balance for OpenOnion managed keys if not already provided
145
+ # This adds ~200ms latency on startup but provides useful account info
146
+ if balance is None and is_free_tier and hasattr(llm, 'get_balance'):
147
+ balance = llm.get_balance()
148
+
141
149
  # Calculate separator length (at least as long as agent name, min 20)
142
150
  separator_len = max(len(agent_name), 20)
143
151
  separator = "─" * separator_len
@@ -154,6 +162,10 @@ class Console:
154
162
  if meta_line:
155
163
  lines.append(f" [{DIM_COLOR}]{meta_line}[/{DIM_COLOR}]")
156
164
 
165
+ # Add balance if available (only for co/ models)
166
+ if balance is not None:
167
+ lines.append(f" [{DIM_COLOR}]balance: ${balance:.2f}[/{DIM_COLOR}]")
168
+
157
169
  # Add log paths if logging is enabled
158
170
  if log_dir:
159
171
  lines.append(f" [{DIM_COLOR}]{log_dir}logs/ · {log_dir}evals/[/{DIM_COLOR}]")
@@ -181,6 +193,8 @@ class Console:
181
193
  ]
182
194
  if meta_line:
183
195
  plain_lines.append(f" {meta_line}")
196
+ if balance is not None:
197
+ plain_lines.append(f" balance: ${balance:.2f}")
184
198
  if log_dir:
185
199
  plain_lines.append(f" {log_dir}logs/ · {log_dir}evals/")
186
200
  if aaron_message:
@@ -1,4 +1,13 @@
1
- """Core agent execution engine.
1
+ """
2
+ Purpose: Core agent execution engine - minimal components for running an agent
3
+ LLM-Note:
4
+ Dependencies: imports from [agent.py, llm.py, events.py, tool_factory.py, tool_registry.py, tool_executor.py, usage.py] | imported by [connectonion/__init__.py, network/, debug/, useful_tools/] | tested indirectly via component tests
5
+ Data flow: bundles all core components → exports via __all__ → imported as `from connectonion.core import Agent, LLM, ...`
6
+ State/Effects: none (pure re-export module)
7
+ Integration: exposes core API: Agent (orchestrator), LLM (multi-provider abstraction), event decorators (lifecycle hooks), tool utilities (factory, registry, executor), usage tracking (TokenUsage, calculate_cost, get_context_limit)
8
+ Performance: no overhead (just imports)
9
+ Errors: import errors bubble from submodules
10
+ Core agent execution engine.
2
11
 
3
12
  This module contains the minimal set of components needed to run an agent:
4
13
  - Agent: Main orchestrator
@@ -51,8 +51,8 @@ class Agent:
51
51
  # Current session context (runtime only)
52
52
  self.current_session = None
53
53
 
54
- # Connection to client (None locally, injected by host() for WebSocket)
55
- self.connection = None
54
+ # I/O to client (None locally, injected by host() for WebSocket)
55
+ self.io = None
56
56
 
57
57
  # Token usage tracking
58
58
  self.total_cost: float = 0.0 # Cumulative cost in USD
@@ -144,6 +144,27 @@ class Agent:
144
144
  llm=self.llm
145
145
  )
146
146
 
147
+ def _next_trace_id(self) -> str:
148
+ """Generate unique trace entry ID (UUID)."""
149
+ import uuid
150
+ return str(uuid.uuid4())
151
+
152
+ def _record_trace(self, entry: dict) -> None:
153
+ """Record trace entry and stream to io if connected.
154
+
155
+ This is the single place where trace entries are recorded.
156
+ Ensures both local trace and remote streaming stay in sync.
157
+ """
158
+ if 'id' not in entry:
159
+ entry['id'] = self._next_trace_id()
160
+ if 'ts' not in entry:
161
+ entry['ts'] = time.time()
162
+
163
+ self.current_session['trace'].append(entry)
164
+
165
+ if self.io:
166
+ self.io.send(entry)
167
+
147
168
  def _invoke_events(self, event_type: str):
148
169
  """Invoke all event handlers for given type. Exceptions propagate (fail fast)."""
149
170
  for handler in self.events.get(event_type, []):
@@ -231,12 +252,12 @@ class Agent:
231
252
  self.current_session['user_prompt'] = prompt # Store user prompt for xray/debugging
232
253
  turn_start = time.time()
233
254
 
234
- # Add trace entry for this input
235
- self.current_session['trace'].append({
255
+ # Record trace entry (also streams to io if connected)
256
+ self._record_trace({
236
257
  'type': 'user_input',
258
+ 'content': prompt,
237
259
  'turn': self.current_session['turn'],
238
- 'prompt': prompt, # Keep 'prompt' in trace for backward compatibility
239
- 'timestamp': turn_start
260
+ 'ts': turn_start,
240
261
  })
241
262
 
242
263
  # Invoke after_user_input events
@@ -316,11 +337,11 @@ class Agent:
316
337
 
317
338
  # Return simplified result (omit internal fields)
318
339
  return {
319
- "name": trace_entry["tool_name"],
320
- "arguments": trace_entry["arguments"],
340
+ "name": trace_entry["name"],
341
+ "args": trace_entry.get("args", {}),
321
342
  "result": trace_entry["result"],
322
343
  "status": trace_entry["status"],
323
- "timing": trace_entry["timing"]
344
+ "timing_ms": trace_entry.get("timing_ms")
324
345
  }
325
346
 
326
347
  def _create_initial_messages(self, prompt: str) -> List[Dict[str, Any]]:
@@ -338,9 +359,11 @@ class Agent:
338
359
  # Get LLM response
339
360
  response = self._get_llm_decision()
340
361
 
341
- # If no tool calls, we're done
362
+ # If no tool calls, we're done - return the response
363
+ # Note: Don't send 'assistant' trace here - OUTPUT message will carry the result
342
364
  if not response.tool_calls:
343
- return response.content if response.content else "Task completed."
365
+ content = response.content if response.content else "Task completed."
366
+ return content
344
367
 
345
368
  # Process tool calls
346
369
  self._execute_and_record_tools(response.tool_calls)
@@ -372,11 +395,10 @@ class Agent:
372
395
  self.last_usage = response.usage
373
396
  self.total_cost += response.usage.cost
374
397
 
375
- # Add to trace
376
- self.current_session['trace'].append({
398
+ # Record trace (also streams to io if connected)
399
+ self._record_trace({
377
400
  'type': 'llm_call',
378
401
  'model': self.llm.model,
379
- 'timestamp': start,
380
402
  'duration_ms': duration,
381
403
  'tool_calls_count': len(response.tool_calls) if response.tool_calls else 0,
382
404
  'iteration': self.current_session['iteration'],
@@ -447,7 +469,6 @@ class Agent:
447
469
  # Single prompt mode
448
470
  agent.auto_debug("Find information about Python")
449
471
  """
450
- from .debug import AutoDebugger
472
+ from ..debug.auto_debug import AutoDebugger
451
473
  debugger = AutoDebugger(self)
452
474
  debugger.start_debug_session(prompt)
453
-
@@ -0,0 +1,74 @@
1
+ """
2
+ ConnectOnion exceptions.
3
+
4
+ Purpose: Custom exceptions for ConnectOnion framework with formatted, actionable error messages
5
+ LLM-Note:
6
+ Dependencies: none | imported by [llm.py] | tested by [tests/test_billing_error_agent.py]
7
+ Data flow: OpenOnionLLM catches openai.APIStatusError(402) → transforms to InsufficientCreditsError → raises with formatted message
8
+ State/Effects: parses error detail from API response | formats beautiful error message with account, balance, cost, shortfall | preserves original error in __cause__
9
+ Integration: exposes InsufficientCreditsError exception class | raised by OpenOnionLLM when insufficient credits
10
+ Performance: lightweight exception creation | formats string message once on init
11
+ Errors: none (this module defines error types)
12
+ """
13
+
14
+
15
+ class InsufficientCreditsError(Exception):
16
+ """
17
+ Raised when an LLM request fails due to insufficient ConnectOnion credits.
18
+
19
+ This indicates your ConnectOnion managed keys account needs more credits.
20
+ Join Discord to add credits or ask Aaron for free credits to get started.
21
+
22
+ Attributes:
23
+ balance (float): Current account balance in USD
24
+ required (float): Cost of the failed request in USD
25
+ shortfall (float): Additional credits needed in USD
26
+ address (str): Your ConnectOnion account address
27
+ """
28
+
29
+ def __init__(self, original_error):
30
+ """
31
+ Create InsufficientCreditsError from OpenAI API error.
32
+
33
+ Args:
34
+ original_error: The original openai.APIStatusError from the API
35
+ """
36
+ # Parse error details from API response
37
+ body = getattr(original_error, 'body', {}) or {}
38
+ detail = body.get('detail', {})
39
+
40
+ # Extract billing information
41
+ self.balance = detail.get('balance', 0)
42
+ self.required = detail.get('required', 0)
43
+ self.shortfall = detail.get('shortfall', 0)
44
+ self.address = detail.get('address', 'unknown') # Server provides formatted address
45
+ self.public_key = detail.get('public_key', 'unknown') # Full public key
46
+ self.original_message = detail.get('message', '')
47
+
48
+ # Create clear, beautiful error message
49
+ message = self._format_message()
50
+ super().__init__(message)
51
+
52
+ # Keep original error for debugging
53
+ self.__cause__ = original_error
54
+
55
+ def _format_message(self):
56
+ """Format a clear, actionable error message."""
57
+ return (
58
+ f"\n"
59
+ f"{'='*70}\n"
60
+ f"❌ Insufficient ConnectOnion Credits\n"
61
+ f"{'='*70}\n"
62
+ f"\n"
63
+ f"Account: {self.address}\n"
64
+ f"Balance: ${self.balance:.4f}\n"
65
+ f"Required: ${self.required:.4f}\n"
66
+ f"Shortfall: ${self.shortfall:.4f}\n"
67
+ f"\n"
68
+ f"💡 How to add credits:\n"
69
+ f" • Join Discord: https://discord.gg/4xfD9k8AUF\n"
70
+ f" • Ask Aaron for free credits to get started\n"
71
+ f" • Check balance: Run 'co status' in terminal\n"
72
+ f"\n"
73
+ f"{'='*70}\n"
74
+ )
connectonion/core/llm.py CHANGED
@@ -1,12 +1,12 @@
1
1
  """
2
2
  Purpose: Unified LLM provider abstraction with factory pattern for OpenAI, Anthropic, Gemini, and OpenOnion
3
3
  LLM-Note:
4
- Dependencies: imports from [abc, typing, dataclasses, json, os, openai, anthropic, google.generativeai, requests, pathlib, toml, pydantic] | imported by [agent.py, llm_do.py, conftest.py] | tested by [tests/test_llm.py, tests/test_llm_do.py, tests/test_real_*.py]
4
+ Dependencies: imports from [abc, typing, dataclasses, json, os, base64, openai, anthropic, requests, pathlib, toml, pydantic, .usage, .exceptions] | imported by [agent.py, llm_do.py, conftest.py] | tested by [tests/test_llm.py, tests/test_llm_do.py, tests/test_real_*.py, tests/test_billing_error_agent.py]
5
5
  Data flow: Agent/llm_do calls create_llm(model, api_key) → factory routes to provider class → Provider.__init__() validates API key → Agent calls complete(messages, tools) OR structured_complete(messages, output_schema) → provider converts to native format → calls API → parses response → returns LLMResponse(content, tool_calls, raw_response) OR Pydantic model instance
6
6
  State/Effects: reads environment variables (OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, OPENONION_API_KEY) | reads ~/.connectonion/.co/config.toml for OpenOnion auth | makes HTTP requests to LLM APIs | no caching or persistence
7
7
  Integration: exposes create_llm(model, api_key), LLM abstract base class, OpenAILLM, AnthropicLLM, GeminiLLM, OpenOnionLLM, LLMResponse, ToolCall dataclasses | providers implement complete() and structured_complete() | OpenAI message format is lingua franca | tool calling uses OpenAI schema converted per-provider
8
8
  Performance: stateless (no caching) | synchronous (no streaming) | default max_tokens=8192 for Anthropic (required) | each call hits API
9
- Errors: raises ValueError for missing API keys, unknown models, invalid parameters | provider-specific errors bubble up (openai.APIError, anthropic.APIError, etc.) | Pydantic ValidationError for invalid structured output
9
+ Errors: raises ValueError for missing API keys, unknown models, invalid parameters | provider-specific errors bubble up (openai.APIError, anthropic.APIError, etc.) | OpenOnionLLM transforms 402 errors to InsufficientCreditsError with formatted message and typed attributes | Pydantic ValidationError for invalid structured output
10
10
 
11
11
  Unified LLM provider abstraction layer for ConnectOnion framework.
12
12
 
@@ -146,6 +146,10 @@ from typing import List, Dict, Any, Optional, Type
146
146
  from dataclasses import dataclass
147
147
  import json
148
148
  import os
149
+ import base64
150
+ import logging
151
+
152
+ logger = logging.getLogger(__name__)
149
153
  import openai
150
154
  import anthropic
151
155
  # google-genai not needed - using OpenAI-compatible endpoint instead
@@ -175,6 +179,7 @@ class ToolCall:
175
179
 
176
180
  # Import TokenUsage from usage module
177
181
  from .usage import TokenUsage, calculate_cost
182
+ from .exceptions import InsufficientCreditsError
178
183
 
179
184
 
180
185
  @dataclass
@@ -670,13 +675,13 @@ class OpenOnionLLM(LLM):
670
675
 
671
676
  # Determine base URL for OpenAI-compatible endpoint
672
677
  if os.getenv("OPENONION_DEV") or os.getenv("ENVIRONMENT") == "development":
673
- base_url = "http://localhost:8000/v1"
678
+ self.base_url = "http://localhost:8000/v1"
674
679
  else:
675
- base_url = "https://oo.openonion.ai/v1"
680
+ self.base_url = "https://oo.openonion.ai/v1"
676
681
 
677
682
  # Use OpenAI client with OpenOnion endpoint
678
683
  self.client = openai.OpenAI(
679
- base_url=base_url,
684
+ base_url=self.base_url,
680
685
  api_key=self.auth_token
681
686
  )
682
687
 
@@ -693,7 +698,17 @@ class OpenOnionLLM(LLM):
693
698
  api_kwargs["tools"] = [{"type": "function", "function": tool} for tool in tools]
694
699
  api_kwargs["tool_choice"] = "auto"
695
700
 
696
- response = self.client.chat.completions.create(**api_kwargs)
701
+ try:
702
+ response = self.client.chat.completions.create(**api_kwargs)
703
+ except openai.APIStatusError as e:
704
+ if e.status_code == 402:
705
+ raise InsufficientCreditsError(e) from e
706
+ logger.error(f"APIStatusError: status={e.status_code}, message={e.message}, body={getattr(e, 'body', None)}")
707
+ raise
708
+ except Exception as e:
709
+ logger.error(f"LLM error: {type(e).__name__}: {e}")
710
+ raise
711
+
697
712
  message = response.choices[0].message
698
713
 
699
714
  # Parse tool calls if present
@@ -747,6 +762,39 @@ class OpenOnionLLM(LLM):
747
762
  )
748
763
  return completion.choices[0].message.parsed
749
764
 
765
+ def get_balance(self) -> Optional[float]:
766
+ """Fetch current account balance from OpenOnion API.
767
+
768
+ Makes a GET request to /api/v1/auth/me endpoint to retrieve the user's
769
+ current balance. This is called once at agent startup to display balance
770
+ in the banner.
771
+
772
+ Returns:
773
+ Balance in USD (e.g., 4.22 for $4.22), or None if request fails
774
+
775
+ Note:
776
+ - Fast timeout (2s) to avoid hanging on network issues
777
+ - Only called for co/ models (OpenOnion managed keys)
778
+ - Returns None on any error (network, auth, etc.)
779
+ - ~200ms typical latency, acceptable for startup
780
+ """
781
+ import requests
782
+
783
+ # Build auth endpoint URL (strip /v1 suffix)
784
+ auth_url = f"{self.base_url.rstrip('/v1')}/api/v1/auth/me"
785
+
786
+ response = requests.get(
787
+ auth_url,
788
+ headers={"Authorization": f"Bearer {self.auth_token}"},
789
+ timeout=2
790
+ )
791
+
792
+ if response.status_code == 200:
793
+ data = response.json()
794
+ return data.get("balance_usd")
795
+
796
+ return None
797
+
750
798
 
751
799
  def create_llm(model: str, api_key: Optional[str] = None, **kwargs) -> LLM:
752
800
  """Factory function to create the appropriate LLM based on model name.
@@ -106,17 +106,14 @@ def execute_single_tool(
106
106
  # Log tool call before execution
107
107
  logger.log_tool_call(tool_name, tool_args)
108
108
 
109
- # Create single trace entry
110
109
  trace_entry = {
111
- "type": "tool_execution",
112
- "tool_name": tool_name,
113
- "arguments": tool_args,
114
- "call_id": tool_id,
115
- "timing": 0,
110
+ "type": "tool_result",
111
+ "tool_id": tool_id, # LLM's tool call ID for client-side matching
112
+ "name": tool_name,
113
+ "args": tool_args,
116
114
  "status": "pending",
117
115
  "result": None,
118
- "iteration": agent.current_session['iteration'],
119
- "timestamp": time.time()
116
+ "timing_ms": 0,
120
117
  }
121
118
 
122
119
  # Check if tool exists
@@ -124,30 +121,31 @@ def execute_single_tool(
124
121
  if tool_func is None:
125
122
  error_msg = f"Tool '{tool_name}' not found"
126
123
 
127
- # Update trace entry
128
124
  trace_entry["result"] = error_msg
129
125
  trace_entry["status"] = "not_found"
130
126
  trace_entry["error"] = error_msg
131
127
 
132
- # Add trace entry to session (so on_error handlers can see it)
133
- agent.current_session['trace'].append(trace_entry)
134
-
135
- # Logger output
128
+ agent._record_trace(trace_entry)
136
129
  logger.print(f"[red]✗[/red] {error_msg}")
137
130
 
138
- # Note: on_error event will fire in execute_and_record_tools after result message added
139
-
140
131
  return trace_entry
141
132
 
142
133
  # Check if tool has @xray decorator
143
134
  xray_enabled = is_xray_enabled(tool_func)
144
135
 
145
- # Prepare context data for xray
146
136
  previous_tools = [
147
- entry.get("tool_name") for entry in agent.current_session['trace']
148
- if entry.get("type") == "tool_execution"
137
+ entry.get("name") for entry in agent.current_session['trace']
138
+ if entry.get("type") == "tool_result"
149
139
  ]
150
140
 
141
+ # Record tool_call event BEFORE execution (for real-time UI updates)
142
+ agent._record_trace({
143
+ "type": "tool_call",
144
+ "tool_id": tool_id, # LLM's tool call ID
145
+ "name": tool_name,
146
+ "args": tool_args,
147
+ })
148
+
151
149
  # Inject xray context before tool execution
152
150
  inject_xray_context(
153
151
  agent=agent,
@@ -177,19 +175,19 @@ def execute_single_tool(
177
175
 
178
176
  # Execute the tool with timing (restart timer AFTER events for accurate tool timing)
179
177
  tool_start = time.time()
178
+
179
+ # Inject agent for ask_user tool (YAGNI - only generalize when needed)
180
+ if tool_name == 'ask_user':
181
+ tool_args['agent'] = agent
182
+
180
183
  result = tool_func(**tool_args)
181
184
  tool_duration = (time.time() - tool_start) * 1000 # milliseconds
182
185
 
183
- # Update trace entry
184
- trace_entry["timing"] = tool_duration
186
+ trace_entry["timing_ms"] = tool_duration
185
187
  trace_entry["result"] = str(result)
186
188
  trace_entry["status"] = "success"
187
189
 
188
- # Add trace entry to session BEFORE auto-trace
189
- # (so it shows up in xray.trace() output)
190
- agent.current_session['trace'].append(trace_entry)
191
-
192
- # Logger output - result on separate line
190
+ agent._record_trace(trace_entry)
193
191
  logger.log_tool_result(str(result), tool_duration)
194
192
 
195
193
  # Auto-print Rich table if @xray enabled
@@ -208,19 +206,22 @@ def execute_single_tool(
208
206
  # Calculate timing from initial start (includes before_tool if it succeeded)
209
207
  tool_duration = (time.time() - tool_start) * 1000
210
208
 
211
- # Update trace entry
212
- trace_entry["timing"] = tool_duration
209
+ trace_entry["timing_ms"] = tool_duration
213
210
  trace_entry["status"] = "error"
214
211
  trace_entry["error"] = str(e)
215
212
  trace_entry["error_type"] = type(e).__name__
216
213
 
217
- error_msg = f"Error executing tool: {str(e)}"
214
+ # Always include schema info so LLM knows how to fix the call
215
+ schema = getattr(tool_func, 'get_parameters_schema', lambda: {})()
216
+ required = schema.get('required', [])
217
+ properties = list(schema.get('properties', {}).keys())
218
+
219
+ error_msg = f"Error: {str(e)}"
220
+ error_msg += f"\n\nTool '{tool_name}' schema: required={required}, all_params={properties}, you_provided={list(tool_args.keys())}"
218
221
  trace_entry["result"] = error_msg
219
222
 
220
- # Add error trace entry to session (so on_error handlers can see it)
221
- agent.current_session['trace'].append(trace_entry)
223
+ agent._record_trace(trace_entry)
222
224
 
223
- # Logger output
224
225
  time_str = f"{tool_duration/1000:.4f}s" if tool_duration < 100 else f"{tool_duration/1000:.1f}s"
225
226
  logger.print(f"[red]✗[/red] Error ({time_str}): {str(e)}")
226
227