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.
- connectonion/__init__.py +46 -9
- connectonion/cli/__init__.py +11 -1
- connectonion/cli/browser_agent/__init__.py +11 -1
- connectonion/cli/browser_agent/browser.py +95 -142
- connectonion/cli/browser_agent/element_finder.py +147 -0
- connectonion/cli/browser_agent/highlight_screenshot.py +182 -0
- connectonion/cli/browser_agent/prompt.md +188 -105
- connectonion/cli/browser_agent/prompts/element_matcher.md +59 -0
- connectonion/cli/browser_agent/prompts/form_filler.md +19 -0
- connectonion/cli/browser_agent/prompts/scroll_strategy.md +36 -0
- connectonion/cli/browser_agent/scripts/extract_elements.js +126 -0
- connectonion/cli/browser_agent/scroll.py +145 -0
- connectonion/cli/co_ai/__init__.py +6 -0
- connectonion/cli/co_ai/agent.py +87 -0
- connectonion/cli/co_ai/agents/__init__.py +5 -0
- connectonion/cli/co_ai/agents/registry.py +57 -0
- connectonion/cli/co_ai/commands/__init__.py +45 -0
- connectonion/cli/co_ai/commands/compact.py +173 -0
- connectonion/cli/co_ai/commands/cost.py +77 -0
- connectonion/cli/co_ai/commands/export.py +60 -0
- connectonion/cli/co_ai/commands/help.py +80 -0
- connectonion/cli/co_ai/commands/init.py +101 -0
- connectonion/cli/co_ai/commands/sessions.py +55 -0
- connectonion/cli/co_ai/commands/tasks.py +63 -0
- connectonion/cli/co_ai/commands/undo.py +103 -0
- connectonion/cli/co_ai/context.py +127 -0
- connectonion/cli/co_ai/main.py +52 -0
- connectonion/cli/co_ai/plugins/__init__.py +6 -0
- connectonion/cli/co_ai/plugins/reminder.py +76 -0
- connectonion/cli/co_ai/plugins/shell_approval.py +105 -0
- connectonion/cli/co_ai/prompts/agents/explore.md +79 -0
- connectonion/cli/co_ai/prompts/agents/plan.md +60 -0
- connectonion/cli/co_ai/prompts/assembler.py +303 -0
- connectonion/cli/{docs/co-vibecoding-principles-docs-contexts-all-in-one.md → co_ai/prompts/connectonion/README.md} +26 -0
- connectonion/cli/co_ai/prompts/connectonion/api.md +457 -0
- connectonion/cli/co_ai/prompts/connectonion/cli/README.md +805 -0
- connectonion/cli/co_ai/prompts/connectonion/cli/auth.md +46 -0
- connectonion/cli/co_ai/prompts/connectonion/cli/browser.md +235 -0
- connectonion/cli/co_ai/prompts/connectonion/cli/copy.md +184 -0
- connectonion/cli/co_ai/prompts/connectonion/cli/create.md +335 -0
- connectonion/cli/co_ai/prompts/connectonion/cli/init.md +431 -0
- connectonion/cli/co_ai/prompts/connectonion/co-directory-structure.md +214 -0
- connectonion/cli/co_ai/prompts/connectonion/concepts/agent.md +1078 -0
- connectonion/cli/co_ai/prompts/connectonion/concepts/events.md +816 -0
- connectonion/cli/co_ai/prompts/connectonion/concepts/llm_do.md +256 -0
- connectonion/cli/co_ai/prompts/connectonion/concepts/max_iterations.md +362 -0
- connectonion/cli/co_ai/prompts/connectonion/concepts/models.md +641 -0
- connectonion/cli/co_ai/prompts/connectonion/concepts/plugins.md +100 -0
- connectonion/cli/co_ai/prompts/connectonion/concepts/prompts.md +122 -0
- connectonion/cli/co_ai/prompts/connectonion/concepts/tools.md +512 -0
- connectonion/cli/co_ai/prompts/connectonion/concepts/transcribe.md +156 -0
- connectonion/cli/co_ai/prompts/connectonion/concepts/trust.md +291 -0
- connectonion/cli/co_ai/prompts/connectonion/debug/README.md +18 -0
- connectonion/cli/co_ai/prompts/connectonion/debug/auto_debug.md +1026 -0
- connectonion/cli/co_ai/prompts/connectonion/debug/console.md +129 -0
- connectonion/cli/co_ai/prompts/connectonion/debug/eval-format.md +178 -0
- connectonion/cli/co_ai/prompts/connectonion/debug/eval.md +230 -0
- connectonion/cli/co_ai/prompts/connectonion/debug/exceptions.md +307 -0
- connectonion/cli/co_ai/prompts/connectonion/debug/log.md +117 -0
- connectonion/cli/co_ai/prompts/connectonion/debug/xray.md +215 -0
- connectonion/cli/co_ai/prompts/connectonion/design-decisions/001-choosing-input-method.md +202 -0
- connectonion/cli/co_ai/prompts/connectonion/design-decisions/002-choosing-llm-function-name.md +202 -0
- connectonion/cli/co_ai/prompts/connectonion/design-decisions/003-choosing-trust-keyword.md +141 -0
- connectonion/cli/co_ai/prompts/connectonion/design-decisions/004-cli-create-flow.md +117 -0
- connectonion/cli/co_ai/prompts/connectonion/design-decisions/005-designing-agent-network-protocol.md +503 -0
- connectonion/cli/co_ai/prompts/connectonion/design-decisions/006-agent-address-format.md +305 -0
- connectonion/cli/co_ai/prompts/connectonion/design-decisions/007-authentication-backend-design.md +240 -0
- connectonion/cli/co_ai/prompts/connectonion/design-decisions/008-naming-is-hard.md +228 -0
- connectonion/cli/co_ai/prompts/connectonion/design-decisions/009-why-connect-function.md +167 -0
- connectonion/cli/co_ai/prompts/connectonion/design-decisions/010-cli-ux-progressive-disclosure.md +176 -0
- connectonion/cli/co_ai/prompts/connectonion/design-decisions/011-global-config-identity-management.md +357 -0
- connectonion/cli/co_ai/prompts/connectonion/design-decisions/012-tool-execution-separation.md +259 -0
- connectonion/cli/co_ai/prompts/connectonion/design-decisions/013-debug-and-logging-design.md +253 -0
- connectonion/cli/co_ai/prompts/connectonion/design-decisions/014-hook-system-design.md +510 -0
- connectonion/cli/co_ai/prompts/connectonion/design-decisions/015-interactive-auto-debug-design.md +837 -0
- connectonion/cli/co_ai/prompts/connectonion/design-decisions/016-why-no-zero-knowledge-proofs.md +358 -0
- connectonion/cli/co_ai/prompts/connectonion/design-decisions/017-session-logging-and-eval-format.md +120 -0
- connectonion/cli/co_ai/prompts/connectonion/design-decisions/018-event-api-naming.md +274 -0
- connectonion/cli/co_ai/prompts/connectonion/design-decisions/019-agent-lifecycle-design.md +655 -0
- connectonion/cli/co_ai/prompts/connectonion/design-decisions/020-trust-system-and-network-architecture.md +503 -0
- connectonion/cli/co_ai/prompts/connectonion/design-decisions/021-task-storage-jsonl-design.md +496 -0
- connectonion/cli/co_ai/prompts/connectonion/design-decisions/022-raw-asgi-implementation.md +273 -0
- connectonion/cli/co_ai/prompts/connectonion/examples/agent_reasoning.md +62 -0
- connectonion/cli/co_ai/prompts/connectonion/examples/atomic_tools.md +24 -0
- connectonion/cli/co_ai/prompts/connectonion/examples/load_guide.md +18 -0
- connectonion/cli/co_ai/prompts/connectonion/examples.md +0 -0
- connectonion/cli/co_ai/prompts/connectonion/hook-system-options.md +364 -0
- connectonion/cli/co_ai/prompts/connectonion/index.md +162 -0
- connectonion/cli/co_ai/prompts/connectonion/integrations/README.md +12 -0
- connectonion/cli/co_ai/prompts/connectonion/integrations/auth.md +450 -0
- connectonion/cli/co_ai/prompts/connectonion/integrations/google.md +431 -0
- connectonion/cli/co_ai/prompts/connectonion/integrations/microsoft.md +370 -0
- connectonion/cli/co_ai/prompts/connectonion/network/README.md +14 -0
- connectonion/cli/co_ai/prompts/connectonion/network/connect.md +543 -0
- connectonion/cli/co_ai/prompts/connectonion/network/connection.md +538 -0
- connectonion/cli/co_ai/prompts/connectonion/network/deploy.md +123 -0
- connectonion/cli/co_ai/prompts/connectonion/network/host.md +1049 -0
- connectonion/cli/co_ai/prompts/connectonion/network/protocol/agent-relay-protocol.md +495 -0
- connectonion/cli/co_ai/prompts/connectonion/network/protocol/announce-message.md +115 -0
- connectonion/cli/co_ai/prompts/connectonion/principles.md +124 -0
- connectonion/cli/co_ai/prompts/connectonion/quickstart.md +261 -0
- connectonion/cli/co_ai/prompts/connectonion/roadmap.md +81 -0
- connectonion/cli/co_ai/prompts/connectonion/templates/README.md +77 -0
- connectonion/cli/co_ai/prompts/connectonion/templates/meta-agent.md +152 -0
- connectonion/cli/co_ai/prompts/connectonion/templates/minimal.md +105 -0
- connectonion/cli/co_ai/prompts/connectonion/templates/playwright.md +130 -0
- connectonion/cli/co_ai/prompts/connectonion/templates/web-research.md +144 -0
- connectonion/cli/co_ai/prompts/connectonion/tui/README.md +95 -0
- connectonion/cli/co_ai/prompts/connectonion/tui/chat.md +181 -0
- connectonion/cli/co_ai/prompts/connectonion/tui/divider.md +63 -0
- connectonion/cli/co_ai/prompts/connectonion/tui/dropdown.md +83 -0
- connectonion/cli/co_ai/prompts/connectonion/tui/footer.md +44 -0
- connectonion/cli/co_ai/prompts/connectonion/tui/fuzzy.md +68 -0
- connectonion/cli/co_ai/prompts/connectonion/tui/input.md +84 -0
- connectonion/cli/co_ai/prompts/connectonion/tui/keys.md +77 -0
- connectonion/cli/co_ai/prompts/connectonion/tui/pick.md +71 -0
- connectonion/cli/co_ai/prompts/connectonion/tui/providers.md +89 -0
- connectonion/cli/co_ai/prompts/connectonion/tui/status_bar.md +67 -0
- connectonion/cli/co_ai/prompts/connectonion/useful_plugins/README.md +156 -0
- connectonion/cli/co_ai/prompts/connectonion/useful_plugins/calendar_plugin.md +68 -0
- connectonion/cli/co_ai/prompts/connectonion/useful_plugins/eval.md +89 -0
- connectonion/cli/co_ai/prompts/connectonion/useful_plugins/gmail_plugin.md +68 -0
- connectonion/cli/co_ai/prompts/connectonion/useful_plugins/image_result_formatter.md +74 -0
- connectonion/cli/co_ai/prompts/connectonion/useful_plugins/re_act.md +86 -0
- connectonion/cli/co_ai/prompts/connectonion/useful_plugins/shell_approval.md +69 -0
- connectonion/cli/co_ai/prompts/connectonion/useful_tools/README.md +81 -0
- connectonion/cli/co_ai/prompts/connectonion/useful_tools/diff_writer.md +138 -0
- connectonion/cli/co_ai/prompts/connectonion/useful_tools/get_emails.md +499 -0
- connectonion/cli/co_ai/prompts/connectonion/useful_tools/gmail.md +135 -0
- connectonion/cli/co_ai/prompts/connectonion/useful_tools/google_calendar.md +106 -0
- connectonion/cli/co_ai/prompts/connectonion/useful_tools/memory.md +486 -0
- connectonion/cli/co_ai/prompts/connectonion/useful_tools/microsoft_calendar.md +106 -0
- connectonion/cli/co_ai/prompts/connectonion/useful_tools/outlook.md +120 -0
- connectonion/cli/co_ai/prompts/connectonion/useful_tools/send_email.md +403 -0
- connectonion/cli/co_ai/prompts/connectonion/useful_tools/shell.md +95 -0
- connectonion/cli/co_ai/prompts/connectonion/useful_tools/slash_command.md +96 -0
- connectonion/cli/co_ai/prompts/connectonion/useful_tools/terminal.md +97 -0
- connectonion/cli/co_ai/prompts/connectonion/useful_tools/todo_list.md +252 -0
- connectonion/cli/co_ai/prompts/connectonion/useful_tools/web_fetch.md +130 -0
- connectonion/cli/co_ai/prompts/connectonion/vibe-coding-guide.md +97 -0
- connectonion/cli/co_ai/prompts/connectonion/windows-support.md +258 -0
- connectonion/cli/co_ai/prompts/main.md +247 -0
- connectonion/cli/co_ai/prompts/reminders/plan_mode.md +34 -0
- connectonion/cli/co_ai/prompts/summarization.md +55 -0
- connectonion/cli/co_ai/prompts/tools/ask_user.md +61 -0
- connectonion/cli/co_ai/prompts/tools/background.md +57 -0
- connectonion/cli/co_ai/prompts/tools/edit.md +90 -0
- connectonion/cli/co_ai/prompts/tools/glob.md +52 -0
- connectonion/cli/co_ai/prompts/tools/grep.md +55 -0
- connectonion/cli/co_ai/prompts/tools/plan_mode.md +80 -0
- connectonion/cli/co_ai/prompts/tools/read.md +40 -0
- connectonion/cli/co_ai/prompts/tools/shell.md +67 -0
- connectonion/cli/co_ai/prompts/tools/task.md +51 -0
- connectonion/cli/co_ai/prompts/tools/todo.md +139 -0
- connectonion/cli/co_ai/prompts/tools/write.md +47 -0
- connectonion/cli/co_ai/prompts/workflow.md +89 -0
- connectonion/cli/co_ai/reminders.py +159 -0
- connectonion/cli/co_ai/sessions.py +110 -0
- connectonion/cli/co_ai/skills/__init__.py +37 -0
- connectonion/cli/co_ai/skills/builtin/commit/SKILL.md +63 -0
- connectonion/cli/co_ai/skills/builtin/review-pr/SKILL.md +76 -0
- connectonion/cli/co_ai/skills/loader.py +166 -0
- connectonion/cli/co_ai/skills/tool.py +46 -0
- connectonion/cli/co_ai/tools/__init__.py +92 -0
- connectonion/cli/co_ai/tools/ask_user.py +35 -0
- connectonion/cli/co_ai/tools/background.py +201 -0
- connectonion/cli/co_ai/tools/diff_writer.py +291 -0
- connectonion/cli/co_ai/tools/edit.py +89 -0
- connectonion/cli/co_ai/tools/glob.py +84 -0
- connectonion/cli/co_ai/tools/grep.py +158 -0
- connectonion/cli/co_ai/tools/load_guide.py +23 -0
- connectonion/cli/co_ai/tools/multi_edit.py +116 -0
- connectonion/cli/co_ai/tools/plan_mode.py +172 -0
- connectonion/cli/co_ai/tools/read.py +67 -0
- connectonion/cli/co_ai/tools/task.py +59 -0
- connectonion/cli/co_ai/tools/todo_list.py +159 -0
- connectonion/cli/co_ai/tools/write.py +126 -0
- connectonion/cli/commands/__init__.py +11 -1
- connectonion/cli/commands/ai_commands.py +34 -0
- connectonion/cli/commands/copy_commands.py +55 -6
- connectonion/cli/commands/create.py +20 -17
- connectonion/cli/commands/init.py +19 -22
- connectonion/cli/commands/project_cmd_lib.py +15 -0
- connectonion/cli/main.py +11 -0
- connectonion/console.py +15 -1
- connectonion/core/__init__.py +10 -1
- connectonion/core/agent.py +37 -16
- connectonion/core/exceptions.py +74 -0
- connectonion/core/llm.py +54 -6
- connectonion/core/tool_executor.py +32 -31
- connectonion/core/tool_factory.py +47 -10
- connectonion/debug/__init__.py +10 -1
- connectonion/debug/debug_explainer/__init__.py +10 -1
- connectonion/debug/execution_analyzer/__init__.py +10 -1
- connectonion/debug/execution_analyzer/execution_analysis.py +5 -2
- connectonion/debug/runtime_inspector/__init__.py +10 -1
- connectonion/docs/.package-ignore +6 -0
- connectonion/docs/README.md +2036 -0
- connectonion/docs/api.md +457 -0
- connectonion/docs/archive/001-ai-agent-is-just-prompt-plus-function.md +249 -0
- connectonion/docs/archive/README.md +53 -0
- connectonion/docs/archive/archive/consolidation-plan.md +72 -0
- connectonion/docs/archive/archive/core-principles-extracted.md +239 -0
- connectonion/docs/archive/archive/master-principles.md +222 -0
- connectonion/docs/archive/archive/principles.md +293 -0
- connectonion/docs/archive/archive/simplicity-principles.md +221 -0
- connectonion/docs/archive/attack-defense-insights.md +410 -0
- connectonion/docs/archive/business-model.md +305 -0
- connectonion/docs/archive/core-principles-unified.md +190 -0
- connectonion/docs/archive/discussion-journey.md +178 -0
- connectonion/docs/archive/economic-analysis.md +323 -0
- connectonion/docs/archive/features/01-share-and-find.md +256 -0
- connectonion/docs/archive/features/02-agent-authentication.md +93 -0
- connectonion/docs/archive/features/03-test-before-trust.md +71 -0
- connectonion/docs/archive/features/06-reliability-and-offline.md +197 -0
- connectonion/docs/archive/features/README.md +46 -0
- connectonion/docs/archive/features-roadmap.md +247 -0
- connectonion/docs/archive/mcp-comparison-insights.md +215 -0
- connectonion/docs/archive/migration-strategy.md +571 -0
- connectonion/docs/archive/mini-whitepaper.md +293 -0
- connectonion/docs/archive/network-protocol.md +394 -0
- connectonion/docs/archive/semantic-revolution.md +367 -0
- connectonion/docs/archive/technical-architecture.md +453 -0
- connectonion/docs/archive/the-semantic-insight.md +207 -0
- connectonion/docs/archive/threat-model.md +164 -0
- connectonion/docs/cli/README.md +805 -0
- connectonion/docs/cli/auth.md +46 -0
- connectonion/docs/cli/browser.md +235 -0
- connectonion/docs/cli/copy.md +232 -0
- connectonion/docs/cli/create.md +335 -0
- connectonion/docs/cli/init.md +431 -0
- connectonion/docs/co-directory-structure.md +214 -0
- connectonion/docs/concepts/agent.md +1078 -0
- connectonion/docs/concepts/events.md +699 -0
- connectonion/docs/concepts/llm_do.md +256 -0
- connectonion/docs/concepts/max_iterations.md +362 -0
- connectonion/docs/concepts/models.md +641 -0
- connectonion/docs/concepts/plugins.md +100 -0
- connectonion/docs/concepts/prompts.md +122 -0
- connectonion/docs/concepts/session.md +428 -0
- connectonion/docs/concepts/tools.md +512 -0
- connectonion/docs/concepts/transcribe.md +156 -0
- connectonion/docs/concepts/trust.md +291 -0
- connectonion/docs/connectonion.md +1256 -0
- connectonion/docs/debug/README.md +18 -0
- connectonion/docs/debug/auto_debug.md +1026 -0
- connectonion/docs/debug/console.md +129 -0
- connectonion/docs/debug/eval-format.md +178 -0
- connectonion/docs/debug/eval.md +230 -0
- connectonion/docs/debug/exceptions.md +307 -0
- connectonion/docs/debug/log.md +117 -0
- connectonion/docs/debug/xray.md +215 -0
- connectonion/docs/design-decisions/001-choosing-input-method.md +202 -0
- connectonion/docs/design-decisions/002-choosing-llm-function-name.md +202 -0
- connectonion/docs/design-decisions/003-choosing-trust-keyword.md +141 -0
- connectonion/docs/design-decisions/004-cli-create-flow.md +117 -0
- connectonion/docs/design-decisions/005-designing-agent-network-protocol.md +503 -0
- connectonion/docs/design-decisions/006-agent-address-format.md +305 -0
- connectonion/docs/design-decisions/007-authentication-backend-design.md +240 -0
- connectonion/docs/design-decisions/008-naming-is-hard.md +228 -0
- connectonion/docs/design-decisions/009-why-connect-function.md +167 -0
- connectonion/docs/design-decisions/010-cli-ux-progressive-disclosure.md +176 -0
- connectonion/docs/design-decisions/011-global-config-identity-management.md +357 -0
- connectonion/docs/design-decisions/012-tool-execution-separation.md +259 -0
- connectonion/docs/design-decisions/013-debug-and-logging-design.md +253 -0
- connectonion/docs/design-decisions/014-hook-system-design.md +510 -0
- connectonion/docs/design-decisions/015-interactive-auto-debug-design.md +837 -0
- connectonion/docs/design-decisions/016-why-no-zero-knowledge-proofs.md +358 -0
- connectonion/docs/design-decisions/017-session-logging-and-eval-format.md +120 -0
- connectonion/docs/design-decisions/018-event-api-naming.md +274 -0
- connectonion/docs/design-decisions/019-agent-lifecycle-design.md +655 -0
- connectonion/docs/design-decisions/020-trust-system-and-network-architecture.md +503 -0
- connectonion/docs/design-decisions/021-task-storage-jsonl-design.md +496 -0
- connectonion/docs/design-decisions/022-raw-asgi-implementation.md +273 -0
- connectonion/docs/examples.md +0 -0
- connectonion/docs/hook-system-options.md +364 -0
- connectonion/docs/integrations/README.md +12 -0
- connectonion/docs/integrations/auth.md +450 -0
- connectonion/docs/integrations/google.md +431 -0
- connectonion/docs/integrations/microsoft.md +370 -0
- connectonion/docs/network/README.md +14 -0
- connectonion/docs/network/connect.md +629 -0
- connectonion/docs/network/deploy.md +124 -0
- connectonion/docs/network/host.md +1087 -0
- connectonion/docs/network/io.md +538 -0
- connectonion/docs/network/protocol/agent-relay-protocol.md +495 -0
- connectonion/docs/network/protocol/announce-message.md +115 -0
- connectonion/docs/principles.md +124 -0
- connectonion/docs/quickstart.md +261 -0
- connectonion/docs/roadmap.md +81 -0
- connectonion/docs/templates/README.md +77 -0
- connectonion/docs/templates/meta-agent.md +152 -0
- connectonion/docs/templates/minimal.md +105 -0
- connectonion/docs/templates/playwright.md +130 -0
- connectonion/docs/templates/web-research.md +144 -0
- connectonion/docs/tui/README.md +95 -0
- connectonion/docs/tui/chat.md +181 -0
- connectonion/docs/tui/divider.md +63 -0
- connectonion/docs/tui/dropdown.md +83 -0
- connectonion/docs/tui/footer.md +44 -0
- connectonion/docs/tui/fuzzy.md +68 -0
- connectonion/docs/tui/input.md +84 -0
- connectonion/docs/tui/keys.md +77 -0
- connectonion/docs/tui/pick.md +71 -0
- connectonion/docs/tui/providers.md +89 -0
- connectonion/docs/tui/status_bar.md +67 -0
- connectonion/docs/useful_plugins/README.md +160 -0
- connectonion/docs/useful_plugins/calendar_plugin.md +68 -0
- connectonion/docs/useful_plugins/eval.md +89 -0
- connectonion/docs/useful_plugins/gmail_plugin.md +68 -0
- connectonion/docs/useful_plugins/image_result_formatter.md +74 -0
- connectonion/docs/useful_plugins/re_act.md +86 -0
- connectonion/docs/useful_plugins/shell_approval.md +69 -0
- connectonion/docs/useful_plugins/system_reminder.md +210 -0
- connectonion/docs/useful_prompts/README.md +127 -0
- connectonion/docs/useful_prompts/coding_agent.md +214 -0
- connectonion/docs/useful_tools/README.md +81 -0
- connectonion/docs/useful_tools/ask_user.md +103 -0
- connectonion/docs/useful_tools/diff_writer.md +158 -0
- connectonion/docs/useful_tools/get_emails.md +519 -0
- connectonion/docs/useful_tools/gmail.md +155 -0
- connectonion/docs/useful_tools/google_calendar.md +126 -0
- connectonion/docs/useful_tools/memory.md +506 -0
- connectonion/docs/useful_tools/microsoft_calendar.md +126 -0
- connectonion/docs/useful_tools/outlook.md +140 -0
- connectonion/docs/useful_tools/send_email.md +423 -0
- connectonion/docs/useful_tools/shell.md +115 -0
- connectonion/docs/useful_tools/slash_command.md +116 -0
- connectonion/docs/useful_tools/terminal.md +115 -0
- connectonion/docs/useful_tools/todo_list.md +272 -0
- connectonion/docs/useful_tools/web_fetch.md +150 -0
- connectonion/docs/vibe-coding-guide.md +97 -0
- connectonion/docs/windows-support.md +258 -0
- connectonion/logger.py +3 -3
- connectonion/network/__init__.py +19 -6
- connectonion/network/asgi/__init__.py +81 -0
- connectonion/network/asgi/http.py +205 -0
- connectonion/network/asgi/websocket.py +217 -0
- connectonion/network/connect.py +232 -185
- connectonion/network/host/__init__.py +59 -0
- connectonion/network/host/auth.py +191 -0
- connectonion/network/host/routes.py +135 -0
- connectonion/network/host/server.py +289 -0
- connectonion/network/host/session.py +78 -0
- connectonion/network/io/__init__.py +21 -0
- connectonion/network/{connection.py → io/base.py} +17 -42
- connectonion/network/io/websocket.py +55 -0
- connectonion/network/relay.py +37 -16
- connectonion/network/trust/__init__.py +30 -0
- connectonion/network/trust/factory.py +138 -0
- connectonion/network/{trust_agents.py → trust/prompts.py} +3 -3
- connectonion/network/{trust_functions.py → trust/tools.py} +2 -2
- connectonion/prompt_files/__init__.py +11 -1
- connectonion/prompt_files/react_acknowledge.md +26 -0
- connectonion/prompts.py +10 -1
- connectonion/tui/chat.py +10 -1
- connectonion/tui/divider.py +10 -1
- connectonion/tui/dropdown.py +10 -1
- connectonion/tui/footer.py +8 -0
- connectonion/tui/fuzzy.py +11 -1
- connectonion/tui/input.py +118 -70
- connectonion/tui/keys.py +133 -6
- connectonion/tui/providers.py +11 -1
- connectonion/tui/status_bar.py +10 -1
- connectonion/useful_events_handlers/__init__.py +8 -0
- connectonion/useful_events_handlers/reflect.py +19 -4
- connectonion/useful_plugins/__init__.py +2 -1
- connectonion/useful_plugins/eval.py +2 -2
- connectonion/useful_plugins/gmail_plugin.py +3 -3
- connectonion/useful_plugins/image_result_formatter.py +3 -3
- connectonion/useful_plugins/re_act.py +114 -28
- connectonion/useful_plugins/shell_approval.py +2 -2
- connectonion/useful_plugins/system_reminder.py +103 -0
- connectonion/useful_plugins/ui_stream.py +18 -133
- connectonion/useful_prompts/README.md +61 -0
- connectonion/useful_prompts/__init__.py +45 -0
- connectonion/useful_prompts/coding_agent/README.md +106 -0
- connectonion/useful_prompts/coding_agent/assembler.py +123 -0
- connectonion/useful_prompts/coding_agent/prompts/main.md +227 -0
- connectonion/useful_prompts/coding_agent/prompts/tools/ask_user.md +61 -0
- connectonion/useful_prompts/coding_agent/prompts/tools/background.md +57 -0
- connectonion/useful_prompts/coding_agent/prompts/tools/edit.md +90 -0
- connectonion/useful_prompts/coding_agent/prompts/tools/glob.md +52 -0
- connectonion/useful_prompts/coding_agent/prompts/tools/grep.md +55 -0
- connectonion/useful_prompts/coding_agent/prompts/tools/plan_mode.md +80 -0
- connectonion/useful_prompts/coding_agent/prompts/tools/read.md +40 -0
- connectonion/useful_prompts/coding_agent/prompts/tools/shell.md +67 -0
- connectonion/useful_prompts/coding_agent/prompts/tools/task.md +51 -0
- connectonion/useful_prompts/coding_agent/prompts/tools/todo.md +139 -0
- connectonion/useful_prompts/coding_agent/prompts/tools/write.md +48 -0
- connectonion/useful_prompts/system-reminders/security-warning.md +14 -0
- connectonion/useful_prompts/system-reminders/test-reminder.md +11 -0
- connectonion/useful_tools/__init__.py +31 -4
- connectonion/useful_tools/ask_user.py +35 -0
- connectonion/useful_tools/bash.py +69 -0
- connectonion/useful_tools/diff_writer.py +186 -94
- connectonion/useful_tools/edit.py +102 -0
- connectonion/useful_tools/glob_files.py +97 -0
- connectonion/useful_tools/grep_files.py +171 -0
- connectonion/useful_tools/multi_edit.py +116 -0
- connectonion/useful_tools/read_file.py +73 -0
- connectonion/useful_tools/shell.py +50 -45
- connectonion/useful_tools/write_file.py +129 -0
- {connectonion-0.6.1.dist-info → connectonion-0.6.3.dist-info}/METADATA +10 -3
- connectonion-0.6.3.dist-info/RECORD +469 -0
- connectonion/cli/browser_agent/scroll_strategies.py +0 -276
- connectonion/network/asgi.py +0 -407
- connectonion/network/host.py +0 -616
- connectonion/network/trust.py +0 -166
- connectonion-0.6.1.dist-info/RECORD +0 -123
- /connectonion/cli/{docs → co_ai/prompts/connectonion}/connectonion.md +0 -0
- {connectonion-0.6.1.dist-info → connectonion-0.6.3.dist-info}/WHEEL +0 -0
- {connectonion-0.6.1.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
|
-
#
|
|
342
|
-
|
|
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
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
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:
|
|
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
|
|
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
|
|
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:
|
connectonion/core/__init__.py
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
"""
|
|
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
|
connectonion/core/agent.py
CHANGED
|
@@ -51,8 +51,8 @@ class Agent:
|
|
|
51
51
|
# Current session context (runtime only)
|
|
52
52
|
self.current_session = None
|
|
53
53
|
|
|
54
|
-
#
|
|
55
|
-
self.
|
|
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
|
-
#
|
|
235
|
-
self.
|
|
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
|
-
'
|
|
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["
|
|
320
|
-
"
|
|
340
|
+
"name": trace_entry["name"],
|
|
341
|
+
"args": trace_entry.get("args", {}),
|
|
321
342
|
"result": trace_entry["result"],
|
|
322
343
|
"status": trace_entry["status"],
|
|
323
|
-
"
|
|
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
|
-
|
|
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
|
-
#
|
|
376
|
-
self.
|
|
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 .
|
|
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,
|
|
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
|
-
|
|
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": "
|
|
112
|
-
"
|
|
113
|
-
"
|
|
114
|
-
"
|
|
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
|
-
"
|
|
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
|
-
|
|
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("
|
|
148
|
-
if entry.get("type") == "
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|