superqode 0.1.5__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.
- superqode/__init__.py +33 -0
- superqode/acp/__init__.py +23 -0
- superqode/acp/client.py +913 -0
- superqode/acp/permission_screen.py +457 -0
- superqode/acp/types.py +480 -0
- superqode/acp_discovery.py +856 -0
- superqode/agent/__init__.py +22 -0
- superqode/agent/edit_strategies.py +334 -0
- superqode/agent/loop.py +892 -0
- superqode/agent/qe_report_templates.py +39 -0
- superqode/agent/system_prompts.py +353 -0
- superqode/agent_output.py +721 -0
- superqode/agent_stream.py +953 -0
- superqode/agents/__init__.py +59 -0
- superqode/agents/acp_registry.py +305 -0
- superqode/agents/client.py +249 -0
- superqode/agents/data/augmentcode.com.toml +51 -0
- superqode/agents/data/cagent.dev.toml +51 -0
- superqode/agents/data/claude.com.toml +60 -0
- superqode/agents/data/codeassistant.dev.toml +51 -0
- superqode/agents/data/codex.openai.com.toml +57 -0
- superqode/agents/data/fastagent.ai.toml +66 -0
- superqode/agents/data/geminicli.com.toml +77 -0
- superqode/agents/data/goose.block.xyz.toml +54 -0
- superqode/agents/data/junie.jetbrains.com.toml +56 -0
- superqode/agents/data/kimi.moonshot.cn.toml +57 -0
- superqode/agents/data/llmlingagent.dev.toml +51 -0
- superqode/agents/data/molt.bot.toml +49 -0
- superqode/agents/data/opencode.ai.toml +60 -0
- superqode/agents/data/stakpak.dev.toml +51 -0
- superqode/agents/data/vtcode.dev.toml +51 -0
- superqode/agents/discovery.py +266 -0
- superqode/agents/messaging.py +160 -0
- superqode/agents/persona.py +166 -0
- superqode/agents/registry.py +421 -0
- superqode/agents/schema.py +72 -0
- superqode/agents/unified.py +367 -0
- superqode/app/__init__.py +111 -0
- superqode/app/constants.py +314 -0
- superqode/app/css.py +366 -0
- superqode/app/models.py +118 -0
- superqode/app/suggester.py +125 -0
- superqode/app/widgets.py +1591 -0
- superqode/app_enhanced.py +399 -0
- superqode/app_main.py +17187 -0
- superqode/approval.py +312 -0
- superqode/atomic.py +296 -0
- superqode/commands/__init__.py +1 -0
- superqode/commands/acp.py +965 -0
- superqode/commands/agents.py +180 -0
- superqode/commands/auth.py +278 -0
- superqode/commands/config.py +374 -0
- superqode/commands/init.py +826 -0
- superqode/commands/providers.py +819 -0
- superqode/commands/qe.py +1145 -0
- superqode/commands/roles.py +380 -0
- superqode/commands/serve.py +172 -0
- superqode/commands/suggestions.py +127 -0
- superqode/commands/superqe.py +460 -0
- superqode/config/__init__.py +51 -0
- superqode/config/loader.py +812 -0
- superqode/config/schema.py +498 -0
- superqode/core/__init__.py +111 -0
- superqode/core/roles.py +281 -0
- superqode/danger.py +386 -0
- superqode/data/superqode-template.yaml +1522 -0
- superqode/design_system.py +1080 -0
- superqode/dialogs/__init__.py +6 -0
- superqode/dialogs/base.py +39 -0
- superqode/dialogs/model.py +130 -0
- superqode/dialogs/provider.py +870 -0
- superqode/diff_view.py +919 -0
- superqode/enterprise.py +21 -0
- superqode/evaluation/__init__.py +25 -0
- superqode/evaluation/adapters.py +93 -0
- superqode/evaluation/behaviors.py +89 -0
- superqode/evaluation/engine.py +209 -0
- superqode/evaluation/scenarios.py +96 -0
- superqode/execution/__init__.py +36 -0
- superqode/execution/linter.py +538 -0
- superqode/execution/modes.py +347 -0
- superqode/execution/resolver.py +283 -0
- superqode/execution/runner.py +642 -0
- superqode/file_explorer.py +811 -0
- superqode/file_viewer.py +471 -0
- superqode/flash.py +183 -0
- superqode/guidance/__init__.py +58 -0
- superqode/guidance/config.py +203 -0
- superqode/guidance/prompts.py +71 -0
- superqode/harness/__init__.py +54 -0
- superqode/harness/accelerator.py +291 -0
- superqode/harness/config.py +319 -0
- superqode/harness/validator.py +147 -0
- superqode/history.py +279 -0
- superqode/integrations/superopt_runner.py +124 -0
- superqode/logging/__init__.py +49 -0
- superqode/logging/adapters.py +219 -0
- superqode/logging/formatter.py +923 -0
- superqode/logging/integration.py +341 -0
- superqode/logging/sinks.py +170 -0
- superqode/logging/unified_log.py +417 -0
- superqode/lsp/__init__.py +26 -0
- superqode/lsp/client.py +544 -0
- superqode/main.py +1069 -0
- superqode/mcp/__init__.py +89 -0
- superqode/mcp/auth_storage.py +380 -0
- superqode/mcp/client.py +1236 -0
- superqode/mcp/config.py +319 -0
- superqode/mcp/integration.py +337 -0
- superqode/mcp/oauth.py +436 -0
- superqode/mcp/oauth_callback.py +385 -0
- superqode/mcp/types.py +290 -0
- superqode/memory/__init__.py +31 -0
- superqode/memory/feedback.py +342 -0
- superqode/memory/store.py +522 -0
- superqode/notifications.py +369 -0
- superqode/optimization/__init__.py +5 -0
- superqode/optimization/config.py +33 -0
- superqode/permissions/__init__.py +25 -0
- superqode/permissions/rules.py +488 -0
- superqode/plan.py +323 -0
- superqode/providers/__init__.py +33 -0
- superqode/providers/gateway/__init__.py +165 -0
- superqode/providers/gateway/base.py +228 -0
- superqode/providers/gateway/litellm_gateway.py +1170 -0
- superqode/providers/gateway/openresponses_gateway.py +436 -0
- superqode/providers/health.py +297 -0
- superqode/providers/huggingface/__init__.py +74 -0
- superqode/providers/huggingface/downloader.py +472 -0
- superqode/providers/huggingface/endpoints.py +442 -0
- superqode/providers/huggingface/hub.py +531 -0
- superqode/providers/huggingface/inference.py +394 -0
- superqode/providers/huggingface/transformers_runner.py +516 -0
- superqode/providers/local/__init__.py +100 -0
- superqode/providers/local/base.py +438 -0
- superqode/providers/local/discovery.py +418 -0
- superqode/providers/local/lmstudio.py +256 -0
- superqode/providers/local/mlx.py +457 -0
- superqode/providers/local/ollama.py +486 -0
- superqode/providers/local/sglang.py +268 -0
- superqode/providers/local/tgi.py +260 -0
- superqode/providers/local/tool_support.py +477 -0
- superqode/providers/local/vllm.py +258 -0
- superqode/providers/manager.py +1338 -0
- superqode/providers/models.py +1016 -0
- superqode/providers/models_dev.py +578 -0
- superqode/providers/openresponses/__init__.py +87 -0
- superqode/providers/openresponses/converters/__init__.py +17 -0
- superqode/providers/openresponses/converters/messages.py +343 -0
- superqode/providers/openresponses/converters/tools.py +268 -0
- superqode/providers/openresponses/schema/__init__.py +56 -0
- superqode/providers/openresponses/schema/models.py +585 -0
- superqode/providers/openresponses/streaming/__init__.py +5 -0
- superqode/providers/openresponses/streaming/parser.py +338 -0
- superqode/providers/openresponses/tools/__init__.py +21 -0
- superqode/providers/openresponses/tools/apply_patch.py +352 -0
- superqode/providers/openresponses/tools/code_interpreter.py +290 -0
- superqode/providers/openresponses/tools/file_search.py +333 -0
- superqode/providers/openresponses/tools/mcp_adapter.py +252 -0
- superqode/providers/registry.py +716 -0
- superqode/providers/usage.py +332 -0
- superqode/pure_mode.py +384 -0
- superqode/qr/__init__.py +23 -0
- superqode/qr/dashboard.py +781 -0
- superqode/qr/generator.py +1018 -0
- superqode/qr/templates.py +135 -0
- superqode/safety/__init__.py +41 -0
- superqode/safety/sandbox.py +413 -0
- superqode/safety/warnings.py +256 -0
- superqode/server/__init__.py +33 -0
- superqode/server/lsp_server.py +775 -0
- superqode/server/web.py +250 -0
- superqode/session/__init__.py +25 -0
- superqode/session/persistence.py +580 -0
- superqode/session/sharing.py +477 -0
- superqode/session.py +475 -0
- superqode/sidebar.py +2991 -0
- superqode/stream_view.py +648 -0
- superqode/styles/__init__.py +3 -0
- superqode/superqe/__init__.py +184 -0
- superqode/superqe/acp_runner.py +1064 -0
- superqode/superqe/constitution/__init__.py +62 -0
- superqode/superqe/constitution/evaluator.py +308 -0
- superqode/superqe/constitution/loader.py +432 -0
- superqode/superqe/constitution/schema.py +250 -0
- superqode/superqe/events.py +591 -0
- superqode/superqe/frameworks/__init__.py +65 -0
- superqode/superqe/frameworks/base.py +234 -0
- superqode/superqe/frameworks/e2e.py +263 -0
- superqode/superqe/frameworks/executor.py +237 -0
- superqode/superqe/frameworks/javascript.py +409 -0
- superqode/superqe/frameworks/python.py +373 -0
- superqode/superqe/frameworks/registry.py +92 -0
- superqode/superqe/mcp_tools/__init__.py +47 -0
- superqode/superqe/mcp_tools/core_tools.py +418 -0
- superqode/superqe/mcp_tools/registry.py +230 -0
- superqode/superqe/mcp_tools/testing_tools.py +167 -0
- superqode/superqe/noise.py +89 -0
- superqode/superqe/orchestrator.py +778 -0
- superqode/superqe/roles.py +609 -0
- superqode/superqe/session.py +713 -0
- superqode/superqe/skills/__init__.py +57 -0
- superqode/superqe/skills/base.py +106 -0
- superqode/superqe/skills/core_skills.py +899 -0
- superqode/superqe/skills/registry.py +90 -0
- superqode/superqe/verifier.py +101 -0
- superqode/superqe_cli.py +76 -0
- superqode/tool_call.py +358 -0
- superqode/tools/__init__.py +93 -0
- superqode/tools/agent_tools.py +496 -0
- superqode/tools/base.py +324 -0
- superqode/tools/batch_tool.py +133 -0
- superqode/tools/diagnostics.py +311 -0
- superqode/tools/edit_tools.py +653 -0
- superqode/tools/enhanced_base.py +515 -0
- superqode/tools/file_tools.py +269 -0
- superqode/tools/file_tracking.py +45 -0
- superqode/tools/lsp_tools.py +610 -0
- superqode/tools/network_tools.py +350 -0
- superqode/tools/permissions.py +400 -0
- superqode/tools/question_tool.py +324 -0
- superqode/tools/search_tools.py +598 -0
- superqode/tools/shell_tools.py +259 -0
- superqode/tools/todo_tools.py +121 -0
- superqode/tools/validation.py +80 -0
- superqode/tools/web_tools.py +639 -0
- superqode/tui.py +1152 -0
- superqode/tui_integration.py +875 -0
- superqode/tui_widgets/__init__.py +27 -0
- superqode/tui_widgets/widgets/__init__.py +18 -0
- superqode/tui_widgets/widgets/progress.py +185 -0
- superqode/tui_widgets/widgets/tool_display.py +188 -0
- superqode/undo_manager.py +574 -0
- superqode/utils/__init__.py +5 -0
- superqode/utils/error_handling.py +323 -0
- superqode/utils/fuzzy.py +257 -0
- superqode/widgets/__init__.py +477 -0
- superqode/widgets/agent_collab.py +390 -0
- superqode/widgets/agent_store.py +936 -0
- superqode/widgets/agent_switcher.py +395 -0
- superqode/widgets/animation_manager.py +284 -0
- superqode/widgets/code_context.py +356 -0
- superqode/widgets/command_palette.py +412 -0
- superqode/widgets/connection_status.py +537 -0
- superqode/widgets/conversation_history.py +470 -0
- superqode/widgets/diff_indicator.py +155 -0
- superqode/widgets/enhanced_status_bar.py +385 -0
- superqode/widgets/enhanced_toast.py +476 -0
- superqode/widgets/file_browser.py +809 -0
- superqode/widgets/file_reference.py +585 -0
- superqode/widgets/issue_timeline.py +340 -0
- superqode/widgets/leader_key.py +264 -0
- superqode/widgets/mode_switcher.py +445 -0
- superqode/widgets/model_picker.py +234 -0
- superqode/widgets/permission_preview.py +1205 -0
- superqode/widgets/prompt.py +358 -0
- superqode/widgets/provider_connect.py +725 -0
- superqode/widgets/pty_shell.py +587 -0
- superqode/widgets/qe_dashboard.py +321 -0
- superqode/widgets/resizable_sidebar.py +377 -0
- superqode/widgets/response_changes.py +218 -0
- superqode/widgets/response_display.py +528 -0
- superqode/widgets/rich_tool_display.py +613 -0
- superqode/widgets/sidebar_panels.py +1180 -0
- superqode/widgets/slash_complete.py +356 -0
- superqode/widgets/split_view.py +612 -0
- superqode/widgets/status_bar.py +273 -0
- superqode/widgets/superqode_display.py +786 -0
- superqode/widgets/thinking_display.py +815 -0
- superqode/widgets/throbber.py +87 -0
- superqode/widgets/toast.py +206 -0
- superqode/widgets/unified_output.py +1073 -0
- superqode/workspace/__init__.py +75 -0
- superqode/workspace/artifacts.py +472 -0
- superqode/workspace/coordinator.py +353 -0
- superqode/workspace/diff_tracker.py +429 -0
- superqode/workspace/git_guard.py +373 -0
- superqode/workspace/git_snapshot.py +526 -0
- superqode/workspace/manager.py +750 -0
- superqode/workspace/snapshot.py +357 -0
- superqode/workspace/watcher.py +535 -0
- superqode/workspace/worktree.py +440 -0
- superqode-0.1.5.dist-info/METADATA +204 -0
- superqode-0.1.5.dist-info/RECORD +288 -0
- superqode-0.1.5.dist-info/WHEEL +5 -0
- superqode-0.1.5.dist-info/entry_points.txt +3 -0
- superqode-0.1.5.dist-info/licenses/LICENSE +648 -0
- superqode-0.1.5.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
"""Unified agent interface for both ACP agents and SuperQode models."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
5
|
+
from typing import Optional, Dict, Any, List, AsyncIterator
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from .client import ACPAgentManager
|
|
10
|
+
from .schema import ResolvedRole
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class AgentResponse:
|
|
15
|
+
"""Response from an agent."""
|
|
16
|
+
|
|
17
|
+
content: str
|
|
18
|
+
agent_type: str
|
|
19
|
+
agent_name: str
|
|
20
|
+
metadata: Dict[str, Any] = None
|
|
21
|
+
|
|
22
|
+
def __post_init__(self):
|
|
23
|
+
if self.metadata is None:
|
|
24
|
+
self.metadata = {}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class UnifiedAgent(ABC):
|
|
28
|
+
"""Abstract base class for unified agent interface."""
|
|
29
|
+
|
|
30
|
+
def __init__(self, role_config: ResolvedRole):
|
|
31
|
+
self.role_config = role_config
|
|
32
|
+
self.agent_type = role_config.agent_type
|
|
33
|
+
self.agent_name = role_config.coding_agent
|
|
34
|
+
|
|
35
|
+
@abstractmethod
|
|
36
|
+
async def initialize(self) -> bool:
|
|
37
|
+
"""Initialize the agent."""
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
@abstractmethod
|
|
41
|
+
async def send_message(self, message: str, **kwargs) -> AgentResponse:
|
|
42
|
+
"""Send a message to the agent and get response."""
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
@abstractmethod
|
|
46
|
+
async def get_capabilities(self) -> List[str]:
|
|
47
|
+
"""Get agent capabilities."""
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
@abstractmethod
|
|
51
|
+
async def cleanup(self) -> None:
|
|
52
|
+
"""Clean up agent resources."""
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def description(self) -> str:
|
|
57
|
+
"""Get agent description."""
|
|
58
|
+
return self.role_config.description
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def job_description(self) -> str:
|
|
62
|
+
"""Get agent job description."""
|
|
63
|
+
return self.role_config.job_description
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class SuperQodeAgent(UnifiedAgent):
|
|
67
|
+
"""Agent implementation for SuperQode models (via LLM providers) with full tool access."""
|
|
68
|
+
|
|
69
|
+
def __init__(self, role_config: ResolvedRole):
|
|
70
|
+
super().__init__(role_config)
|
|
71
|
+
self.provider = role_config.provider
|
|
72
|
+
self.model = role_config.model
|
|
73
|
+
self._initialized = False
|
|
74
|
+
self._agent_loop = None
|
|
75
|
+
self._working_directory = Path.cwd()
|
|
76
|
+
|
|
77
|
+
async def initialize(self) -> bool:
|
|
78
|
+
"""Initialize the SuperQode agent with AgentLoop and tools."""
|
|
79
|
+
if not self.provider or not self.model:
|
|
80
|
+
return False
|
|
81
|
+
|
|
82
|
+
# Import here to avoid circular imports
|
|
83
|
+
from ..agent.loop import AgentLoop, AgentConfig
|
|
84
|
+
from ..agent.system_prompts import SystemPromptLevel, get_job_description_prompt
|
|
85
|
+
from ..tools.base import ToolRegistry
|
|
86
|
+
from ..providers.gateway.litellm_gateway import LiteLLMGateway
|
|
87
|
+
|
|
88
|
+
# Initialize gateway
|
|
89
|
+
gateway = LiteLLMGateway()
|
|
90
|
+
|
|
91
|
+
# Initialize tools
|
|
92
|
+
tools = ToolRegistry.default()
|
|
93
|
+
|
|
94
|
+
# Build job description prompt (OSS does not merge expert prompts)
|
|
95
|
+
# Get base job description from role config
|
|
96
|
+
base_job_description = self.role_config.job_description or ""
|
|
97
|
+
merged_job_description = get_job_description_prompt(
|
|
98
|
+
base_job_description, role_config=self.role_config
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# Determine system prompt level (OSS uses standard guidance)
|
|
102
|
+
system_level = SystemPromptLevel.STANDARD
|
|
103
|
+
|
|
104
|
+
# Create agent config with merged job description
|
|
105
|
+
config = AgentConfig(
|
|
106
|
+
provider=self.provider,
|
|
107
|
+
model=self.model,
|
|
108
|
+
system_prompt_level=system_level,
|
|
109
|
+
custom_system_prompt=None, # Job description is added via config
|
|
110
|
+
job_description=merged_job_description,
|
|
111
|
+
working_directory=self._working_directory,
|
|
112
|
+
tools_enabled=True,
|
|
113
|
+
temperature=0.7,
|
|
114
|
+
max_tokens=4000,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# Create agent loop (on_thinking will be set via send_message if provided)
|
|
118
|
+
self._agent_loop = AgentLoop(
|
|
119
|
+
gateway=gateway,
|
|
120
|
+
tools=tools,
|
|
121
|
+
config=config,
|
|
122
|
+
parallel_tools=True,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
self._initialized = True
|
|
126
|
+
return True
|
|
127
|
+
|
|
128
|
+
async def send_message(self, message: str, **kwargs) -> AgentResponse:
|
|
129
|
+
"""Send message to SuperQode model using AgentLoop with tools."""
|
|
130
|
+
if not self._initialized or not self._agent_loop:
|
|
131
|
+
raise RuntimeError("Agent not initialized")
|
|
132
|
+
|
|
133
|
+
# Set up thinking callback if provided
|
|
134
|
+
on_thinking = kwargs.get("on_thinking")
|
|
135
|
+
if on_thinking:
|
|
136
|
+
self._agent_loop.on_thinking = on_thinking
|
|
137
|
+
|
|
138
|
+
try:
|
|
139
|
+
# Use AgentLoop to run with tools
|
|
140
|
+
response = await self._agent_loop.run(message)
|
|
141
|
+
|
|
142
|
+
return AgentResponse(
|
|
143
|
+
content=response.content,
|
|
144
|
+
agent_type="superqode",
|
|
145
|
+
agent_name=f"{self.provider}/{self.model}",
|
|
146
|
+
metadata={
|
|
147
|
+
"provider": self.provider,
|
|
148
|
+
"model": self.model,
|
|
149
|
+
"tool_calls_made": response.tool_calls_made,
|
|
150
|
+
"iterations": response.iterations,
|
|
151
|
+
"stopped_reason": response.stopped_reason,
|
|
152
|
+
"error": response.error,
|
|
153
|
+
},
|
|
154
|
+
)
|
|
155
|
+
except Exception as e:
|
|
156
|
+
return AgentResponse(
|
|
157
|
+
content=f"Error communicating with {self.provider}/{self.model}: {str(e)}",
|
|
158
|
+
agent_type="superqode",
|
|
159
|
+
agent_name=f"{self.provider}/{self.model}",
|
|
160
|
+
metadata={"error": str(e)},
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
async def send_message_streaming(self, message: str, **kwargs) -> AsyncIterator[str]:
|
|
164
|
+
"""Send message with streaming output."""
|
|
165
|
+
if not self._initialized or not self._agent_loop:
|
|
166
|
+
raise RuntimeError("Agent not initialized")
|
|
167
|
+
|
|
168
|
+
async for chunk in self._agent_loop.run_streaming(message):
|
|
169
|
+
yield chunk
|
|
170
|
+
|
|
171
|
+
async def get_capabilities(self) -> List[str]:
|
|
172
|
+
"""Get SuperQode agent capabilities."""
|
|
173
|
+
capabilities = ["text_generation", "code_generation", "analysis"]
|
|
174
|
+
|
|
175
|
+
# Add provider-specific capabilities
|
|
176
|
+
if self.provider == "anthropic":
|
|
177
|
+
capabilities.extend(["reasoning", "code_review", "architecture"])
|
|
178
|
+
elif self.provider == "openai":
|
|
179
|
+
capabilities.extend(["creativity", "problem_solving", "research"])
|
|
180
|
+
elif self.provider == "google":
|
|
181
|
+
capabilities.extend(["multimodal", "analysis", "synthesis"])
|
|
182
|
+
elif self.provider == "deepseek":
|
|
183
|
+
capabilities.extend(["deep_reasoning", "mathematical", "logical"])
|
|
184
|
+
elif self.provider == "zhipuai":
|
|
185
|
+
capabilities.extend(["multilingual", "vision", "reasoning"])
|
|
186
|
+
|
|
187
|
+
return capabilities
|
|
188
|
+
|
|
189
|
+
async def cleanup(self) -> None:
|
|
190
|
+
"""Clean up SuperQode agent resources."""
|
|
191
|
+
self._agent_loop = None
|
|
192
|
+
self._initialized = False
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
class ACPUnifiedAgent(UnifiedAgent):
|
|
196
|
+
"""Agent implementation for ACP coding agents."""
|
|
197
|
+
|
|
198
|
+
def __init__(self, role_config: ResolvedRole):
|
|
199
|
+
super().__init__(role_config)
|
|
200
|
+
self.agent_manager: Optional[ACPAgentManager] = None
|
|
201
|
+
self._initialized = False
|
|
202
|
+
|
|
203
|
+
async def initialize(self) -> bool:
|
|
204
|
+
"""Initialize the ACP agent."""
|
|
205
|
+
try:
|
|
206
|
+
self.agent_manager = ACPAgentManager()
|
|
207
|
+
|
|
208
|
+
# Get agent command from discovery
|
|
209
|
+
from .discovery import get_agent_by_short_name
|
|
210
|
+
|
|
211
|
+
agent_config = get_agent_by_short_name(self.agent_name)
|
|
212
|
+
|
|
213
|
+
if not agent_config:
|
|
214
|
+
return False
|
|
215
|
+
|
|
216
|
+
# Get run command for the agent
|
|
217
|
+
run_command = agent_config.get("run_command", {}).get("*")
|
|
218
|
+
if not run_command:
|
|
219
|
+
return False
|
|
220
|
+
|
|
221
|
+
# Initialize the agent manager
|
|
222
|
+
success = await self.agent_manager.connect_to_agent(run_command)
|
|
223
|
+
if success:
|
|
224
|
+
self._initialized = True
|
|
225
|
+
return True
|
|
226
|
+
|
|
227
|
+
except Exception:
|
|
228
|
+
pass
|
|
229
|
+
|
|
230
|
+
return False
|
|
231
|
+
|
|
232
|
+
async def send_message(self, message: str, **kwargs) -> AgentResponse:
|
|
233
|
+
"""Send message to ACP agent."""
|
|
234
|
+
if not self._initialized or not self.agent_manager:
|
|
235
|
+
raise RuntimeError("ACP agent not initialized")
|
|
236
|
+
|
|
237
|
+
try:
|
|
238
|
+
# Send message to ACP agent
|
|
239
|
+
await self.agent_manager.send_message(message)
|
|
240
|
+
|
|
241
|
+
# Wait a bit for response
|
|
242
|
+
await asyncio.sleep(0.1)
|
|
243
|
+
|
|
244
|
+
# Get responses from the queue
|
|
245
|
+
responses = await self.agent_manager.receive_messages()
|
|
246
|
+
|
|
247
|
+
# Combine all responses
|
|
248
|
+
content_parts = []
|
|
249
|
+
for response in responses:
|
|
250
|
+
if hasattr(response, "content"):
|
|
251
|
+
# Handle different response types
|
|
252
|
+
if hasattr(response, "text"):
|
|
253
|
+
content_parts.append(response.text)
|
|
254
|
+
elif hasattr(response, "content"):
|
|
255
|
+
content_parts.append(str(response.content))
|
|
256
|
+
else:
|
|
257
|
+
content_parts.append(str(response))
|
|
258
|
+
|
|
259
|
+
content = "\n".join(content_parts) if content_parts else "No response from agent"
|
|
260
|
+
|
|
261
|
+
return AgentResponse(
|
|
262
|
+
content=content,
|
|
263
|
+
agent_type="acp",
|
|
264
|
+
agent_name=self.agent_name,
|
|
265
|
+
metadata={"responses_count": len(responses), "agent_type": "acp"},
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
except Exception as e:
|
|
269
|
+
return AgentResponse(
|
|
270
|
+
content=f"Error communicating with ACP agent {self.agent_name}: {str(e)}",
|
|
271
|
+
agent_type="acp",
|
|
272
|
+
agent_name=self.agent_name,
|
|
273
|
+
metadata={"error": str(e)},
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
async def get_capabilities(self) -> List[str]:
|
|
277
|
+
"""Get ACP agent capabilities."""
|
|
278
|
+
capabilities = ["coding", "terminal_access", "file_operations"]
|
|
279
|
+
|
|
280
|
+
# Add agent-specific capabilities
|
|
281
|
+
if self.agent_name == "claude-code":
|
|
282
|
+
capabilities.extend(["code_editing", "project_navigation", "refactoring"])
|
|
283
|
+
elif self.agent_name == "openhands":
|
|
284
|
+
capabilities.extend(["multi_file_editing", "testing", "deployment"])
|
|
285
|
+
elif self.agent_name == "goose":
|
|
286
|
+
capabilities.extend(["automation", "scripting", "productivity"])
|
|
287
|
+
|
|
288
|
+
return capabilities
|
|
289
|
+
|
|
290
|
+
async def cleanup(self) -> None:
|
|
291
|
+
"""Clean up ACP agent resources."""
|
|
292
|
+
if self.agent_manager:
|
|
293
|
+
await self.agent_manager.disconnect()
|
|
294
|
+
self._initialized = False
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def create_unified_agent(role_config: ResolvedRole) -> UnifiedAgent:
|
|
298
|
+
"""Factory function to create the appropriate agent type."""
|
|
299
|
+
if role_config.agent_type == "acp":
|
|
300
|
+
return ACPUnifiedAgent(role_config)
|
|
301
|
+
elif role_config.agent_type == "superqode":
|
|
302
|
+
return SuperQodeAgent(role_config)
|
|
303
|
+
else:
|
|
304
|
+
raise ValueError(f"Unknown agent type: {role_config.agent_type}")
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
class AgentManager:
|
|
308
|
+
"""Manager for unified agents with session handling."""
|
|
309
|
+
|
|
310
|
+
def __init__(self):
|
|
311
|
+
self.active_agents: Dict[str, UnifiedAgent] = {}
|
|
312
|
+
self.current_agent: Optional[UnifiedAgent] = None
|
|
313
|
+
|
|
314
|
+
async def switch_to_role(self, mode: str, role: Optional[str] = None) -> bool:
|
|
315
|
+
"""Switch to a specific role/mode."""
|
|
316
|
+
from .config import load_config, resolve_role
|
|
317
|
+
|
|
318
|
+
config = load_config()
|
|
319
|
+
resolved_role = resolve_role(mode, role, config)
|
|
320
|
+
|
|
321
|
+
if not resolved_role:
|
|
322
|
+
return False
|
|
323
|
+
|
|
324
|
+
# Create agent key
|
|
325
|
+
agent_key = f"{mode}.{role}" if role else mode
|
|
326
|
+
|
|
327
|
+
# Check if agent is already active
|
|
328
|
+
if agent_key in self.active_agents:
|
|
329
|
+
self.current_agent = self.active_agents[agent_key]
|
|
330
|
+
return True
|
|
331
|
+
|
|
332
|
+
# Create new agent
|
|
333
|
+
agent = create_unified_agent(resolved_role)
|
|
334
|
+
|
|
335
|
+
# Initialize agent
|
|
336
|
+
if await agent.initialize():
|
|
337
|
+
self.active_agents[agent_key] = agent
|
|
338
|
+
self.current_agent = agent
|
|
339
|
+
return True
|
|
340
|
+
|
|
341
|
+
return False
|
|
342
|
+
|
|
343
|
+
async def send_message(self, message: str, **kwargs) -> Optional[AgentResponse]:
|
|
344
|
+
"""Send message to current agent."""
|
|
345
|
+
if not self.current_agent:
|
|
346
|
+
return None
|
|
347
|
+
|
|
348
|
+
return await self.current_agent.send_message(message, **kwargs)
|
|
349
|
+
|
|
350
|
+
def get_current_agent_info(self) -> Optional[Dict[str, Any]]:
|
|
351
|
+
"""Get information about the current agent."""
|
|
352
|
+
if not self.current_agent:
|
|
353
|
+
return None
|
|
354
|
+
|
|
355
|
+
return {
|
|
356
|
+
"name": self.current_agent.agent_name,
|
|
357
|
+
"type": self.current_agent.agent_type,
|
|
358
|
+
"description": self.current_agent.description,
|
|
359
|
+
"capabilities": asyncio.run(self.current_agent.get_capabilities()),
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
async def cleanup(self) -> None:
|
|
363
|
+
"""Clean up all agents."""
|
|
364
|
+
for agent in self.active_agents.values():
|
|
365
|
+
await agent.cleanup()
|
|
366
|
+
self.active_agents.clear()
|
|
367
|
+
self.current_agent = None
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SuperQode Textual App Package.
|
|
3
|
+
|
|
4
|
+
This package contains the TUI application components for SuperQode.
|
|
5
|
+
Modules:
|
|
6
|
+
- constants.py: Theme, icons, colors, messages
|
|
7
|
+
- css.py: Textual CSS styles
|
|
8
|
+
- models.py: Data models (AgentInfo, AgentStatus)
|
|
9
|
+
- suggester.py: Command autocompletion
|
|
10
|
+
- widgets.py: UI widget classes
|
|
11
|
+
|
|
12
|
+
The main SuperQodeApp class is kept in the parent app.py for now
|
|
13
|
+
to maintain backward compatibility, but imports from these modules.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from .constants import (
|
|
17
|
+
ASCII_LOGO,
|
|
18
|
+
COMPACT_LOGO,
|
|
19
|
+
TAGLINE_PART1,
|
|
20
|
+
TAGLINE_PART2,
|
|
21
|
+
GRADIENT,
|
|
22
|
+
RAINBOW,
|
|
23
|
+
THEME,
|
|
24
|
+
ICONS,
|
|
25
|
+
AGENT_COLORS,
|
|
26
|
+
AGENT_ICONS,
|
|
27
|
+
THINKING_MSGS,
|
|
28
|
+
COMMANDS,
|
|
29
|
+
)
|
|
30
|
+
from .css import APP_CSS
|
|
31
|
+
from .models import AgentStatus, AgentInfo, check_installed, load_agents_sync
|
|
32
|
+
from .suggester import CommandSuggester
|
|
33
|
+
from .widgets import (
|
|
34
|
+
GradientLogo,
|
|
35
|
+
ColorfulStatusBar,
|
|
36
|
+
GradientTagline,
|
|
37
|
+
PulseWaveBar,
|
|
38
|
+
RainbowProgressBar,
|
|
39
|
+
ScanningLine,
|
|
40
|
+
TopScanningLine,
|
|
41
|
+
BottomScanningLine,
|
|
42
|
+
ProgressChase,
|
|
43
|
+
SparkleTrail,
|
|
44
|
+
ThinkingWave,
|
|
45
|
+
StreamingThinkingIndicator,
|
|
46
|
+
ModeBadge,
|
|
47
|
+
HintsBar,
|
|
48
|
+
ConversationLog,
|
|
49
|
+
ApprovalWidget,
|
|
50
|
+
DiffDisplay,
|
|
51
|
+
PlanDisplay,
|
|
52
|
+
ToolCallDisplay,
|
|
53
|
+
FlashMessage,
|
|
54
|
+
DangerWarning,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def run_textual_app():
|
|
59
|
+
"""Run the SuperQode Textual TUI application."""
|
|
60
|
+
# Import from parent module to avoid duplication
|
|
61
|
+
from superqode.app_main import SuperQodeApp
|
|
62
|
+
|
|
63
|
+
app = SuperQodeApp()
|
|
64
|
+
app.run()
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
__all__ = [
|
|
68
|
+
# Constants
|
|
69
|
+
"ASCII_LOGO",
|
|
70
|
+
"COMPACT_LOGO",
|
|
71
|
+
"TAGLINE_PART1",
|
|
72
|
+
"TAGLINE_PART2",
|
|
73
|
+
"GRADIENT",
|
|
74
|
+
"RAINBOW",
|
|
75
|
+
"THEME",
|
|
76
|
+
"ICONS",
|
|
77
|
+
"AGENT_COLORS",
|
|
78
|
+
"AGENT_ICONS",
|
|
79
|
+
"THINKING_MSGS",
|
|
80
|
+
"COMMANDS",
|
|
81
|
+
# CSS
|
|
82
|
+
"APP_CSS",
|
|
83
|
+
# Models
|
|
84
|
+
"AgentStatus",
|
|
85
|
+
"AgentInfo",
|
|
86
|
+
"check_installed",
|
|
87
|
+
"load_agents_sync",
|
|
88
|
+
# Suggester
|
|
89
|
+
"CommandSuggester",
|
|
90
|
+
# Widgets
|
|
91
|
+
"GradientLogo",
|
|
92
|
+
"ColorfulStatusBar",
|
|
93
|
+
"GradientTagline",
|
|
94
|
+
"PulseWaveBar",
|
|
95
|
+
"RainbowProgressBar",
|
|
96
|
+
"ScanningLine",
|
|
97
|
+
"TopScanningLine",
|
|
98
|
+
"BottomScanningLine",
|
|
99
|
+
"StreamingThinkingIndicator",
|
|
100
|
+
"ModeBadge",
|
|
101
|
+
"HintsBar",
|
|
102
|
+
"ConversationLog",
|
|
103
|
+
"ApprovalWidget",
|
|
104
|
+
"DiffDisplay",
|
|
105
|
+
"PlanDisplay",
|
|
106
|
+
"ToolCallDisplay",
|
|
107
|
+
"FlashMessage",
|
|
108
|
+
"DangerWarning",
|
|
109
|
+
# Main function
|
|
110
|
+
"run_textual_app",
|
|
111
|
+
]
|