codex-autorunner 0.1.2__py3-none-any.whl → 1.1.0__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 (276) hide show
  1. codex_autorunner/__init__.py +12 -1
  2. codex_autorunner/__main__.py +4 -0
  3. codex_autorunner/agents/codex/harness.py +1 -1
  4. codex_autorunner/agents/opencode/client.py +68 -35
  5. codex_autorunner/agents/opencode/constants.py +3 -0
  6. codex_autorunner/agents/opencode/harness.py +6 -1
  7. codex_autorunner/agents/opencode/logging.py +21 -5
  8. codex_autorunner/agents/opencode/run_prompt.py +1 -0
  9. codex_autorunner/agents/opencode/runtime.py +176 -47
  10. codex_autorunner/agents/opencode/supervisor.py +36 -48
  11. codex_autorunner/agents/registry.py +155 -8
  12. codex_autorunner/api.py +25 -0
  13. codex_autorunner/bootstrap.py +22 -37
  14. codex_autorunner/cli.py +5 -1156
  15. codex_autorunner/codex_cli.py +20 -84
  16. codex_autorunner/core/__init__.py +4 -0
  17. codex_autorunner/core/about_car.py +49 -32
  18. codex_autorunner/core/adapter_utils.py +21 -0
  19. codex_autorunner/core/app_server_ids.py +59 -0
  20. codex_autorunner/core/app_server_logging.py +7 -3
  21. codex_autorunner/core/app_server_prompts.py +27 -260
  22. codex_autorunner/core/app_server_threads.py +26 -28
  23. codex_autorunner/core/app_server_utils.py +165 -0
  24. codex_autorunner/core/archive.py +349 -0
  25. codex_autorunner/core/codex_runner.py +12 -2
  26. codex_autorunner/core/config.py +587 -103
  27. codex_autorunner/core/docs.py +10 -2
  28. codex_autorunner/core/drafts.py +136 -0
  29. codex_autorunner/core/engine.py +1531 -866
  30. codex_autorunner/core/exceptions.py +4 -0
  31. codex_autorunner/core/flows/__init__.py +25 -0
  32. codex_autorunner/core/flows/controller.py +202 -0
  33. codex_autorunner/core/flows/definition.py +82 -0
  34. codex_autorunner/core/flows/models.py +88 -0
  35. codex_autorunner/core/flows/reasons.py +52 -0
  36. codex_autorunner/core/flows/reconciler.py +131 -0
  37. codex_autorunner/core/flows/runtime.py +382 -0
  38. codex_autorunner/core/flows/store.py +568 -0
  39. codex_autorunner/core/flows/transition.py +138 -0
  40. codex_autorunner/core/flows/ux_helpers.py +257 -0
  41. codex_autorunner/core/flows/worker_process.py +242 -0
  42. codex_autorunner/core/git_utils.py +62 -0
  43. codex_autorunner/core/hub.py +136 -16
  44. codex_autorunner/core/locks.py +4 -0
  45. codex_autorunner/core/notifications.py +14 -2
  46. codex_autorunner/core/ports/__init__.py +28 -0
  47. codex_autorunner/core/ports/agent_backend.py +150 -0
  48. codex_autorunner/core/ports/backend_orchestrator.py +41 -0
  49. codex_autorunner/core/ports/run_event.py +91 -0
  50. codex_autorunner/core/prompt.py +15 -7
  51. codex_autorunner/core/redaction.py +29 -0
  52. codex_autorunner/core/review_context.py +5 -8
  53. codex_autorunner/core/run_index.py +6 -0
  54. codex_autorunner/core/runner_process.py +5 -2
  55. codex_autorunner/core/state.py +0 -88
  56. codex_autorunner/core/state_roots.py +57 -0
  57. codex_autorunner/core/supervisor_protocol.py +15 -0
  58. codex_autorunner/core/supervisor_utils.py +67 -0
  59. codex_autorunner/core/text_delta_coalescer.py +54 -0
  60. codex_autorunner/core/ticket_linter_cli.py +201 -0
  61. codex_autorunner/core/ticket_manager_cli.py +432 -0
  62. codex_autorunner/core/update.py +24 -16
  63. codex_autorunner/core/update_paths.py +28 -0
  64. codex_autorunner/core/update_runner.py +2 -0
  65. codex_autorunner/core/usage.py +164 -12
  66. codex_autorunner/core/utils.py +120 -11
  67. codex_autorunner/discovery.py +2 -4
  68. codex_autorunner/flows/review/__init__.py +17 -0
  69. codex_autorunner/{core/review.py → flows/review/service.py} +15 -10
  70. codex_autorunner/flows/ticket_flow/__init__.py +3 -0
  71. codex_autorunner/flows/ticket_flow/definition.py +98 -0
  72. codex_autorunner/integrations/agents/__init__.py +17 -0
  73. codex_autorunner/integrations/agents/backend_orchestrator.py +284 -0
  74. codex_autorunner/integrations/agents/codex_adapter.py +90 -0
  75. codex_autorunner/integrations/agents/codex_backend.py +448 -0
  76. codex_autorunner/integrations/agents/opencode_adapter.py +108 -0
  77. codex_autorunner/integrations/agents/opencode_backend.py +598 -0
  78. codex_autorunner/integrations/agents/runner.py +91 -0
  79. codex_autorunner/integrations/agents/wiring.py +271 -0
  80. codex_autorunner/integrations/app_server/client.py +583 -152
  81. codex_autorunner/integrations/app_server/env.py +2 -107
  82. codex_autorunner/{core/app_server_events.py → integrations/app_server/event_buffer.py} +15 -8
  83. codex_autorunner/integrations/app_server/supervisor.py +59 -33
  84. codex_autorunner/integrations/telegram/adapter.py +204 -165
  85. codex_autorunner/integrations/telegram/api_schemas.py +120 -0
  86. codex_autorunner/integrations/telegram/config.py +221 -0
  87. codex_autorunner/integrations/telegram/constants.py +17 -2
  88. codex_autorunner/integrations/telegram/dispatch.py +17 -0
  89. codex_autorunner/integrations/telegram/doctor.py +47 -0
  90. codex_autorunner/integrations/telegram/handlers/callbacks.py +7 -4
  91. codex_autorunner/integrations/telegram/handlers/commands/__init__.py +2 -0
  92. codex_autorunner/integrations/telegram/handlers/commands/execution.py +53 -57
  93. codex_autorunner/integrations/telegram/handlers/commands/files.py +2 -6
  94. codex_autorunner/integrations/telegram/handlers/commands/flows.py +1364 -0
  95. codex_autorunner/integrations/telegram/handlers/commands/formatting.py +1 -1
  96. codex_autorunner/integrations/telegram/handlers/commands/github.py +41 -582
  97. codex_autorunner/integrations/telegram/handlers/commands/workspace.py +8 -8
  98. codex_autorunner/integrations/telegram/handlers/commands_runtime.py +137 -478
  99. codex_autorunner/integrations/telegram/handlers/commands_spec.py +17 -4
  100. codex_autorunner/integrations/telegram/handlers/messages.py +121 -9
  101. codex_autorunner/integrations/telegram/handlers/selections.py +61 -1
  102. codex_autorunner/integrations/telegram/helpers.py +111 -16
  103. codex_autorunner/integrations/telegram/outbox.py +208 -37
  104. codex_autorunner/integrations/telegram/progress_stream.py +3 -10
  105. codex_autorunner/integrations/telegram/service.py +221 -42
  106. codex_autorunner/integrations/telegram/state.py +100 -2
  107. codex_autorunner/integrations/telegram/ticket_flow_bridge.py +611 -0
  108. codex_autorunner/integrations/telegram/transport.py +39 -4
  109. codex_autorunner/integrations/telegram/trigger_mode.py +53 -0
  110. codex_autorunner/manifest.py +2 -0
  111. codex_autorunner/plugin_api.py +22 -0
  112. codex_autorunner/routes/__init__.py +37 -67
  113. codex_autorunner/routes/agents.py +2 -137
  114. codex_autorunner/routes/analytics.py +3 -0
  115. codex_autorunner/routes/app_server.py +2 -131
  116. codex_autorunner/routes/base.py +2 -624
  117. codex_autorunner/routes/file_chat.py +7 -0
  118. codex_autorunner/routes/flows.py +7 -0
  119. codex_autorunner/routes/messages.py +7 -0
  120. codex_autorunner/routes/repos.py +2 -196
  121. codex_autorunner/routes/review.py +2 -147
  122. codex_autorunner/routes/sessions.py +2 -175
  123. codex_autorunner/routes/settings.py +2 -168
  124. codex_autorunner/routes/shared.py +2 -275
  125. codex_autorunner/routes/system.py +4 -188
  126. codex_autorunner/routes/usage.py +3 -0
  127. codex_autorunner/routes/voice.py +2 -119
  128. codex_autorunner/routes/workspace.py +3 -0
  129. codex_autorunner/server.py +3 -2
  130. codex_autorunner/static/agentControls.js +41 -11
  131. codex_autorunner/static/agentEvents.js +248 -0
  132. codex_autorunner/static/app.js +35 -24
  133. codex_autorunner/static/archive.js +826 -0
  134. codex_autorunner/static/archiveApi.js +37 -0
  135. codex_autorunner/static/autoRefresh.js +36 -8
  136. codex_autorunner/static/bootstrap.js +1 -0
  137. codex_autorunner/static/bus.js +1 -0
  138. codex_autorunner/static/cache.js +1 -0
  139. codex_autorunner/static/constants.js +20 -4
  140. codex_autorunner/static/dashboard.js +344 -325
  141. codex_autorunner/static/diffRenderer.js +37 -0
  142. codex_autorunner/static/docChatCore.js +324 -0
  143. codex_autorunner/static/docChatStorage.js +65 -0
  144. codex_autorunner/static/docChatVoice.js +65 -0
  145. codex_autorunner/static/docEditor.js +133 -0
  146. codex_autorunner/static/env.js +1 -0
  147. codex_autorunner/static/eventSummarizer.js +166 -0
  148. codex_autorunner/static/fileChat.js +182 -0
  149. codex_autorunner/static/health.js +155 -0
  150. codex_autorunner/static/hub.js +126 -185
  151. codex_autorunner/static/index.html +839 -863
  152. codex_autorunner/static/liveUpdates.js +1 -0
  153. codex_autorunner/static/loader.js +1 -0
  154. codex_autorunner/static/messages.js +873 -0
  155. codex_autorunner/static/mobileCompact.js +2 -1
  156. codex_autorunner/static/preserve.js +17 -0
  157. codex_autorunner/static/settings.js +149 -217
  158. codex_autorunner/static/smartRefresh.js +52 -0
  159. codex_autorunner/static/styles.css +8850 -3876
  160. codex_autorunner/static/tabs.js +175 -11
  161. codex_autorunner/static/terminal.js +32 -0
  162. codex_autorunner/static/terminalManager.js +34 -59
  163. codex_autorunner/static/ticketChatActions.js +333 -0
  164. codex_autorunner/static/ticketChatEvents.js +16 -0
  165. codex_autorunner/static/ticketChatStorage.js +16 -0
  166. codex_autorunner/static/ticketChatStream.js +264 -0
  167. codex_autorunner/static/ticketEditor.js +844 -0
  168. codex_autorunner/static/ticketVoice.js +9 -0
  169. codex_autorunner/static/tickets.js +1988 -0
  170. codex_autorunner/static/utils.js +43 -3
  171. codex_autorunner/static/voice.js +1 -0
  172. codex_autorunner/static/workspace.js +765 -0
  173. codex_autorunner/static/workspaceApi.js +53 -0
  174. codex_autorunner/static/workspaceFileBrowser.js +504 -0
  175. codex_autorunner/surfaces/__init__.py +5 -0
  176. codex_autorunner/surfaces/cli/__init__.py +6 -0
  177. codex_autorunner/surfaces/cli/cli.py +1224 -0
  178. codex_autorunner/surfaces/cli/codex_cli.py +20 -0
  179. codex_autorunner/surfaces/telegram/__init__.py +3 -0
  180. codex_autorunner/surfaces/web/__init__.py +1 -0
  181. codex_autorunner/surfaces/web/app.py +2019 -0
  182. codex_autorunner/surfaces/web/hub_jobs.py +192 -0
  183. codex_autorunner/surfaces/web/middleware.py +587 -0
  184. codex_autorunner/surfaces/web/pty_session.py +370 -0
  185. codex_autorunner/surfaces/web/review.py +6 -0
  186. codex_autorunner/surfaces/web/routes/__init__.py +78 -0
  187. codex_autorunner/surfaces/web/routes/agents.py +138 -0
  188. codex_autorunner/surfaces/web/routes/analytics.py +277 -0
  189. codex_autorunner/surfaces/web/routes/app_server.py +132 -0
  190. codex_autorunner/surfaces/web/routes/archive.py +357 -0
  191. codex_autorunner/surfaces/web/routes/base.py +615 -0
  192. codex_autorunner/surfaces/web/routes/file_chat.py +836 -0
  193. codex_autorunner/surfaces/web/routes/flows.py +1164 -0
  194. codex_autorunner/surfaces/web/routes/messages.py +459 -0
  195. codex_autorunner/surfaces/web/routes/repos.py +197 -0
  196. codex_autorunner/surfaces/web/routes/review.py +148 -0
  197. codex_autorunner/surfaces/web/routes/sessions.py +176 -0
  198. codex_autorunner/surfaces/web/routes/settings.py +169 -0
  199. codex_autorunner/surfaces/web/routes/shared.py +280 -0
  200. codex_autorunner/surfaces/web/routes/system.py +196 -0
  201. codex_autorunner/surfaces/web/routes/usage.py +89 -0
  202. codex_autorunner/surfaces/web/routes/voice.py +120 -0
  203. codex_autorunner/surfaces/web/routes/workspace.py +271 -0
  204. codex_autorunner/surfaces/web/runner_manager.py +25 -0
  205. codex_autorunner/surfaces/web/schemas.py +417 -0
  206. codex_autorunner/surfaces/web/static_assets.py +490 -0
  207. codex_autorunner/surfaces/web/static_refresh.py +86 -0
  208. codex_autorunner/surfaces/web/terminal_sessions.py +78 -0
  209. codex_autorunner/tickets/__init__.py +27 -0
  210. codex_autorunner/tickets/agent_pool.py +399 -0
  211. codex_autorunner/tickets/files.py +89 -0
  212. codex_autorunner/tickets/frontmatter.py +55 -0
  213. codex_autorunner/tickets/lint.py +102 -0
  214. codex_autorunner/tickets/models.py +97 -0
  215. codex_autorunner/tickets/outbox.py +244 -0
  216. codex_autorunner/tickets/replies.py +179 -0
  217. codex_autorunner/tickets/runner.py +881 -0
  218. codex_autorunner/tickets/spec_ingest.py +77 -0
  219. codex_autorunner/web/__init__.py +5 -1
  220. codex_autorunner/web/app.py +2 -1771
  221. codex_autorunner/web/hub_jobs.py +2 -191
  222. codex_autorunner/web/middleware.py +2 -587
  223. codex_autorunner/web/pty_session.py +2 -369
  224. codex_autorunner/web/runner_manager.py +2 -24
  225. codex_autorunner/web/schemas.py +2 -396
  226. codex_autorunner/web/static_assets.py +4 -484
  227. codex_autorunner/web/static_refresh.py +2 -85
  228. codex_autorunner/web/terminal_sessions.py +2 -77
  229. codex_autorunner/workspace/__init__.py +40 -0
  230. codex_autorunner/workspace/paths.py +335 -0
  231. codex_autorunner-1.1.0.dist-info/METADATA +154 -0
  232. codex_autorunner-1.1.0.dist-info/RECORD +308 -0
  233. {codex_autorunner-0.1.2.dist-info → codex_autorunner-1.1.0.dist-info}/WHEEL +1 -1
  234. codex_autorunner/agents/execution/policy.py +0 -292
  235. codex_autorunner/agents/factory.py +0 -52
  236. codex_autorunner/agents/orchestrator.py +0 -358
  237. codex_autorunner/core/doc_chat.py +0 -1446
  238. codex_autorunner/core/snapshot.py +0 -580
  239. codex_autorunner/integrations/github/chatops.py +0 -268
  240. codex_autorunner/integrations/github/pr_flow.py +0 -1314
  241. codex_autorunner/routes/docs.py +0 -381
  242. codex_autorunner/routes/github.py +0 -327
  243. codex_autorunner/routes/runs.py +0 -250
  244. codex_autorunner/spec_ingest.py +0 -812
  245. codex_autorunner/static/docChatActions.js +0 -287
  246. codex_autorunner/static/docChatEvents.js +0 -300
  247. codex_autorunner/static/docChatRender.js +0 -205
  248. codex_autorunner/static/docChatStream.js +0 -361
  249. codex_autorunner/static/docs.js +0 -20
  250. codex_autorunner/static/docsClipboard.js +0 -69
  251. codex_autorunner/static/docsCrud.js +0 -257
  252. codex_autorunner/static/docsDocUpdates.js +0 -62
  253. codex_autorunner/static/docsDrafts.js +0 -16
  254. codex_autorunner/static/docsElements.js +0 -69
  255. codex_autorunner/static/docsInit.js +0 -285
  256. codex_autorunner/static/docsParse.js +0 -160
  257. codex_autorunner/static/docsSnapshot.js +0 -87
  258. codex_autorunner/static/docsSpecIngest.js +0 -263
  259. codex_autorunner/static/docsState.js +0 -127
  260. codex_autorunner/static/docsThreadRegistry.js +0 -44
  261. codex_autorunner/static/docsUi.js +0 -153
  262. codex_autorunner/static/docsVoice.js +0 -56
  263. codex_autorunner/static/github.js +0 -504
  264. codex_autorunner/static/logs.js +0 -678
  265. codex_autorunner/static/review.js +0 -157
  266. codex_autorunner/static/runs.js +0 -418
  267. codex_autorunner/static/snapshot.js +0 -124
  268. codex_autorunner/static/state.js +0 -94
  269. codex_autorunner/static/todoPreview.js +0 -27
  270. codex_autorunner/workspace.py +0 -16
  271. codex_autorunner-0.1.2.dist-info/METADATA +0 -249
  272. codex_autorunner-0.1.2.dist-info/RECORD +0 -222
  273. /codex_autorunner/{routes → surfaces/web/routes}/terminal_images.py +0 -0
  274. {codex_autorunner-0.1.2.dist-info → codex_autorunner-1.1.0.dist-info}/entry_points.txt +0 -0
  275. {codex_autorunner-0.1.2.dist-info → codex_autorunner-1.1.0.dist-info}/licenses/LICENSE +0 -0
  276. {codex_autorunner-0.1.2.dist-info → codex_autorunner-1.1.0.dist-info}/top_level.txt +0 -0
@@ -1,52 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import Optional, cast
4
-
5
- from ..core.app_server_events import AppServerEventBuffer
6
- from ..integrations.app_server.supervisor import WorkspaceAppServerSupervisor
7
- from .codex.harness import CodexHarness
8
- from .opencode.harness import OpenCodeHarness
9
- from .opencode.supervisor import OpenCodeSupervisor
10
- from .orchestrator import AgentOrchestrator, CodexOrchestrator, OpenCodeOrchestrator
11
- from .registry import get_agent_descriptor
12
-
13
-
14
- def create_orchestrator(
15
- agent_id: str,
16
- codex_supervisor: Optional[WorkspaceAppServerSupervisor] = None,
17
- codex_events: Optional[AppServerEventBuffer] = None,
18
- opencode_supervisor: Optional[OpenCodeSupervisor] = None,
19
- ) -> AgentOrchestrator:
20
- descriptor = get_agent_descriptor(agent_id)
21
- if descriptor is None:
22
- raise ValueError(f"Unknown agent: {agent_id}")
23
-
24
- class _AppContext:
25
- def __init__(
26
- self,
27
- app_server_supervisor: Optional[WorkspaceAppServerSupervisor] = None,
28
- app_server_events: Optional[AppServerEventBuffer] = None,
29
- opencode_supervisor: Optional[OpenCodeSupervisor] = None,
30
- ):
31
- self.app_server_supervisor = app_server_supervisor
32
- self.app_server_events = app_server_events
33
- self.opencode_supervisor = opencode_supervisor
34
-
35
- app_ctx = _AppContext(codex_supervisor, codex_events, opencode_supervisor)
36
- harness = descriptor.make_harness(app_ctx)
37
-
38
- if agent_id == "codex":
39
- if not isinstance(harness, CodexHarness):
40
- raise RuntimeError(f"Expected CodexHarness but got {type(harness)}")
41
- return CodexOrchestrator(harness, cast(AppServerEventBuffer, codex_events))
42
- elif agent_id == "opencode":
43
- if not isinstance(harness, OpenCodeHarness):
44
- raise RuntimeError(f"Expected OpenCodeHarness but got {type(harness)}")
45
- return OpenCodeOrchestrator(harness)
46
- else:
47
- raise RuntimeError(f"No orchestrator implementation for agent: {agent_id}")
48
-
49
-
50
- __all__ = [
51
- "create_orchestrator",
52
- ]
@@ -1,358 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import logging
4
- from pathlib import Path
5
- from typing import Any, AsyncIterator, Callable, Optional
6
-
7
- from ..core.app_server_events import AppServerEventBuffer
8
- from .codex.harness import CodexHarness
9
- from .opencode.harness import OpenCodeHarness
10
- from .opencode.runtime import collect_opencode_output
11
- from .types import ConversationRef, TurnRef
12
-
13
- _logger = logging.getLogger(__name__)
14
-
15
-
16
- class TurnStatus(str):
17
- PENDING = "pending"
18
- RUNNING = "running"
19
- COMPLETED = "completed"
20
- FAILED = "failed"
21
- INTERRUPTED = "interrupted"
22
- TIMEOUT = "timeout"
23
-
24
-
25
- class AgentOrchestrator:
26
- async def create_or_resume_conversation(
27
- self,
28
- workspace_root: Path,
29
- agent_id: str,
30
- *,
31
- conversation_id: Optional[str] = None,
32
- title: Optional[str] = None,
33
- ) -> ConversationRef:
34
- raise NotImplementedError
35
-
36
- async def run_turn(
37
- self,
38
- workspace_root: Path,
39
- conversation_id: str,
40
- prompt: str,
41
- *,
42
- model: Optional[str] = None,
43
- reasoning: Optional[str] = None,
44
- approval_mode: Optional[str] = None,
45
- sandbox_policy: Optional[Any] = None,
46
- timeout_seconds: Optional[float] = None,
47
- should_stop: Optional[Callable[[], bool]] = None,
48
- ) -> dict[str, Any]:
49
- raise NotImplementedError
50
-
51
- async def stream_turn_events(
52
- self,
53
- workspace_root: Path,
54
- conversation_id: str,
55
- prompt: str,
56
- *,
57
- model: Optional[str] = None,
58
- reasoning: Optional[str] = None,
59
- approval_mode: Optional[str] = None,
60
- sandbox_policy: Optional[Any] = None,
61
- timeout_seconds: Optional[float] = None,
62
- should_stop: Optional[Callable[[], bool]] = None,
63
- ) -> AsyncIterator[dict[str, Any]]:
64
- raise NotImplementedError
65
-
66
- async def interrupt_turn(
67
- self,
68
- workspace_root: Path,
69
- conversation_id: str,
70
- turn_id: Optional[str] = None,
71
- grace_seconds: float = 30.0,
72
- ) -> bool:
73
- raise NotImplementedError
74
-
75
- async def start_review(
76
- self,
77
- workspace_root: Path,
78
- conversation_id: str,
79
- prompt: Optional[str] = None,
80
- *,
81
- model: Optional[str] = None,
82
- reasoning: Optional[str] = None,
83
- approval_mode: Optional[str] = None,
84
- sandbox_policy: Optional[Any] = None,
85
- timeout_seconds: Optional[float] = None,
86
- ) -> TurnRef:
87
- raise NotImplementedError
88
-
89
-
90
- class CodexOrchestrator(AgentOrchestrator):
91
- def __init__(
92
- self,
93
- harness: CodexHarness,
94
- events: AppServerEventBuffer,
95
- ):
96
- self._harness = harness
97
- self._events = events
98
-
99
- async def create_or_resume_conversation(
100
- self,
101
- workspace_root: Path,
102
- agent_id: str,
103
- *,
104
- conversation_id: Optional[str] = None,
105
- title: Optional[str] = None,
106
- ) -> ConversationRef:
107
- if conversation_id:
108
- return await self._harness.resume_conversation(
109
- workspace_root, conversation_id
110
- )
111
- return await self._harness.new_conversation(workspace_root, title)
112
-
113
- async def run_turn(
114
- self,
115
- workspace_root: Path,
116
- conversation_id: str,
117
- prompt: str,
118
- *,
119
- model: Optional[str] = None,
120
- reasoning: Optional[str] = None,
121
- approval_mode: Optional[str] = None,
122
- sandbox_policy: Optional[Any] = None,
123
- timeout_seconds: Optional[float] = None,
124
- should_stop: Optional[Callable[[], bool]] = None,
125
- ) -> dict[str, Any]:
126
- turn_ref = await self._harness.start_turn(
127
- workspace_root,
128
- conversation_id,
129
- prompt,
130
- model,
131
- reasoning,
132
- approval_mode=approval_mode,
133
- sandbox_policy=sandbox_policy,
134
- )
135
-
136
- output_lines = []
137
- async for event_str in self._harness.stream_events(
138
- workspace_root, turn_ref.conversation_id, turn_ref.turn_id
139
- ):
140
- try:
141
- import json
142
-
143
- event = json.loads(event_str)
144
- if "message" in event:
145
- msg = event["message"]
146
- if "params" in msg:
147
- params = msg["params"]
148
- if isinstance(params, dict):
149
- if "output" in params:
150
- output_lines.append(params["output"])
151
- except Exception:
152
- pass
153
-
154
- return {
155
- "turn_id": turn_ref.turn_id,
156
- "conversation_id": turn_ref.conversation_id,
157
- "status": TurnStatus.COMPLETED,
158
- "output": "\n".join(output_lines),
159
- }
160
-
161
- async def stream_turn_events(
162
- self,
163
- workspace_root: Path,
164
- conversation_id: str,
165
- prompt: str,
166
- *,
167
- model: Optional[str] = None,
168
- reasoning: Optional[str] = None,
169
- approval_mode: Optional[str] = None,
170
- sandbox_policy: Optional[Any] = None,
171
- timeout_seconds: Optional[float] = None,
172
- should_stop: Optional[Callable[[], bool]] = None,
173
- ) -> AsyncIterator[dict[str, Any]]:
174
- turn_ref = await self._harness.start_turn(
175
- workspace_root,
176
- conversation_id,
177
- prompt,
178
- model,
179
- reasoning,
180
- approval_mode=approval_mode,
181
- sandbox_policy=sandbox_policy,
182
- )
183
- yield {"type": "turn_started", "data": {"turn_id": turn_ref.turn_id}}
184
-
185
- async for event_str in self._harness.stream_events(
186
- workspace_root, turn_ref.conversation_id, turn_ref.turn_id
187
- ):
188
- yield {"type": "event", "data": event_str}
189
-
190
- yield {"type": "turn_completed", "data": {"turn_id": turn_ref.turn_id}}
191
-
192
- async def interrupt_turn(
193
- self,
194
- workspace_root: Path,
195
- conversation_id: str,
196
- turn_id: Optional[str] = None,
197
- grace_seconds: float = 30.0,
198
- ) -> bool:
199
- await self._harness.interrupt(workspace_root, conversation_id, turn_id)
200
- return True
201
-
202
- async def start_review(
203
- self,
204
- workspace_root: Path,
205
- conversation_id: str,
206
- prompt: Optional[str] = None,
207
- *,
208
- model: Optional[str] = None,
209
- reasoning: Optional[str] = None,
210
- approval_mode: Optional[str] = None,
211
- sandbox_policy: Optional[Any] = None,
212
- timeout_seconds: Optional[float] = None,
213
- ) -> TurnRef:
214
- return await self._harness.start_review(
215
- workspace_root,
216
- conversation_id,
217
- prompt or "",
218
- model,
219
- reasoning,
220
- approval_mode=approval_mode,
221
- sandbox_policy=sandbox_policy,
222
- )
223
-
224
-
225
- class OpenCodeOrchestrator(AgentOrchestrator):
226
- def __init__(
227
- self,
228
- harness: OpenCodeHarness,
229
- ):
230
- self._harness = harness
231
-
232
- async def create_or_resume_conversation(
233
- self,
234
- workspace_root: Path,
235
- agent_id: str,
236
- *,
237
- conversation_id: Optional[str] = None,
238
- title: Optional[str] = None,
239
- ) -> ConversationRef:
240
- if conversation_id:
241
- return await self._harness.resume_conversation(
242
- workspace_root, conversation_id
243
- )
244
- return await self._harness.new_conversation(workspace_root, title)
245
-
246
- async def run_turn(
247
- self,
248
- workspace_root: Path,
249
- conversation_id: str,
250
- prompt: str,
251
- *,
252
- model: Optional[str] = None,
253
- reasoning: Optional[str] = None,
254
- approval_mode: Optional[str] = None,
255
- sandbox_policy: Optional[Any] = None,
256
- timeout_seconds: Optional[float] = None,
257
- should_stop: Optional[Callable[[], bool]] = None,
258
- ) -> dict[str, Any]:
259
- turn_ref = await self._harness.start_turn(
260
- workspace_root,
261
- conversation_id,
262
- prompt,
263
- model,
264
- reasoning,
265
- approval_mode=approval_mode,
266
- sandbox_policy=sandbox_policy,
267
- )
268
-
269
- client = await self._harness._supervisor.get_client(workspace_root)
270
- output_result = await collect_opencode_output(
271
- client,
272
- session_id=conversation_id,
273
- workspace_path=str(workspace_root),
274
- permission_policy=approval_mode or "allow",
275
- question_policy="auto_first_option",
276
- should_stop=should_stop or (lambda: False),
277
- )
278
-
279
- status = TurnStatus.COMPLETED if not output_result.error else TurnStatus.FAILED
280
-
281
- return {
282
- "turn_id": turn_ref.turn_id,
283
- "conversation_id": turn_ref.conversation_id,
284
- "status": status,
285
- "output": output_result.text,
286
- "error": output_result.error,
287
- }
288
-
289
- async def stream_turn_events(
290
- self,
291
- workspace_root: Path,
292
- conversation_id: str,
293
- prompt: str,
294
- *,
295
- model: Optional[str] = None,
296
- reasoning: Optional[str] = None,
297
- approval_mode: Optional[str] = None,
298
- sandbox_policy: Optional[Any] = None,
299
- timeout_seconds: Optional[float] = None,
300
- should_stop: Optional[Callable[[], bool]] = None,
301
- ) -> AsyncIterator[dict[str, Any]]:
302
- turn_ref = await self._harness.start_turn(
303
- workspace_root,
304
- conversation_id,
305
- prompt,
306
- model,
307
- reasoning,
308
- approval_mode=approval_mode,
309
- sandbox_policy=sandbox_policy,
310
- )
311
- yield {"type": "turn_started", "data": {"turn_id": turn_ref.turn_id}}
312
-
313
- async for event_str in self._harness.stream_events(
314
- workspace_root, conversation_id, turn_ref.turn_id
315
- ):
316
- yield {"type": "event", "data": event_str}
317
-
318
- yield {"type": "turn_completed", "data": {"turn_id": turn_ref.turn_id}}
319
-
320
- async def interrupt_turn(
321
- self,
322
- workspace_root: Path,
323
- conversation_id: str,
324
- turn_id: Optional[str] = None,
325
- grace_seconds: float = 30.0,
326
- ) -> bool:
327
- await self._harness.interrupt(workspace_root, conversation_id, turn_id)
328
- return True
329
-
330
- async def start_review(
331
- self,
332
- workspace_root: Path,
333
- conversation_id: str,
334
- prompt: Optional[str] = None,
335
- *,
336
- model: Optional[str] = None,
337
- reasoning: Optional[str] = None,
338
- approval_mode: Optional[str] = None,
339
- sandbox_policy: Optional[Any] = None,
340
- timeout_seconds: Optional[float] = None,
341
- ) -> TurnRef:
342
- return await self._harness.start_review(
343
- workspace_root,
344
- conversation_id,
345
- prompt or "",
346
- model,
347
- reasoning,
348
- approval_mode=approval_mode,
349
- sandbox_policy=sandbox_policy,
350
- )
351
-
352
-
353
- __all__ = [
354
- "AgentOrchestrator",
355
- "CodexOrchestrator",
356
- "OpenCodeOrchestrator",
357
- "TurnStatus",
358
- ]