@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,28 +1,37 @@
1
+ import { codexAppServerErrorMessage, codexAppServerMessageRequiresNewTurn, codexAppServerMessageText, codexAppServerMessageDisplayText, codexPromptInputFromRequest } from "./codexTurnState.js";
1
2
  import {
2
- codexAppServerTurnStatusIsSuccessfulComplete,
3
- codexAppServerTurnStatusIsProviderFailure,
4
- normalizeCodexRunText,
5
- codexAppServerErrorMessage,
6
- codexAppServerSteerFailure,
7
- codexAppServerMessageRequiresNewTurn,
8
- codexAppServerMessageDeferred,
9
- codexAppServerMessageText,
10
- codexAppServerMessageDisplayText,
11
- codexPromptInputFromRequest
12
- } from "./codexTurnState.js";
13
- import {
14
- codexAppServerRequestIsInvalid,
15
3
  codexAppServerThreadIsMissing,
16
- codexLocalImageInput,
17
- ensureCodexAppServerThread,
18
- codexAppServerDeliveredTurn,
19
- sendCodexAppServerPrompt
20
- } from "./codexProvider.js";
4
+ ensureCodexAppServerThread
5
+ } from "./codexProviderThreads.js";
21
6
  import crypto from "node:crypto";
22
- import { isRecord } from "@jskit-ai/kernel/shared/support/normalize";
7
+ import { isRecord, normalizeText } from "@jskit-ai/kernel/shared/support/normalize";
23
8
 
24
- // Original Main message admission, preparation, dispatch and steering.
25
- // Prompt delivery and receipt state remain the same run-owner references.
9
+ /**
10
+ * Main message admission, preparation and dispatch. Prompt delivery and receipt state remain the same run-owner
11
+ * references.
12
+ * @param {object} dependencies
13
+ * @param {import("./codexOutput.js").CodexAppServerOutput} dependencies.output
14
+ * @param {import("./codexRunJournal.js").CodexRunJournal} dependencies.journal
15
+ * @param {import("./codexTurnRecovery.js").CodexTurnRecovery} dependencies.recovery
16
+ * @param {import("./codexThreadStatus.js").CodexThreadStatus} dependencies.threadStatus
17
+ * @param {import("./codexProviderSelection.js").CodexProviderSelection} dependencies.selection
18
+ * @param {import("./codexNotificationObserver.js").CodexNotificationObserver} dependencies.observer
19
+ * @param {import("./codexMessageDelivery.js").CodexAppServerMessageDelivery} dependencies.delivery
20
+ * @param {import("./codexPromptDispatch.js").CodexPromptDispatch} dependencies.promptDispatch
21
+ * @param {Set<string>} dependencies.promptDeliveries
22
+ * @param {import("./codexTurn.js").CodexCreateRuntime} dependencies.createRuntime
23
+ * @param {import("./codexTurn.js").CodexDebugError} dependencies.debugError
24
+ * @param {import("./codexTurn.js").CodexDebugLog} dependencies.debugLog
25
+ * @param {string} dependencies.errorPrefix
26
+ * @param {string} dependencies.messageIdPrefix
27
+ * @param {import("./codexTurn.js").CodexMessageMetadataHooks} dependencies.messageMetadata
28
+ * @param {import("./codexTurn.js").CodexSessionNamespace} dependencies.namespace
29
+ * @param {import("./codexTurn.js").CodexProviderSessions} [dependencies.providerSessions]
30
+ * @param {import("./codexTurn.js").CodexAdmissionRecovery} dependencies.recoverAdmission
31
+ * @param {string} dependencies.steerFailedCode
32
+ * @param {string} dependencies.turnAlreadyRunningError
33
+ * @param {import("./codexTurn.js").CodexTurnStateReader} dependencies.turnState
34
+ */
26
35
  export function createCodexMessageCommands({
27
36
  output,
28
37
  journal,
@@ -31,7 +40,8 @@ export function createCodexMessageCommands({
31
40
  selection,
32
41
  observer,
33
42
  delivery,
34
- promptDeliveries: codexAppServerPromptDeliveries,
43
+ promptDispatch,
44
+ promptDeliveries,
35
45
  createRuntime,
36
46
  debugError,
37
47
  debugLog,
@@ -45,37 +55,12 @@ export function createCodexMessageCommands({
45
55
  turnAlreadyRunningError,
46
56
  turnState
47
57
  }) {
48
- const {
49
- submitAssistantResult: submitCodexAppServerAssistantResult,
50
- splitReasoningTurn: splitCodexAppServerReasoningTurn
51
- } = output;
52
- const {
53
- recoverAbandonedPromptClaim: recoverAbandonedCodexAppServerPromptClaim,
54
- claimMessageStart: claimCodexAppServerMessageStart,
55
- markTurnIdle: markCodexAppServerTurnIdle,
56
- writeUserMessageOwnership: writeCodexAppServerUserMessageOwnership
57
- } = journal;
58
- const {
59
- stopTurnWithProviderFailure: stopCodexAppServerTurnWithProviderFailure,
60
- completeTurn: completeCodexAppServerTurn,
61
- markTurnActive: markCodexAppServerTurnActive
62
- } = recovery;
63
- const {
64
- reconcileThreadStatus: reconcileCodexAppServerThreadStatus
65
- } = threadStatus;
66
58
  const {
67
59
  codexAppServerMessageContext,
68
60
  codexAppServerSessionObserverOptions,
69
61
  sessionConnection,
70
62
  rememberManagedSession
71
63
  } = selection;
72
- const {
73
- subscribeEvents: subscribeCodexAppServerEvents
74
- } = observer;
75
- const {
76
- writeDeliveredUserMessage: writeCodexAppServerDeliveredUserMessage,
77
- pendingUserMessage: pendingCodexAppServerUserMessage
78
- } = delivery;
79
64
 
80
65
  async function selectCodexAppServerMessageTurn(sessionId, { messageId = "", startedAt = Date.now() } = {}, context = {}) {
81
66
  if (providerSessions) context = codexAppServerMessageContext(sessionId, context);
@@ -85,9 +70,9 @@ export function createCodexMessageCommands({
85
70
  if (
86
71
  turn.state === "starting" &&
87
72
  !turn.turnId &&
88
- !codexAppServerPromptDeliveries.has(namespace(sessionId))
73
+ !promptDeliveries.has(namespace(sessionId))
89
74
  ) {
90
- const abandonedClaim = await (recoverAdmission || recoverAbandonedCodexAppServerPromptClaim)(
75
+ const abandonedClaim = await recoverAdmission(
91
76
  runtime,
92
77
  currentSession,
93
78
  { promptDeliveryActive: false }
@@ -101,11 +86,11 @@ export function createCodexMessageCommands({
101
86
  code: `${errorPrefix}codex_observation_lost`
102
87
  });
103
88
  }
104
- const recovered = await submitCodexAppServerAssistantResult(sessionId, turn.threadId, turn.turnId, { recoverFromProvider: true });
89
+ const recovered = await output.submitAssistantResult(sessionId, turn.threadId, turn.turnId, { recoverFromProvider: true });
105
90
  if (recovered.reason === "error") throw new Error(recovered.error);
106
91
  return { value: codexAppServerMessageRequiresNewTurn({ reason: "observation_lost", threadId: turn.threadId, turnId: turn.turnId }), session: currentSession };
107
92
  }
108
- const threadId = normalizeCodexRunText(turn.threadId) || context.threadId(currentSession);
93
+ const threadId = normalizeText(turn.threadId) || context.threadId(currentSession);
109
94
  if (!threadId) {
110
95
  debugLog("appServerMessage.newTurn", {
111
96
  messageId,
@@ -125,7 +110,7 @@ export function createCodexMessageCommands({
125
110
  messageId,
126
111
  sessionId,
127
112
  threadId,
128
- turnId: normalizeCodexRunText(turn.turnId)
113
+ turnId: normalizeText(turn.turnId)
129
114
  });
130
115
  }
131
116
  const providerReadyAt = Date.now();
@@ -135,7 +120,7 @@ export function createCodexMessageCommands({
135
120
  sessionId
136
121
  });
137
122
  try {
138
- await reconcileCodexAppServerThreadStatus(sessionId, provider, threadId, {
123
+ await threadStatus.reconcileThreadStatus(sessionId, provider, threadId, {
139
124
  source: "message_delivery"
140
125
  });
141
126
  } catch (error) {
@@ -148,12 +133,12 @@ export function createCodexMessageCommands({
148
133
  reason: "provider_thread_missing",
149
134
  sessionId,
150
135
  threadId,
151
- turnId: normalizeCodexRunText(turn.turnId)
136
+ turnId: normalizeText(turn.turnId)
152
137
  });
153
138
  return { value: codexAppServerMessageRequiresNewTurn({
154
139
  reason: "provider_thread_missing",
155
140
  threadId,
156
- turnId: normalizeCodexRunText(turn.turnId)
141
+ turnId: normalizeText(turn.turnId)
157
142
  }), session: currentSession };
158
143
  }
159
144
  debugLog("appServerMessage.reconciled", {
@@ -163,7 +148,7 @@ export function createCodexMessageCommands({
163
148
  });
164
149
  currentSession = await runtime.getSession(sessionId);
165
150
  turn = turnState(currentSession);
166
- const turnId = normalizeCodexRunText(turn.turnId);
151
+ const turnId = normalizeText(turn.turnId);
167
152
  const goalAwaitingTurn = !turn.active && turn.goalStatus === "active" && turn.goalThreadId === threadId;
168
153
  if (!turn.active && !goalAwaitingTurn) {
169
154
  debugLog("appServerMessage.newTurn", {
@@ -205,7 +190,7 @@ export function createCodexMessageCommands({
205
190
  const connection = source.provider ? null : sessionConnection(sessionId, source.providerOptions);
206
191
  const providerAlreadyAvailable = source.provider
207
192
  ? source.providerAlreadyAvailable
208
- : providerSessions.owner.providers.get(connection.providerKey)?.isAvailable?.() === true;
193
+ : providerSessions.owner.providers.get(connection.providerKey)?.isAvailable() === true;
209
194
  if (!providerAlreadyAvailable && facility.running) await facility.running();
210
195
  let stageStartedAt = Date.now();
211
196
  const provider = source.provider || await providerSessions.owner.ensureSession(connection, source.mainThreadId);
@@ -217,7 +202,7 @@ export function createCodexMessageCommands({
217
202
  const thread = await ensureCodexAppServerThread({
218
203
  ...(source.preparation || facility.preparation(currentSession)),
219
204
  ...(preparation.applicationTools ? { applicationTools: preparation.applicationTools, providerReady: preparation.providerReady } : {}),
220
- observeThread: threadId => subscribeCodexAppServerEvents(sessionId, provider, threadId, observerOptions),
205
+ observeThread: threadId => observer.subscribeEvents(sessionId, provider, threadId, observerOptions),
221
206
  provider,
222
207
  workdir: source.workdir ?? workdir
223
208
  });
@@ -241,7 +226,7 @@ export function createCodexMessageCommands({
241
226
  durationMs: Date.now() - startedAt, messageId, sessionId, stage: "startup-ready"
242
227
  });
243
228
  if (!Object.hasOwn(facility, "failureThreadId")) prepared.activeThreadId = thread.threadId;
244
- subscribeCodexAppServerEvents(sessionId, provider, thread.threadId, observerOptions);
229
+ observer.subscribeEvents(sessionId, provider, thread.threadId, observerOptions);
245
230
  if (connection) {
246
231
  rememberManagedSession(sessionId, providerOptions, {
247
232
  executionRoot: prepared.executionRoot, workdir: prepared.workdir, threadId: thread.threadId
@@ -250,8 +235,8 @@ export function createCodexMessageCommands({
250
235
  if (facility.ready) await facility.ready();
251
236
  return { preparedSession, provider, providerAlreadyAvailable, providerOptions, thread, ...settings };
252
237
  } finally {
253
- // Standalone preparation historically retained the exact binding on
254
- // failure as well as success; Main records it after the startup gate.
238
+ // Standalone preparation keeps the exact binding on failure as well as
239
+ // success; Main records it after the startup gate.
255
240
  if (Object.hasOwn(facility, "failureThreadId")) prepared.activeThreadId = facility.failureThreadId;
256
241
  }
257
242
  }
@@ -262,7 +247,7 @@ export function createCodexMessageCommands({
262
247
  ? options.agentSettings
263
248
  : isRecord(input.agentSettings) ? input.agentSettings : {};
264
249
  const actorContext = options.actorContext || null;
265
- const messageId = normalizeCodexRunText(input.messageId) ||
250
+ const messageId = normalizeText(input.messageId) ||
266
251
  `${messageIdPrefix}${crypto.randomUUID()}`;
267
252
  const userRequest = codexPromptInputFromRequest(input);
268
253
  if (!userRequest && options.preparedInput === undefined) {
@@ -279,14 +264,14 @@ export function createCodexMessageCommands({
279
264
  return { value: context };
280
265
  }
281
266
  const { runtime } = context;
282
- const turnMetadata = { ...input.turnMetadata, ...await messageMetadata.actor?.(actorContext) };
267
+ const turnMetadata = { ...input.turnMetadata, ...await messageMetadata.actor(actorContext) };
283
268
  debugLog("appServerPrompt.start", {
284
269
  durationMs: Date.now() - startedAt,
285
270
  messageId,
286
271
  sessionId
287
272
  });
288
273
 
289
- const claim = await claimCodexAppServerMessageStart(runtime, sessionId, messageId);
274
+ const claim = await journal.claimCodexAppServerMessageStart(runtime, sessionId, messageId);
290
275
  if (!claim?.claimed) {
291
276
  debugLog("appServerPrompt.claimObserved", {
292
277
  code: String(claim?.response?.value?.code || ""),
@@ -300,9 +285,9 @@ export function createCodexMessageCommands({
300
285
  } };
301
286
  }
302
287
 
303
- const normalizedSessionId = normalizeCodexRunText(sessionId);
288
+ const normalizedSessionId = normalizeText(sessionId);
304
289
  const promptDeliveryKey = namespace(normalizedSessionId);
305
- codexAppServerPromptDeliveries.add(promptDeliveryKey);
290
+ promptDeliveries.add(promptDeliveryKey);
306
291
  const prepared = {
307
292
  ...context, agentSettings, actorContext, messageId, userRequest, startedAt,
308
293
  activeThreadId: ""
@@ -312,12 +297,12 @@ export function createCodexMessageCommands({
312
297
  try {
313
298
  Object.assign(prepared, await prepareCodexAppServerMessageThread(sessionId, input, prepared, prepare));
314
299
  const { provider, providerAlreadyAvailable, thread } = prepared;
315
- await markCodexAppServerTurnActive(sessionId, {
300
+ await recovery.markTurnActive(sessionId, {
316
301
  status: "starting",
317
302
  threadId: thread.threadId
318
303
  });
319
304
  const prompt = await prepare.prepareMessage(input, prepared, { starting: true });
320
- const started = await startCodexAppServerTurn(sessionId, input, {
305
+ const started = await promptDispatch.startTurn(sessionId, input, {
321
306
  runtime, provider, threadId: thread.threadId, messageId, renderedPrompt: prompt.renderedPrompt, turnMetadata,
322
307
  preparedInput: options.preparedInput,
323
308
  get turnSettings() { return prompt.turnSettings; }
@@ -345,7 +330,7 @@ export function createCodexMessageCommands({
345
330
  }, session: currentSession, nativeIdentity: { threadId: thread.threadId, turnId: deliveredTurnId } };
346
331
  } catch (error) {
347
332
  if (!turnFailureHandled) {
348
- await markCodexAppServerTurnIdle(sessionId, {
333
+ await journal.markTurnIdle(sessionId, {
349
334
  error: codexAppServerErrorMessage(error, "Codex app-server prompt delivery failed."),
350
335
  status: "failed",
351
336
  threadId: prepared.activeThreadId
@@ -353,16 +338,16 @@ export function createCodexMessageCommands({
353
338
  }
354
339
  return await prepare.finishMessage(input, prepared, { error });
355
340
  } finally {
356
- codexAppServerPromptDeliveries.delete(promptDeliveryKey);
341
+ promptDeliveries.delete(promptDeliveryKey);
357
342
  }
358
343
  }
359
344
 
360
- async function sendCodexAppServerMessage(sessionId, input = {}, options = {}, prepare) {
345
+ async function sendCodexAppServerMessage(sessionId, input, options = {}, prepare) {
361
346
  const startedAt = Date.now();
362
347
  const turnOwnership = options.turnOwnership || null;
363
348
  const message = codexAppServerMessageText(input);
364
349
  const displayMessage = codexAppServerMessageDisplayText(input, message);
365
- const messageId = normalizeCodexRunText(input?.messageId);
350
+ const messageId = normalizeText(input?.messageId);
366
351
  if (!message && options.preparedInput === undefined) {
367
352
  return { value: {
368
353
  code: steerFailedCode,
@@ -381,7 +366,6 @@ export function createCodexMessageCommands({
381
366
  const { runtime, session } = context;
382
367
  if (
383
368
  messageId &&
384
- typeof runtime.store.conversationMessageIdExists === "function" &&
385
369
  await runtime.store.conversationMessageIdExists(sessionId, messageId)
386
370
  ) {
387
371
  return { value: {
@@ -392,7 +376,7 @@ export function createCodexMessageCommands({
392
376
  }, session };
393
377
  }
394
378
  const actorContext = options.actorContext || null;
395
- const turnMetadata = { ...input.turnMetadata, ...await messageMetadata.actor?.(actorContext) };
379
+ const turnMetadata = { ...input.turnMetadata, ...await messageMetadata.actor(actorContext) };
396
380
  debugLog("appServerMessage.contextReady", {
397
381
  durationMs: Date.now() - startedAt,
398
382
  messageId,
@@ -406,7 +390,7 @@ export function createCodexMessageCommands({
406
390
  const policy = await prepare.prepareMessage(input, prepared, { starting: false, selected });
407
391
  if (policy) return policy;
408
392
  const clientUserMessageId = messageId || `${messageIdPrefix}${crypto.randomUUID()}`;
409
- return steerCodexAppServerTurn(sessionId, input, {
393
+ return promptDispatch.steerTurn(sessionId, input, {
410
394
  runtime, provider, threadId, turnId, message, displayMessage, messageId, clientUserMessageId, turnMetadata,
411
395
  preparedInput: options.preparedInput
412
396
  });
@@ -418,7 +402,7 @@ export function createCodexMessageCommands({
418
402
  return result;
419
403
  }
420
404
  const message = codexAppServerMessageText(input);
421
- const messageId = normalizeCodexRunText(input?.messageId) ||
405
+ const messageId = normalizeText(input.messageId) ||
422
406
  `${messageIdPrefix}${crypto.randomUUID()}`;
423
407
  const started = await startCodexAppServerMessage(sessionId, isRecord(input) ? {
424
408
  ...input,
@@ -428,27 +412,27 @@ export function createCodexMessageCommands({
428
412
  message,
429
413
  messageId
430
414
  }, {
431
- agentSettings: input?.agentSettings || {},
415
+ agentSettings: input.agentSettings || {},
432
416
  runtime: options.runtime || null,
433
417
  session: options.session || null,
434
418
  actorContext: options.actorContext || null,
435
419
  preparedInput: options.preparedInput
436
420
  }, prepare);
437
- // The original unavailable-worktree return starts its policy operation,
438
- // releases the prompt marker in finally, then awaits the returned value.
421
+ // An unavailable-worktree result starts its policy operation, releases
422
+ // the prompt marker in finally, and then this awaits the returned value.
439
423
  started.value = await started.value;
440
424
  if (started.value?.ok === false || started.value?.delivered === false) {
441
425
  return started;
442
426
  }
443
427
  const runtime = await createRuntime(sessionId);
444
428
  const displayMessage = codexAppServerMessageDisplayText(input, message);
445
- const conversationTurn = await writeCodexAppServerDeliveredUserMessage(
429
+ const conversationTurn = await delivery.writeDeliveredUserMessage(
446
430
  runtime,
447
431
  sessionId,
448
432
  displayMessage || message,
449
433
  messageId,
450
434
  started.value.turnMetadata || null,
451
- input?.displayAttachments,
435
+ input.displayAttachments,
452
436
  started.nativeIdentity
453
437
  );
454
438
  return {
@@ -464,210 +448,8 @@ export function createCodexMessageCommands({
464
448
  };
465
449
  }
466
450
 
467
- async function startCodexAppServerTurn(sessionId, input = {}, context = {}) {
468
- const { runtime, provider, threadId, messageId, renderedPrompt, turnMetadata } = context;
469
- let providerFailure = "";
470
- let delivery = null;
471
- const promptSessionId = normalizeCodexRunText(sessionId);
472
- const clientUserMessageId = messageId;
473
- await writeCodexAppServerUserMessageOwnership(runtime.store, sessionId, clientUserMessageId, {
474
- eventKind: "codex-app-server-user-message-owned",
475
- owned: true
476
- });
477
- try {
478
- await input.onPromptSending?.({ threadId: threadId, displayAttachments: input.displayAttachments, turnMetadata });
479
- const response = sendCodexAppServerPrompt({
480
- clientUserMessageId,
481
- prompt: renderedPrompt,
482
- attachments: input.attachments,
483
- provider,
484
- threadId
485
- }, context);
486
- const receipt = pendingCodexAppServerUserMessage(promptSessionId, clientUserMessageId)?.receipt;
487
- // An exact, persisted user-message receipt confirms delivery too.
488
- // Finish bookkeeping once; a late RPC reply must not hold admission
489
- // or change a turn that has already continued or completed.
490
- delivery = receipt
491
- ? await Promise.race([response, receipt.promise.then((turn) => ({ turn }))])
492
- : await response;
493
- } catch (error) {
494
- if (Number.isInteger(error?.code) && error.code < 0) await input.onPromptRejected?.();
495
- await writeCodexAppServerUserMessageOwnership(runtime.store, sessionId, clientUserMessageId, {
496
- eventKind: "codex-app-server-user-message-released",
497
- owned: false
498
- });
499
- await markCodexAppServerTurnIdle(sessionId, {
500
- error: codexAppServerErrorMessage(error, "Codex app-server prompt delivery failed."),
501
- status: "failed",
502
- threadId: threadId
503
- });
504
- return { error, turnFailureHandled: true };
505
- }
506
- const { turnId: deliveredTurnId, status: deliveredTurnStatus } = codexAppServerDeliveredTurn(delivery);
507
- if (!deliveredTurnId) {
508
- throw new Error("Codex app-server accepted the prompt without returning a turn id.");
509
- }
510
- pendingCodexAppServerUserMessage(promptSessionId, clientUserMessageId)?.onNativeReceipt?.();
511
- await markCodexAppServerTurnActive(sessionId, {
512
- requireTrackedTurn: true,
513
- status: "inProgress",
514
- threadId: threadId,
515
- turnId: deliveredTurnId
516
- });
517
- if (codexAppServerTurnStatusIsProviderFailure(deliveredTurnStatus)) {
518
- providerFailure = `Codex turn ${deliveredTurnStatus}.`;
519
- await stopCodexAppServerTurnWithProviderFailure(sessionId, threadId, deliveredTurnId, {
520
- provider,
521
- status: deliveredTurnStatus
522
- });
523
- } else if (codexAppServerTurnStatusIsSuccessfulComplete(deliveredTurnStatus)) {
524
- const completion = await completeCodexAppServerTurn(sessionId, threadId, deliveredTurnId, {
525
- provider,
526
- status: deliveredTurnStatus
527
- });
528
- if (completion?.ok === false) {
529
- providerFailure = normalizeCodexRunText(completion.error) || "Codex completed, but its response could not be processed.";
530
- }
531
- }
532
- return { delivery, deliveredTurnId, providerFailure };
533
- }
534
-
535
- async function steerCodexAppServerTurn(sessionId, input = {}, context = {}) {
536
- const { runtime, provider, threadId, turnId, message, displayMessage, messageId, clientUserMessageId, turnMetadata } = context;
537
- let currentSession;
538
- await writeCodexAppServerUserMessageOwnership(runtime.store, sessionId, clientUserMessageId, {
539
- eventKind: "codex-app-server-user-message-owned",
540
- owned: true
541
- });
542
- debugLog("appServerMessage.activeTurn.start", {
543
- messageId,
544
- sessionId,
545
- threadId,
546
- turnId
547
- });
548
- async function recoverAfterSteerFailure(error = null) {
549
- await writeCodexAppServerUserMessageOwnership(runtime.store, sessionId, clientUserMessageId, {
550
- eventKind: "codex-app-server-user-message-released",
551
- owned: false
552
- });
553
- await reconcileCodexAppServerThreadStatus(sessionId, provider, threadId, {
554
- source: "message_delivery_steer_race"
555
- }).catch(() => null);
556
- currentSession = await runtime.getSession(sessionId);
557
- const currentTurn = turnState(currentSession);
558
- const sameTurnIsActive = currentTurn.active === true &&
559
- normalizeCodexRunText(currentTurn.threadId) === threadId &&
560
- normalizeCodexRunText(currentTurn.turnId) === turnId &&
561
- currentTurn.state !== "finalizing";
562
- if (sameTurnIsActive) {
563
- return codexAppServerRequestIsInvalid(error, "turn/steer")
564
- ? { value: codexAppServerMessageDeferred({ threadId, turnId }, steerFailedCode), session: currentSession }
565
- : null;
566
- }
567
- debugLog("appServerMessage.newTurn", {
568
- error: debugError(error),
569
- messageId,
570
- reason: "active_turn_completed_before_delivery",
571
- sessionId,
572
- threadId,
573
- turnId
574
- });
575
- return { value: codexAppServerMessageRequiresNewTurn({
576
- reason: "active_turn_completed_before_delivery",
577
- threadId,
578
- turnId
579
- }), session: currentSession };
580
- }
581
- let result;
582
- try {
583
- await input.onPromptSending?.({ threadId, displayAttachments: input.displayAttachments, turnMetadata });
584
- const response = provider.steerTurn(
585
- threadId,
586
- turnId,
587
- context.preparedInput === undefined
588
- ? input.attachments?.some((attachment) => attachment.contentType?.startsWith("image/"))
589
- ? [message, ...codexLocalImageInput(input.attachments)]
590
- : message
591
- : context.preparedInput,
592
- {
593
- clientUserMessageId
594
- }
595
- );
596
- const receipt = pendingCodexAppServerUserMessage(sessionId, clientUserMessageId)?.receipt;
597
- result = receipt ? await Promise.race([response, receipt.promise]) : await response;
598
- } catch (error) {
599
- if (Number.isInteger(error?.code) && error.code < 0) await input.onPromptRejected?.();
600
- const recovered = await recoverAfterSteerFailure(error);
601
- if (recovered) {
602
- return recovered;
603
- }
604
- debugLog("appServerMessage.activeTurn.error", {
605
- error: debugError(error),
606
- messageId,
607
- sessionId,
608
- threadId,
609
- turnId
610
- });
611
- throw error;
612
- }
613
- const steerFailure = codexAppServerSteerFailure(result, steerFailedCode);
614
- if (steerFailure) {
615
- const recovered = await recoverAfterSteerFailure(result);
616
- if (recovered) {
617
- return recovered;
618
- }
619
- debugLog("appServerMessage.activeTurn.failed", {
620
- error: steerFailure.error,
621
- messageId,
622
- operationOutcome: steerFailure.operationOutcome,
623
- sessionId,
624
- threadId,
625
- turnId
626
- });
627
- return { value: {
628
- ...steerFailure,
629
- result,
630
- threadId,
631
- turnId
632
- } };
633
- }
634
- pendingCodexAppServerUserMessage(sessionId, clientUserMessageId)?.onNativeReceipt?.();
635
- const conversationTurn = await writeCodexAppServerDeliveredUserMessage(
636
- runtime,
637
- sessionId,
638
- displayMessage || message,
639
- messageId,
640
- turnMetadata,
641
- input?.displayAttachments,
642
- { threadId, turnId }
643
- );
644
- splitCodexAppServerReasoningTurn(threadId, turnId);
645
- currentSession = await runtime.getSession(sessionId);
646
- debugLog("appServerMessage.activeTurn.done", {
647
- conversationTurnId: normalizeCodexRunText(conversationTurn?.turnId || conversationTurn?.id),
648
- messageId,
649
- sessionId,
650
- threadId,
651
- turnId
652
- });
653
- return { value: {
654
- conversationTurn,
655
- conversationTurns: [conversationTurn],
656
- delivered: true,
657
- deliveryMode: "active_turn",
658
- newTurnRequired: false,
659
- ok: true,
660
- operationOutcome: "delivered_to_active_turn",
661
- result,
662
- threadId,
663
- turnId
664
- }, session: currentSession };
665
- }
666
-
667
- return {
451
+ return Object.freeze({
668
452
  selectMessageTurn: selectCodexAppServerMessageTurn,
669
- dispatchMessage: dispatchCodexAppServerMessage,
670
- startTurn: startCodexAppServerTurn,
671
- steerTurn: steerCodexAppServerTurn
672
- };
453
+ dispatchMessage: dispatchCodexAppServerMessage
454
+ });
673
455
  }