@jskit-ai/assistant-core 0.2.7 → 0.2.8

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 (214) hide show
  1. package/examples/conversation/package.json +5 -5
  2. package/package.json +18 -7
  3. package/src/client/browser.js +21 -0
  4. package/src/client/conversation/AssistantAttachmentQueue.vue +25 -108
  5. package/src/client/conversation/AssistantComposerActions.vue +1 -1
  6. package/src/client/conversation/AssistantConversationElement.vue +14 -52
  7. package/src/client/conversation/AssistantGoalControl.vue +13 -10
  8. package/src/client/conversation/AssistantPromptInput.vue +6 -91
  9. package/src/client/conversation/AssistantTranscript.css +505 -0
  10. package/src/client/conversation/AssistantTranscript.vue +24 -1197
  11. package/src/client/conversation/attachmentFiles.js +158 -0
  12. package/src/client/conversation/attachmentQueueItems.js +121 -0
  13. package/src/client/conversation/attachmentUploadRows.js +265 -0
  14. package/src/client/conversation/conversationDisplay.js +54 -0
  15. package/src/client/conversation/messageDelivery.js +13 -9
  16. package/src/client/conversation/retainedConversation.js +14 -3
  17. package/src/client/conversation/submitText.js +13 -2
  18. package/src/client/conversation/transcriptEntries.js +225 -0
  19. package/src/client/conversation/useAssistantAttachments.js +86 -388
  20. package/src/client/conversation/useAssistantQuestions.js +16 -3
  21. package/src/client/conversation/useAssistantSuggestions.js +16 -2
  22. package/src/client/conversation/useScrollToBottom.js +17 -19
  23. package/src/client/conversation/useTextareaAutoGrow.js +115 -0
  24. package/src/client/conversation/useTranscriptScrollFollow.js +525 -0
  25. package/src/client/lib/assistantApi.js +192 -161
  26. package/src/client/types.js +110 -0
  27. package/src/server/conversation/attachments.js +21 -6
  28. package/src/server/conversation/boundedToolLoop.js +1 -0
  29. package/src/server/conversation/claudeClient.js +71 -20
  30. package/src/server/conversation/claudeCommandRun.js +191 -0
  31. package/src/server/conversation/claudeHistory.js +7 -0
  32. package/src/server/conversation/claudeNativeTurn.js +708 -0
  33. package/src/server/conversation/claudeProcess.js +186 -112
  34. package/src/server/conversation/claudeProcessStart.js +214 -0
  35. package/src/server/conversation/claudePromptDelivery.js +183 -0
  36. package/src/server/conversation/claudeSessionCleanup.js +248 -0
  37. package/src/server/conversation/claudeTools.js +15 -3
  38. package/src/server/conversation/claudeTurn.js +212 -1388
  39. package/src/server/conversation/codexAccountReader.js +168 -0
  40. package/src/server/conversation/codexAuthPreflight.js +5 -4
  41. package/src/server/conversation/codexClient.js +18 -6
  42. package/src/server/conversation/codexConfiguration.js +8 -844
  43. package/src/server/conversation/codexConversationStops.js +377 -0
  44. package/src/server/conversation/codexConversationStore.js +119 -85
  45. package/src/server/conversation/codexConversationTurns.js +378 -0
  46. package/src/server/conversation/codexConversations.js +134 -866
  47. package/src/server/conversation/codexDetachedConversation.js +203 -0
  48. package/src/server/conversation/codexDetachedTurn.js +145 -104
  49. package/src/server/conversation/codexEvents.js +5 -200
  50. package/src/server/conversation/codexGoalCommands.js +14 -4
  51. package/src/server/conversation/codexHelperExecution.js +57 -57
  52. package/src/server/conversation/codexHelperThreadLedger.js +30 -288
  53. package/src/server/conversation/codexHelperThreadRecord.js +304 -0
  54. package/src/server/conversation/codexHelperThreadRecovery.js +54 -76
  55. package/src/server/conversation/codexHelperThreads.js +94 -93
  56. package/src/server/conversation/codexHistoryAdapter.js +13 -8
  57. package/src/server/conversation/codexIsolation.js +672 -0
  58. package/src/server/conversation/codexLiveItems.js +379 -0
  59. package/src/server/conversation/codexMessageCommands.js +68 -286
  60. package/src/server/conversation/codexMessageDelivery.js +46 -37
  61. package/src/server/conversation/codexModelCatalog.js +86 -7
  62. package/src/server/conversation/codexNotificationObserver.js +81 -88
  63. package/src/server/conversation/codexNotificationQueue.js +21 -10
  64. package/src/server/conversation/codexObservationControl.js +105 -89
  65. package/src/server/conversation/codexOutput.js +84 -419
  66. package/src/server/conversation/codexProcess.js +29 -1053
  67. package/src/server/conversation/codexProcessLeader.js +1 -0
  68. package/src/server/conversation/codexPromptDispatch.js +241 -0
  69. package/src/server/conversation/codexProvider.js +147 -1807
  70. package/src/server/conversation/codexProviderAuth.js +348 -0
  71. package/src/server/conversation/codexProviderInvalidation.js +371 -0
  72. package/src/server/conversation/codexProviderInventories.js +437 -0
  73. package/src/server/conversation/codexProviderOwner.js +149 -957
  74. package/src/server/conversation/codexProviderRelease.js +465 -0
  75. package/src/server/conversation/codexProviderSelection.js +26 -15
  76. package/src/server/conversation/codexProviderThreads.js +698 -0
  77. package/src/server/conversation/codexProviderTurns.js +453 -0
  78. package/src/server/conversation/codexReasoning.js +32 -23
  79. package/src/server/conversation/codexRenewalCommands.js +18 -6
  80. package/src/server/conversation/codexRenewalThreads.js +7 -22
  81. package/src/server/conversation/codexResultSettlement.js +70 -88
  82. package/src/server/conversation/codexRunJournal.js +91 -97
  83. package/src/server/conversation/codexRuntime.js +426 -0
  84. package/src/server/conversation/codexRuntimeInventory.js +113 -0
  85. package/src/server/conversation/codexRuntimeLifecycle.js +39 -13
  86. package/src/server/conversation/codexRuntimeStart.js +431 -0
  87. package/src/server/conversation/codexRuntimeStop.js +324 -0
  88. package/src/server/conversation/codexSessionCleanup.js +25 -10
  89. package/src/server/conversation/codexSessionReconciliation.js +21 -7
  90. package/src/server/conversation/codexThreadReadiness.js +49 -52
  91. package/src/server/conversation/codexThreadSnapshot.js +210 -0
  92. package/src/server/conversation/codexThreadStatus.js +48 -62
  93. package/src/server/conversation/codexTurn.js +171 -55
  94. package/src/server/conversation/codexTurnActivity.js +210 -0
  95. package/src/server/conversation/codexTurnControl.js +44 -48
  96. package/src/server/conversation/codexTurnEndings.js +610 -0
  97. package/src/server/conversation/codexTurnRecovery.js +97 -848
  98. package/src/server/conversation/codexTurnState.js +138 -111
  99. package/src/server/conversation/completedResponses.js +227 -0
  100. package/src/server/conversation/configuration.js +2 -2
  101. package/src/server/conversation/continuity.js +43 -6
  102. package/src/server/conversation/conversationDelivery.js +394 -0
  103. package/src/server/conversation/conversationEntries.js +365 -0
  104. package/src/server/conversation/conversationEvents.js +192 -0
  105. package/src/server/conversation/conversationGoals.js +187 -0
  106. package/src/server/conversation/conversationHandles.js +237 -0
  107. package/src/server/conversation/conversationReads.js +206 -0
  108. package/src/server/conversation/conversationRefusals.js +58 -0
  109. package/src/server/conversation/conversationReplacement.js +254 -0
  110. package/src/server/conversation/conversationSending.js +273 -0
  111. package/src/server/conversation/conversationStopping.js +121 -0
  112. package/src/server/conversation/conversationTurnDelivery.js +413 -0
  113. package/src/server/conversation/conversationTurns.js +511 -0
  114. package/src/server/conversation/deliveryTiming.js +25 -3
  115. package/src/server/conversation/fileStorage.js +11 -6
  116. package/src/server/conversation/hookBridge.js +14 -3
  117. package/src/server/conversation/index.js +1 -1
  118. package/src/server/conversation/localExecution.js +82 -625
  119. package/src/server/conversation/nativeCommandCallbacks.js +10 -0
  120. package/src/server/conversation/nativeConversationLifecycle.js +379 -0
  121. package/src/server/conversation/nativeHistoryExport.js +27 -18
  122. package/src/server/conversation/normalize.js +9 -0
  123. package/src/server/conversation/openCodeClient.js +295 -366
  124. package/src/server/conversation/openCodeNativeHistory.js +141 -0
  125. package/src/server/conversation/openCodeNativeSession.js +79 -0
  126. package/src/server/conversation/openCodeProcess.js +109 -53
  127. package/src/server/conversation/openCodeProcessOwner.js +565 -0
  128. package/src/server/conversation/openCodeRuntime.js +111 -1814
  129. package/src/server/conversation/openCodeSessionTurns.js +547 -0
  130. package/src/server/conversation/openCodeTemporaryConversations.js +394 -0
  131. package/src/server/conversation/openCodeTools.js +28 -14
  132. package/src/server/conversation/openCodeTurn.js +80 -74
  133. package/src/server/conversation/openCodeTurnMonitor.js +388 -0
  134. package/src/server/conversation/processIdentity.js +582 -0
  135. package/src/server/conversation/provider.js +21 -6
  136. package/src/server/conversation/providers/api.js +268 -107
  137. package/src/server/conversation/providers/claude.js +29 -6
  138. package/src/server/conversation/providers/claudeDriver.js +325 -250
  139. package/src/server/conversation/providers/codex.js +69 -33
  140. package/src/server/conversation/providers/codexDriver.js +503 -1081
  141. package/src/server/conversation/providers/codexDriverConnection.js +331 -0
  142. package/src/server/conversation/providers/codexDriverTurns.js +464 -0
  143. package/src/server/conversation/providers/opencode.js +30 -4
  144. package/src/server/conversation/providers/opencodeDriver.js +321 -659
  145. package/src/server/conversation/providers/opencodeStandalone.js +475 -0
  146. package/src/server/conversation/providers/scoped.js +64 -19
  147. package/src/server/conversation/runtime.js +171 -2863
  148. package/src/server/conversation/storage.js +91 -50
  149. package/src/server/conversation/streams.js +15 -2
  150. package/src/server/conversation/structuredOutput.js +7 -11
  151. package/src/server/conversation/systemPrompt.js +13 -1
  152. package/src/server/conversation/tools.js +47 -15
  153. package/src/server/conversation/transcript.js +49 -20
  154. package/src/server/hosts/claudeTurn.js +2 -4
  155. package/src/server/hosts/codexConfiguration.js +6 -8
  156. package/src/server/hosts/codexEvents.js +4 -2
  157. package/src/server/hosts/codexProcess.js +1 -1
  158. package/src/server/hosts/codexProvider.js +11 -9
  159. package/src/server/hosts/codexTurn.js +3 -3
  160. package/src/server/hosts/openCodeClient.js +4 -2
  161. package/src/server/index.js +0 -2
  162. package/src/server/lib/aiConnectionClient.js +35 -25
  163. package/src/server/lib/ndjson.js +1 -0
  164. package/src/server/lib/providers/anthropicClient.js +15 -6
  165. package/src/server/lib/providers/common.js +10 -6
  166. package/src/server/lib/providers/openAiCompatibleClient.js +40 -23
  167. package/src/server/lib/serviceToolCatalog.js +29 -283
  168. package/src/server/lib/serviceToolEntries.js +270 -0
  169. package/src/server/types.js +78 -0
  170. package/src/shared/assistantResource.js +0 -23
  171. package/src/shared/conversation/answerChoiceSugar.js +2 -14
  172. package/src/shared/conversation/messageInputSugar.js +18 -0
  173. package/src/shared/conversation/numberedQuestionSugar.js +6 -16
  174. package/src/shared/conversation/pagination.js +1 -1
  175. package/src/shared/conversation/questions.js +1 -0
  176. package/src/shared/conversation/streaming.js +1 -0
  177. package/src/shared/index.js +0 -1
  178. package/src/testing/conversationStorageContract.js +20 -0
  179. package/test/aiConnectionClient.test.js +42 -1
  180. package/test/apiConversationDriver.test.js +217 -38
  181. package/test/assistantBoundedToolLoop.test.js +1 -1
  182. package/test/claudeConversationSession.test.js +15 -11
  183. package/test/claudeInstructionResume.test.js +1 -1
  184. package/test/claudeProcess.test.js +9 -9
  185. package/test/claudeTurn.test.js +21 -8
  186. package/test/codexAccountChange.test.js +5 -3
  187. package/test/codexConversationSession.test.js +22 -21
  188. package/test/codexEvents.test.js +3 -1
  189. package/test/codexHelperDeletion.test.js +3 -7
  190. package/test/codexIsolation.test.js +6 -6
  191. package/test/codexModelCatalog.test.js +6 -7
  192. package/test/codexProcess.test.js +3 -3
  193. package/test/codexThreadSelection.test.js +4 -1
  194. package/test/codexTurn.test.js +29 -20
  195. package/test/conversationApiFacilities.test.js +11 -9
  196. package/test/conversationAttachments.test.js +3 -3
  197. package/test/conversationConfiguration.test.js +4 -4
  198. package/test/conversationNativeStorage.test.js +11 -10
  199. package/test/conversationReplacement.test.js +13 -13
  200. package/test/conversationRuntime.test.js +9 -5
  201. package/test/conversationSession.test.js +78 -22
  202. package/test/conversationTools.test.js +47 -26
  203. package/test/fileConversationStorage.test.js +10 -3
  204. package/test/fixtures/codexHelperThreadLedger.js +3 -3
  205. package/test/frameworkActions.test.js +33 -18
  206. package/test/localConversationExecution.test.js +4 -4
  207. package/test/localExecution.test.js +1 -1
  208. package/test/openCodeConnectionChange.test.js +3 -2
  209. package/test/openCodeRuntime.test.js +8 -7
  210. package/test/openCodeTools.test.js +1 -1
  211. package/test/opencodeConversationSession.test.js +4 -3
  212. package/test/serviceToolCatalog.test.js +3 -8
  213. package/src/server/lib/assistantCompletion.js +0 -190
  214. package/src/server/lib/assistantToolLoop.js +0 -259
@@ -8,8 +8,20 @@ import {
8
8
  CODEX_APP_SERVER_RUN_STATE
9
9
  } from "./codexTurnState.js";
10
10
 
11
- // Original observation-loss barriers, stop settlement and saved-stop inspection.
12
- // The shared conversation registry and journal remain their existing owners.
11
+ /**
12
+ * Observation-loss barriers, stop settlement and saved-stop inspection. The conversation registry and the run
13
+ * journal own the state they change.
14
+ * @param {object} dependencies
15
+ * @param {import("./codexConversations.js").CodexConversationCommands} dependencies.conversations
16
+ * @param {import("./codexOutput.js").CodexAppServerOutput} dependencies.output
17
+ * @param {import("./codexRunJournal.js").CodexRunJournal} dependencies.journal
18
+ * @param {import("./codexTurn.js").CodexSessionNamespace} dependencies.namespace
19
+ * @param {import("./codexTurn.js").CodexCreateRuntime} dependencies.createRuntime
20
+ * @param {import("./codexTurn.js").CodexPublish} dependencies.publish
21
+ * @param {import("./codexTurn.js").CodexRunInContext} dependencies.runInContext
22
+ * @param {import("./codexTurn.js").CodexTurnStateReader} dependencies.turnState
23
+ * @param {string} dependencies.errorPrefix
24
+ */
13
25
  export function createCodexObservationControl({
14
26
  conversations,
15
27
  output,
@@ -22,11 +34,6 @@ export function createCodexObservationControl({
22
34
  errorPrefix
23
35
  }) {
24
36
  const { codexAppServerConversations } = conversations;
25
- const { readAgentRunForSession: readCodexAppServerAgentRunForSession } = output;
26
- const {
27
- agentRunRealtimePayload: codexAppServerAgentRunRealtimePayload,
28
- clearActiveTimer: clearCodexAppServerActiveTimer
29
- } = journal;
30
37
 
31
38
  function assertCodexAppServerThreadCanResume(run, threadId) {
32
39
  if (run?.providerThreadId === threadId && run.providerStatus === "observation_lost") {
@@ -38,90 +45,97 @@ export function createCodexObservationControl({
38
45
 
39
46
  function createCodexAppServerObservation(sessionId, context = {}) {
40
47
  const { projectContext, target, retireProvider } = context;
41
- return {
42
- prepare({ provider, error, threadIds }) {
43
- return runInContext(projectContext, async () => {
44
- const managed = target(error);
45
- const threads = new Map();
46
- for (const entry of codexAppServerConversations.get(namespace(sessionId))?.values() || []) {
47
- if (entry.provider !== provider || threadIds && !threadIds.includes(entry.conversationId)) continue;
48
- threads.set(entry.conversationId, entry.runId);
49
- if (codexAppServerConversationTurnIsActive(entry.status) || entry.goal?.status === "active") {
50
- entry.error = managed.pendingMessage;
51
- }
52
- }
53
- // A helper owns only its own threads. Main chat belongs to its managed provider.
54
- if (managed.threadId && (!threadIds || threadIds.includes(managed.threadId))) {
55
- const runtime = await createRuntime();
56
- const turn = turnState(await runtime.getSession(sessionId));
57
- threads.set(managed.threadId, turn.turnId);
58
- if (turn.active || codexAppServerTurnOwnsActiveGoal(turn, managed.threadId)) {
59
- await runtime.store.writeAgentRunEvent(sessionId, CODEX_APP_SERVER_AGENT_RUN_ID, {
60
- event: { kind: "observation-lost", message: error.message },
61
- patch: { providerStatus: "observation_lost", error: managed.pendingMessage }
62
- });
63
- await publish(sessionId, { reason: "codex-observation-lost" });
64
- }
48
+
49
+ function prepare({ provider, error, threadIds }) {
50
+ return runInContext(projectContext, async () => {
51
+ const managed = target(error);
52
+ const threads = new Map();
53
+ for (const entry of codexAppServerConversations.get(namespace(sessionId))?.values() || []) {
54
+ if (entry.provider !== provider || threadIds && !threadIds.includes(entry.conversationId)) continue;
55
+ threads.set(entry.conversationId, entry.runId);
56
+ if (codexAppServerConversationTurnIsActive(entry.status) || entry.goal?.status === "active") {
57
+ entry.error = managed.pendingMessage;
65
58
  }
66
- return threads;
67
- });
68
- },
69
- barrier({ error, threadIds }) {
70
- return runInContext(projectContext, async () => {
71
- const managed = target(error);
72
- if (!managed.threadId || threadIds && !threadIds.includes(managed.threadId)) return;
59
+ }
60
+ // A helper owns only its own threads. Main chat belongs to its managed provider.
61
+ if (managed.threadId && (!threadIds || threadIds.includes(managed.threadId))) {
73
62
  const runtime = await createRuntime();
74
63
  const turn = turnState(await runtime.getSession(sessionId));
75
- if (!turn.active && !codexAppServerTurnOwnsActiveGoal(turn, managed.threadId)) return;
76
- await runtime.store.writeAgentRunEvent(sessionId, CODEX_APP_SERVER_AGENT_RUN_ID, {
77
- event: { kind: "observation-lost", message: error.message },
78
- patch: { providerStatus: "observation_lost", error: managed.pendingMessage }
79
- });
80
- });
81
- },
82
- complete({ provider, error, sharedStop, threadIds }) {
83
- return runInContext(projectContext, async () => {
84
- const managed = target(error);
85
- let stoppedRun = null;
86
- let conversationStream = null;
87
- if (managed.threadId && (!threadIds || threadIds.includes(managed.threadId))) {
88
- const runtime = await createRuntime();
89
- stoppedRun = await runtime.store.mutateSession(sessionId, async () => {
90
- const run = await readCodexAppServerAgentRunForSession(runtime.store, sessionId);
91
- if (run?.providerThreadId !== managed.threadId || run.providerStatus !== "observation_lost") return null;
92
- const stopped = await runtime.store.writeAgentRunEvent(sessionId, CODEX_APP_SERVER_AGENT_RUN_ID, {
93
- event: { kind: "codex-observation-stopped", state: CODEX_APP_SERVER_RUN_STATE.INTERRUPTED },
94
- patch: {
95
- error: sharedStop ? `${managed.message} Its shared service was stopped, affecting other sessions using it.` : managed.message,
96
- providerStatus: "observation_lost", state: CODEX_APP_SERVER_RUN_STATE.INTERRUPTED
97
- }
98
- });
99
- conversationStream = runtime.store.clearConversationStream(sessionId);
100
- return stopped;
64
+ threads.set(managed.threadId, turn.turnId);
65
+ if (turn.active || codexAppServerTurnOwnsActiveGoal(turn, managed.threadId)) {
66
+ await runtime.store.writeAgentRunEvent(sessionId, CODEX_APP_SERVER_AGENT_RUN_ID, {
67
+ event: { kind: "observation-lost", message: error.message },
68
+ patch: { providerStatus: "observation_lost", error: managed.pendingMessage }
101
69
  });
70
+ await publish(sessionId, { reason: "codex-observation-lost" });
102
71
  }
103
- // Retain the stop owner until the stopped state is durable. Make the
104
- // provider ready for explicit control before publishing that state.
105
- if (sharedStop) await retireProvider(provider);
106
- else provider.observationFailure = null;
107
- for (const entry of codexAppServerConversations.get(namespace(sessionId))?.values() || []) {
108
- if (entry.provider === provider && (!threadIds || threadIds.includes(entry.conversationId)) && (
109
- codexAppServerConversationTurnIsActive(entry.status) || entry.goal?.status === "active"
110
- )) {
111
- entry.status = "interrupted";
112
- entry.error = managed.message;
113
- entry.watcher?.failNow(error);
114
- }
115
- }
116
- if (stoppedRun) {
117
- await publish(sessionId, {
118
- payload: { ...codexAppServerAgentRunRealtimePayload(stoppedRun), conversationStream },
119
- reason: "codex-observation-stopped"
72
+ }
73
+ return threads;
74
+ });
75
+ }
76
+
77
+ function barrier({ error, threadIds }) {
78
+ return runInContext(projectContext, async () => {
79
+ const managed = target(error);
80
+ if (!managed.threadId || threadIds && !threadIds.includes(managed.threadId)) return;
81
+ const runtime = await createRuntime();
82
+ const turn = turnState(await runtime.getSession(sessionId));
83
+ if (!turn.active && !codexAppServerTurnOwnsActiveGoal(turn, managed.threadId)) return;
84
+ await runtime.store.writeAgentRunEvent(sessionId, CODEX_APP_SERVER_AGENT_RUN_ID, {
85
+ event: { kind: "observation-lost", message: error.message },
86
+ patch: { providerStatus: "observation_lost", error: managed.pendingMessage }
87
+ });
88
+ });
89
+ }
90
+
91
+ function complete({ provider, error, sharedStop, threadIds }) {
92
+ return runInContext(projectContext, async () => {
93
+ const managed = target(error);
94
+ let stoppedRun = null;
95
+ let conversationStream = null;
96
+ if (managed.threadId && (!threadIds || threadIds.includes(managed.threadId))) {
97
+ const runtime = await createRuntime();
98
+ stoppedRun = await runtime.store.mutateSession(sessionId, async () => {
99
+ const run = await output.readAgentRunForSession(runtime.store, sessionId);
100
+ if (run?.providerThreadId !== managed.threadId || run.providerStatus !== "observation_lost") return null;
101
+ const stopped = await runtime.store.writeAgentRunEvent(sessionId, CODEX_APP_SERVER_AGENT_RUN_ID, {
102
+ event: { kind: "codex-observation-stopped", state: CODEX_APP_SERVER_RUN_STATE.INTERRUPTED },
103
+ patch: {
104
+ error: sharedStop ? `${managed.message} Its shared service was stopped, affecting other sessions using it.` : managed.message,
105
+ providerStatus: "observation_lost", state: CODEX_APP_SERVER_RUN_STATE.INTERRUPTED
106
+ }
120
107
  });
108
+ conversationStream = runtime.store.clearConversationStream(sessionId);
109
+ return stopped;
110
+ });
111
+ }
112
+ // Retain the stop owner until the stopped state is durable. Make the
113
+ // provider ready for explicit control before publishing that state.
114
+ if (sharedStop) await retireProvider(provider);
115
+ else provider.observationFailure = null;
116
+ for (const entry of codexAppServerConversations.get(namespace(sessionId))?.values() || []) {
117
+ if (entry.provider === provider && (!threadIds || threadIds.includes(entry.conversationId)) && (
118
+ codexAppServerConversationTurnIsActive(entry.status) || entry.goal?.status === "active"
119
+ )) {
120
+ entry.status = "interrupted";
121
+ entry.error = managed.message;
122
+ entry.watcher?.failNow(error);
121
123
  }
122
- });
123
- }
124
- };
124
+ }
125
+ if (stoppedRun) {
126
+ await publish(sessionId, {
127
+ payload: { ...journal.agentRunRealtimePayload(stoppedRun), conversationStream },
128
+ reason: "codex-observation-stopped"
129
+ });
130
+ }
131
+ });
132
+ }
133
+
134
+ return Object.freeze({
135
+ prepare,
136
+ barrier,
137
+ complete
138
+ });
125
139
  }
126
140
 
127
141
  async function recoverCodexAppServerObservationLoss(runtime, session, context = {}) {
@@ -140,7 +154,7 @@ export function createCodexObservationControl({
140
154
  if (!codexAppServerTurnStatusIsSuccessfulComplete(status)) return current;
141
155
 
142
156
  const stoppedRun = await runtime.store.mutateSession(sessionId, async () => {
143
- const latest = await readCodexAppServerAgentRunForSession(runtime.store, sessionId);
157
+ const latest = await output.readAgentRunForSession(runtime.store, sessionId);
144
158
  if (JSON.stringify(latest) !== JSON.stringify(codexAppServerAgentRun(current))) return null;
145
159
  return runtime.store.writeAgentRunEvent(sessionId, CODEX_APP_SERVER_AGENT_RUN_ID, {
146
160
  event: { kind: "codex-observation-stop-recovered", message: "Codex confirmed that the conversation is stopped." },
@@ -154,10 +168,10 @@ export function createCodexObservationControl({
154
168
  });
155
169
  });
156
170
  if (stoppedRun) {
157
- clearCodexAppServerActiveTimer(sessionId);
171
+ journal.clearActiveTimer(sessionId);
158
172
  await publish(sessionId, {
159
173
  payload: {
160
- ...codexAppServerAgentRunRealtimePayload(stoppedRun),
174
+ ...journal.agentRunRealtimePayload(stoppedRun),
161
175
  conversationStream: runtime.store.clearConversationStream(sessionId)
162
176
  },
163
177
  reason: "codex-observation-stop-recovered"
@@ -166,9 +180,11 @@ export function createCodexObservationControl({
166
180
  return runtime.getSession(sessionId);
167
181
  }
168
182
 
169
- return {
183
+ return Object.freeze({
170
184
  assertThreadCanResume: assertCodexAppServerThreadCanResume,
171
185
  createObservation: createCodexAppServerObservation,
172
186
  recoverObservationLoss: recoverCodexAppServerObservationLoss
173
- };
187
+ });
174
188
  }
189
+
190
+ /** @typedef {ReturnType<typeof createCodexObservationControl>} CodexObservationControl */