connectonion 0.6.2__py3-none-any.whl → 0.6.4__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 +13 -3
- connectonion/cli/browser_agent/element_finder.py +8 -0
- connectonion/cli/browser_agent/highlight_screenshot.py +9 -1
- connectonion/cli/browser_agent/scroll.py +8 -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 +5 -0
- connectonion/cli/co_ai/plugins/system_reminder.py +154 -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/summarization.md +55 -0
- connectonion/cli/co_ai/prompts/system-reminders/agent.md +23 -0
- connectonion/cli/co_ai/prompts/system-reminders/plan_mode.md +13 -0
- connectonion/cli/co_ai/prompts/system-reminders/security.md +14 -0
- connectonion/cli/co_ai/prompts/system-reminders/simplicity.md +14 -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/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 +169 -0
- connectonion/cli/co_ai/tools/read.py +61 -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 +101 -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_plugins/tool_approval.md +139 -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 +3 -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/tool_approval.py +233 -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.2.dist-info → connectonion-0.6.4.dist-info}/METADATA +10 -3
- connectonion-0.6.4.dist-info/RECORD +472 -0
- connectonion/network/asgi.py +0 -407
- connectonion/network/host.py +0 -616
- connectonion/network/trust.py +0 -166
- connectonion-0.6.2.dist-info/RECORD +0 -129
- /connectonion/cli/{docs → co_ai/prompts/connectonion}/connectonion.md +0 -0
- {connectonion-0.6.2.dist-info → connectonion-0.6.4.dist-info}/WHEEL +0 -0
- {connectonion-0.6.2.dist-info → connectonion-0.6.4.dist-info}/entry_points.txt +0 -0
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
"""
|
|
2
|
-
Purpose: ReAct (Reasoning + Acting) plugin that adds
|
|
2
|
+
Purpose: ReAct (Reasoning + Acting) plugin that adds intent recognition and reflection to agent execution
|
|
3
3
|
LLM-Note:
|
|
4
|
-
Dependencies: imports from [pathlib, typing, events.after_user_input, llm_do, useful_events_handlers.reflect] | imported by [useful_plugins/__init__.py] | uses prompt file [prompt_files/
|
|
5
|
-
Data flow: after_user_input →
|
|
6
|
-
State/Effects: modifies agent.current_session['
|
|
7
|
-
Integration: exposes re_act plugin list with [
|
|
8
|
-
Performance:
|
|
4
|
+
Dependencies: imports from [pathlib, typing, events.after_user_input, llm_do, useful_events_handlers.reflect] | imported by [useful_plugins/__init__.py] | uses prompt file [prompt_files/react_acknowledge.md] | tested by [tests/unit/test_re_act_plugin.py]
|
|
5
|
+
Data flow: after_user_input → acknowledge_request() → after_tools → reflect()
|
|
6
|
+
State/Effects: modifies agent.current_session['intent'] | makes LLM calls for intent, reflection | no file I/O
|
|
7
|
+
Integration: exposes re_act plugin list with [acknowledge_request, reflect] event handlers | used via Agent(plugins=[re_act])
|
|
8
|
+
Performance: 2 LLM calls per turn (intent + reflect) | adds latency but improves agent reasoning
|
|
9
9
|
Errors: no explicit error handling | LLM failures propagate | silent skip if no user_prompt
|
|
10
10
|
|
|
11
11
|
ReAct plugin - Reasoning and Acting pattern for AI agents.
|
|
12
12
|
|
|
13
|
-
Implements
|
|
14
|
-
1. After user input:
|
|
15
|
-
2. After tool execution: Reflect on results
|
|
13
|
+
Implements a simplified ReAct pattern:
|
|
14
|
+
1. After user input: Acknowledge request (show we understood)
|
|
15
|
+
2. After tool execution: Reflect on results
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Planning is left to the main agent - this plugin just adds intent recognition and reflection.
|
|
18
|
+
|
|
19
|
+
Trace kinds for frontend rendering:
|
|
20
|
+
- kind='intent' → Show as "Understanding..." card
|
|
21
|
+
- kind='reflect' → Show as "Reflecting..." card
|
|
18
22
|
|
|
19
23
|
Usage:
|
|
20
24
|
from connectonion import Agent
|
|
@@ -37,42 +41,124 @@ if TYPE_CHECKING:
|
|
|
37
41
|
from ..core.agent import Agent
|
|
38
42
|
|
|
39
43
|
# Prompts
|
|
40
|
-
|
|
44
|
+
ACKNOWLEDGE_PROMPT = Path(__file__).parent.parent / "prompt_files" / "react_acknowledge.md"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _format_conversation(
|
|
48
|
+
messages: list,
|
|
49
|
+
max_tokens: int = 4000,
|
|
50
|
+
max_messages: int = 50,
|
|
51
|
+
) -> str:
|
|
52
|
+
"""Format conversation history with smart truncation.
|
|
53
|
+
|
|
54
|
+
Only truncates when context exceeds budget. Priorities:
|
|
55
|
+
1. User messages: always kept full (important context)
|
|
56
|
+
2. Recent assistant messages: kept longer
|
|
57
|
+
3. Older assistant messages: truncated first
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
messages: List of message dicts with 'role' and 'content'
|
|
61
|
+
max_tokens: Approximate token budget (~4 chars per token)
|
|
62
|
+
max_messages: Max number of messages to consider
|
|
63
|
+
"""
|
|
64
|
+
max_chars = max_tokens * 4 # ~4 chars per token approximation
|
|
65
|
+
|
|
66
|
+
recent = messages[-max_messages:] if len(messages) > max_messages else messages
|
|
67
|
+
if not recent:
|
|
68
|
+
return ""
|
|
69
|
+
|
|
70
|
+
# First pass: calculate total size with full messages
|
|
71
|
+
total_chars = sum(len(m.get('content', '')) for m in recent)
|
|
72
|
+
|
|
73
|
+
# If under budget, return everything full
|
|
74
|
+
if total_chars <= max_chars:
|
|
75
|
+
lines = []
|
|
76
|
+
for msg in recent:
|
|
77
|
+
role = msg.get('role', 'unknown')
|
|
78
|
+
content = msg.get('content', '')
|
|
79
|
+
if content:
|
|
80
|
+
lines.append(f"{role}: {content}")
|
|
81
|
+
return "\n".join(lines)
|
|
82
|
+
|
|
83
|
+
# Over budget: smart truncation
|
|
84
|
+
# User messages kept full, truncate assistant messages
|
|
85
|
+
user_chars = sum(len(m.get('content', '')) for m in recent if m.get('role') == 'user')
|
|
86
|
+
available_for_assistant = max_chars - user_chars
|
|
87
|
+
|
|
88
|
+
assistant_msgs = [m for m in recent if m.get('role') == 'assistant' and m.get('content')]
|
|
89
|
+
if not assistant_msgs:
|
|
90
|
+
return "\n".join(f"user: {m.get('content', '')}" for m in recent if m.get('role') == 'user')
|
|
91
|
+
|
|
92
|
+
# Distribute chars to assistant messages (more to recent ones)
|
|
93
|
+
n = len(assistant_msgs)
|
|
94
|
+
weights = [1 + (i / n) for i in range(n)] # older=1.0, recent=~2.0
|
|
95
|
+
total_weight = sum(weights)
|
|
96
|
+
char_budgets = [int(available_for_assistant * w / total_weight) for w in weights]
|
|
97
|
+
|
|
98
|
+
# Build output
|
|
99
|
+
lines = []
|
|
100
|
+
assistant_idx = 0
|
|
101
|
+
for msg in recent:
|
|
102
|
+
role = msg.get('role', 'unknown')
|
|
103
|
+
content = msg.get('content', '')
|
|
104
|
+
if not content:
|
|
105
|
+
continue
|
|
106
|
+
|
|
107
|
+
if role == 'user':
|
|
108
|
+
lines.append(f"user: {content}")
|
|
109
|
+
elif role == 'assistant':
|
|
110
|
+
budget = char_budgets[assistant_idx] if assistant_idx < len(char_budgets) else 200
|
|
111
|
+
assistant_idx += 1
|
|
112
|
+
if len(content) > budget:
|
|
113
|
+
content = content[:budget] + "..."
|
|
114
|
+
lines.append(f"assistant: {content}")
|
|
115
|
+
|
|
116
|
+
return "\n".join(lines)
|
|
41
117
|
|
|
42
118
|
|
|
43
119
|
@after_user_input
|
|
44
|
-
def
|
|
45
|
-
"""
|
|
120
|
+
def acknowledge_request(agent: 'Agent') -> None:
|
|
121
|
+
"""Immediately acknowledge the user's request to show we understood."""
|
|
46
122
|
user_prompt = agent.current_session.get('user_prompt', '')
|
|
47
123
|
if not user_prompt:
|
|
48
124
|
return
|
|
49
125
|
|
|
50
|
-
|
|
51
|
-
|
|
126
|
+
# Include conversation history for context
|
|
127
|
+
messages = agent.current_session.get('messages', [])
|
|
128
|
+
conversation = _format_conversation(messages)
|
|
52
129
|
|
|
53
|
-
prompt = f"""
|
|
130
|
+
prompt = f"""Conversation so far:
|
|
131
|
+
{conversation}
|
|
54
132
|
|
|
55
|
-
|
|
133
|
+
Current user input: {user_prompt}
|
|
56
134
|
|
|
57
|
-
|
|
135
|
+
Acknowledge this request (1-2 sentences):"""
|
|
58
136
|
|
|
59
|
-
|
|
137
|
+
model = "co/gemini-2.5-flash"
|
|
138
|
+
agent.logger.print(f"[dim]/understanding ({model})...[/dim]")
|
|
60
139
|
|
|
61
|
-
|
|
140
|
+
ack = llm_do(
|
|
62
141
|
prompt,
|
|
63
|
-
model=
|
|
64
|
-
temperature=0.
|
|
65
|
-
system_prompt=
|
|
142
|
+
model=model,
|
|
143
|
+
temperature=0.3,
|
|
144
|
+
system_prompt=ACKNOWLEDGE_PROMPT
|
|
66
145
|
)
|
|
67
146
|
|
|
68
|
-
|
|
69
|
-
|
|
147
|
+
agent.current_session['intent'] = ack
|
|
148
|
+
|
|
149
|
+
agent._record_trace({
|
|
150
|
+
'type': 'thinking',
|
|
151
|
+
'kind': 'intent',
|
|
152
|
+
'content': ack,
|
|
153
|
+
})
|
|
70
154
|
|
|
155
|
+
# Add to messages so LLM sees the understanding
|
|
71
156
|
agent.current_session['messages'].append({
|
|
72
157
|
'role': 'assistant',
|
|
73
|
-
'content':
|
|
158
|
+
'content': ack
|
|
74
159
|
})
|
|
75
160
|
|
|
76
161
|
|
|
77
|
-
# Bundle as plugin:
|
|
78
|
-
|
|
162
|
+
# Bundle as plugin: acknowledge (after_user_input) + reflect (after_tools)
|
|
163
|
+
# Planning is handled by the main agent
|
|
164
|
+
re_act = [acknowledge_request, reflect]
|
|
@@ -105,9 +105,9 @@ def _check_approval(agent: 'Agent') -> None:
|
|
|
105
105
|
if not pending:
|
|
106
106
|
return
|
|
107
107
|
|
|
108
|
-
# Only check bash/shell tools
|
|
108
|
+
# Only check bash/shell tools (including run_in_dir)
|
|
109
109
|
tool_name = pending['name']
|
|
110
|
-
if tool_name not in ('bash', 'shell', 'run'):
|
|
110
|
+
if tool_name not in ('bash', 'shell', 'run', 'run_in_dir'):
|
|
111
111
|
return
|
|
112
112
|
|
|
113
113
|
# Get command from arguments
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""
|
|
2
|
+
System Reminder Plugin - Injects contextual guidance into tool results.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
from connectonion.useful_plugins import system_reminder
|
|
6
|
+
agent = Agent("assistant", plugins=[system_reminder])
|
|
7
|
+
|
|
8
|
+
To customize, use `co copy system_reminder` which copies both the plugin
|
|
9
|
+
and the prompt files to your project.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
import fnmatch
|
|
14
|
+
from typing import TYPE_CHECKING
|
|
15
|
+
|
|
16
|
+
from ..core.events import after_each_tool
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from ..core.agent import Agent
|
|
20
|
+
|
|
21
|
+
# Default reminders directory
|
|
22
|
+
REMINDERS_DIR = Path(__file__).parent.parent / "useful_prompts" / "system-reminders"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _parse_frontmatter(text):
|
|
26
|
+
"""Parse YAML frontmatter from markdown."""
|
|
27
|
+
if not text.startswith('---'):
|
|
28
|
+
return {}, text
|
|
29
|
+
parts = text.split('---', 2)
|
|
30
|
+
if len(parts) < 3:
|
|
31
|
+
return {}, text
|
|
32
|
+
import yaml
|
|
33
|
+
return yaml.safe_load(parts[1]) or {}, parts[2].strip()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _load_reminders(reminders_dir):
|
|
37
|
+
"""Load all .md reminder files from directory."""
|
|
38
|
+
reminders_dir = Path(reminders_dir)
|
|
39
|
+
if not reminders_dir.exists():
|
|
40
|
+
return {}
|
|
41
|
+
reminders = {}
|
|
42
|
+
for f in reminders_dir.glob("*.md"):
|
|
43
|
+
meta, body = _parse_frontmatter(f.read_text())
|
|
44
|
+
if meta.get('name'):
|
|
45
|
+
reminders[meta['name']] = {'content': body, 'triggers': meta.get('triggers', [])}
|
|
46
|
+
return reminders
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _matches_pattern(pattern, value):
|
|
50
|
+
"""Check if value matches glob pattern(s)."""
|
|
51
|
+
if not pattern or not value:
|
|
52
|
+
return False
|
|
53
|
+
patterns = [pattern] if isinstance(pattern, str) else pattern
|
|
54
|
+
return any(fnmatch.fnmatch(value, p) for p in patterns)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _find_reminder(reminders, tool_name, args):
|
|
58
|
+
"""Find matching reminder content."""
|
|
59
|
+
for reminder in reminders.values():
|
|
60
|
+
for trigger in reminder['triggers']:
|
|
61
|
+
if trigger.get('tool') and trigger['tool'] != tool_name:
|
|
62
|
+
continue
|
|
63
|
+
if trigger.get('path_pattern'):
|
|
64
|
+
path = args.get('path') or args.get('file_path', '')
|
|
65
|
+
if not _matches_pattern(trigger['path_pattern'], path):
|
|
66
|
+
continue
|
|
67
|
+
if trigger.get('command_pattern'):
|
|
68
|
+
cmd = args.get('command') or args.get('cmd', '')
|
|
69
|
+
if not _matches_pattern(trigger['command_pattern'], cmd):
|
|
70
|
+
continue
|
|
71
|
+
# All conditions matched
|
|
72
|
+
content = reminder['content']
|
|
73
|
+
path = args.get('path') or args.get('file_path', '')
|
|
74
|
+
return content.replace('${file_path}', path).replace('${tool_name}', tool_name)
|
|
75
|
+
return None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
# Load reminders once at import
|
|
79
|
+
_REMINDERS = _load_reminders(REMINDERS_DIR)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@after_each_tool
|
|
83
|
+
def inject_reminder(agent: 'Agent') -> None:
|
|
84
|
+
"""Inject matching system reminder into tool result."""
|
|
85
|
+
trace = agent.current_session.get('trace', [])
|
|
86
|
+
messages = agent.current_session.get('messages', [])
|
|
87
|
+
if not trace or not messages:
|
|
88
|
+
return
|
|
89
|
+
|
|
90
|
+
last = trace[-1]
|
|
91
|
+
if last.get('type') != 'tool_result':
|
|
92
|
+
return
|
|
93
|
+
|
|
94
|
+
content = _find_reminder(_REMINDERS, last.get('name', ''), last.get('args', {}))
|
|
95
|
+
if content:
|
|
96
|
+
for msg in reversed(messages):
|
|
97
|
+
if msg.get('role') == 'tool':
|
|
98
|
+
msg['content'] = msg.get('content', '') + '\n\n' + content
|
|
99
|
+
break
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# Export plugin
|
|
103
|
+
system_reminder = [inject_reminder]
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Purpose: Web-based tool approval plugin - request user approval before dangerous tools
|
|
3
|
+
LLM-Note:
|
|
4
|
+
Dependencies: imports from [core/events.py] | imported by [useful_plugins/__init__.py] | tested by [tests/unit/test_tool_approval.py]
|
|
5
|
+
Data flow: before_each_tool fires → check if dangerous tool → io.send(approval_needed) → io.receive() blocks → approved: continue, rejected: raise ValueError
|
|
6
|
+
State/Effects: stores approved_tools in session for "session" scope approvals | blocks on io.receive() until client responds | logs all approval decisions via agent.logger
|
|
7
|
+
Integration: exposes tool_approval plugin list | uses agent.io for WebSocket communication | requires client to handle "approval_needed" events
|
|
8
|
+
Errors: raises ValueError on rejection (stops batch, feedback sent to LLM)
|
|
9
|
+
|
|
10
|
+
Tool Approval Plugin - Request client approval before executing dangerous tools.
|
|
11
|
+
|
|
12
|
+
WebSocket-only. Uses io.send/receive pattern:
|
|
13
|
+
1. Sends {type: "approval_needed", tool, arguments} to client
|
|
14
|
+
2. Blocks until client responds with {approved: bool, scope?, feedback?}
|
|
15
|
+
3. If approved: execute tool (optionally save to session memory)
|
|
16
|
+
4. If rejected: raise ValueError, stopping batch, LLM sees feedback
|
|
17
|
+
|
|
18
|
+
Tool Classification:
|
|
19
|
+
- SAFE_TOOLS: Read-only operations (read, glob, grep, etc.) - never need approval
|
|
20
|
+
- DANGEROUS_TOOLS: Write/execute operations (bash, write, edit, etc.) - always need approval
|
|
21
|
+
- Unknown tools: Treated as safe (no approval needed)
|
|
22
|
+
|
|
23
|
+
Session Memory:
|
|
24
|
+
- scope="once": Approve for this call only
|
|
25
|
+
- scope="session": Approve for rest of session (no re-prompting)
|
|
26
|
+
|
|
27
|
+
Rejection Behavior:
|
|
28
|
+
- Raises ValueError with user feedback
|
|
29
|
+
- Stops entire tool batch (remaining tools skipped)
|
|
30
|
+
- LLM receives error message and can adjust approach
|
|
31
|
+
|
|
32
|
+
Usage:
|
|
33
|
+
from connectonion import Agent
|
|
34
|
+
from connectonion.useful_plugins import tool_approval
|
|
35
|
+
|
|
36
|
+
agent = Agent("assistant", tools=[bash, write], plugins=[tool_approval])
|
|
37
|
+
|
|
38
|
+
Client Protocol:
|
|
39
|
+
# Receive from server:
|
|
40
|
+
{"type": "approval_needed", "tool": "bash", "arguments": {"command": "npm install"}}
|
|
41
|
+
|
|
42
|
+
# Send response:
|
|
43
|
+
{"approved": true, "scope": "session"} # Approve for session
|
|
44
|
+
{"approved": true, "scope": "once"} # Approve once
|
|
45
|
+
{"approved": false, "feedback": "Use yarn instead"} # Reject with feedback
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
from typing import TYPE_CHECKING
|
|
49
|
+
|
|
50
|
+
from ..core.events import before_each_tool
|
|
51
|
+
|
|
52
|
+
if TYPE_CHECKING:
|
|
53
|
+
from ..core.agent import Agent
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# Tools that NEVER need approval (read-only, safe)
|
|
57
|
+
# These tools cannot modify system state or have external side effects.
|
|
58
|
+
# Add new read-only tools here to skip approval prompts.
|
|
59
|
+
SAFE_TOOLS = {
|
|
60
|
+
# File reading - read contents without modification
|
|
61
|
+
'read', 'read_file',
|
|
62
|
+
# Search operations - find files/content without modification
|
|
63
|
+
'glob', 'grep', 'search',
|
|
64
|
+
# Info operations - query metadata only
|
|
65
|
+
'list_files', 'get_file_info',
|
|
66
|
+
# Agent operations - sub-agents handle their own approval
|
|
67
|
+
'task',
|
|
68
|
+
# Documentation - load reference materials
|
|
69
|
+
'load_guide',
|
|
70
|
+
# Planning - state management without side effects
|
|
71
|
+
'enter_plan_mode', 'exit_plan_mode', 'write_plan',
|
|
72
|
+
# Task management - read-only task status
|
|
73
|
+
'task_output',
|
|
74
|
+
# User interaction - prompts user, not system modification
|
|
75
|
+
'ask_user',
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
# Tools that ALWAYS need approval (destructive/side-effects)
|
|
79
|
+
# These tools can modify files, execute code, or have external effects.
|
|
80
|
+
# User approval required before execution in web mode.
|
|
81
|
+
DANGEROUS_TOOLS = {
|
|
82
|
+
# Shell execution - arbitrary command execution
|
|
83
|
+
'bash', 'shell', 'run', 'run_in_dir',
|
|
84
|
+
# File modification - write/edit file contents
|
|
85
|
+
'write', 'edit', 'multi_edit',
|
|
86
|
+
# Background tasks - long-running command execution
|
|
87
|
+
'run_background',
|
|
88
|
+
# Task control - terminate running processes
|
|
89
|
+
'kill_task',
|
|
90
|
+
# External communication - send data outside system
|
|
91
|
+
'send_email', 'post',
|
|
92
|
+
# Deletion - remove files/resources
|
|
93
|
+
'delete', 'remove',
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
# Session state helpers for approval memory
|
|
98
|
+
# These functions manage the session['approval'] dict which tracks
|
|
99
|
+
# which tools have been approved for the current session.
|
|
100
|
+
|
|
101
|
+
def _init_approval_state(session: dict) -> None:
|
|
102
|
+
"""Initialize approval state in session if not present.
|
|
103
|
+
|
|
104
|
+
Creates session['approval']['approved_tools'] dict for storing
|
|
105
|
+
tool approvals with scope='session'.
|
|
106
|
+
"""
|
|
107
|
+
if 'approval' not in session:
|
|
108
|
+
session['approval'] = {
|
|
109
|
+
'approved_tools': {}, # tool_name -> 'session'
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _is_approved_for_session(session: dict, tool_name: str) -> bool:
|
|
114
|
+
"""Check if tool was approved for this session.
|
|
115
|
+
|
|
116
|
+
Returns True if user previously approved this tool with scope='session'.
|
|
117
|
+
"""
|
|
118
|
+
approval = session.get('approval', {})
|
|
119
|
+
return approval.get('approved_tools', {}).get(tool_name) == 'session'
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _save_session_approval(session: dict, tool_name: str) -> None:
|
|
123
|
+
"""Save tool as approved for this session.
|
|
124
|
+
|
|
125
|
+
Future calls to the same tool will skip approval prompts.
|
|
126
|
+
"""
|
|
127
|
+
_init_approval_state(session)
|
|
128
|
+
session['approval']['approved_tools'][tool_name] = 'session'
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _log(agent: 'Agent', message: str, style: str = None) -> None:
|
|
132
|
+
"""Log message via agent's logger if available.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
agent: Agent instance
|
|
136
|
+
message: Message to log
|
|
137
|
+
style: Rich style string (e.g., "[green]", "[red]")
|
|
138
|
+
"""
|
|
139
|
+
if hasattr(agent, 'logger') and agent.logger:
|
|
140
|
+
agent.logger.print(message, style)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@before_each_tool
|
|
144
|
+
def check_approval(agent: 'Agent') -> None:
|
|
145
|
+
"""Check if tool needs approval and request from client.
|
|
146
|
+
|
|
147
|
+
Flow:
|
|
148
|
+
1. Skip if no IO (not web mode)
|
|
149
|
+
2. Skip if safe tool
|
|
150
|
+
3. Skip if unknown tool (default: safe)
|
|
151
|
+
4. Skip if already approved for session
|
|
152
|
+
5. Send approval_needed, wait for response
|
|
153
|
+
6. If approved: optionally save to session, continue
|
|
154
|
+
7. If rejected: raise ValueError (stops batch)
|
|
155
|
+
|
|
156
|
+
Logging:
|
|
157
|
+
- Logs approval requests, approvals, and rejections
|
|
158
|
+
- Uses agent.logger.print() for terminal output
|
|
159
|
+
|
|
160
|
+
Raises:
|
|
161
|
+
ValueError: If user rejects the tool (includes feedback if provided)
|
|
162
|
+
"""
|
|
163
|
+
# No IO = not web mode, skip
|
|
164
|
+
if not agent.io:
|
|
165
|
+
return
|
|
166
|
+
|
|
167
|
+
# Get pending tool info
|
|
168
|
+
pending = agent.current_session.get('pending_tool')
|
|
169
|
+
if not pending:
|
|
170
|
+
return
|
|
171
|
+
|
|
172
|
+
tool_name = pending['name']
|
|
173
|
+
tool_args = pending['arguments']
|
|
174
|
+
|
|
175
|
+
# Safe tools don't need approval
|
|
176
|
+
if tool_name in SAFE_TOOLS:
|
|
177
|
+
return
|
|
178
|
+
|
|
179
|
+
# Unknown tools (not in SAFE or DANGEROUS) are treated as safe
|
|
180
|
+
if tool_name not in DANGEROUS_TOOLS:
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
# Already approved for this session
|
|
184
|
+
if _is_approved_for_session(agent.current_session, tool_name):
|
|
185
|
+
_log(agent, f"[dim]⏭ {tool_name} (session-approved)[/dim]")
|
|
186
|
+
return
|
|
187
|
+
|
|
188
|
+
# Send approval request to client
|
|
189
|
+
agent.io.send({
|
|
190
|
+
'type': 'approval_needed',
|
|
191
|
+
'tool': tool_name,
|
|
192
|
+
'arguments': tool_args,
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
# Wait for client response (BLOCKS)
|
|
196
|
+
response = agent.io.receive()
|
|
197
|
+
|
|
198
|
+
# Handle connection closed
|
|
199
|
+
if response.get('type') == 'io_closed':
|
|
200
|
+
_log(agent, f"[red]✗ {tool_name} - connection closed[/red]")
|
|
201
|
+
raise ValueError(f"Connection closed while waiting for approval of '{tool_name}'")
|
|
202
|
+
|
|
203
|
+
# Check approval
|
|
204
|
+
approved = response.get('approved', False)
|
|
205
|
+
|
|
206
|
+
if approved:
|
|
207
|
+
# Save to session if scope is "session"
|
|
208
|
+
scope = response.get('scope', 'once')
|
|
209
|
+
if scope == 'session':
|
|
210
|
+
_save_session_approval(agent.current_session, tool_name)
|
|
211
|
+
_log(agent, f"[green]✓ {tool_name} approved (session)[/green]")
|
|
212
|
+
else:
|
|
213
|
+
_log(agent, f"[green]✓ {tool_name} approved (once)[/green]")
|
|
214
|
+
# Continue to execute tool
|
|
215
|
+
return
|
|
216
|
+
|
|
217
|
+
# Rejected - raise ValueError to stop batch
|
|
218
|
+
feedback = response.get('feedback', '')
|
|
219
|
+
if feedback:
|
|
220
|
+
_log(agent, f"[red]✗ {tool_name} rejected: {feedback}[/red]")
|
|
221
|
+
else:
|
|
222
|
+
_log(agent, f"[red]✗ {tool_name} rejected[/red]")
|
|
223
|
+
|
|
224
|
+
error_msg = f"User rejected tool '{tool_name}'."
|
|
225
|
+
if feedback:
|
|
226
|
+
error_msg += f" Feedback: {feedback}"
|
|
227
|
+
raise ValueError(error_msg)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
# Export as plugin (list of event handlers)
|
|
231
|
+
# Usage: Agent("name", plugins=[tool_approval])
|
|
232
|
+
# The plugin registers check_approval as a before_each_tool handler
|
|
233
|
+
tool_approval = [check_approval]
|