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.
Files changed (288) hide show
  1. superqode/__init__.py +33 -0
  2. superqode/acp/__init__.py +23 -0
  3. superqode/acp/client.py +913 -0
  4. superqode/acp/permission_screen.py +457 -0
  5. superqode/acp/types.py +480 -0
  6. superqode/acp_discovery.py +856 -0
  7. superqode/agent/__init__.py +22 -0
  8. superqode/agent/edit_strategies.py +334 -0
  9. superqode/agent/loop.py +892 -0
  10. superqode/agent/qe_report_templates.py +39 -0
  11. superqode/agent/system_prompts.py +353 -0
  12. superqode/agent_output.py +721 -0
  13. superqode/agent_stream.py +953 -0
  14. superqode/agents/__init__.py +59 -0
  15. superqode/agents/acp_registry.py +305 -0
  16. superqode/agents/client.py +249 -0
  17. superqode/agents/data/augmentcode.com.toml +51 -0
  18. superqode/agents/data/cagent.dev.toml +51 -0
  19. superqode/agents/data/claude.com.toml +60 -0
  20. superqode/agents/data/codeassistant.dev.toml +51 -0
  21. superqode/agents/data/codex.openai.com.toml +57 -0
  22. superqode/agents/data/fastagent.ai.toml +66 -0
  23. superqode/agents/data/geminicli.com.toml +77 -0
  24. superqode/agents/data/goose.block.xyz.toml +54 -0
  25. superqode/agents/data/junie.jetbrains.com.toml +56 -0
  26. superqode/agents/data/kimi.moonshot.cn.toml +57 -0
  27. superqode/agents/data/llmlingagent.dev.toml +51 -0
  28. superqode/agents/data/molt.bot.toml +49 -0
  29. superqode/agents/data/opencode.ai.toml +60 -0
  30. superqode/agents/data/stakpak.dev.toml +51 -0
  31. superqode/agents/data/vtcode.dev.toml +51 -0
  32. superqode/agents/discovery.py +266 -0
  33. superqode/agents/messaging.py +160 -0
  34. superqode/agents/persona.py +166 -0
  35. superqode/agents/registry.py +421 -0
  36. superqode/agents/schema.py +72 -0
  37. superqode/agents/unified.py +367 -0
  38. superqode/app/__init__.py +111 -0
  39. superqode/app/constants.py +314 -0
  40. superqode/app/css.py +366 -0
  41. superqode/app/models.py +118 -0
  42. superqode/app/suggester.py +125 -0
  43. superqode/app/widgets.py +1591 -0
  44. superqode/app_enhanced.py +399 -0
  45. superqode/app_main.py +17187 -0
  46. superqode/approval.py +312 -0
  47. superqode/atomic.py +296 -0
  48. superqode/commands/__init__.py +1 -0
  49. superqode/commands/acp.py +965 -0
  50. superqode/commands/agents.py +180 -0
  51. superqode/commands/auth.py +278 -0
  52. superqode/commands/config.py +374 -0
  53. superqode/commands/init.py +826 -0
  54. superqode/commands/providers.py +819 -0
  55. superqode/commands/qe.py +1145 -0
  56. superqode/commands/roles.py +380 -0
  57. superqode/commands/serve.py +172 -0
  58. superqode/commands/suggestions.py +127 -0
  59. superqode/commands/superqe.py +460 -0
  60. superqode/config/__init__.py +51 -0
  61. superqode/config/loader.py +812 -0
  62. superqode/config/schema.py +498 -0
  63. superqode/core/__init__.py +111 -0
  64. superqode/core/roles.py +281 -0
  65. superqode/danger.py +386 -0
  66. superqode/data/superqode-template.yaml +1522 -0
  67. superqode/design_system.py +1080 -0
  68. superqode/dialogs/__init__.py +6 -0
  69. superqode/dialogs/base.py +39 -0
  70. superqode/dialogs/model.py +130 -0
  71. superqode/dialogs/provider.py +870 -0
  72. superqode/diff_view.py +919 -0
  73. superqode/enterprise.py +21 -0
  74. superqode/evaluation/__init__.py +25 -0
  75. superqode/evaluation/adapters.py +93 -0
  76. superqode/evaluation/behaviors.py +89 -0
  77. superqode/evaluation/engine.py +209 -0
  78. superqode/evaluation/scenarios.py +96 -0
  79. superqode/execution/__init__.py +36 -0
  80. superqode/execution/linter.py +538 -0
  81. superqode/execution/modes.py +347 -0
  82. superqode/execution/resolver.py +283 -0
  83. superqode/execution/runner.py +642 -0
  84. superqode/file_explorer.py +811 -0
  85. superqode/file_viewer.py +471 -0
  86. superqode/flash.py +183 -0
  87. superqode/guidance/__init__.py +58 -0
  88. superqode/guidance/config.py +203 -0
  89. superqode/guidance/prompts.py +71 -0
  90. superqode/harness/__init__.py +54 -0
  91. superqode/harness/accelerator.py +291 -0
  92. superqode/harness/config.py +319 -0
  93. superqode/harness/validator.py +147 -0
  94. superqode/history.py +279 -0
  95. superqode/integrations/superopt_runner.py +124 -0
  96. superqode/logging/__init__.py +49 -0
  97. superqode/logging/adapters.py +219 -0
  98. superqode/logging/formatter.py +923 -0
  99. superqode/logging/integration.py +341 -0
  100. superqode/logging/sinks.py +170 -0
  101. superqode/logging/unified_log.py +417 -0
  102. superqode/lsp/__init__.py +26 -0
  103. superqode/lsp/client.py +544 -0
  104. superqode/main.py +1069 -0
  105. superqode/mcp/__init__.py +89 -0
  106. superqode/mcp/auth_storage.py +380 -0
  107. superqode/mcp/client.py +1236 -0
  108. superqode/mcp/config.py +319 -0
  109. superqode/mcp/integration.py +337 -0
  110. superqode/mcp/oauth.py +436 -0
  111. superqode/mcp/oauth_callback.py +385 -0
  112. superqode/mcp/types.py +290 -0
  113. superqode/memory/__init__.py +31 -0
  114. superqode/memory/feedback.py +342 -0
  115. superqode/memory/store.py +522 -0
  116. superqode/notifications.py +369 -0
  117. superqode/optimization/__init__.py +5 -0
  118. superqode/optimization/config.py +33 -0
  119. superqode/permissions/__init__.py +25 -0
  120. superqode/permissions/rules.py +488 -0
  121. superqode/plan.py +323 -0
  122. superqode/providers/__init__.py +33 -0
  123. superqode/providers/gateway/__init__.py +165 -0
  124. superqode/providers/gateway/base.py +228 -0
  125. superqode/providers/gateway/litellm_gateway.py +1170 -0
  126. superqode/providers/gateway/openresponses_gateway.py +436 -0
  127. superqode/providers/health.py +297 -0
  128. superqode/providers/huggingface/__init__.py +74 -0
  129. superqode/providers/huggingface/downloader.py +472 -0
  130. superqode/providers/huggingface/endpoints.py +442 -0
  131. superqode/providers/huggingface/hub.py +531 -0
  132. superqode/providers/huggingface/inference.py +394 -0
  133. superqode/providers/huggingface/transformers_runner.py +516 -0
  134. superqode/providers/local/__init__.py +100 -0
  135. superqode/providers/local/base.py +438 -0
  136. superqode/providers/local/discovery.py +418 -0
  137. superqode/providers/local/lmstudio.py +256 -0
  138. superqode/providers/local/mlx.py +457 -0
  139. superqode/providers/local/ollama.py +486 -0
  140. superqode/providers/local/sglang.py +268 -0
  141. superqode/providers/local/tgi.py +260 -0
  142. superqode/providers/local/tool_support.py +477 -0
  143. superqode/providers/local/vllm.py +258 -0
  144. superqode/providers/manager.py +1338 -0
  145. superqode/providers/models.py +1016 -0
  146. superqode/providers/models_dev.py +578 -0
  147. superqode/providers/openresponses/__init__.py +87 -0
  148. superqode/providers/openresponses/converters/__init__.py +17 -0
  149. superqode/providers/openresponses/converters/messages.py +343 -0
  150. superqode/providers/openresponses/converters/tools.py +268 -0
  151. superqode/providers/openresponses/schema/__init__.py +56 -0
  152. superqode/providers/openresponses/schema/models.py +585 -0
  153. superqode/providers/openresponses/streaming/__init__.py +5 -0
  154. superqode/providers/openresponses/streaming/parser.py +338 -0
  155. superqode/providers/openresponses/tools/__init__.py +21 -0
  156. superqode/providers/openresponses/tools/apply_patch.py +352 -0
  157. superqode/providers/openresponses/tools/code_interpreter.py +290 -0
  158. superqode/providers/openresponses/tools/file_search.py +333 -0
  159. superqode/providers/openresponses/tools/mcp_adapter.py +252 -0
  160. superqode/providers/registry.py +716 -0
  161. superqode/providers/usage.py +332 -0
  162. superqode/pure_mode.py +384 -0
  163. superqode/qr/__init__.py +23 -0
  164. superqode/qr/dashboard.py +781 -0
  165. superqode/qr/generator.py +1018 -0
  166. superqode/qr/templates.py +135 -0
  167. superqode/safety/__init__.py +41 -0
  168. superqode/safety/sandbox.py +413 -0
  169. superqode/safety/warnings.py +256 -0
  170. superqode/server/__init__.py +33 -0
  171. superqode/server/lsp_server.py +775 -0
  172. superqode/server/web.py +250 -0
  173. superqode/session/__init__.py +25 -0
  174. superqode/session/persistence.py +580 -0
  175. superqode/session/sharing.py +477 -0
  176. superqode/session.py +475 -0
  177. superqode/sidebar.py +2991 -0
  178. superqode/stream_view.py +648 -0
  179. superqode/styles/__init__.py +3 -0
  180. superqode/superqe/__init__.py +184 -0
  181. superqode/superqe/acp_runner.py +1064 -0
  182. superqode/superqe/constitution/__init__.py +62 -0
  183. superqode/superqe/constitution/evaluator.py +308 -0
  184. superqode/superqe/constitution/loader.py +432 -0
  185. superqode/superqe/constitution/schema.py +250 -0
  186. superqode/superqe/events.py +591 -0
  187. superqode/superqe/frameworks/__init__.py +65 -0
  188. superqode/superqe/frameworks/base.py +234 -0
  189. superqode/superqe/frameworks/e2e.py +263 -0
  190. superqode/superqe/frameworks/executor.py +237 -0
  191. superqode/superqe/frameworks/javascript.py +409 -0
  192. superqode/superqe/frameworks/python.py +373 -0
  193. superqode/superqe/frameworks/registry.py +92 -0
  194. superqode/superqe/mcp_tools/__init__.py +47 -0
  195. superqode/superqe/mcp_tools/core_tools.py +418 -0
  196. superqode/superqe/mcp_tools/registry.py +230 -0
  197. superqode/superqe/mcp_tools/testing_tools.py +167 -0
  198. superqode/superqe/noise.py +89 -0
  199. superqode/superqe/orchestrator.py +778 -0
  200. superqode/superqe/roles.py +609 -0
  201. superqode/superqe/session.py +713 -0
  202. superqode/superqe/skills/__init__.py +57 -0
  203. superqode/superqe/skills/base.py +106 -0
  204. superqode/superqe/skills/core_skills.py +899 -0
  205. superqode/superqe/skills/registry.py +90 -0
  206. superqode/superqe/verifier.py +101 -0
  207. superqode/superqe_cli.py +76 -0
  208. superqode/tool_call.py +358 -0
  209. superqode/tools/__init__.py +93 -0
  210. superqode/tools/agent_tools.py +496 -0
  211. superqode/tools/base.py +324 -0
  212. superqode/tools/batch_tool.py +133 -0
  213. superqode/tools/diagnostics.py +311 -0
  214. superqode/tools/edit_tools.py +653 -0
  215. superqode/tools/enhanced_base.py +515 -0
  216. superqode/tools/file_tools.py +269 -0
  217. superqode/tools/file_tracking.py +45 -0
  218. superqode/tools/lsp_tools.py +610 -0
  219. superqode/tools/network_tools.py +350 -0
  220. superqode/tools/permissions.py +400 -0
  221. superqode/tools/question_tool.py +324 -0
  222. superqode/tools/search_tools.py +598 -0
  223. superqode/tools/shell_tools.py +259 -0
  224. superqode/tools/todo_tools.py +121 -0
  225. superqode/tools/validation.py +80 -0
  226. superqode/tools/web_tools.py +639 -0
  227. superqode/tui.py +1152 -0
  228. superqode/tui_integration.py +875 -0
  229. superqode/tui_widgets/__init__.py +27 -0
  230. superqode/tui_widgets/widgets/__init__.py +18 -0
  231. superqode/tui_widgets/widgets/progress.py +185 -0
  232. superqode/tui_widgets/widgets/tool_display.py +188 -0
  233. superqode/undo_manager.py +574 -0
  234. superqode/utils/__init__.py +5 -0
  235. superqode/utils/error_handling.py +323 -0
  236. superqode/utils/fuzzy.py +257 -0
  237. superqode/widgets/__init__.py +477 -0
  238. superqode/widgets/agent_collab.py +390 -0
  239. superqode/widgets/agent_store.py +936 -0
  240. superqode/widgets/agent_switcher.py +395 -0
  241. superqode/widgets/animation_manager.py +284 -0
  242. superqode/widgets/code_context.py +356 -0
  243. superqode/widgets/command_palette.py +412 -0
  244. superqode/widgets/connection_status.py +537 -0
  245. superqode/widgets/conversation_history.py +470 -0
  246. superqode/widgets/diff_indicator.py +155 -0
  247. superqode/widgets/enhanced_status_bar.py +385 -0
  248. superqode/widgets/enhanced_toast.py +476 -0
  249. superqode/widgets/file_browser.py +809 -0
  250. superqode/widgets/file_reference.py +585 -0
  251. superqode/widgets/issue_timeline.py +340 -0
  252. superqode/widgets/leader_key.py +264 -0
  253. superqode/widgets/mode_switcher.py +445 -0
  254. superqode/widgets/model_picker.py +234 -0
  255. superqode/widgets/permission_preview.py +1205 -0
  256. superqode/widgets/prompt.py +358 -0
  257. superqode/widgets/provider_connect.py +725 -0
  258. superqode/widgets/pty_shell.py +587 -0
  259. superqode/widgets/qe_dashboard.py +321 -0
  260. superqode/widgets/resizable_sidebar.py +377 -0
  261. superqode/widgets/response_changes.py +218 -0
  262. superqode/widgets/response_display.py +528 -0
  263. superqode/widgets/rich_tool_display.py +613 -0
  264. superqode/widgets/sidebar_panels.py +1180 -0
  265. superqode/widgets/slash_complete.py +356 -0
  266. superqode/widgets/split_view.py +612 -0
  267. superqode/widgets/status_bar.py +273 -0
  268. superqode/widgets/superqode_display.py +786 -0
  269. superqode/widgets/thinking_display.py +815 -0
  270. superqode/widgets/throbber.py +87 -0
  271. superqode/widgets/toast.py +206 -0
  272. superqode/widgets/unified_output.py +1073 -0
  273. superqode/workspace/__init__.py +75 -0
  274. superqode/workspace/artifacts.py +472 -0
  275. superqode/workspace/coordinator.py +353 -0
  276. superqode/workspace/diff_tracker.py +429 -0
  277. superqode/workspace/git_guard.py +373 -0
  278. superqode/workspace/git_snapshot.py +526 -0
  279. superqode/workspace/manager.py +750 -0
  280. superqode/workspace/snapshot.py +357 -0
  281. superqode/workspace/watcher.py +535 -0
  282. superqode/workspace/worktree.py +440 -0
  283. superqode-0.1.5.dist-info/METADATA +204 -0
  284. superqode-0.1.5.dist-info/RECORD +288 -0
  285. superqode-0.1.5.dist-info/WHEEL +5 -0
  286. superqode-0.1.5.dist-info/entry_points.txt +3 -0
  287. superqode-0.1.5.dist-info/licenses/LICENSE +648 -0
  288. 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
+ ]