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,338 @@
1
+ """
2
+ Streaming Event Parser for Open Responses.
3
+
4
+ Handles 45+ streaming event types from the Open Responses API.
5
+ Converts SSE events to StreamChunk objects for the gateway.
6
+
7
+ Event Categories:
8
+ - Response lifecycle: created, in_progress, completed, failed, incomplete
9
+ - Output items: added, done
10
+ - Content parts: added, done
11
+ - Text: delta, done
12
+ - Reasoning: delta, done
13
+ - Function calls: arguments.delta, arguments.done
14
+ - Code interpreter: code.delta, code.done, output
15
+ - File search: results
16
+ - Web search: results
17
+ - Rate limits: updated
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import json
23
+ from dataclasses import dataclass, field
24
+ from typing import Any, Dict, List, Optional, Tuple
25
+
26
+ from ...gateway.base import StreamChunk, Usage
27
+
28
+
29
+ @dataclass
30
+ class ParsedEvent:
31
+ """Parsed streaming event with extracted data."""
32
+
33
+ event_type: str
34
+ content: Optional[str] = None
35
+ thinking_content: Optional[str] = None
36
+ tool_call_delta: Optional[Dict[str, Any]] = None
37
+ finish_reason: Optional[str] = None
38
+ usage: Optional[Usage] = None
39
+ raw_data: Dict[str, Any] = field(default_factory=dict)
40
+ is_error: bool = False
41
+ error_message: Optional[str] = None
42
+
43
+
44
+ def parse_sse_event(line: str) -> Optional[Tuple[str, str]]:
45
+ """
46
+ Parse a single SSE line.
47
+
48
+ Returns:
49
+ Tuple of (field_name, value) or None if not a valid SSE line
50
+ """
51
+ if not line or line.startswith(":"):
52
+ # Comment or empty line
53
+ return None
54
+
55
+ if ":" in line:
56
+ field_name, _, value = line.partition(":")
57
+ # Remove leading space from value (per SSE spec)
58
+ if value.startswith(" "):
59
+ value = value[1:]
60
+ return (field_name, value)
61
+
62
+ return None
63
+
64
+
65
+ class StreamingEventParser:
66
+ """
67
+ Parser for Open Responses streaming events.
68
+
69
+ Accumulates SSE events and converts them to StreamChunk objects.
70
+ Handles the full range of 45+ event types.
71
+
72
+ Usage:
73
+ parser = StreamingEventParser()
74
+
75
+ async for line in response.aiter_lines():
76
+ chunk = parser.parse_line(line)
77
+ if chunk:
78
+ yield chunk
79
+ """
80
+
81
+ def __init__(self):
82
+ self._event_type: Optional[str] = None
83
+ self._event_data: List[str] = []
84
+ self._accumulated_content: str = ""
85
+ self._accumulated_thinking: str = ""
86
+ self._tool_calls: Dict[str, Dict[str, Any]] = {}
87
+ self._current_tool_call_id: Optional[str] = None
88
+
89
+ def reset(self) -> None:
90
+ """Reset parser state for a new stream."""
91
+ self._event_type = None
92
+ self._event_data = []
93
+ self._accumulated_content = ""
94
+ self._accumulated_thinking = ""
95
+ self._tool_calls = {}
96
+ self._current_tool_call_id = None
97
+
98
+ def parse_line(self, line: str) -> Optional[StreamChunk]:
99
+ """
100
+ Parse a single SSE line and return a StreamChunk if ready.
101
+
102
+ Args:
103
+ line: Raw SSE line
104
+
105
+ Returns:
106
+ StreamChunk if an event is complete, None otherwise
107
+ """
108
+ line = line.strip()
109
+
110
+ # Empty line indicates end of event
111
+ if not line:
112
+ if self._event_data:
113
+ chunk = self._process_event()
114
+ self._event_type = None
115
+ self._event_data = []
116
+ return chunk
117
+ return None
118
+
119
+ # Parse SSE field
120
+ parsed = parse_sse_event(line)
121
+ if not parsed:
122
+ return None
123
+
124
+ field_name, value = parsed
125
+
126
+ if field_name == "event":
127
+ self._event_type = value
128
+ elif field_name == "data":
129
+ self._event_data.append(value)
130
+
131
+ return None
132
+
133
+ def _process_event(self) -> Optional[StreamChunk]:
134
+ """Process accumulated event data and return a StreamChunk."""
135
+ if not self._event_data:
136
+ return None
137
+
138
+ # Combine multi-line data
139
+ data_str = "\n".join(self._event_data)
140
+
141
+ # Handle [DONE] signal
142
+ if data_str == "[DONE]":
143
+ return StreamChunk(finish_reason="stop")
144
+
145
+ # Parse JSON data
146
+ try:
147
+ data = json.loads(data_str)
148
+ except json.JSONDecodeError:
149
+ return None
150
+
151
+ event_type = self._event_type or data.get("type", "")
152
+
153
+ # Route to appropriate handler
154
+ return self._handle_event(event_type, data)
155
+
156
+ def _handle_event(self, event_type: str, data: Dict[str, Any]) -> Optional[StreamChunk]:
157
+ """Handle a specific event type."""
158
+
159
+ # Response lifecycle events
160
+ if event_type == "response.created":
161
+ return None # No content to emit
162
+
163
+ elif event_type == "response.in_progress":
164
+ return None # No content to emit
165
+
166
+ elif event_type == "response.completed":
167
+ response = data.get("response", {})
168
+ usage_data = response.get("usage", {})
169
+ usage = None
170
+ if usage_data:
171
+ usage = Usage(
172
+ prompt_tokens=usage_data.get("input_tokens", 0),
173
+ completion_tokens=usage_data.get("output_tokens", 0),
174
+ total_tokens=usage_data.get("total_tokens", 0),
175
+ )
176
+ return StreamChunk(finish_reason="stop", usage=usage)
177
+
178
+ elif event_type == "response.failed":
179
+ response = data.get("response", {})
180
+ error = response.get("error", {})
181
+ error_msg = error.get("message", "Unknown error")
182
+ # Return error as content
183
+ return StreamChunk(content=f"[Error: {error_msg}]", finish_reason="error")
184
+
185
+ elif event_type == "response.incomplete":
186
+ details = data.get("response", {}).get("incomplete_details", {})
187
+ reason = details.get("reason", "unknown")
188
+ return StreamChunk(finish_reason=f"incomplete:{reason}")
189
+
190
+ # Output item events
191
+ elif event_type == "response.output_item.added":
192
+ return None # No content to emit
193
+
194
+ elif event_type == "response.output_item.done":
195
+ return None # No content to emit
196
+
197
+ # Content part events
198
+ elif event_type == "response.content_part.added":
199
+ return None # No content to emit
200
+
201
+ elif event_type == "response.content_part.done":
202
+ return None # No content to emit
203
+
204
+ # Text delta events
205
+ elif event_type == "response.output_text.delta":
206
+ delta = data.get("delta", "")
207
+ if delta:
208
+ self._accumulated_content += delta
209
+ return StreamChunk(content=delta)
210
+ return None
211
+
212
+ elif event_type == "response.output_text.done":
213
+ return None # Already handled via deltas
214
+
215
+ # Reasoning/thinking events
216
+ elif event_type == "response.reasoning.delta":
217
+ delta = data.get("delta", "")
218
+ if delta:
219
+ self._accumulated_thinking += delta
220
+ return StreamChunk(thinking_content=delta)
221
+ return None
222
+
223
+ elif event_type == "response.reasoning.done":
224
+ return None # Already handled via deltas
225
+
226
+ # Function call events
227
+ elif event_type == "response.function_call_arguments.delta":
228
+ call_id = data.get("call_id", "")
229
+ delta = data.get("delta", "")
230
+ output_index = data.get("output_index", 0)
231
+
232
+ if call_id:
233
+ if call_id not in self._tool_calls:
234
+ self._tool_calls[call_id] = {
235
+ "id": call_id,
236
+ "type": "function",
237
+ "function": {
238
+ "name": "",
239
+ "arguments": "",
240
+ },
241
+ "index": output_index,
242
+ }
243
+ self._tool_calls[call_id]["function"]["arguments"] += delta
244
+
245
+ return None # Don't emit until done
246
+
247
+ elif event_type == "response.function_call_arguments.done":
248
+ call_id = data.get("call_id", "")
249
+ name = data.get("name", "")
250
+ arguments = data.get("arguments", "{}")
251
+
252
+ if call_id:
253
+ if call_id not in self._tool_calls:
254
+ self._tool_calls[call_id] = {
255
+ "id": call_id,
256
+ "type": "function",
257
+ "function": {"name": name, "arguments": arguments},
258
+ }
259
+ else:
260
+ self._tool_calls[call_id]["function"]["name"] = name
261
+ if not self._tool_calls[call_id]["function"]["arguments"]:
262
+ self._tool_calls[call_id]["function"]["arguments"] = arguments
263
+
264
+ # Emit the completed tool call
265
+ tool_call = self._tool_calls[call_id].copy()
266
+ return StreamChunk(tool_calls=[tool_call])
267
+
268
+ return None
269
+
270
+ # Code interpreter events
271
+ elif event_type == "response.code_interpreter_call.code.delta":
272
+ # Code delta - treat as content for now
273
+ delta = data.get("delta", "")
274
+ if delta:
275
+ return StreamChunk(content=f"```\n{delta}")
276
+ return None
277
+
278
+ elif event_type == "response.code_interpreter_call.code.done":
279
+ return StreamChunk(content="\n```\n")
280
+
281
+ elif event_type == "response.code_interpreter_call.output":
282
+ output = data.get("output", "")
283
+ if output:
284
+ return StreamChunk(content=f"\n[Output]: {output}\n")
285
+ return None
286
+
287
+ # File search events
288
+ elif event_type == "response.file_search_call.results":
289
+ results = data.get("results", [])
290
+ if results:
291
+ result_text = "\n".join(
292
+ f"- {r.get('filename', 'unknown')}: {r.get('text', '')[:100]}..."
293
+ for r in results[:5]
294
+ )
295
+ return StreamChunk(content=f"\n[File Search Results]:\n{result_text}\n")
296
+ return None
297
+
298
+ # Web search events
299
+ elif event_type == "response.web_search_call.results":
300
+ results = data.get("results", [])
301
+ if results:
302
+ result_text = "\n".join(
303
+ f"- [{r.get('title', '')}]({r.get('url', '')})" for r in results[:5]
304
+ )
305
+ return StreamChunk(content=f"\n[Web Search Results]:\n{result_text}\n")
306
+ return None
307
+
308
+ # Rate limit events
309
+ elif event_type == "rate_limits.updated":
310
+ # Could log rate limit info, but don't emit content
311
+ return None
312
+
313
+ # Error events
314
+ elif event_type == "error":
315
+ error = data.get("error", {})
316
+ message = error.get("message", "Unknown error")
317
+ return StreamChunk(content=f"\n[Error: {message}]\n", finish_reason="error")
318
+
319
+ # Unknown event type
320
+ else:
321
+ # Log unknown events for debugging
322
+ return None
323
+
324
+ def get_accumulated_content(self) -> str:
325
+ """Get all accumulated content."""
326
+ return self._accumulated_content
327
+
328
+ def get_accumulated_thinking(self) -> str:
329
+ """Get all accumulated thinking/reasoning."""
330
+ return self._accumulated_thinking
331
+
332
+ def get_tool_calls(self) -> List[Dict[str, Any]]:
333
+ """Get all accumulated tool calls."""
334
+ return list(self._tool_calls.values())
335
+
336
+ def has_tool_calls(self) -> bool:
337
+ """Check if any tool calls have been accumulated."""
338
+ return bool(self._tool_calls)
@@ -0,0 +1,21 @@
1
+ """
2
+ Open Responses Built-in Tools.
3
+
4
+ Implements the built-in tools from the Open Responses specification:
5
+ - apply_patch: Apply patches to files (critical for QIR fixes)
6
+ - code_interpreter: Execute code in a sandboxed environment
7
+ - file_search: Search files in vector stores
8
+ - mcp_adapter: Adapter for MCP tool compatibility
9
+ """
10
+
11
+ from .apply_patch import ApplyPatchTool
12
+ from .code_interpreter import CodeInterpreterTool
13
+ from .file_search import FileSearchTool
14
+ from .mcp_adapter import MCPToolAdapter
15
+
16
+ __all__ = [
17
+ "ApplyPatchTool",
18
+ "CodeInterpreterTool",
19
+ "FileSearchTool",
20
+ "MCPToolAdapter",
21
+ ]