@jskit-ai/assistant-core 0.2.7 → 0.2.9

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
@@ -0,0 +1,210 @@
1
+ import { codexAppServerTurnStatusIsActive, codexAppServerAgentRun, codexAppServerPendingUserMessageClientIds, codexAppServerTurnOwnsActiveGoal, codexAppServerTurnCanReceiveProviderActivity, codexAppServerTurnCanAdoptSuccessor, codexAppServerTurnKey, CODEX_APP_SERVER_RUN_STATE } from "./codexTurnState.js";
2
+ import { } from "./codexThreadSnapshot.js";
3
+ import { normalizeText } from "@jskit-ai/kernel/shared/support/normalize";
4
+
5
+ /**
6
+ * Records the native activity the provider reports for the tracked turn: a turn that is starting or working, and
7
+ * the provider's own identity for it.
8
+ * @param {object} dependencies
9
+ * @param {import("./codexRunJournal.js").CodexRunJournal} dependencies.journal
10
+ * @param {import("./codexOutput.js").CodexAppServerOutput} dependencies.output
11
+ * @param {import("./codexResultSettlement.js").CodexResultSettlement} dependencies.settlement
12
+ * @param {import("./codexTurn.js").CodexCreateRuntime} dependencies.createRuntime
13
+ * @param {import("./codexTurn.js").CodexCreateStore} dependencies.createStore
14
+ * @param {import("./codexTurn.js").CodexDebugLog} dependencies.debugLog
15
+ * @param {import("./codexTurn.js").CodexTurnStateReader} dependencies.turnState
16
+ * @param {import("./codexTurn.js").CodexAgentRunTurnStateReader} dependencies.turnStateFromAgentRun
17
+ * @param {(sessionId: string, delayMs?: number) => void} dependencies.scheduleActiveRecovery
18
+ */
19
+ export function createCodexTurnActivity({
20
+ journal,
21
+ output,
22
+ settlement,
23
+ createRuntime,
24
+ createStore,
25
+ debugLog,
26
+ turnState,
27
+ turnStateFromAgentRun,
28
+ scheduleActiveRecovery
29
+ }) {
30
+
31
+ async function markCodexAppServerTurnActive(sessionId = "", input = {}) {
32
+ if (input.requireTrackedTurn === true) {
33
+ const runtime = await createRuntime();
34
+ const session = await runtime.getSession(sessionId);
35
+ const turn = turnState(session);
36
+ if (!codexAppServerTurnCanReceiveProviderActivity(turn, input.threadId, input.turnId)) {
37
+ debugLog("appServerTurn.active.ignored", {
38
+ currentState: turn.state,
39
+ currentStatus: turn.status,
40
+ currentThreadId: turn.threadId,
41
+ currentTurnId: turn.turnId,
42
+ sessionId: normalizeText(sessionId),
43
+ threadId: normalizeText(input.threadId),
44
+ turnId: normalizeText(input.turnId)
45
+ });
46
+ return {
47
+ ok: true,
48
+ processed: false,
49
+ reason: "untracked_terminal_turn"
50
+ };
51
+ }
52
+ }
53
+ const status = normalizeText(input.status) || "inProgress";
54
+ const result = await journal.publishAgentRun(sessionId, {
55
+ inputSource: normalizeText(input.inputSource),
56
+ phase: input.phase,
57
+ publishReason: "codex-app-server-turn-active",
58
+ observedRun: input.observedRun,
59
+ runState: status === "starting" ? CODEX_APP_SERVER_RUN_STATE.STARTING : CODEX_APP_SERVER_RUN_STATE.ACTIVE,
60
+ status,
61
+ threadId: normalizeText(input.threadId),
62
+ turnId: normalizeText(input.turnId)
63
+ });
64
+ if (status === "starting") {
65
+ scheduleActiveRecovery(sessionId);
66
+ } else {
67
+ journal.clearActiveTimer(sessionId);
68
+ }
69
+ return result;
70
+ }
71
+
72
+ async function markCodexAppServerProviderTurnActive(sessionId = "", input = {}) {
73
+ const normalizedSessionId = normalizeText(sessionId);
74
+ const normalizedThreadId = normalizeText(input.threadId);
75
+ const normalizedTurnId = normalizeText(input.turnId);
76
+ const requestedStatus = normalizeText(input.status) || "inProgress";
77
+ const store = await createStore(normalizedSessionId);
78
+ const persistedRun = await output.readAgentRunForSession(
79
+ store,
80
+ normalizedSessionId
81
+ );
82
+ const persistedTurn = turnStateFromAgentRun(persistedRun || {});
83
+ const requestedInputSource = normalizeText(input.inputSource);
84
+ if (
85
+ persistedTurn.active &&
86
+ persistedTurn.state === "active" &&
87
+ persistedTurn.threadId === normalizedThreadId &&
88
+ persistedTurn.turnId === normalizedTurnId &&
89
+ codexAppServerTurnStatusIsActive(requestedStatus) &&
90
+ (!requestedInputSource || requestedInputSource === persistedTurn.inputSource)
91
+ ) {
92
+ journal.clearActiveTimer(normalizedSessionId);
93
+ return {
94
+ ok: true,
95
+ processed: false,
96
+ reason: "already_active"
97
+ };
98
+ }
99
+ const runtime = await createRuntime();
100
+ let session = await runtime.getSession(normalizedSessionId);
101
+ let turn = turnState(session);
102
+ if (
103
+ input.observedRun &&
104
+ [CODEX_APP_SERVER_RUN_STATE.FAILED, CODEX_APP_SERVER_RUN_STATE.INTERRUPTED].includes(turn.runState) &&
105
+ turn.threadId === normalizedThreadId &&
106
+ turn.turnId === normalizedTurnId &&
107
+ !journal.turnResultWasProcessed(session, normalizedThreadId, normalizedTurnId)
108
+ ) {
109
+ const recovered = await markCodexAppServerTurnActive(normalizedSessionId, {
110
+ inputSource: turn.inputSource,
111
+ observedRun: input.observedRun,
112
+ status: requestedStatus,
113
+ threadId: normalizedThreadId,
114
+ turnId: normalizedTurnId
115
+ });
116
+ if (recovered.processed !== false) {
117
+ journal.completedTurns.delete(codexAppServerTurnKey(normalizedThreadId, normalizedTurnId));
118
+ output.finalizedTurns.delete(output.resultFinalizationKey(
119
+ normalizedSessionId, normalizedThreadId, normalizedTurnId
120
+ ));
121
+ }
122
+ return recovered;
123
+ }
124
+ if (journal.turnWasCompleted(session, normalizedThreadId, normalizedTurnId)) {
125
+ debugLog("appServerProviderTurn.completed.ignored", {
126
+ currentState: turn.state,
127
+ currentThreadId: turn.threadId,
128
+ currentTurnId: turn.turnId,
129
+ sessionId: normalizedSessionId,
130
+ threadId: normalizedThreadId,
131
+ turnId: normalizedTurnId
132
+ });
133
+ return {
134
+ ok: true,
135
+ processed: false,
136
+ reason: "completed_turn"
137
+ };
138
+ }
139
+ if (
140
+ turn.state === "finalizing" &&
141
+ codexAppServerTurnCanAdoptSuccessor(turn, normalizedThreadId, normalizedTurnId) &&
142
+ journal.turnResultWasProcessed(session, normalizedThreadId, turn.turnId)
143
+ ) {
144
+ await settlement.finalizeAssistantResult(
145
+ normalizedSessionId,
146
+ normalizedThreadId,
147
+ turn.turnId,
148
+ {
149
+ status: turn.status || "completed"
150
+ }
151
+ );
152
+ session = await runtime.getSession(normalizedSessionId);
153
+ turn = turnState(session);
154
+ }
155
+ const currentRun = codexAppServerAgentRun(session);
156
+ const pendingInputSource = codexAppServerPendingUserMessageClientIds(currentRun).length > 0
157
+ ? journal.runInputSource(currentRun)
158
+ : "";
159
+ const goalInputSource = codexAppServerTurnOwnsActiveGoal(turn, normalizedThreadId)
160
+ ? journal.runInputSource(currentRun)
161
+ : "";
162
+ const inputSource = normalizeText(input.inputSource) || pendingInputSource || goalInputSource;
163
+ if (codexAppServerTurnCanReceiveProviderActivity(turn, normalizedThreadId, normalizedTurnId)) {
164
+ return markCodexAppServerTurnActive(normalizedSessionId, {
165
+ inputSource,
166
+ status: requestedStatus,
167
+ threadId: normalizedThreadId,
168
+ turnId: normalizedTurnId
169
+ });
170
+ }
171
+ if (codexAppServerTurnCanAdoptSuccessor(turn, normalizedThreadId, normalizedTurnId)) {
172
+ return settlement.adoptSuccessorTurn(normalizedSessionId, {
173
+ previousTurnId: turn.turnId,
174
+ source: normalizeText(input.source) || "provider_activity",
175
+ status: requestedStatus,
176
+ threadId: normalizedThreadId,
177
+ turnId: normalizedTurnId
178
+ });
179
+ }
180
+ if (turn.active || !normalizedTurnId) {
181
+ debugLog("appServerProviderTurn.active.ignored", {
182
+ currentState: turn.state,
183
+ currentStatus: turn.status,
184
+ currentThreadId: turn.threadId,
185
+ currentTurnId: turn.turnId,
186
+ sessionId: normalizedSessionId,
187
+ threadId: normalizedThreadId,
188
+ turnId: normalizedTurnId
189
+ });
190
+ return {
191
+ ok: true,
192
+ processed: false,
193
+ reason: turn.active ? "active_turn_mismatch" : "missing_turn"
194
+ };
195
+ }
196
+ return markCodexAppServerTurnActive(normalizedSessionId, {
197
+ inputSource: inputSource || "terminal",
198
+ status: requestedStatus,
199
+ threadId: normalizedThreadId,
200
+ turnId: normalizedTurnId
201
+ });
202
+ }
203
+
204
+ return Object.freeze({
205
+ markTurnActive: markCodexAppServerTurnActive,
206
+ markProviderTurnActive: markCodexAppServerProviderTurnActive
207
+ });
208
+ }
209
+
210
+ /** @typedef {ReturnType<typeof createCodexTurnActivity>} CodexTurnActivity */
@@ -1,19 +1,23 @@
1
- import {
2
- codexAppServerTurnStatusIsComplete,
3
- codexAppServerTurnStatusIsProviderFailure,
4
- codexAppServerThreadStatus,
5
- codexAppServerReadThreadStatus,
6
- normalizeCodexRunText,
7
- codexAppServerTurnCanAdoptSuccessor,
8
- codexAppServerInterruptFailure,
9
- codexAppServerInterruptUnavailableResponse,
10
- codexAppServerFrozenTurnInterruptResponse
11
- } from "./codexTurnState.js";
12
- import { codexAppServerRequestIsInvalid } from "./codexProvider.js";
13
- import { codexAppServerThreadTurnId } from "./codexEvents.js";
1
+ import { codexAppServerTurnStatusIsComplete, codexAppServerTurnStatusIsProviderFailure, codexAppServerThreadStatus, codexAppServerReadThreadStatus, codexAppServerTurnCanAdoptSuccessor, codexAppServerInterruptFailure, codexAppServerInterruptUnavailableResponse, codexAppServerFrozenTurnInterruptResponse } from "./codexTurnState.js";
2
+ import { codexAppServerRequestIsInvalid } from "./codexProviderThreads.js";
3
+ import { codexAppServerThreadTurnId } from "./codexThreadSnapshot.js";
4
+ import { normalizeText } from "@jskit-ai/kernel/shared/support/normalize";
14
5
 
15
- // Original user Stop control, including preflight and bounded successor races.
16
- // Existing journal, recovery and status owners retain their state.
6
+ /**
7
+ * The person's Stop of a running turn, including its preflight and bounded successor races. The journal, recovery and
8
+ * status owners keep their state.
9
+ * @param {object} dependencies
10
+ * @param {import("./codexRunJournal.js").CodexRunJournal} dependencies.journal
11
+ * @param {import("./codexResultSettlement.js").CodexResultSettlement} dependencies.settlement
12
+ * @param {import("./codexTurnRecovery.js").CodexTurnRecovery} dependencies.recovery
13
+ * @param {import("./codexThreadStatus.js").CodexThreadStatus} dependencies.threadStatus
14
+ * @param {import("./codexTurn.js").CodexDebugError} dependencies.debugError
15
+ * @param {import("./codexTurn.js").CodexDebugLog} dependencies.debugLog
16
+ * @param {string} dependencies.errorPrefix
17
+ * @param {string} dependencies.interruptFailedCode
18
+ * @param {import("./codexTurn.js").CodexTurnOutcomes} dependencies.turnOutcomes
19
+ * @param {import("./codexTurn.js").CodexTurnStateReader} dependencies.turnState
20
+ */
17
21
  export function createCodexTurnControl({
18
22
  journal,
19
23
  settlement,
@@ -26,23 +30,13 @@ export function createCodexTurnControl({
26
30
  turnOutcomes,
27
31
  turnState
28
32
  }) {
29
- const { turnResultWasProcessed: codexAppServerTurnResultWasProcessed } = journal;
30
- const {
31
- adoptSuccessorTurn: adoptCodexAppServerSuccessorTurn,
32
- finalizeAssistantResult: finalizeCodexAppServerAssistantResult
33
- } = settlement;
34
- const {
35
- stopTurnWithProviderFailure: stopCodexAppServerTurnWithProviderFailure,
36
- completeTurn: completeCodexAppServerTurn
37
- } = recovery;
38
- const { reconcileThreadStatus: reconcileCodexAppServerThreadStatus } = threadStatus;
39
33
 
40
- async function interruptCodexAppServerTurn(sessionId, input = {}, context = {}) {
34
+ async function interruptCodexAppServerTurn(sessionId, input, context = {}) {
41
35
  const { runtime } = context;
42
- const controlRequestId = normalizeCodexRunText(input?.controlRequestId);
36
+ const controlRequestId = normalizeText(input?.controlRequestId);
43
37
  let currentSession = await runtime.getSession(sessionId);
44
38
  let currentTurn = turnState(currentSession);
45
- let threadId = normalizeCodexRunText(currentTurn.threadId) ||
39
+ let threadId = normalizeText(currentTurn.threadId) ||
46
40
  context.threadId(currentSession);
47
41
  let provider = null;
48
42
  let providerPreflight = null;
@@ -72,13 +66,13 @@ export function createCodexTurnControl({
72
66
  providerPreflight = {
73
67
  status: providerStatus,
74
68
  threadId,
75
- turnId: providerTurnId || normalizeCodexRunText(currentTurn.turnId)
69
+ turnId: providerTurnId || normalizeText(currentTurn.turnId)
76
70
  };
77
71
  if (
78
72
  providerTurnId &&
79
73
  codexAppServerTurnCanAdoptSuccessor(currentTurn, threadId, providerTurnId)
80
74
  ) {
81
- await adoptCodexAppServerSuccessorTurn(sessionId, {
75
+ await settlement.adoptSuccessorTurn(sessionId, {
82
76
  previousTurnId: currentTurn.turnId,
83
77
  source: "interrupt_preflight",
84
78
  status: "inProgress",
@@ -100,15 +94,15 @@ export function createCodexTurnControl({
100
94
  for (let attempt = 0; attempt < 3; attempt += 1) {
101
95
  currentSession = await runtime.getSession(sessionId);
102
96
  currentTurn = turnState(currentSession);
103
- threadId = normalizeCodexRunText(currentTurn.threadId) ||
97
+ threadId = normalizeText(currentTurn.threadId) ||
104
98
  context.threadId(currentSession);
105
- const turnId = normalizeCodexRunText(currentTurn.turnId);
99
+ const turnId = normalizeText(currentTurn.turnId);
106
100
  if (context.admissionError()) {
107
101
  return { value: codexAppServerFrozenTurnInterruptResponse({ threadId, turnId }) };
108
102
  }
109
103
  if (currentTurn.state === "finalizing" && threadId) {
110
- if (codexAppServerTurnResultWasProcessed(currentSession, threadId, turnId)) {
111
- await finalizeCodexAppServerAssistantResult(sessionId, threadId, turnId, {
104
+ if (journal.turnResultWasProcessed(currentSession, threadId, turnId)) {
105
+ await settlement.finalizeAssistantResult(sessionId, threadId, turnId, {
112
106
  status: currentTurn.status || "completed"
113
107
  });
114
108
  currentSession = await runtime.getSession(sessionId);
@@ -123,9 +117,9 @@ export function createCodexTurnControl({
123
117
  turnId
124
118
  }, session: currentSession };
125
119
  }
126
- const stoppedThreadId = normalizeCodexRunText(currentTurn.threadId) || threadId;
127
- const stoppedTurnId = normalizeCodexRunText(currentTurn.turnId) || turnId;
128
- const stopped = await stopCodexAppServerTurnWithProviderFailure(
120
+ const stoppedThreadId = normalizeText(currentTurn.threadId) || threadId;
121
+ const stoppedTurnId = normalizeText(currentTurn.turnId) || turnId;
122
+ const stopped = await recovery.stopTurnWithProviderFailure(
129
123
  sessionId,
130
124
  stoppedThreadId,
131
125
  stoppedTurnId,
@@ -202,12 +196,12 @@ export function createCodexTurnControl({
202
196
  codexAppServerTurnStatusIsComplete(providerPreflight.status)
203
197
  ) {
204
198
  if (codexAppServerTurnStatusIsProviderFailure(providerPreflight.status)) {
205
- await stopCodexAppServerTurnWithProviderFailure(sessionId, threadId, turnId, {
199
+ await recovery.stopTurnWithProviderFailure(sessionId, threadId, turnId, {
206
200
  status: providerPreflight.status,
207
201
  verifyInactive: false
208
202
  });
209
203
  } else {
210
- await completeCodexAppServerTurn(sessionId, threadId, turnId, {
204
+ await recovery.completeTurn(sessionId, threadId, turnId, {
211
205
  status: providerPreflight.status,
212
206
  verifyInactive: false
213
207
  });
@@ -222,22 +216,22 @@ export function createCodexTurnControl({
222
216
  }, session: settledSession };
223
217
  }
224
218
  providerPreflight = null;
225
- await reconcileCodexAppServerThreadStatus(sessionId, provider, threadId, {
219
+ await threadStatus.reconcileThreadStatus(sessionId, provider, threadId, {
226
220
  source: "interrupt_race"
227
221
  }).catch(() => null);
228
222
  const reconciledSession = await runtime.getSession(sessionId);
229
223
  const reconciledTurn = turnState(reconciledSession);
230
224
  const successorIsActive = reconciledTurn.active === true &&
231
- normalizeCodexRunText(reconciledTurn.threadId) === threadId &&
232
- Boolean(normalizeCodexRunText(reconciledTurn.turnId)) &&
233
- normalizeCodexRunText(reconciledTurn.turnId) !== turnId;
225
+ normalizeText(reconciledTurn.threadId) === threadId &&
226
+ Boolean(normalizeText(reconciledTurn.turnId)) &&
227
+ normalizeText(reconciledTurn.turnId) !== turnId;
234
228
  if (successorIsActive && attempt < 2) {
235
229
  continue;
236
230
  }
237
231
  const sameTurnIsActive = reconciledTurn.state === "active" &&
238
232
  reconciledTurn.active === true &&
239
- normalizeCodexRunText(reconciledTurn.threadId) === threadId &&
240
- normalizeCodexRunText(reconciledTurn.turnId) === turnId;
233
+ normalizeText(reconciledTurn.threadId) === threadId &&
234
+ normalizeText(reconciledTurn.turnId) === turnId;
241
235
  if (!sameTurnIsActive) {
242
236
  debugLog("appServerInterrupt.alreadyIdle", {
243
237
  controlRequestId,
@@ -278,7 +272,7 @@ export function createCodexTurnControl({
278
272
  turnId
279
273
  } };
280
274
  }
281
- const stopped = await stopCodexAppServerTurnWithProviderFailure(sessionId, threadId, turnId, {
275
+ const stopped = await recovery.stopTurnWithProviderFailure(sessionId, threadId, turnId, {
282
276
  error: "Stopped by user.",
283
277
  ok: true,
284
278
  outcome: turnOutcomes.USER_CANCELLED,
@@ -286,7 +280,7 @@ export function createCodexTurnControl({
286
280
  verifyInactive: false
287
281
  });
288
282
  if (stopped?.reason === "stale_turn_state" && attempt < 2) {
289
- await reconcileCodexAppServerThreadStatus(sessionId, provider, threadId, {
283
+ await threadStatus.reconcileThreadStatus(sessionId, provider, threadId, {
290
284
  source: "interrupt_settlement_race"
291
285
  }).catch(() => null);
292
286
  continue;
@@ -314,5 +308,7 @@ export function createCodexTurnControl({
314
308
  }, interruptFailedCode) };
315
309
  }
316
310
 
317
- return { interruptTurn: interruptCodexAppServerTurn };
311
+ return Object.freeze({ interruptTurn: interruptCodexAppServerTurn });
318
312
  }
313
+
314
+ /** @typedef {ReturnType<typeof createCodexTurnControl>} CodexTurnControl */