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,324 @@
1
+ """
2
+ Question Tool - Ask User Clarifying Questions.
3
+
4
+ Allows agents to ask the user questions during task execution.
5
+ This enables interactive workflows where agents can:
6
+ - Clarify ambiguous requirements
7
+ - Get user preferences
8
+ - Confirm risky operations
9
+ - Present choices for implementation
10
+
11
+ Features:
12
+ - Multiple choice questions
13
+ - Free-form text input
14
+ - Confirmation dialogs
15
+ - Rating/ranking questions
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import asyncio
21
+ from dataclasses import dataclass, field
22
+ from enum import Enum
23
+ from typing import Any, Callable, Dict, List, Optional, Awaitable
24
+
25
+ from .base import Tool, ToolResult, ToolContext
26
+
27
+
28
+ class QuestionType(Enum):
29
+ """Type of question to ask."""
30
+
31
+ TEXT = "text" # Free-form text input
32
+ CHOICE = "choice" # Single selection from options
33
+ MULTI_CHOICE = "multi_choice" # Multiple selection from options
34
+ CONFIRM = "confirm" # Yes/no confirmation
35
+ RATING = "rating" # Rating on a scale
36
+
37
+
38
+ @dataclass
39
+ class Question:
40
+ """A question to ask the user."""
41
+
42
+ question: str
43
+ question_type: QuestionType = QuestionType.TEXT
44
+ options: List[str] = field(default_factory=list)
45
+ default: Optional[str] = None
46
+ allow_custom: bool = True
47
+ min_rating: int = 1
48
+ max_rating: int = 5
49
+
50
+
51
+ @dataclass
52
+ class Answer:
53
+ """An answer from the user."""
54
+
55
+ value: Any
56
+ custom: bool = False
57
+
58
+
59
+ # Global question handler - set by the UI
60
+ _question_handler: Optional[Callable[[Question], Awaitable[Answer]]] = None
61
+
62
+
63
+ def set_question_handler(handler: Optional[Callable[[Question], Awaitable[Answer]]]) -> None:
64
+ """Set the global question handler for UI integration."""
65
+ global _question_handler
66
+ _question_handler = handler
67
+
68
+
69
+ def get_question_handler() -> Optional[Callable[[Question], Awaitable[Answer]]]:
70
+ """Get the current question handler."""
71
+ return _question_handler
72
+
73
+
74
+ class QuestionTool(Tool):
75
+ """
76
+ Ask the user a question during execution.
77
+
78
+ Allows agents to:
79
+ - Get clarification on requirements
80
+ - Present implementation choices
81
+ - Confirm risky operations
82
+ - Gather user preferences
83
+
84
+ The question is presented through the UI and execution
85
+ pauses until the user responds.
86
+ """
87
+
88
+ @property
89
+ def name(self) -> str:
90
+ return "ask_user"
91
+
92
+ @property
93
+ def description(self) -> str:
94
+ return """Ask the user a clarifying question.
95
+
96
+ Use this when you need:
97
+ - Clarification on ambiguous requirements
98
+ - User choice between implementation options
99
+ - Confirmation before risky operations
100
+ - User preferences for configuration
101
+
102
+ The question is shown to the user and execution pauses until they respond.
103
+ Use sparingly - prefer to make reasonable assumptions when possible."""
104
+
105
+ @property
106
+ def parameters(self) -> Dict[str, Any]:
107
+ return {
108
+ "type": "object",
109
+ "properties": {
110
+ "question": {"type": "string", "description": "The question to ask the user"},
111
+ "type": {
112
+ "type": "string",
113
+ "enum": ["text", "choice", "multi_choice", "confirm", "rating"],
114
+ "description": "Question type: text (free input), choice (single), multi_choice (multiple), confirm (yes/no), rating",
115
+ },
116
+ "options": {
117
+ "type": "array",
118
+ "items": {"type": "string"},
119
+ "description": "Options for choice/multi_choice questions",
120
+ },
121
+ "default": {
122
+ "type": "string",
123
+ "description": "Default value if user doesn't provide input",
124
+ },
125
+ "allow_custom": {
126
+ "type": "boolean",
127
+ "description": "Allow custom input in addition to options (default: true)",
128
+ },
129
+ "context": {
130
+ "type": "string",
131
+ "description": "Additional context to show with the question",
132
+ },
133
+ },
134
+ "required": ["question"],
135
+ }
136
+
137
+ async def execute(self, args: Dict[str, Any], ctx: ToolContext) -> ToolResult:
138
+ question_text = args.get("question", "")
139
+ question_type = args.get("type", "text")
140
+ options = args.get("options", [])
141
+ default = args.get("default")
142
+ allow_custom = args.get("allow_custom", True)
143
+ context = args.get("context", "")
144
+
145
+ if not question_text:
146
+ return ToolResult(success=False, output="", error="Question text is required")
147
+
148
+ # Validate question type
149
+ try:
150
+ q_type = QuestionType(question_type)
151
+ except ValueError:
152
+ return ToolResult(
153
+ success=False, output="", error=f"Invalid question type: {question_type}"
154
+ )
155
+
156
+ # Validate options for choice questions
157
+ if q_type in (QuestionType.CHOICE, QuestionType.MULTI_CHOICE):
158
+ if not options:
159
+ return ToolResult(
160
+ success=False, output="", error="Options are required for choice questions"
161
+ )
162
+
163
+ # Create question object
164
+ question = Question(
165
+ question=question_text,
166
+ question_type=q_type,
167
+ options=options,
168
+ default=default,
169
+ allow_custom=allow_custom,
170
+ )
171
+
172
+ # Try to get answer through UI handler
173
+ handler = get_question_handler()
174
+
175
+ if handler:
176
+ try:
177
+ answer = await handler(question)
178
+ return self._format_answer(answer, question, context)
179
+ except asyncio.CancelledError:
180
+ return ToolResult(success=False, output="", error="Question was cancelled")
181
+ except Exception as e:
182
+ return ToolResult(success=False, output="", error=f"Error getting answer: {str(e)}")
183
+
184
+ # Fallback: Use context output callback for simple text display
185
+ if ctx.on_output:
186
+ await ctx.emit_output(f"\n[Question] {question_text}\n")
187
+ if options:
188
+ await ctx.emit_output("Options:\n")
189
+ for i, opt in enumerate(options, 1):
190
+ await ctx.emit_output(f" {i}. {opt}\n")
191
+ if default:
192
+ await ctx.emit_output(f"Default: {default}\n")
193
+ await ctx.emit_output("[Waiting for user response...]\n")
194
+
195
+ # Without a UI handler, use default or return pending
196
+ if default:
197
+ return ToolResult(
198
+ success=True,
199
+ output=f"User response: {default}",
200
+ metadata={"question": question_text, "answer": default, "used_default": True},
201
+ )
202
+
203
+ return ToolResult(
204
+ success=False,
205
+ output="",
206
+ error="No question handler available and no default value provided. Run in interactive mode to ask questions.",
207
+ )
208
+
209
+ def _format_answer(self, answer: Answer, question: Question, context: str) -> ToolResult:
210
+ """Format the answer as a tool result."""
211
+ if question.question_type == QuestionType.CONFIRM:
212
+ response = "Yes" if answer.value else "No"
213
+ elif question.question_type == QuestionType.MULTI_CHOICE:
214
+ if isinstance(answer.value, list):
215
+ response = ", ".join(answer.value)
216
+ else:
217
+ response = str(answer.value)
218
+ elif question.question_type == QuestionType.RATING:
219
+ response = f"{answer.value}/{question.max_rating}"
220
+ else:
221
+ response = str(answer.value)
222
+
223
+ output = f"User response: {response}"
224
+ if answer.custom:
225
+ output += " (custom input)"
226
+
227
+ return ToolResult(
228
+ success=True,
229
+ output=output,
230
+ metadata={
231
+ "question": question.question,
232
+ "type": question.question_type.value,
233
+ "answer": answer.value,
234
+ "custom": answer.custom,
235
+ },
236
+ )
237
+
238
+
239
+ class ConfirmTool(Tool):
240
+ """
241
+ Quick confirmation dialog.
242
+
243
+ Simplified version of ask_user for yes/no confirmations.
244
+ Use for confirming risky or irreversible operations.
245
+ """
246
+
247
+ @property
248
+ def name(self) -> str:
249
+ return "confirm"
250
+
251
+ @property
252
+ def description(self) -> str:
253
+ return """Ask the user for a yes/no confirmation.
254
+
255
+ Use for:
256
+ - Confirming risky or destructive operations
257
+ - Verifying important decisions
258
+ - Getting go-ahead for changes
259
+
260
+ Returns 'confirmed' if user says yes, 'denied' if no."""
261
+
262
+ @property
263
+ def parameters(self) -> Dict[str, Any]:
264
+ return {
265
+ "type": "object",
266
+ "properties": {
267
+ "message": {"type": "string", "description": "What to confirm"},
268
+ "details": {
269
+ "type": "string",
270
+ "description": "Additional details about what will happen",
271
+ },
272
+ "default": {
273
+ "type": "boolean",
274
+ "description": "Default if user doesn't respond (default: false for safety)",
275
+ },
276
+ },
277
+ "required": ["message"],
278
+ }
279
+
280
+ async def execute(self, args: Dict[str, Any], ctx: ToolContext) -> ToolResult:
281
+ message = args.get("message", "")
282
+ details = args.get("details", "")
283
+ default = args.get("default", False)
284
+
285
+ if not message:
286
+ return ToolResult(success=False, output="", error="Confirmation message is required")
287
+
288
+ # Create confirmation question
289
+ question = Question(
290
+ question=message,
291
+ question_type=QuestionType.CONFIRM,
292
+ options=["Yes", "No"],
293
+ default="No" if not default else "Yes",
294
+ allow_custom=False,
295
+ )
296
+
297
+ handler = get_question_handler()
298
+
299
+ if handler:
300
+ try:
301
+ answer = await handler(question)
302
+ confirmed = bool(answer.value)
303
+
304
+ return ToolResult(
305
+ success=True,
306
+ output="confirmed" if confirmed else "denied",
307
+ metadata={"message": message, "confirmed": confirmed},
308
+ )
309
+ except Exception as e:
310
+ return ToolResult(success=False, output="", error=f"Confirmation failed: {str(e)}")
311
+
312
+ # Fallback with context output
313
+ if ctx.on_output:
314
+ await ctx.emit_output(f"\n[Confirm] {message}\n")
315
+ if details:
316
+ await ctx.emit_output(f"Details: {details}\n")
317
+ await ctx.emit_output("[Waiting for confirmation...]\n")
318
+
319
+ # Use default for safety
320
+ return ToolResult(
321
+ success=True,
322
+ output="denied" if not default else "confirmed",
323
+ metadata={"message": message, "confirmed": default, "used_default": True},
324
+ )