bazaar-compute-node 0.1.3__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.
- bazaar_compute_node/__init__.py +3 -0
- bazaar_compute_node/app/__init__.py +1 -0
- bazaar_compute_node/app/application.py +398 -0
- bazaar_compute_node/app/attachments.py +154 -0
- bazaar_compute_node/app/command.py +342 -0
- bazaar_compute_node/app/config.py +121 -0
- bazaar_compute_node/app/registry.py +120 -0
- bazaar_compute_node/app/transport.py +264 -0
- bazaar_compute_node/app/windows_pipe.py +463 -0
- bazaar_compute_node/app/wrapper.py +63 -0
- bazaar_compute_node/bcc.py +524 -0
- bazaar_compute_node/cli.py +382 -0
- bazaar_compute_node/contrib/__init__.py +1 -0
- bazaar_compute_node/contrib/codex_app_server/__init__.py +63 -0
- bazaar_compute_node/contrib/codex_app_server/approval.py +168 -0
- bazaar_compute_node/contrib/codex_app_server/client.py +408 -0
- bazaar_compute_node/contrib/codex_app_server/events.py +431 -0
- bazaar_compute_node/contrib/codex_app_server/plugin.py +15 -0
- bazaar_compute_node/contrib/codex_app_server/process.py +583 -0
- bazaar_compute_node/contrib/codex_app_server/protocol.py +103 -0
- bazaar_compute_node/contrib/codex_app_server/runtime.py +513 -0
- bazaar_compute_node/contrib/logging/__init__.py +5 -0
- bazaar_compute_node/contrib/logging/audit.py +61 -0
- bazaar_compute_node/contrib/logging/plugin.py +11 -0
- bazaar_compute_node/contrib/sqlite/__init__.py +14 -0
- bazaar_compute_node/contrib/sqlite/codec.py +768 -0
- bazaar_compute_node/contrib/sqlite/database.py +282 -0
- bazaar_compute_node/contrib/sqlite/migrations.py +646 -0
- bazaar_compute_node/contrib/sqlite/plugin.py +11 -0
- bazaar_compute_node/contrib/sqlite/repository.py +1059 -0
- bazaar_compute_node/contrib/wecom/__init__.py +1 -0
- bazaar_compute_node/contrib/wecom/channel.py +960 -0
- bazaar_compute_node/contrib/wecom/markdown.py +146 -0
- bazaar_compute_node/contrib/wecom/plugin.py +29 -0
- bazaar_compute_node/core/__init__.py +5 -0
- bazaar_compute_node/core/approval.py +51 -0
- bazaar_compute_node/core/audit.py +101 -0
- bazaar_compute_node/core/channel.py +121 -0
- bazaar_compute_node/core/client.py +30 -0
- bazaar_compute_node/core/command.py +85 -0
- bazaar_compute_node/core/concurrency.py +29 -0
- bazaar_compute_node/core/correlation.py +48 -0
- bazaar_compute_node/core/instruction.py +224 -0
- bazaar_compute_node/core/lifecycle.py +48 -0
- bazaar_compute_node/core/models/__init__.py +63 -0
- bazaar_compute_node/core/models/entities.py +514 -0
- bazaar_compute_node/core/models/states.py +369 -0
- bazaar_compute_node/core/observability.py +47 -0
- bazaar_compute_node/core/orchestration/__init__.py +5 -0
- bazaar_compute_node/core/orchestration/command.py +614 -0
- bazaar_compute_node/core/orchestration/services.py +135 -0
- bazaar_compute_node/core/orchestration/session.py +891 -0
- bazaar_compute_node/core/orchestration/turn.py +451 -0
- bazaar_compute_node/core/outcomes.py +51 -0
- bazaar_compute_node/core/paths.py +19 -0
- bazaar_compute_node/core/runtime.py +118 -0
- bazaar_compute_node/core/storage.py +167 -0
- bazaar_compute_node-0.1.3.dist-info/METADATA +178 -0
- bazaar_compute_node-0.1.3.dist-info/RECORD +62 -0
- bazaar_compute_node-0.1.3.dist-info/WHEEL +4 -0
- bazaar_compute_node-0.1.3.dist-info/entry_points.txt +15 -0
- bazaar_compute_node-0.1.3.dist-info/licenses/LICENSE +613 -0
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from collections.abc import Callable, Mapping
|
|
5
|
+
from time import time_ns
|
|
6
|
+
from typing import Self, cast
|
|
7
|
+
from uuid import uuid7
|
|
8
|
+
|
|
9
|
+
from ...core.approval import IApprovalHandler
|
|
10
|
+
from ...core.models import (
|
|
11
|
+
RuntimeEvent,
|
|
12
|
+
RuntimeEventState,
|
|
13
|
+
StreamEvent,
|
|
14
|
+
StreamEventKind,
|
|
15
|
+
)
|
|
16
|
+
from ...core.runtime import IRuntimeTurnStream, RuntimeStreamItem
|
|
17
|
+
from .approval import (
|
|
18
|
+
approval_error,
|
|
19
|
+
build_approval_response,
|
|
20
|
+
is_approval_method,
|
|
21
|
+
parse_approval_request,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
_DURABLE_ITEM_METHODS = {
|
|
25
|
+
"item/started",
|
|
26
|
+
"item/completed",
|
|
27
|
+
"item/autoApprovalReview/started",
|
|
28
|
+
"item/autoApprovalReview/completed",
|
|
29
|
+
}
|
|
30
|
+
_STREAM_EVENT_KINDS = {
|
|
31
|
+
"item/agentMessage/delta": StreamEventKind.AGENT_MESSAGE_DELTA,
|
|
32
|
+
"item/plan/delta": StreamEventKind.PLAN_DELTA,
|
|
33
|
+
"item/reasoning/summaryTextDelta": StreamEventKind.REASONING_SUMMARY_DELTA,
|
|
34
|
+
"item/reasoning/textDelta": StreamEventKind.REASONING_TEXT_DELTA,
|
|
35
|
+
"item/commandExecution/outputDelta": StreamEventKind.COMMAND_OUTPUT_DELTA,
|
|
36
|
+
"item/commandExecution/terminalInteraction": StreamEventKind.COMMAND_INTERACTION,
|
|
37
|
+
"item/fileChange/outputDelta": StreamEventKind.FILE_CHANGE_UPDATE,
|
|
38
|
+
"item/fileChange/patchUpdated": StreamEventKind.FILE_CHANGE_UPDATE,
|
|
39
|
+
"item/mcpToolCall/progress": StreamEventKind.TOOL_PROGRESS,
|
|
40
|
+
}
|
|
41
|
+
from .client import parse_error_notification, parse_turn_notification
|
|
42
|
+
from .process import JsonlProcessSupervisor
|
|
43
|
+
from .protocol import (
|
|
44
|
+
CodexAppServerProtocolError,
|
|
45
|
+
JsonlMessage,
|
|
46
|
+
JsonlRequestId,
|
|
47
|
+
JsonlTransportError,
|
|
48
|
+
is_request_id,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class CodexTurnEventStream(IRuntimeTurnStream):
|
|
53
|
+
"""Normalize one Codex turn's notifications into runtime-neutral items."""
|
|
54
|
+
|
|
55
|
+
def __init__(
|
|
56
|
+
self,
|
|
57
|
+
supervisor: JsonlProcessSupervisor,
|
|
58
|
+
*,
|
|
59
|
+
node_id: str,
|
|
60
|
+
runtime: str,
|
|
61
|
+
session_id: str,
|
|
62
|
+
runtime_session_id: str,
|
|
63
|
+
turn_id: str,
|
|
64
|
+
provider_thread_id: str,
|
|
65
|
+
provider_turn_id: str | None,
|
|
66
|
+
approval_handler: IApprovalHandler | None = None,
|
|
67
|
+
approval_timeout: float = 30,
|
|
68
|
+
initial_error: BaseException | None = None,
|
|
69
|
+
initial_error_kind: str = "provider_unknown",
|
|
70
|
+
initial_error_state: RuntimeEventState = RuntimeEventState.UNKNOWN,
|
|
71
|
+
on_closed: Callable[[], None] | None = None,
|
|
72
|
+
) -> None:
|
|
73
|
+
self._supervisor = supervisor
|
|
74
|
+
self._node_id = node_id
|
|
75
|
+
self._runtime = runtime
|
|
76
|
+
self._session_id = session_id
|
|
77
|
+
self._runtime_session_id = runtime_session_id
|
|
78
|
+
self._turn_id = turn_id
|
|
79
|
+
self._provider_thread_id = provider_thread_id
|
|
80
|
+
self._provider_turn_id = provider_turn_id
|
|
81
|
+
self._approval_handler = approval_handler
|
|
82
|
+
self._approval_timeout = approval_timeout
|
|
83
|
+
self._responded_request_ids: set[JsonlRequestId] = set()
|
|
84
|
+
self._initial_error = initial_error
|
|
85
|
+
self._initial_error_kind = initial_error_kind
|
|
86
|
+
self._initial_error_state = initial_error_state
|
|
87
|
+
self._initial_emitted = False
|
|
88
|
+
self._terminal_emitted = False
|
|
89
|
+
self._closed = False
|
|
90
|
+
self._on_closed = on_closed
|
|
91
|
+
self._closed_callback_called = False
|
|
92
|
+
|
|
93
|
+
def __aiter__(self) -> Self:
|
|
94
|
+
return self
|
|
95
|
+
|
|
96
|
+
async def __anext__(self) -> RuntimeStreamItem:
|
|
97
|
+
if self._closed or self._terminal_emitted:
|
|
98
|
+
raise StopAsyncIteration
|
|
99
|
+
if not self._initial_emitted:
|
|
100
|
+
self._initial_emitted = True
|
|
101
|
+
if self._initial_error is not None:
|
|
102
|
+
return self._terminal_event(
|
|
103
|
+
self._initial_error_state,
|
|
104
|
+
event_name="codex.turn.start.unknown",
|
|
105
|
+
error_kind=self._initial_error_kind,
|
|
106
|
+
error_message=_safe_error_message(self._initial_error),
|
|
107
|
+
metadata={"provider_method": "turn/start"},
|
|
108
|
+
)
|
|
109
|
+
return self._event(
|
|
110
|
+
event_name="codex.turn.started",
|
|
111
|
+
state=RuntimeEventState.STARTED,
|
|
112
|
+
metadata={
|
|
113
|
+
"provider_method": "turn/start",
|
|
114
|
+
"provider_thread_id": self._provider_thread_id,
|
|
115
|
+
"provider_turn_id": self._provider_turn_id,
|
|
116
|
+
},
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
while not self._closed:
|
|
120
|
+
try:
|
|
121
|
+
message = await self._supervisor.receive()
|
|
122
|
+
except JsonlTransportError as error:
|
|
123
|
+
return self._terminal_event(
|
|
124
|
+
RuntimeEventState.UNKNOWN,
|
|
125
|
+
event_name="codex.turn.transport.unknown",
|
|
126
|
+
error_kind="provider_unknown",
|
|
127
|
+
error_message=_safe_error_message(error),
|
|
128
|
+
metadata={"provider_method": "transport"},
|
|
129
|
+
)
|
|
130
|
+
try:
|
|
131
|
+
if await self._handle_provider_request(message):
|
|
132
|
+
continue
|
|
133
|
+
event = self._map_message(message)
|
|
134
|
+
except JsonlTransportError as error:
|
|
135
|
+
return self._terminal_event(
|
|
136
|
+
RuntimeEventState.UNKNOWN,
|
|
137
|
+
event_name="codex.turn.transport.unknown",
|
|
138
|
+
error_kind="provider_unknown",
|
|
139
|
+
error_message=_safe_error_message(error),
|
|
140
|
+
metadata={"provider_method": "transport"},
|
|
141
|
+
)
|
|
142
|
+
except (CodexAppServerProtocolError, TypeError, ValueError) as error:
|
|
143
|
+
return self._terminal_event(
|
|
144
|
+
RuntimeEventState.UNKNOWN,
|
|
145
|
+
event_name="codex.turn.protocol.unknown",
|
|
146
|
+
error_kind="provider_unknown",
|
|
147
|
+
error_message=_safe_error_message(error),
|
|
148
|
+
metadata={"provider_method": "protocol"},
|
|
149
|
+
)
|
|
150
|
+
if event is not None:
|
|
151
|
+
return event
|
|
152
|
+
raise StopAsyncIteration
|
|
153
|
+
|
|
154
|
+
async def aclose(self) -> None:
|
|
155
|
+
self._closed = True
|
|
156
|
+
self._call_closed_callback()
|
|
157
|
+
|
|
158
|
+
def _map_message(self, message: JsonlMessage) -> RuntimeStreamItem | None:
|
|
159
|
+
method = message.get("method")
|
|
160
|
+
params = message.get("params")
|
|
161
|
+
if not isinstance(method, str) or not method:
|
|
162
|
+
return None
|
|
163
|
+
if not isinstance(params, Mapping):
|
|
164
|
+
return None
|
|
165
|
+
if not _belongs_to_thread(params, self._provider_thread_id):
|
|
166
|
+
return None
|
|
167
|
+
|
|
168
|
+
if method == "turn/completed":
|
|
169
|
+
thread_id, turn = parse_turn_notification(message)
|
|
170
|
+
if thread_id != self._provider_thread_id or turn.turn_id != (
|
|
171
|
+
self._provider_turn_id
|
|
172
|
+
):
|
|
173
|
+
return None
|
|
174
|
+
metadata = self._provider_metadata(method, params)
|
|
175
|
+
metadata["provider_status"] = turn.status
|
|
176
|
+
if turn.status == "completed":
|
|
177
|
+
return self._terminal_event(
|
|
178
|
+
RuntimeEventState.COMPLETED,
|
|
179
|
+
event_name="codex.turn.completed",
|
|
180
|
+
metadata=metadata,
|
|
181
|
+
)
|
|
182
|
+
if turn.status == "failed":
|
|
183
|
+
return self._terminal_event(
|
|
184
|
+
RuntimeEventState.FAILED,
|
|
185
|
+
event_name="codex.turn.failed",
|
|
186
|
+
error_kind="provider_failed",
|
|
187
|
+
error_message=turn.error_message or "Codex turn failed",
|
|
188
|
+
metadata=metadata,
|
|
189
|
+
)
|
|
190
|
+
if turn.status == "interrupted":
|
|
191
|
+
return self._terminal_event(
|
|
192
|
+
RuntimeEventState.CANCELLED,
|
|
193
|
+
event_name="codex.turn.interrupted",
|
|
194
|
+
error_kind="cancelled",
|
|
195
|
+
error_message=turn.error_message,
|
|
196
|
+
metadata=metadata,
|
|
197
|
+
)
|
|
198
|
+
return self._terminal_event(
|
|
199
|
+
RuntimeEventState.UNKNOWN,
|
|
200
|
+
event_name="codex.turn.unknown",
|
|
201
|
+
error_kind="provider_unknown",
|
|
202
|
+
error_message=f"Unsupported Codex turn status: {turn.status}",
|
|
203
|
+
metadata=metadata,
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
if method == "error":
|
|
207
|
+
error = parse_error_notification(message)
|
|
208
|
+
if error.thread_id != self._provider_thread_id or (
|
|
209
|
+
self._provider_turn_id is not None
|
|
210
|
+
and error.turn_id != self._provider_turn_id
|
|
211
|
+
):
|
|
212
|
+
return None
|
|
213
|
+
metadata = self._provider_metadata(method, params)
|
|
214
|
+
metadata["will_retry"] = error.will_retry
|
|
215
|
+
if error.error_type is not None:
|
|
216
|
+
metadata["provider_error_type"] = error.error_type
|
|
217
|
+
return self._event(
|
|
218
|
+
event_name="codex.turn.error",
|
|
219
|
+
state=RuntimeEventState.STARTED,
|
|
220
|
+
error_type=error.error_type,
|
|
221
|
+
error_message=error.message,
|
|
222
|
+
metadata=metadata,
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
provider_turn_id = _provider_turn_id(params)
|
|
226
|
+
if (
|
|
227
|
+
provider_turn_id is not None
|
|
228
|
+
and self._provider_turn_id is not None
|
|
229
|
+
and provider_turn_id != self._provider_turn_id
|
|
230
|
+
):
|
|
231
|
+
return None
|
|
232
|
+
if method == "item/reasoning/summaryPartAdded":
|
|
233
|
+
return None
|
|
234
|
+
if method == "turn/progress" or (
|
|
235
|
+
method.startswith("item/") and method not in _DURABLE_ITEM_METHODS
|
|
236
|
+
):
|
|
237
|
+
stream_id = params.get("itemId")
|
|
238
|
+
if not isinstance(stream_id, str) or not stream_id:
|
|
239
|
+
stream_id = None
|
|
240
|
+
content = params.get("delta")
|
|
241
|
+
if method == "item/mcpToolCall/progress":
|
|
242
|
+
content = params.get("message")
|
|
243
|
+
elif method == "item/commandExecution/terminalInteraction":
|
|
244
|
+
content = params.get("stdin")
|
|
245
|
+
if not isinstance(content, str):
|
|
246
|
+
content = None
|
|
247
|
+
return StreamEvent(
|
|
248
|
+
kind=(
|
|
249
|
+
StreamEventKind.TURN_PROGRESS
|
|
250
|
+
if method == "turn/progress"
|
|
251
|
+
else _STREAM_EVENT_KINDS.get(method, StreamEventKind.ITEM_PROGRESS)
|
|
252
|
+
),
|
|
253
|
+
created_at_ms=time_ns() // 1_000_000,
|
|
254
|
+
session_id=self._session_id,
|
|
255
|
+
stream_id=stream_id,
|
|
256
|
+
content=content,
|
|
257
|
+
)
|
|
258
|
+
if method == "turn/started" or method in _DURABLE_ITEM_METHODS:
|
|
259
|
+
metadata = self._provider_metadata(method, params)
|
|
260
|
+
if provider_turn_id is not None:
|
|
261
|
+
metadata["provider_turn_id"] = provider_turn_id
|
|
262
|
+
return self._event(
|
|
263
|
+
event_name="codex.turn.progress",
|
|
264
|
+
state=RuntimeEventState.STARTED,
|
|
265
|
+
metadata=metadata,
|
|
266
|
+
)
|
|
267
|
+
return None
|
|
268
|
+
|
|
269
|
+
def _event(
|
|
270
|
+
self,
|
|
271
|
+
*,
|
|
272
|
+
event_name: str,
|
|
273
|
+
state: RuntimeEventState,
|
|
274
|
+
error_kind: str | None = None,
|
|
275
|
+
error_type: str | None = None,
|
|
276
|
+
error_message: str | None = None,
|
|
277
|
+
metadata: Mapping[str, object] | None = None,
|
|
278
|
+
) -> RuntimeEvent:
|
|
279
|
+
return RuntimeEvent(
|
|
280
|
+
event_seq=0,
|
|
281
|
+
event_id=str(uuid7()),
|
|
282
|
+
created_at_ms=time_ns() // 1_000_000,
|
|
283
|
+
level="error" if error_kind else "info",
|
|
284
|
+
event_name=event_name,
|
|
285
|
+
state=state,
|
|
286
|
+
node_id=self._node_id,
|
|
287
|
+
bcn_session_id=self._session_id,
|
|
288
|
+
runtime_session_id=self._runtime_session_id,
|
|
289
|
+
turn_id=self._turn_id,
|
|
290
|
+
error_kind=error_kind,
|
|
291
|
+
error_type=error_type,
|
|
292
|
+
error_message=error_message,
|
|
293
|
+
runtime=self._runtime,
|
|
294
|
+
metadata=dict(metadata or {}),
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
def _terminal_event(
|
|
298
|
+
self,
|
|
299
|
+
state: RuntimeEventState,
|
|
300
|
+
*,
|
|
301
|
+
event_name: str,
|
|
302
|
+
error_kind: str | None = None,
|
|
303
|
+
error_message: str | None = None,
|
|
304
|
+
metadata: Mapping[str, object] | None = None,
|
|
305
|
+
) -> RuntimeEvent:
|
|
306
|
+
self._terminal_emitted = True
|
|
307
|
+
self._call_closed_callback()
|
|
308
|
+
return self._event(
|
|
309
|
+
event_name=event_name,
|
|
310
|
+
state=state,
|
|
311
|
+
error_kind=error_kind,
|
|
312
|
+
error_message=error_message,
|
|
313
|
+
metadata=metadata,
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
def _provider_metadata(
|
|
317
|
+
self,
|
|
318
|
+
method: str,
|
|
319
|
+
params: Mapping[str, object],
|
|
320
|
+
) -> dict[str, object]:
|
|
321
|
+
metadata: dict[str, object] = {
|
|
322
|
+
"provider_method": method,
|
|
323
|
+
"provider_thread_id": self._provider_thread_id,
|
|
324
|
+
}
|
|
325
|
+
if self._provider_turn_id is not None:
|
|
326
|
+
metadata["provider_turn_id"] = self._provider_turn_id
|
|
327
|
+
request_id = params.get("requestId")
|
|
328
|
+
if isinstance(request_id, (int, str)) and not isinstance(request_id, bool):
|
|
329
|
+
metadata["provider_request_id"] = str(request_id)
|
|
330
|
+
return metadata
|
|
331
|
+
|
|
332
|
+
def _call_closed_callback(self) -> None:
|
|
333
|
+
if self._closed_callback_called:
|
|
334
|
+
return
|
|
335
|
+
self._closed_callback_called = True
|
|
336
|
+
if self._on_closed is not None:
|
|
337
|
+
self._on_closed()
|
|
338
|
+
|
|
339
|
+
async def _handle_provider_request(self, message: JsonlMessage) -> bool:
|
|
340
|
+
method = message.get("method")
|
|
341
|
+
request_id = message.get("id")
|
|
342
|
+
if not isinstance(method, str) or request_id is None:
|
|
343
|
+
return False
|
|
344
|
+
if not is_request_id(request_id):
|
|
345
|
+
raise CodexAppServerProtocolError(
|
|
346
|
+
"provider request id must be an integer or string"
|
|
347
|
+
)
|
|
348
|
+
request_id = cast(JsonlRequestId, request_id)
|
|
349
|
+
if request_id in self._responded_request_ids:
|
|
350
|
+
return True
|
|
351
|
+
self._responded_request_ids.add(request_id)
|
|
352
|
+
if not is_approval_method(method):
|
|
353
|
+
await self._respond_with_error(
|
|
354
|
+
request_id,
|
|
355
|
+
CodexAppServerProtocolError(
|
|
356
|
+
f"unsupported provider request method: {method}"
|
|
357
|
+
),
|
|
358
|
+
)
|
|
359
|
+
raise CodexAppServerProtocolError("unsupported provider request")
|
|
360
|
+
response_attempted = False
|
|
361
|
+
try:
|
|
362
|
+
approval = parse_approval_request(
|
|
363
|
+
message,
|
|
364
|
+
session_id=self._session_id,
|
|
365
|
+
runtime_session_id=self._runtime_session_id,
|
|
366
|
+
turn_id=self._turn_id,
|
|
367
|
+
provider_thread_id=self._provider_thread_id,
|
|
368
|
+
provider_turn_id=self._provider_turn_id,
|
|
369
|
+
)
|
|
370
|
+
if self._approval_handler is None:
|
|
371
|
+
raise CodexAppServerProtocolError(
|
|
372
|
+
"runtime approval handler is not configured"
|
|
373
|
+
)
|
|
374
|
+
result = await self._approval_handler.request_approval(
|
|
375
|
+
approval.request,
|
|
376
|
+
timeout=self._approval_timeout,
|
|
377
|
+
)
|
|
378
|
+
response = build_approval_response(approval, result)
|
|
379
|
+
response_attempted = True
|
|
380
|
+
await self._supervisor.respond(
|
|
381
|
+
request_id,
|
|
382
|
+
result=response,
|
|
383
|
+
timeout=self._approval_timeout,
|
|
384
|
+
)
|
|
385
|
+
except asyncio.CancelledError:
|
|
386
|
+
raise
|
|
387
|
+
except Exception as error:
|
|
388
|
+
if not response_attempted:
|
|
389
|
+
await self._respond_with_error(request_id, error)
|
|
390
|
+
if response_attempted and isinstance(error, JsonlTransportError):
|
|
391
|
+
raise
|
|
392
|
+
raise CodexAppServerProtocolError(
|
|
393
|
+
f"approval bridge failed: {type(error).__name__}"
|
|
394
|
+
) from error
|
|
395
|
+
return True
|
|
396
|
+
|
|
397
|
+
async def _respond_with_error(
|
|
398
|
+
self,
|
|
399
|
+
request_id: JsonlRequestId,
|
|
400
|
+
error: BaseException,
|
|
401
|
+
) -> None:
|
|
402
|
+
await self._supervisor.respond(
|
|
403
|
+
request_id,
|
|
404
|
+
error=approval_error(error),
|
|
405
|
+
timeout=self._approval_timeout,
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
def _belongs_to_thread(params: Mapping[str, object], thread_id: str) -> bool:
|
|
410
|
+
value = params.get("threadId")
|
|
411
|
+
return value == thread_id
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
def _provider_turn_id(params: Mapping[str, object]) -> str | None:
|
|
415
|
+
value = params.get("turnId")
|
|
416
|
+
if isinstance(value, str) and value:
|
|
417
|
+
return value
|
|
418
|
+
turn = params.get("turn")
|
|
419
|
+
if isinstance(turn, Mapping):
|
|
420
|
+
value = turn.get("id")
|
|
421
|
+
if isinstance(value, str) and value:
|
|
422
|
+
return value
|
|
423
|
+
return None
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def _safe_error_message(error: BaseException) -> str:
|
|
427
|
+
message = str(error).strip()
|
|
428
|
+
return message or type(error).__name__
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
__all__ = ["CodexTurnEventStream"]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from ...core.runtime import IRuntime, RuntimeCommandContext
|
|
4
|
+
from .runtime import CodexAppServerRuntime
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def create_runtime(context: RuntimeCommandContext) -> IRuntime:
|
|
8
|
+
return CodexAppServerRuntime(
|
|
9
|
+
context,
|
|
10
|
+
model=context.runtime_options.get("model"),
|
|
11
|
+
effort=context.runtime_options.get("effort"),
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
__all__ = ["create_runtime"]
|