superqode 0.1.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- superqode/__init__.py +33 -0
- superqode/acp/__init__.py +23 -0
- superqode/acp/client.py +913 -0
- superqode/acp/permission_screen.py +457 -0
- superqode/acp/types.py +480 -0
- superqode/acp_discovery.py +856 -0
- superqode/agent/__init__.py +22 -0
- superqode/agent/edit_strategies.py +334 -0
- superqode/agent/loop.py +892 -0
- superqode/agent/qe_report_templates.py +39 -0
- superqode/agent/system_prompts.py +353 -0
- superqode/agent_output.py +721 -0
- superqode/agent_stream.py +953 -0
- superqode/agents/__init__.py +59 -0
- superqode/agents/acp_registry.py +305 -0
- superqode/agents/client.py +249 -0
- superqode/agents/data/augmentcode.com.toml +51 -0
- superqode/agents/data/cagent.dev.toml +51 -0
- superqode/agents/data/claude.com.toml +60 -0
- superqode/agents/data/codeassistant.dev.toml +51 -0
- superqode/agents/data/codex.openai.com.toml +57 -0
- superqode/agents/data/fastagent.ai.toml +66 -0
- superqode/agents/data/geminicli.com.toml +77 -0
- superqode/agents/data/goose.block.xyz.toml +54 -0
- superqode/agents/data/junie.jetbrains.com.toml +56 -0
- superqode/agents/data/kimi.moonshot.cn.toml +57 -0
- superqode/agents/data/llmlingagent.dev.toml +51 -0
- superqode/agents/data/molt.bot.toml +49 -0
- superqode/agents/data/opencode.ai.toml +60 -0
- superqode/agents/data/stakpak.dev.toml +51 -0
- superqode/agents/data/vtcode.dev.toml +51 -0
- superqode/agents/discovery.py +266 -0
- superqode/agents/messaging.py +160 -0
- superqode/agents/persona.py +166 -0
- superqode/agents/registry.py +421 -0
- superqode/agents/schema.py +72 -0
- superqode/agents/unified.py +367 -0
- superqode/app/__init__.py +111 -0
- superqode/app/constants.py +314 -0
- superqode/app/css.py +366 -0
- superqode/app/models.py +118 -0
- superqode/app/suggester.py +125 -0
- superqode/app/widgets.py +1591 -0
- superqode/app_enhanced.py +399 -0
- superqode/app_main.py +17187 -0
- superqode/approval.py +312 -0
- superqode/atomic.py +296 -0
- superqode/commands/__init__.py +1 -0
- superqode/commands/acp.py +965 -0
- superqode/commands/agents.py +180 -0
- superqode/commands/auth.py +278 -0
- superqode/commands/config.py +374 -0
- superqode/commands/init.py +826 -0
- superqode/commands/providers.py +819 -0
- superqode/commands/qe.py +1145 -0
- superqode/commands/roles.py +380 -0
- superqode/commands/serve.py +172 -0
- superqode/commands/suggestions.py +127 -0
- superqode/commands/superqe.py +460 -0
- superqode/config/__init__.py +51 -0
- superqode/config/loader.py +812 -0
- superqode/config/schema.py +498 -0
- superqode/core/__init__.py +111 -0
- superqode/core/roles.py +281 -0
- superqode/danger.py +386 -0
- superqode/data/superqode-template.yaml +1522 -0
- superqode/design_system.py +1080 -0
- superqode/dialogs/__init__.py +6 -0
- superqode/dialogs/base.py +39 -0
- superqode/dialogs/model.py +130 -0
- superqode/dialogs/provider.py +870 -0
- superqode/diff_view.py +919 -0
- superqode/enterprise.py +21 -0
- superqode/evaluation/__init__.py +25 -0
- superqode/evaluation/adapters.py +93 -0
- superqode/evaluation/behaviors.py +89 -0
- superqode/evaluation/engine.py +209 -0
- superqode/evaluation/scenarios.py +96 -0
- superqode/execution/__init__.py +36 -0
- superqode/execution/linter.py +538 -0
- superqode/execution/modes.py +347 -0
- superqode/execution/resolver.py +283 -0
- superqode/execution/runner.py +642 -0
- superqode/file_explorer.py +811 -0
- superqode/file_viewer.py +471 -0
- superqode/flash.py +183 -0
- superqode/guidance/__init__.py +58 -0
- superqode/guidance/config.py +203 -0
- superqode/guidance/prompts.py +71 -0
- superqode/harness/__init__.py +54 -0
- superqode/harness/accelerator.py +291 -0
- superqode/harness/config.py +319 -0
- superqode/harness/validator.py +147 -0
- superqode/history.py +279 -0
- superqode/integrations/superopt_runner.py +124 -0
- superqode/logging/__init__.py +49 -0
- superqode/logging/adapters.py +219 -0
- superqode/logging/formatter.py +923 -0
- superqode/logging/integration.py +341 -0
- superqode/logging/sinks.py +170 -0
- superqode/logging/unified_log.py +417 -0
- superqode/lsp/__init__.py +26 -0
- superqode/lsp/client.py +544 -0
- superqode/main.py +1069 -0
- superqode/mcp/__init__.py +89 -0
- superqode/mcp/auth_storage.py +380 -0
- superqode/mcp/client.py +1236 -0
- superqode/mcp/config.py +319 -0
- superqode/mcp/integration.py +337 -0
- superqode/mcp/oauth.py +436 -0
- superqode/mcp/oauth_callback.py +385 -0
- superqode/mcp/types.py +290 -0
- superqode/memory/__init__.py +31 -0
- superqode/memory/feedback.py +342 -0
- superqode/memory/store.py +522 -0
- superqode/notifications.py +369 -0
- superqode/optimization/__init__.py +5 -0
- superqode/optimization/config.py +33 -0
- superqode/permissions/__init__.py +25 -0
- superqode/permissions/rules.py +488 -0
- superqode/plan.py +323 -0
- superqode/providers/__init__.py +33 -0
- superqode/providers/gateway/__init__.py +165 -0
- superqode/providers/gateway/base.py +228 -0
- superqode/providers/gateway/litellm_gateway.py +1170 -0
- superqode/providers/gateway/openresponses_gateway.py +436 -0
- superqode/providers/health.py +297 -0
- superqode/providers/huggingface/__init__.py +74 -0
- superqode/providers/huggingface/downloader.py +472 -0
- superqode/providers/huggingface/endpoints.py +442 -0
- superqode/providers/huggingface/hub.py +531 -0
- superqode/providers/huggingface/inference.py +394 -0
- superqode/providers/huggingface/transformers_runner.py +516 -0
- superqode/providers/local/__init__.py +100 -0
- superqode/providers/local/base.py +438 -0
- superqode/providers/local/discovery.py +418 -0
- superqode/providers/local/lmstudio.py +256 -0
- superqode/providers/local/mlx.py +457 -0
- superqode/providers/local/ollama.py +486 -0
- superqode/providers/local/sglang.py +268 -0
- superqode/providers/local/tgi.py +260 -0
- superqode/providers/local/tool_support.py +477 -0
- superqode/providers/local/vllm.py +258 -0
- superqode/providers/manager.py +1338 -0
- superqode/providers/models.py +1016 -0
- superqode/providers/models_dev.py +578 -0
- superqode/providers/openresponses/__init__.py +87 -0
- superqode/providers/openresponses/converters/__init__.py +17 -0
- superqode/providers/openresponses/converters/messages.py +343 -0
- superqode/providers/openresponses/converters/tools.py +268 -0
- superqode/providers/openresponses/schema/__init__.py +56 -0
- superqode/providers/openresponses/schema/models.py +585 -0
- superqode/providers/openresponses/streaming/__init__.py +5 -0
- superqode/providers/openresponses/streaming/parser.py +338 -0
- superqode/providers/openresponses/tools/__init__.py +21 -0
- superqode/providers/openresponses/tools/apply_patch.py +352 -0
- superqode/providers/openresponses/tools/code_interpreter.py +290 -0
- superqode/providers/openresponses/tools/file_search.py +333 -0
- superqode/providers/openresponses/tools/mcp_adapter.py +252 -0
- superqode/providers/registry.py +716 -0
- superqode/providers/usage.py +332 -0
- superqode/pure_mode.py +384 -0
- superqode/qr/__init__.py +23 -0
- superqode/qr/dashboard.py +781 -0
- superqode/qr/generator.py +1018 -0
- superqode/qr/templates.py +135 -0
- superqode/safety/__init__.py +41 -0
- superqode/safety/sandbox.py +413 -0
- superqode/safety/warnings.py +256 -0
- superqode/server/__init__.py +33 -0
- superqode/server/lsp_server.py +775 -0
- superqode/server/web.py +250 -0
- superqode/session/__init__.py +25 -0
- superqode/session/persistence.py +580 -0
- superqode/session/sharing.py +477 -0
- superqode/session.py +475 -0
- superqode/sidebar.py +2991 -0
- superqode/stream_view.py +648 -0
- superqode/styles/__init__.py +3 -0
- superqode/superqe/__init__.py +184 -0
- superqode/superqe/acp_runner.py +1064 -0
- superqode/superqe/constitution/__init__.py +62 -0
- superqode/superqe/constitution/evaluator.py +308 -0
- superqode/superqe/constitution/loader.py +432 -0
- superqode/superqe/constitution/schema.py +250 -0
- superqode/superqe/events.py +591 -0
- superqode/superqe/frameworks/__init__.py +65 -0
- superqode/superqe/frameworks/base.py +234 -0
- superqode/superqe/frameworks/e2e.py +263 -0
- superqode/superqe/frameworks/executor.py +237 -0
- superqode/superqe/frameworks/javascript.py +409 -0
- superqode/superqe/frameworks/python.py +373 -0
- superqode/superqe/frameworks/registry.py +92 -0
- superqode/superqe/mcp_tools/__init__.py +47 -0
- superqode/superqe/mcp_tools/core_tools.py +418 -0
- superqode/superqe/mcp_tools/registry.py +230 -0
- superqode/superqe/mcp_tools/testing_tools.py +167 -0
- superqode/superqe/noise.py +89 -0
- superqode/superqe/orchestrator.py +778 -0
- superqode/superqe/roles.py +609 -0
- superqode/superqe/session.py +713 -0
- superqode/superqe/skills/__init__.py +57 -0
- superqode/superqe/skills/base.py +106 -0
- superqode/superqe/skills/core_skills.py +899 -0
- superqode/superqe/skills/registry.py +90 -0
- superqode/superqe/verifier.py +101 -0
- superqode/superqe_cli.py +76 -0
- superqode/tool_call.py +358 -0
- superqode/tools/__init__.py +93 -0
- superqode/tools/agent_tools.py +496 -0
- superqode/tools/base.py +324 -0
- superqode/tools/batch_tool.py +133 -0
- superqode/tools/diagnostics.py +311 -0
- superqode/tools/edit_tools.py +653 -0
- superqode/tools/enhanced_base.py +515 -0
- superqode/tools/file_tools.py +269 -0
- superqode/tools/file_tracking.py +45 -0
- superqode/tools/lsp_tools.py +610 -0
- superqode/tools/network_tools.py +350 -0
- superqode/tools/permissions.py +400 -0
- superqode/tools/question_tool.py +324 -0
- superqode/tools/search_tools.py +598 -0
- superqode/tools/shell_tools.py +259 -0
- superqode/tools/todo_tools.py +121 -0
- superqode/tools/validation.py +80 -0
- superqode/tools/web_tools.py +639 -0
- superqode/tui.py +1152 -0
- superqode/tui_integration.py +875 -0
- superqode/tui_widgets/__init__.py +27 -0
- superqode/tui_widgets/widgets/__init__.py +18 -0
- superqode/tui_widgets/widgets/progress.py +185 -0
- superqode/tui_widgets/widgets/tool_display.py +188 -0
- superqode/undo_manager.py +574 -0
- superqode/utils/__init__.py +5 -0
- superqode/utils/error_handling.py +323 -0
- superqode/utils/fuzzy.py +257 -0
- superqode/widgets/__init__.py +477 -0
- superqode/widgets/agent_collab.py +390 -0
- superqode/widgets/agent_store.py +936 -0
- superqode/widgets/agent_switcher.py +395 -0
- superqode/widgets/animation_manager.py +284 -0
- superqode/widgets/code_context.py +356 -0
- superqode/widgets/command_palette.py +412 -0
- superqode/widgets/connection_status.py +537 -0
- superqode/widgets/conversation_history.py +470 -0
- superqode/widgets/diff_indicator.py +155 -0
- superqode/widgets/enhanced_status_bar.py +385 -0
- superqode/widgets/enhanced_toast.py +476 -0
- superqode/widgets/file_browser.py +809 -0
- superqode/widgets/file_reference.py +585 -0
- superqode/widgets/issue_timeline.py +340 -0
- superqode/widgets/leader_key.py +264 -0
- superqode/widgets/mode_switcher.py +445 -0
- superqode/widgets/model_picker.py +234 -0
- superqode/widgets/permission_preview.py +1205 -0
- superqode/widgets/prompt.py +358 -0
- superqode/widgets/provider_connect.py +725 -0
- superqode/widgets/pty_shell.py +587 -0
- superqode/widgets/qe_dashboard.py +321 -0
- superqode/widgets/resizable_sidebar.py +377 -0
- superqode/widgets/response_changes.py +218 -0
- superqode/widgets/response_display.py +528 -0
- superqode/widgets/rich_tool_display.py +613 -0
- superqode/widgets/sidebar_panels.py +1180 -0
- superqode/widgets/slash_complete.py +356 -0
- superqode/widgets/split_view.py +612 -0
- superqode/widgets/status_bar.py +273 -0
- superqode/widgets/superqode_display.py +786 -0
- superqode/widgets/thinking_display.py +815 -0
- superqode/widgets/throbber.py +87 -0
- superqode/widgets/toast.py +206 -0
- superqode/widgets/unified_output.py +1073 -0
- superqode/workspace/__init__.py +75 -0
- superqode/workspace/artifacts.py +472 -0
- superqode/workspace/coordinator.py +353 -0
- superqode/workspace/diff_tracker.py +429 -0
- superqode/workspace/git_guard.py +373 -0
- superqode/workspace/git_snapshot.py +526 -0
- superqode/workspace/manager.py +750 -0
- superqode/workspace/snapshot.py +357 -0
- superqode/workspace/watcher.py +535 -0
- superqode/workspace/worktree.py +440 -0
- superqode-0.1.5.dist-info/METADATA +204 -0
- superqode-0.1.5.dist-info/RECORD +288 -0
- superqode-0.1.5.dist-info/WHEEL +5 -0
- superqode-0.1.5.dist-info/entry_points.txt +3 -0
- superqode-0.1.5.dist-info/licenses/LICENSE +648 -0
- superqode-0.1.5.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,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
|
+
]
|