@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
@@ -1,44 +1,29 @@
1
- import {
2
- codexAppServerTurnStatusIsActive,
3
- codexAppServerTurnStatusIsComplete,
4
- codexAppServerTurnStatusIsSuccessfulComplete,
5
- codexAppServerTurnStatusIsProviderFailure,
6
- codexAppServerThreadStatus,
7
- codexAppServerReadThreadStatus,
8
- normalizeCodexRunText,
9
- codexAppServerAgentRun,
10
- codexAppServerTurnCanReceiveProviderCompletion,
11
- codexAppServerTurnCanAdoptSuccessor,
12
- codexAppServerErrorMessage
13
- } from "./codexTurnState.js";
14
- import { isRecord } from "@jskit-ai/kernel/shared/support/normalize";
15
- import {
16
- codexAppServerStatusFromValue,
17
- codexAppServerThreadRawValue,
18
- codexAppServerThreadTurnId,
19
- codexAppServerThreadError
20
- } from "./codexEvents.js";
1
+ import { codexAppServerTurnStatusIsActive, codexAppServerTurnStatusIsComplete, codexAppServerTurnStatusIsSuccessfulComplete, codexAppServerTurnStatusIsProviderFailure, codexAppServerThreadStatus, codexAppServerReadThreadStatus, codexAppServerAgentRun, codexAppServerTurnCanReceiveProviderCompletion, codexAppServerTurnCanAdoptSuccessor, codexAppServerErrorMessage } from "./codexTurnState.js";
2
+ import { isRecord, normalizeText } from "@jskit-ai/kernel/shared/support/normalize";
3
+ import { codexAppServerStatusFromValue } from "./codexEvents.js";
4
+ import { codexAppServerThreadRawValue, codexAppServerThreadTurnId, codexAppServerThreadError } from "./codexThreadSnapshot.js";
21
5
 
22
- // Native thread snapshot reconciliation; it holds no state of its own.
6
+ /**
7
+ * Native thread snapshot reconciliation; it holds no state of its own.
8
+ * @param {object} dependencies
9
+ * @param {import("./codexRunJournal.js").CodexRunJournal} dependencies.journal
10
+ * @param {import("./codexResultSettlement.js").CodexResultSettlement} dependencies.settlement
11
+ * @param {import("./codexTurnRecovery.js").CodexTurnRecovery} dependencies.recovery
12
+ * @param {import("./codexOutput.js").CodexAppServerOutput} dependencies.output
13
+ * @param {import("./codexTurn.js").CodexCreateRuntime} dependencies.createRuntime
14
+ * @param {import("./codexTurn.js").CodexTurnStateReader} dependencies.turnState
15
+ * @param {import("./codexTurn.js").CodexTurnOutcomes} dependencies.turnOutcomes
16
+ * @param {import("./codexTurn.js").CodexDebugLog} dependencies.debugLog
17
+ * @param {import("./codexTurn.js").CodexDebugError} dependencies.debugError
18
+ */
23
19
  export function createCodexThreadStatus({ journal, settlement, recovery, output, createRuntime, turnState, turnOutcomes, debugLog, debugError }) {
24
- const { turnResultWasProcessed: codexAppServerTurnResultWasProcessed } = journal;
25
- const {
26
- finalizeAssistantResult: finalizeCodexAppServerAssistantResult,
27
- adoptSuccessorTurn: adoptCodexAppServerSuccessorTurn
28
- } = settlement;
29
- const {
30
- stopTurnWithProviderFailure: stopCodexAppServerTurnWithProviderFailure,
31
- markProviderTurnActive: markCodexAppServerProviderTurnActive,
32
- completeTurn: completeCodexAppServerTurn
33
- } = recovery;
34
- const { reconcileObservedTurnItems: reconcileCodexAppServerObservedTurnItems } = output;
35
20
 
36
21
  function codexAppServerReadyTurnFailureMessage(reason = "", error = "") {
37
- const detail = normalizeCodexRunText(error);
22
+ const detail = normalizeText(error);
38
23
  if (detail) {
39
24
  return detail;
40
25
  }
41
- switch (normalizeCodexRunText(reason)) {
26
+ switch (normalizeText(reason)) {
42
27
  case "thread_replaced":
43
28
  return "Codex app-server resumed a different thread before this turn completed.";
44
29
  case "provider_unreadable":
@@ -61,9 +46,9 @@ export function createCodexThreadStatus({ journal, settlement, recovery, output,
61
46
  threadId = "",
62
47
  turnId = ""
63
48
  } = {}) {
64
- const normalizedSessionId = normalizeCodexRunText(sessionId);
65
- const normalizedThreadId = normalizeCodexRunText(threadId) || normalizeCodexRunText(turn.threadId);
66
- const normalizedTurnId = normalizeCodexRunText(turnId) || normalizeCodexRunText(turn.turnId);
49
+ const normalizedSessionId = normalizeText(sessionId);
50
+ const normalizedThreadId = normalizeText(threadId) || normalizeText(turn.threadId);
51
+ const normalizedTurnId = normalizeText(turnId) || normalizeText(turn.turnId);
67
52
  if (!normalizedSessionId || !normalizedThreadId) {
68
53
  return {
69
54
  ok: false,
@@ -71,7 +56,7 @@ export function createCodexThreadStatus({ journal, settlement, recovery, output,
71
56
  reason: "missing_tracked_turn"
72
57
  };
73
58
  }
74
- return stopCodexAppServerTurnWithProviderFailure(
59
+ return recovery.stopTurnWithProviderFailure(
75
60
  normalizedSessionId,
76
61
  normalizedThreadId,
77
62
  normalizedTurnId,
@@ -89,8 +74,8 @@ export function createCodexThreadStatus({ journal, settlement, recovery, output,
89
74
  requireTrackedTurn = false,
90
75
  source = ""
91
76
  } = {}) {
92
- const normalizedSessionId = normalizeCodexRunText(sessionId);
93
- const normalizedThreadId = normalizeCodexRunText(threadId);
77
+ const normalizedSessionId = normalizeText(sessionId);
78
+ const normalizedThreadId = normalizeText(threadId);
94
79
  const runtime = normalizedSessionId
95
80
  ? await createRuntime()
96
81
  : null;
@@ -107,7 +92,7 @@ export function createCodexThreadStatus({ journal, settlement, recovery, output,
107
92
  trackedTurn.threadId
108
93
  ? trackedTurn
109
94
  : null;
110
- const statusThreadId = normalizeCodexRunText(trackedProviderTurn?.threadId) || normalizedThreadId;
95
+ const statusThreadId = normalizeText(trackedProviderTurn?.threadId) || normalizedThreadId;
111
96
  const shouldFailUnconfirmed = failUnconfirmedTrackedTurn && trackedProviderTurn;
112
97
  if (!normalizedSessionId || !normalizedThreadId) {
113
98
  return {
@@ -123,13 +108,13 @@ export function createCodexThreadStatus({ journal, settlement, recovery, output,
123
108
  }
124
109
  if (
125
110
  trackedProviderTurn?.state === "finalizing" &&
126
- codexAppServerTurnResultWasProcessed(
111
+ journal.turnResultWasProcessed(
127
112
  session,
128
113
  trackedProviderTurn.threadId,
129
114
  trackedProviderTurn.turnId
130
115
  )
131
116
  ) {
132
- await finalizeCodexAppServerAssistantResult(
117
+ await settlement.finalizeAssistantResult(
133
118
  normalizedSessionId,
134
119
  trackedProviderTurn.threadId,
135
120
  trackedProviderTurn.turnId,
@@ -148,7 +133,7 @@ export function createCodexThreadStatus({ journal, settlement, recovery, output,
148
133
  debugLog("appServerThread.reconcile.trackedThreadReplaced", {
149
134
  currentThreadId: normalizedThreadId,
150
135
  sessionId: normalizedSessionId,
151
- source: normalizeCodexRunText(source),
136
+ source: normalizeText(source),
152
137
  trackedThreadId: statusThreadId,
153
138
  trackedTurnId: trackedProviderTurn.turnId
154
139
  });
@@ -157,7 +142,7 @@ export function createCodexThreadStatus({ journal, settlement, recovery, output,
157
142
  });
158
143
  }
159
144
 
160
- if (typeof provider?.readThreadStatus !== "function") {
145
+ if (!provider) {
161
146
  if (shouldFailUnconfirmed) {
162
147
  return failCodexAppServerTrackedReadyTurn(normalizedSessionId, trackedProviderTurn, {
163
148
  reason: "provider_unreadable"
@@ -179,7 +164,7 @@ export function createCodexThreadStatus({ journal, settlement, recovery, output,
179
164
  debugLog("appServerThread.reconcile.readFailed", {
180
165
  error: debugError(error),
181
166
  sessionId: normalizedSessionId,
182
- source: normalizeCodexRunText(source),
167
+ source: normalizeText(source),
183
168
  threadId: statusThreadId,
184
169
  turnId: trackedProviderTurn.turnId
185
170
  });
@@ -220,9 +205,9 @@ export function createCodexThreadStatus({ journal, settlement, recovery, output,
220
205
  turnId &&
221
206
  codexAppServerTurnCanAdoptSuccessor(trackedProviderTurn, statusThreadId, turnId)
222
207
  ) {
223
- const adoption = await adoptCodexAppServerSuccessorTurn(normalizedSessionId, {
208
+ const adoption = await settlement.adoptSuccessorTurn(normalizedSessionId, {
224
209
  previousTurnId: trackedProviderTurn.turnId,
225
- source: normalizeCodexRunText(source) || "thread_status",
210
+ source: normalizeText(source) || "thread_status",
226
211
  status: "inProgress",
227
212
  threadId: statusThreadId,
228
213
  turnId
@@ -246,7 +231,7 @@ export function createCodexThreadStatus({ journal, settlement, recovery, output,
246
231
  debugLog("appServerThread.reconcile.activeWithoutTurn", {
247
232
  sessionId: normalizedSessionId,
248
233
  status,
249
- source: normalizeCodexRunText(source),
234
+ source: normalizeText(source),
250
235
  threadId: statusThreadId,
251
236
  trackedTurnId: trackedProviderTurn?.turnId || ""
252
237
  });
@@ -255,16 +240,16 @@ export function createCodexThreadStatus({ journal, settlement, recovery, output,
255
240
  status
256
241
  };
257
242
  }
258
- await markCodexAppServerProviderTurnActive(normalizedSessionId, {
243
+ await recovery.markProviderTurnActive(normalizedSessionId, {
259
244
  observedRun: codexAppServerTurnStatusIsActive(codexAppServerStatusFromValue(
260
245
  codexAppServerThreadRawValue(thread).status || thread.status
261
246
  )) ? codexAppServerAgentRun(session) : null,
262
- source: normalizeCodexRunText(source) || "thread_status",
247
+ source: normalizeText(source) || "thread_status",
263
248
  status,
264
249
  threadId: statusThreadId,
265
250
  turnId
266
251
  });
267
- await reconcileCodexAppServerObservedTurnItems(
252
+ await output.reconcileObservedTurnItems(
268
253
  normalizedSessionId,
269
254
  statusThreadId,
270
255
  thread?.observedTurn,
@@ -283,10 +268,10 @@ export function createCodexThreadStatus({ journal, settlement, recovery, output,
283
268
  ) {
284
269
  const currentSession = await runtime.getSession(normalizedSessionId);
285
270
  const currentTurn = turnState(currentSession);
286
- if (!currentTurn.active && normalizeCodexRunText(currentTurn.turnId) !== turnId) {
287
- await markCodexAppServerProviderTurnActive(normalizedSessionId, {
271
+ if (!currentTurn.active && normalizeText(currentTurn.turnId) !== turnId) {
272
+ await recovery.markProviderTurnActive(normalizedSessionId, {
288
273
  inputSource: "terminal",
289
- source: normalizeCodexRunText(source) || "thread_snapshot",
274
+ source: normalizeText(source) || "thread_snapshot",
290
275
  status: "inProgress",
291
276
  threadId: statusThreadId,
292
277
  turnId
@@ -298,7 +283,7 @@ export function createCodexThreadStatus({ journal, settlement, recovery, output,
298
283
  statusThreadId,
299
284
  turnId
300
285
  )) {
301
- await reconcileCodexAppServerObservedTurnItems(
286
+ await output.reconcileObservedTurnItems(
302
287
  normalizedSessionId,
303
288
  statusThreadId,
304
289
  thread.observedTurn,
@@ -306,7 +291,7 @@ export function createCodexThreadStatus({ journal, settlement, recovery, output,
306
291
  );
307
292
  }
308
293
  }
309
- const completedTurnId = turnId || normalizeCodexRunText(trackedProviderTurn?.turnId);
294
+ const completedTurnId = turnId || normalizeText(trackedProviderTurn?.turnId);
310
295
  if (!completedTurnId) {
311
296
  return {
312
297
  ok: true,
@@ -314,13 +299,13 @@ export function createCodexThreadStatus({ journal, settlement, recovery, output,
314
299
  };
315
300
  }
316
301
  if (codexAppServerTurnStatusIsProviderFailure(status)) {
317
- await stopCodexAppServerTurnWithProviderFailure(normalizedSessionId, statusThreadId, completedTurnId, {
302
+ await recovery.stopTurnWithProviderFailure(normalizedSessionId, statusThreadId, completedTurnId, {
318
303
  error: codexAppServerThreadError(thread),
319
304
  provider,
320
305
  status
321
306
  });
322
307
  } else if (codexAppServerTurnStatusIsSuccessfulComplete(status)) {
323
- await completeCodexAppServerTurn(normalizedSessionId, statusThreadId, completedTurnId, {
308
+ await recovery.completeTurn(normalizedSessionId, statusThreadId, completedTurnId, {
324
309
  status,
325
310
  verifyInactive: false
326
311
  });
@@ -346,9 +331,10 @@ export function createCodexThreadStatus({ journal, settlement, recovery, output,
346
331
  });
347
332
  }
348
333
 
349
-
350
- return {
334
+ return Object.freeze({
351
335
  reconcileThreadStatus: reconcileCodexAppServerThreadStatus,
352
336
  reconcileLoadedThreadStatus: reconcileCodexAppServerLoadedThreadStatus
353
- };
337
+ });
354
338
  }
339
+
340
+ /** @typedef {ReturnType<typeof createCodexThreadStatus>} CodexThreadStatus */
@@ -2,6 +2,7 @@ import { createCodexSessionReconciliation } from "./codexSessionReconciliation.j
2
2
  import { createCodexRuntimeLifecycle } from "./codexRuntimeLifecycle.js";
3
3
  import { createCodexSessionCleanup } from "./codexSessionCleanup.js";
4
4
  import { createCodexMessageCommands } from "./codexMessageCommands.js";
5
+ import { createCodexPromptDispatch } from "./codexPromptDispatch.js";
5
6
  import { createCodexTurnControl } from "./codexTurnControl.js";
6
7
  import { createCodexObservationControl } from "./codexObservationControl.js";
7
8
  import { createCodexThreadReadiness } from "./codexThreadReadiness.js";
@@ -16,14 +17,10 @@ import { createCodexProviderSelection } from "./codexProviderSelection.js";
16
17
  import { createCodexAppServerMessageDelivery } from "./codexMessageDelivery.js";
17
18
  import { createCodexConversationCommands } from "./codexConversations.js";
18
19
  import { createCodexAppServerOutput } from "./codexOutput.js";
19
- import {
20
- normalizeCodexRunText,
21
- normalizeCodexAppServerRunState,
22
- codexAppServerTurnStateFromAgentRun,
23
- codexAppServerTurnState
24
- } from "./codexTurnState.js";
20
+ import { normalizeCodexAppServerRunState, codexAppServerTurnStateFromAgentRun, codexAppServerTurnState } from "./codexTurnState.js";
25
21
 
26
22
  import { createCodexAppServerNotificationQueue } from "./codexNotificationQueue.js";
23
+ import { normalizeText } from "@jskit-ai/kernel/shared/support/normalize";
27
24
  export {
28
25
  CODEX_APP_SERVER_RUN_STATE,
29
26
  normalizeCodexAppServerRunState,
@@ -68,50 +65,158 @@ import {
68
65
  } from "./codexHelperExecution.js";
69
66
  export { sendPreparedCodexAppServerHelperTurn } from "./codexHelperExecution.js";
70
67
  import { createCodexHelperThreadLifecycle } from "./codexHelperThreads.js";
71
- export { codexAppServerThreadIsMissing } from "./codexProvider.js";
68
+ export { codexAppServerThreadIsMissing } from "./codexProviderThreads.js";
69
+
70
+ /** @typedef {(sessionId: string) => string} CodexSessionNamespace */
71
+ /** @typedef {(event: string, details?: object) => void} CodexDebugLog */
72
+ /** @typedef {(error: unknown) => string} CodexDebugError */
73
+ /** @typedef {() => Promise<any>} CodexCreateRuntime */
74
+ /** @typedef {() => Promise<any>} CodexCreateStore */
75
+ /** @typedef {(sessionId: string, event: object) => Promise<unknown>} CodexPublish */
76
+ /** @typedef {(session: object) => ReturnType<typeof codexAppServerTurnState>} CodexTurnStateReader */
77
+ /** @typedef {(run: object) => ReturnType<typeof codexAppServerTurnStateFromAgentRun>} CodexAgentRunTurnStateReader */
78
+ /** @typedef {() => unknown} CodexCaptureContext */
79
+ /** @typedef {(context: unknown, operation: () => any) => any} CodexRunInContext */
80
+ /** @typedef {typeof CODEX_TURN_OUTCOMES} CodexTurnOutcomes */
81
+ /** @typedef {(runtime: any, session: object, options: object) => Promise<any>} CodexAdmissionRecovery */
82
+ /** @typedef {(sessionId: string, input: object) => Promise<unknown>} CodexCheckpoint */
83
+
84
+ /**
85
+ * The application hooks that add metadata to the turns a run writes.
86
+ * @typedef {object} CodexMessageMetadataHooks
87
+ * @property {(actorContext: unknown) => unknown} actor Metadata for the person who sent a message.
88
+ * @property {(store: any, sessionId: string, metadata: object) => unknown} delivered Metadata of a delivered message.
89
+ * @property {(store: any, sessionId: string) => unknown} terminal Metadata of a turn written after the run stopped.
90
+ */
91
+
92
+ /**
93
+ * The managed provider sessions of an application that owns its provider processes.
94
+ * @typedef {object} CodexProviderSessions
95
+ * @property {import("./codexProviderOwner.js").CodexAppServerProviderOwner} owner
96
+ * @property {Map<string, any>} [managed]
97
+ * @property {Function} [context]
98
+ * @property {Function} [keyFields]
99
+ * @property {Function} [connectionPolicy]
100
+ * @property {Function} [outputContext]
101
+ * @property {Function} [assertOpen]
102
+ */
103
+
104
+ const CODEX_TURN_OUTCOMES = Object.freeze({
105
+ PROVIDER_FAILURE: "provider_failure",
106
+ RESPONSE_DELIVERY_FAILURE: "response_delivery_failure",
107
+ SERVICE_RESTART: "service_restart",
108
+ USER_CANCELLED: "user_cancelled",
109
+ CONTROL_RECONFIGURATION: "control_reconfiguration",
110
+ INTERRUPTED: "interrupted"
111
+ });
112
+
113
+ function ignoreDebugLog() {}
114
+
115
+ async function answerNothing() {
116
+ return null;
117
+ }
118
+
119
+ function captureNoContext() {
120
+ return null;
121
+ }
122
+
123
+ function addNoMessageMetadata() {
124
+ return null;
125
+ }
126
+
127
+ function keepDeliveredMessageMetadata(_store, _sessionId, metadata) {
128
+ return metadata;
129
+ }
72
130
 
131
+ function codexResultDeliveryFailureMessage({ error = "" } = {}) {
132
+ const detail = normalizeText(error);
133
+ if (!detail) return "Codex app-server finished this turn, but the assistant result text was not received.";
134
+ const punctuation = [".", "!", "?"].some(character => detail.endsWith(character)) ? "" : ".";
135
+ return "Codex completed, but its response could not be processed: " + detail + punctuation;
136
+ }
137
+
138
+ function runInNoContext(_context, operation) {
139
+ return operation();
140
+ }
141
+
142
+ /**
143
+ * Builds the run owner of one application's Codex turns: messages, turns, recovery, output, conversations and
144
+ * goals over one session store. Every hook without a value does nothing.
145
+ * @param {object} options
146
+ * @param {CodexSessionNamespace} [options.namespace]
147
+ * @param {(state: unknown) => string} [options.normalizeRunState]
148
+ * @param {CodexDebugLog} [options.debugLog]
149
+ * @param {CodexDebugError} [options.debugError]
150
+ * @param {CodexCreateRuntime} options.createRuntime
151
+ * @param {CodexCreateStore} options.createStore
152
+ * @param {CodexPublish} [options.publish]
153
+ * @param {(input: { sessionId: string, runtime: any, session: object }) => Promise<any>} [options.acquireProvider]
154
+ * @param {CodexProviderSessions} [options.providerSessions] Absent when the provider is acquired per call.
155
+ * @param {{ message: string, code?: string, retryable?: boolean }} [options.serverClosingError]
156
+ * @param {object} [options.helperThreads] The helper thread ledger options, when the application runs helpers.
157
+ * @param {number} [options.modelCatalogCacheMs]
158
+ * @param {object} [options.conversationPreparation] Absent when the application starts no scoped conversations.
159
+ * @param {string} [options.sessionIdRequiredError]
160
+ * @param {string} [options.turnAlreadyRunningError]
161
+ * @param {string} [options.messageIdPrefix]
162
+ * @param {object} [options.idlePublishPayload]
163
+ * @param {CodexCheckpoint} [options.checkpoint]
164
+ * @param {Partial<CodexMessageMetadataHooks>} [options.messageMetadata]
165
+ * @param {boolean} [options.persistCommentary]
166
+ * @param {string} [options.deliveryStateMetadataKey]
167
+ * @param {(session: object) => boolean} [options.hasRuntime]
168
+ * @param {CodexAdmissionRecovery} [options.recoverAdmission]
169
+ * @param {(session: object, run: object) => boolean} [options.admissionTaskFinished]
170
+ * @param {(...details: any[]) => Promise<unknown>} [options.outcomeNotice]
171
+ * @param {(details: { error?: string }) => string} [options.resultDeliveryFailureMessage]
172
+ * @param {string} [options.orphanedPromptMessage]
173
+ * @param {(kind: string, details: object) => Promise<unknown>} [options.onNotificationSignal]
174
+ * @param {CodexCaptureContext} [options.captureContext]
175
+ * @param {CodexRunInContext} [options.runInContext]
176
+ * @param {(sessionId: string, input: { threadId: string }) => Promise<unknown>} [options.continueGoalAfterAccountChange]
177
+ * Resumes a goal an account change paused, once the previous account's runtime has stopped. Without it the goal
178
+ * stays paused for the person to resume.
179
+ * @param {import("./codexNotificationQueue.js").CodexAppServerNotificationQueue} [options.notificationQueue]
180
+ * @param {number} [options.activeReconcileMs]
181
+ * @param {number} [options.finalizingGraceMs]
182
+ * @param {boolean} [options.finalizingGraceAfterHistoryRead]
183
+ * @param {number} [options.failureDetailGraceMs]
184
+ * @param {string} [options.steerFailedCode]
185
+ * @param {string} [options.interruptFailedCode]
186
+ * @param {string} [options.errorPrefix]
187
+ */
73
188
  export function createCodexAppServerRunOwner({
74
- namespace = normalizeCodexRunText,
189
+ namespace = normalizeText,
75
190
  normalizeRunState = normalizeCodexAppServerRunState,
76
- debugLog = () => {},
77
- debugError = error => normalizeCodexRunText(error?.message || error),
191
+ debugLog = ignoreDebugLog,
192
+ debugError = error => normalizeText(error?.message || error),
78
193
  createRuntime,
79
194
  createStore,
80
- publish = async () => null,
81
- acquireProvider = async () => null,
82
- providerSessions = null,
83
- serverClosingError = null,
195
+ publish = answerNothing,
196
+ acquireProvider = answerNothing,
197
+ providerSessions,
198
+ serverClosingError,
84
199
  helperThreads = null,
85
200
  modelCatalogCacheMs = 30_000,
86
- conversationPreparation = null,
87
- storeReadError = "The session store does not support agent-run reads.",
201
+ conversationPreparation,
88
202
  sessionIdRequiredError = "A session ID is required.",
89
- turnClaimsUnsupportedError = "The session runtime does not support Codex turn claims.",
90
203
  turnAlreadyRunningError = "Codex is already working on this session.",
91
204
  messageIdPrefix = "codex:",
92
- idlePublishPayload = null,
93
- checkpoint = async () => null,
205
+ idlePublishPayload,
206
+ checkpoint = answerNothing,
94
207
  messageMetadata = {},
95
208
  persistCommentary = true,
96
209
  deliveryStateMetadataKey = "assistant_delivery",
97
210
  hasRuntime = () => true,
98
- recoverAdmission = null,
211
+ recoverAdmission,
99
212
  admissionTaskFinished = () => false,
100
- outcomeNotice = async () => null,
101
- resultDeliveryFailureMessage = ({ error = "" } = {}) => {
102
- const detail = normalizeCodexRunText(error);
103
- if (!detail) return "Codex app-server finished this turn, but the assistant result text was not received.";
104
- const punctuation = [".", "!", "?"].some(character => detail.endsWith(character)) ? "" : ".";
105
- return "Codex completed, but its response could not be processed: " + detail + punctuation;
106
- },
213
+ outcomeNotice = answerNothing,
214
+ resultDeliveryFailureMessage = codexResultDeliveryFailureMessage,
107
215
  orphanedPromptMessage = "The application restarted before Codex confirmed the message. Your message is safe; retry it.",
108
- onNotificationSignal = async () => null,
109
- captureContext = () => null,
110
- runInContext = (_context, operation) => operation(),
111
- // Resumes a goal an account change paused, once the previous account's
112
- // runtime has stopped: `(sessionId, { threadId })`. Without it the goal stays
113
- // paused for the person to resume.
114
- continueGoalAfterAccountChange = null,
216
+ onNotificationSignal = answerNothing,
217
+ captureContext = captureNoContext,
218
+ runInContext = runInNoContext,
219
+ continueGoalAfterAccountChange,
115
220
  notificationQueue = null,
116
221
  activeReconcileMs = 2000,
117
222
  finalizingGraceMs = 10000,
@@ -120,7 +225,7 @@ export function createCodexAppServerRunOwner({
120
225
  steerFailedCode = "codex_turn_steer_failed",
121
226
  interruptFailedCode = "codex_turn_interrupt_failed",
122
227
  errorPrefix = ""
123
- } = {}) {
228
+ }) {
124
229
  if (typeof persistCommentary !== "boolean") throw new TypeError("Invalid Codex commentary persistence policy.");
125
230
  if (!Number.isSafeInteger(finalizingGraceMs) || finalizingGraceMs < 1) {
126
231
  throw new TypeError("Invalid Codex finalizing grace.");
@@ -135,14 +240,13 @@ export function createCodexAppServerRunOwner({
135
240
  providerSessions = { ...providerSessions, managed: providerSessions.managed || new Map() };
136
241
  }
137
242
  const liveProgressMaxLength = 320;
138
- const turnOutcomes = {
139
- PROVIDER_FAILURE: "provider_failure",
140
- RESPONSE_DELIVERY_FAILURE: "response_delivery_failure",
141
- SERVICE_RESTART: "service_restart",
142
- USER_CANCELLED: "user_cancelled",
143
- CONTROL_RECONFIGURATION: "control_reconfiguration",
144
- INTERRUPTED: "interrupted"
145
- };
243
+ const turnOutcomes = CODEX_TURN_OUTCOMES;
244
+ /** @type {CodexMessageMetadataHooks} */
245
+ const messageMetadataHooks = Object.freeze({
246
+ actor: messageMetadata.actor || addNoMessageMetadata,
247
+ delivered: messageMetadata.delivered || keepDeliveredMessageMetadata,
248
+ terminal: messageMetadata.terminal || addNoMessageMetadata
249
+ });
146
250
  const snapshotRecoveryItemLimit = 25;
147
251
  const helperOwnershipError = createCodexHelperOwnershipError({ errorPrefix });
148
252
  const helperLifecycle = helperThreads ? createCodexHelperThreadLifecycle({
@@ -154,9 +258,9 @@ export function createCodexAppServerRunOwner({
154
258
  namespace, runInContext,
155
259
  isClosing: () => runOwner.runtimeLifecycle?.closing === true,
156
260
  reportError: (error, context) => debugLog("appServerNotification.error", {
157
- error: debugError(error), method: normalizeCodexRunText(context.method),
158
- sessionId: normalizeCodexRunText(context.sessionId),
159
- threadId: normalizeCodexRunText(context.threadId), turnId: normalizeCodexRunText(context.turnId)
261
+ error: debugError(error), method: normalizeText(context.method),
262
+ sessionId: normalizeText(context.sessionId),
263
+ threadId: normalizeText(context.threadId), turnId: normalizeText(context.turnId)
160
264
  })
161
265
  });
162
266
  const codexAppServerPromptDeliveries = new Set();
@@ -193,8 +297,7 @@ export function createCodexAppServerRunOwner({
193
297
  debugError,
194
298
  liveProgressMaxLength,
195
299
  persistCommentary,
196
- storeReadError,
197
- messageMetadata,
300
+ messageMetadata: messageMetadataHooks,
198
301
  snapshotRecoveryItemLimit
199
302
  });
200
303
 
@@ -209,7 +312,6 @@ export function createCodexAppServerRunOwner({
209
312
  output: codexAppServerOutput,
210
313
  messageIdPrefix,
211
314
  sessionIdRequiredError,
212
- turnClaimsUnsupportedError,
213
315
  turnAlreadyRunningError,
214
316
  errorPrefix,
215
317
  idlePublishPayload,
@@ -217,6 +319,7 @@ export function createCodexAppServerRunOwner({
217
319
  admissionTaskFinished,
218
320
  orphanedPromptMessage
219
321
  });
322
+ const admissionRecovery = recoverAdmission || codexRunJournal.recoverAbandonedPromptClaim;
220
323
 
221
324
  const codexResultSettlement = createCodexResultSettlement({
222
325
  journal: codexRunJournal,
@@ -248,7 +351,7 @@ export function createCodexAppServerRunOwner({
248
351
  failureDetailGraceMs,
249
352
  notificationQueue: codexAppServerNotificationQueue,
250
353
  hasRuntime,
251
- recoverAdmission,
354
+ recoverAdmission: admissionRecovery,
252
355
  turnOutcomes,
253
356
  outcomeNotice,
254
357
  resultDeliveryFailureMessage
@@ -269,7 +372,7 @@ export function createCodexAppServerRunOwner({
269
372
  const codexMessageDelivery = createCodexAppServerMessageDelivery({
270
373
  namespace,
271
374
  publish,
272
- messageMetadata,
375
+ messageMetadata: messageMetadataHooks,
273
376
  createStore,
274
377
  turnStateFromAgentRun,
275
378
  deliveryStateMetadataKey,
@@ -349,6 +452,18 @@ export function createCodexAppServerRunOwner({
349
452
  turnState
350
453
  });
351
454
 
455
+ const codexPromptDispatch = createCodexPromptDispatch({
456
+ output: codexAppServerOutput,
457
+ journal: codexRunJournal,
458
+ recovery: codexTurnRecovery,
459
+ threadStatus: codexThreadStatus,
460
+ delivery: codexMessageDelivery,
461
+ debugError,
462
+ debugLog,
463
+ steerFailedCode,
464
+ turnState
465
+ });
466
+
352
467
  const codexMessageCommands = createCodexMessageCommands({
353
468
  output: codexAppServerOutput,
354
469
  journal: codexRunJournal,
@@ -357,16 +472,17 @@ export function createCodexAppServerRunOwner({
357
472
  selection: codexProviderSelection,
358
473
  observer: codexNotificationObserver,
359
474
  delivery: codexMessageDelivery,
475
+ promptDispatch: codexPromptDispatch,
360
476
  promptDeliveries: codexAppServerPromptDeliveries,
361
477
  createRuntime,
362
478
  debugError,
363
479
  debugLog,
364
480
  errorPrefix,
365
481
  messageIdPrefix,
366
- messageMetadata,
482
+ messageMetadata: messageMetadataHooks,
367
483
  namespace,
368
484
  providerSessions,
369
- recoverAdmission,
485
+ recoverAdmission: admissionRecovery,
370
486
  steerFailedCode,
371
487
  turnAlreadyRunningError,
372
488
  turnState
@@ -495,8 +611,8 @@ export function createCodexAppServerRunOwner({
495
611
  recoverObservationLoss: codexObservationControl.recoverObservationLoss,
496
612
  runRenewalHandover: codexRenewalCommands.runCodexAppServerRenewalHandover,
497
613
  runRenewalSeed: codexRenewalCommands.runCodexAppServerRenewalSeed,
498
- startTurn: codexMessageCommands.startTurn,
499
- steerTurn: codexMessageCommands.steerTurn,
614
+ startTurn: codexPromptDispatch.startTurn,
615
+ steerTurn: codexPromptDispatch.steerTurn,
500
616
  prepareGoalContext: codexGoalCommands.prepareCodexAppServerGoalContext,
501
617
  validateGoalInput: codexGoalCommands.validateCodexAppServerGoalInput,
502
618
  updateGoal: codexGoalCommands.updateCodexAppServerGoal,