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,343 @@
1
+ """
2
+ Message ↔ Item Conversion.
3
+
4
+ Bidirectional conversion between OpenAI-style messages and Open Responses items.
5
+
6
+ OpenAI Format (messages):
7
+ [
8
+ {"role": "user", "content": "Hello"},
9
+ {"role": "assistant", "content": "Hi!", "tool_calls": [...]},
10
+ {"role": "tool", "tool_call_id": "call_123", "content": "result"}
11
+ ]
12
+
13
+ Open Responses Format (items):
14
+ [
15
+ {"type": "message", "role": "user", "content": "Hello"},
16
+ {"type": "message", "role": "assistant", "content": [...]},
17
+ {"type": "function_call", "call_id": "call_123", "name": "tool", "arguments": "{}"},
18
+ {"type": "function_call_output", "call_id": "call_123", "output": "result"}
19
+ ]
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import json
25
+ from typing import Any, Dict, List, Optional, Union
26
+
27
+ from ..schema.models import (
28
+ ItemParam,
29
+ UserMessageItemParam,
30
+ AssistantMessageItemParam,
31
+ SystemMessageItemParam,
32
+ FunctionCallItemParam,
33
+ FunctionCallOutputItemParam,
34
+ TextContentParam,
35
+ ImageContentParam,
36
+ )
37
+ from ...gateway.base import Message
38
+
39
+
40
+ def messages_to_items(messages: List[Message]) -> List[Dict[str, Any]]:
41
+ """
42
+ Convert OpenAI-style messages to Open Responses items.
43
+
44
+ Handles:
45
+ - User messages → UserMessageItemParam
46
+ - Assistant messages → AssistantMessageItemParam + FunctionCallItemParam (if tool_calls)
47
+ - System messages → SystemMessageItemParam
48
+ - Tool messages → FunctionCallOutputItemParam
49
+
50
+ Args:
51
+ messages: List of Message objects
52
+
53
+ Returns:
54
+ List of Open Responses item dicts
55
+ """
56
+ items: List[Dict[str, Any]] = []
57
+
58
+ for msg in messages:
59
+ role = msg.role
60
+ content = msg.content
61
+
62
+ if role == "system":
63
+ items.append(
64
+ {
65
+ "type": "message",
66
+ "role": "system",
67
+ "content": content,
68
+ }
69
+ )
70
+
71
+ elif role == "user":
72
+ items.append(
73
+ {
74
+ "type": "message",
75
+ "role": "user",
76
+ "content": _convert_content_to_items(content),
77
+ }
78
+ )
79
+
80
+ elif role == "assistant":
81
+ # Assistant message - may include tool calls
82
+ if content:
83
+ items.append(
84
+ {
85
+ "type": "message",
86
+ "role": "assistant",
87
+ "content": _convert_content_to_items(content),
88
+ }
89
+ )
90
+
91
+ # Convert tool calls to function_call items
92
+ if msg.tool_calls:
93
+ for tc in msg.tool_calls:
94
+ func = tc.get("function", {})
95
+ items.append(
96
+ {
97
+ "type": "function_call",
98
+ "call_id": tc.get("id", ""),
99
+ "name": func.get("name", ""),
100
+ "arguments": func.get("arguments", "{}"),
101
+ }
102
+ )
103
+
104
+ elif role == "tool":
105
+ # Tool result → function_call_output
106
+ items.append(
107
+ {
108
+ "type": "function_call_output",
109
+ "call_id": msg.tool_call_id or "",
110
+ "output": content,
111
+ }
112
+ )
113
+
114
+ return items
115
+
116
+
117
+ def items_to_messages(items: List[Dict[str, Any]]) -> List[Message]:
118
+ """
119
+ Convert Open Responses items to OpenAI-style messages.
120
+
121
+ Handles:
122
+ - message items → Message objects
123
+ - function_call items → Assistant message with tool_calls
124
+ - function_call_output items → Tool message
125
+
126
+ Args:
127
+ items: List of Open Responses item dicts
128
+
129
+ Returns:
130
+ List of Message objects
131
+ """
132
+ messages: List[Message] = []
133
+ pending_tool_calls: List[Dict[str, Any]] = []
134
+
135
+ for item in items:
136
+ item_type = item.get("type", "")
137
+
138
+ if item_type == "message":
139
+ # Flush any pending tool calls first
140
+ if pending_tool_calls:
141
+ messages.append(
142
+ Message(
143
+ role="assistant",
144
+ content="",
145
+ tool_calls=pending_tool_calls,
146
+ )
147
+ )
148
+ pending_tool_calls = []
149
+
150
+ role = item.get("role", "user")
151
+ content = _convert_items_to_content(item.get("content", ""))
152
+
153
+ messages.append(
154
+ Message(
155
+ role=role,
156
+ content=content,
157
+ )
158
+ )
159
+
160
+ elif item_type == "function_call":
161
+ # Accumulate tool calls for the assistant message
162
+ pending_tool_calls.append(
163
+ {
164
+ "id": item.get("call_id", ""),
165
+ "type": "function",
166
+ "function": {
167
+ "name": item.get("name", ""),
168
+ "arguments": item.get("arguments", "{}"),
169
+ },
170
+ }
171
+ )
172
+
173
+ elif item_type == "function_call_output":
174
+ # Flush any pending tool calls first
175
+ if pending_tool_calls:
176
+ messages.append(
177
+ Message(
178
+ role="assistant",
179
+ content="",
180
+ tool_calls=pending_tool_calls,
181
+ )
182
+ )
183
+ pending_tool_calls = []
184
+
185
+ # Tool result
186
+ messages.append(
187
+ Message(
188
+ role="tool",
189
+ content=item.get("output", ""),
190
+ tool_call_id=item.get("call_id", ""),
191
+ )
192
+ )
193
+
194
+ # Flush any remaining pending tool calls
195
+ if pending_tool_calls:
196
+ messages.append(
197
+ Message(
198
+ role="assistant",
199
+ content="",
200
+ tool_calls=pending_tool_calls,
201
+ )
202
+ )
203
+
204
+ return messages
205
+
206
+
207
+ def _convert_content_to_items(content: Union[str, List[Any]]) -> Union[str, List[Dict[str, Any]]]:
208
+ """
209
+ Convert message content to Open Responses format.
210
+
211
+ Handles both string content and multi-part content (images, etc.).
212
+ """
213
+ if isinstance(content, str):
214
+ return content
215
+
216
+ if isinstance(content, list):
217
+ items = []
218
+ for part in content:
219
+ if isinstance(part, str):
220
+ items.append({"type": "input_text", "text": part})
221
+ elif isinstance(part, dict):
222
+ part_type = part.get("type", "")
223
+ if part_type == "text":
224
+ items.append({"type": "input_text", "text": part.get("text", "")})
225
+ elif part_type == "image_url":
226
+ image_url = part.get("image_url", {})
227
+ url = image_url.get("url", "") if isinstance(image_url, dict) else image_url
228
+ items.append(
229
+ {
230
+ "type": "input_image",
231
+ "image_url": url,
232
+ "detail": image_url.get("detail", "auto")
233
+ if isinstance(image_url, dict)
234
+ else "auto",
235
+ }
236
+ )
237
+ else:
238
+ # Pass through unknown types
239
+ items.append(part)
240
+ return items
241
+
242
+ return str(content)
243
+
244
+
245
+ def _convert_items_to_content(content: Union[str, List[Any]]) -> str:
246
+ """
247
+ Convert Open Responses content items to string content.
248
+
249
+ For simplicity, concatenates all text parts.
250
+ Image handling would require additional logic in the caller.
251
+ """
252
+ if isinstance(content, str):
253
+ return content
254
+
255
+ if isinstance(content, list):
256
+ text_parts = []
257
+ for part in content:
258
+ if isinstance(part, str):
259
+ text_parts.append(part)
260
+ elif isinstance(part, dict):
261
+ part_type = part.get("type", "")
262
+ if part_type in ("text", "input_text", "output_text"):
263
+ text_parts.append(part.get("text", ""))
264
+ elif part_type == "refusal":
265
+ text_parts.append(f"[Refusal: {part.get('refusal', '')}]")
266
+ return "".join(text_parts)
267
+
268
+ return str(content)
269
+
270
+
271
+ def convert_output_to_message(output_items: List[Dict[str, Any]]) -> Message:
272
+ """
273
+ Convert Open Responses output items to a single assistant message.
274
+
275
+ Extracts text content and tool calls from the output.
276
+
277
+ Args:
278
+ output_items: List of output items from a Response
279
+
280
+ Returns:
281
+ Message object with content and optional tool_calls
282
+ """
283
+ content_parts: List[str] = []
284
+ tool_calls: List[Dict[str, Any]] = []
285
+
286
+ for item in output_items:
287
+ item_type = item.get("type", "")
288
+
289
+ if item_type == "message":
290
+ # Extract text from message content
291
+ item_content = item.get("content", [])
292
+ if isinstance(item_content, str):
293
+ content_parts.append(item_content)
294
+ elif isinstance(item_content, list):
295
+ for part in item_content:
296
+ if isinstance(part, dict):
297
+ part_type = part.get("type", "")
298
+ if part_type in ("text", "output_text"):
299
+ content_parts.append(part.get("text", ""))
300
+ elif part_type == "reasoning":
301
+ # Skip reasoning in main content
302
+ pass
303
+
304
+ elif item_type == "function_call":
305
+ tool_calls.append(
306
+ {
307
+ "id": item.get("call_id", item.get("id", "")),
308
+ "type": "function",
309
+ "function": {
310
+ "name": item.get("name", ""),
311
+ "arguments": item.get("arguments", "{}"),
312
+ },
313
+ }
314
+ )
315
+
316
+ return Message(
317
+ role="assistant",
318
+ content="".join(content_parts),
319
+ tool_calls=tool_calls if tool_calls else None,
320
+ )
321
+
322
+
323
+ def extract_reasoning_from_output(output_items: List[Dict[str, Any]]) -> Optional[str]:
324
+ """
325
+ Extract reasoning/thinking content from Open Responses output.
326
+
327
+ Args:
328
+ output_items: List of output items from a Response
329
+
330
+ Returns:
331
+ Reasoning text if found, None otherwise
332
+ """
333
+ reasoning_parts: List[str] = []
334
+
335
+ for item in output_items:
336
+ if item.get("type") == "message":
337
+ item_content = item.get("content", [])
338
+ if isinstance(item_content, list):
339
+ for part in item_content:
340
+ if isinstance(part, dict) and part.get("type") == "reasoning":
341
+ reasoning_parts.append(part.get("text", ""))
342
+
343
+ return "".join(reasoning_parts) if reasoning_parts else None
@@ -0,0 +1,268 @@
1
+ """
2
+ Tool Definition Conversion.
3
+
4
+ Converts between Gateway ToolDefinition and Open Responses tool formats.
5
+
6
+ Gateway Format:
7
+ ToolDefinition(
8
+ name="read_file",
9
+ description="Read a file",
10
+ parameters={"type": "object", "properties": {...}}
11
+ )
12
+
13
+ Open Responses Format:
14
+ {
15
+ "type": "function",
16
+ "function": {
17
+ "name": "read_file",
18
+ "description": "Read a file",
19
+ "parameters": {"type": "object", "properties": {...}}
20
+ }
21
+ }
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ from typing import Any, Dict, List, Optional
27
+
28
+ from ...gateway.base import ToolDefinition
29
+
30
+
31
+ def convert_tools_to_openresponses(tools: Optional[List[ToolDefinition]]) -> List[Dict[str, Any]]:
32
+ """
33
+ Convert Gateway tool definitions to Open Responses format.
34
+
35
+ Args:
36
+ tools: List of ToolDefinition objects
37
+
38
+ Returns:
39
+ List of Open Responses tool dicts
40
+ """
41
+ if not tools:
42
+ return []
43
+
44
+ result = []
45
+ for tool in tools:
46
+ result.append(
47
+ {
48
+ "type": "function",
49
+ "function": {
50
+ "name": tool.name,
51
+ "description": tool.description,
52
+ "parameters": tool.parameters,
53
+ },
54
+ }
55
+ )
56
+
57
+ return result
58
+
59
+
60
+ def convert_tools_from_openresponses(tools: Optional[List[Dict[str, Any]]]) -> List[ToolDefinition]:
61
+ """
62
+ Convert Open Responses tools to Gateway ToolDefinition objects.
63
+
64
+ Args:
65
+ tools: List of Open Responses tool dicts
66
+
67
+ Returns:
68
+ List of ToolDefinition objects
69
+ """
70
+ if not tools:
71
+ return []
72
+
73
+ result = []
74
+ for tool in tools:
75
+ tool_type = tool.get("type", "")
76
+
77
+ if tool_type == "function":
78
+ func = tool.get("function", {})
79
+ result.append(
80
+ ToolDefinition(
81
+ name=func.get("name", ""),
82
+ description=func.get("description", ""),
83
+ parameters=func.get("parameters", {}),
84
+ )
85
+ )
86
+
87
+ elif tool_type == "code_interpreter":
88
+ # Built-in tool - create a placeholder definition
89
+ result.append(
90
+ ToolDefinition(
91
+ name="code_interpreter",
92
+ description="Execute code in a sandboxed environment",
93
+ parameters={
94
+ "type": "object",
95
+ "properties": {
96
+ "code": {
97
+ "type": "string",
98
+ "description": "The code to execute",
99
+ },
100
+ },
101
+ "required": ["code"],
102
+ },
103
+ )
104
+ )
105
+
106
+ elif tool_type == "file_search":
107
+ # Built-in tool
108
+ result.append(
109
+ ToolDefinition(
110
+ name="file_search",
111
+ description="Search files in vector stores",
112
+ parameters={
113
+ "type": "object",
114
+ "properties": {
115
+ "query": {
116
+ "type": "string",
117
+ "description": "The search query",
118
+ },
119
+ },
120
+ "required": ["query"],
121
+ },
122
+ )
123
+ )
124
+
125
+ elif tool_type == "apply_patch":
126
+ # Built-in tool
127
+ result.append(
128
+ ToolDefinition(
129
+ name="apply_patch",
130
+ description="Apply a patch to files",
131
+ parameters={
132
+ "type": "object",
133
+ "properties": {
134
+ "patch": {
135
+ "type": "string",
136
+ "description": "The patch to apply in unified diff format",
137
+ },
138
+ },
139
+ "required": ["patch"],
140
+ },
141
+ )
142
+ )
143
+
144
+ elif tool_type == "web_search":
145
+ # Built-in tool
146
+ result.append(
147
+ ToolDefinition(
148
+ name="web_search",
149
+ description="Search the web for information",
150
+ parameters={
151
+ "type": "object",
152
+ "properties": {
153
+ "query": {
154
+ "type": "string",
155
+ "description": "The search query",
156
+ },
157
+ },
158
+ "required": ["query"],
159
+ },
160
+ )
161
+ )
162
+
163
+ return result
164
+
165
+
166
+ def create_openresponses_function_tool(
167
+ name: str,
168
+ description: str,
169
+ parameters: Dict[str, Any],
170
+ strict: bool = False,
171
+ ) -> Dict[str, Any]:
172
+ """
173
+ Create an Open Responses function tool definition.
174
+
175
+ Args:
176
+ name: Tool name
177
+ description: Tool description
178
+ parameters: JSON Schema for parameters
179
+ strict: Enable strict mode for structured outputs
180
+
181
+ Returns:
182
+ Open Responses tool dict
183
+ """
184
+ return {
185
+ "type": "function",
186
+ "function": {
187
+ "name": name,
188
+ "description": description,
189
+ "parameters": parameters,
190
+ "strict": strict,
191
+ },
192
+ }
193
+
194
+
195
+ def create_code_interpreter_tool(container: Optional[str] = None) -> Dict[str, Any]:
196
+ """
197
+ Create an Open Responses code interpreter tool.
198
+
199
+ Args:
200
+ container: Optional container configuration
201
+
202
+ Returns:
203
+ Open Responses tool dict
204
+ """
205
+ tool = {"type": "code_interpreter"}
206
+ if container:
207
+ tool["container"] = container
208
+ return tool
209
+
210
+
211
+ def create_file_search_tool(
212
+ vector_store_ids: Optional[List[str]] = None,
213
+ max_num_results: int = 20,
214
+ ranking_options: Optional[Dict[str, Any]] = None,
215
+ ) -> Dict[str, Any]:
216
+ """
217
+ Create an Open Responses file search tool.
218
+
219
+ Args:
220
+ vector_store_ids: List of vector store IDs to search
221
+ max_num_results: Maximum number of results
222
+ ranking_options: Ranking configuration
223
+
224
+ Returns:
225
+ Open Responses tool dict
226
+ """
227
+ tool: Dict[str, Any] = {
228
+ "type": "file_search",
229
+ "max_num_results": max_num_results,
230
+ }
231
+ if vector_store_ids:
232
+ tool["vector_store_ids"] = vector_store_ids
233
+ if ranking_options:
234
+ tool["ranking_options"] = ranking_options
235
+ return tool
236
+
237
+
238
+ def create_apply_patch_tool() -> Dict[str, Any]:
239
+ """
240
+ Create an Open Responses apply patch tool.
241
+
242
+ Returns:
243
+ Open Responses tool dict
244
+ """
245
+ return {"type": "apply_patch"}
246
+
247
+
248
+ def create_web_search_tool(
249
+ search_context_size: str = "medium",
250
+ user_location: Optional[Dict[str, Any]] = None,
251
+ ) -> Dict[str, Any]:
252
+ """
253
+ Create an Open Responses web search tool.
254
+
255
+ Args:
256
+ search_context_size: Size of search context ("low", "medium", "high")
257
+ user_location: Optional user location for localized results
258
+
259
+ Returns:
260
+ Open Responses tool dict
261
+ """
262
+ tool: Dict[str, Any] = {
263
+ "type": "web_search",
264
+ "search_context_size": search_context_size,
265
+ }
266
+ if user_location:
267
+ tool["user_location"] = user_location
268
+ return tool
@@ -0,0 +1,56 @@
1
+ """Open Responses schema types."""
2
+
3
+ from .models import (
4
+ # Request/Response types
5
+ ResponseRequest,
6
+ Response,
7
+ ResponseUsage,
8
+ # Item types
9
+ ItemParam,
10
+ UserMessageItemParam,
11
+ AssistantMessageItemParam,
12
+ SystemMessageItemParam,
13
+ FunctionCallItemParam,
14
+ FunctionCallOutputItemParam,
15
+ # Content types
16
+ TextContentParam,
17
+ ImageContentParam,
18
+ # Tool types
19
+ FunctionToolParam,
20
+ CodeInterpreterToolParam,
21
+ FileSearchToolParam,
22
+ ApplyPatchToolParam,
23
+ # Streaming events
24
+ StreamingEvent,
25
+ ResponseCreatedEvent,
26
+ ResponseInProgressEvent,
27
+ ResponseCompletedEvent,
28
+ ResponseOutputTextDeltaEvent,
29
+ ResponseReasoningDeltaEvent,
30
+ ResponseFunctionCallArgumentsDeltaEvent,
31
+ )
32
+
33
+ __all__ = [
34
+ "ResponseRequest",
35
+ "Response",
36
+ "ResponseUsage",
37
+ "ItemParam",
38
+ "UserMessageItemParam",
39
+ "AssistantMessageItemParam",
40
+ "SystemMessageItemParam",
41
+ "FunctionCallItemParam",
42
+ "FunctionCallOutputItemParam",
43
+ "TextContentParam",
44
+ "ImageContentParam",
45
+ "FunctionToolParam",
46
+ "CodeInterpreterToolParam",
47
+ "FileSearchToolParam",
48
+ "ApplyPatchToolParam",
49
+ "StreamingEvent",
50
+ "ResponseCreatedEvent",
51
+ "ResponseInProgressEvent",
52
+ "ResponseCompletedEvent",
53
+ "ResponseOutputTextDeltaEvent",
54
+ "ResponseReasoningDeltaEvent",
55
+ "ResponseFunctionCallArgumentsDeltaEvent",
56
+ ]