@jskit-ai/assistant-core 0.2.7 → 0.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/examples/conversation/package.json +5 -5
  2. package/package.json +18 -7
  3. package/src/client/browser.js +21 -0
  4. package/src/client/conversation/AssistantAttachmentQueue.vue +25 -108
  5. package/src/client/conversation/AssistantComposerActions.vue +1 -1
  6. package/src/client/conversation/AssistantConversationElement.vue +14 -52
  7. package/src/client/conversation/AssistantGoalControl.vue +13 -10
  8. package/src/client/conversation/AssistantPromptInput.vue +6 -91
  9. package/src/client/conversation/AssistantTranscript.css +505 -0
  10. package/src/client/conversation/AssistantTranscript.vue +24 -1197
  11. package/src/client/conversation/attachmentFiles.js +158 -0
  12. package/src/client/conversation/attachmentQueueItems.js +121 -0
  13. package/src/client/conversation/attachmentUploadRows.js +265 -0
  14. package/src/client/conversation/conversationDisplay.js +54 -0
  15. package/src/client/conversation/messageDelivery.js +13 -9
  16. package/src/client/conversation/retainedConversation.js +14 -3
  17. package/src/client/conversation/submitText.js +13 -2
  18. package/src/client/conversation/transcriptEntries.js +225 -0
  19. package/src/client/conversation/useAssistantAttachments.js +86 -388
  20. package/src/client/conversation/useAssistantQuestions.js +16 -3
  21. package/src/client/conversation/useAssistantSuggestions.js +16 -2
  22. package/src/client/conversation/useScrollToBottom.js +17 -19
  23. package/src/client/conversation/useTextareaAutoGrow.js +115 -0
  24. package/src/client/conversation/useTranscriptScrollFollow.js +525 -0
  25. package/src/client/lib/assistantApi.js +192 -161
  26. package/src/client/types.js +110 -0
  27. package/src/server/conversation/attachments.js +21 -6
  28. package/src/server/conversation/boundedToolLoop.js +1 -0
  29. package/src/server/conversation/claudeClient.js +71 -20
  30. package/src/server/conversation/claudeCommandRun.js +191 -0
  31. package/src/server/conversation/claudeHistory.js +7 -0
  32. package/src/server/conversation/claudeNativeTurn.js +708 -0
  33. package/src/server/conversation/claudeProcess.js +186 -112
  34. package/src/server/conversation/claudeProcessStart.js +214 -0
  35. package/src/server/conversation/claudePromptDelivery.js +183 -0
  36. package/src/server/conversation/claudeSessionCleanup.js +248 -0
  37. package/src/server/conversation/claudeTools.js +15 -3
  38. package/src/server/conversation/claudeTurn.js +212 -1388
  39. package/src/server/conversation/codexAccountReader.js +168 -0
  40. package/src/server/conversation/codexAuthPreflight.js +5 -4
  41. package/src/server/conversation/codexClient.js +18 -6
  42. package/src/server/conversation/codexConfiguration.js +8 -844
  43. package/src/server/conversation/codexConversationStops.js +377 -0
  44. package/src/server/conversation/codexConversationStore.js +119 -85
  45. package/src/server/conversation/codexConversationTurns.js +378 -0
  46. package/src/server/conversation/codexConversations.js +134 -866
  47. package/src/server/conversation/codexDetachedConversation.js +203 -0
  48. package/src/server/conversation/codexDetachedTurn.js +145 -104
  49. package/src/server/conversation/codexEvents.js +5 -200
  50. package/src/server/conversation/codexGoalCommands.js +14 -4
  51. package/src/server/conversation/codexHelperExecution.js +57 -57
  52. package/src/server/conversation/codexHelperThreadLedger.js +30 -288
  53. package/src/server/conversation/codexHelperThreadRecord.js +304 -0
  54. package/src/server/conversation/codexHelperThreadRecovery.js +54 -76
  55. package/src/server/conversation/codexHelperThreads.js +94 -93
  56. package/src/server/conversation/codexHistoryAdapter.js +13 -8
  57. package/src/server/conversation/codexIsolation.js +672 -0
  58. package/src/server/conversation/codexLiveItems.js +379 -0
  59. package/src/server/conversation/codexMessageCommands.js +68 -286
  60. package/src/server/conversation/codexMessageDelivery.js +46 -37
  61. package/src/server/conversation/codexModelCatalog.js +86 -7
  62. package/src/server/conversation/codexNotificationObserver.js +81 -88
  63. package/src/server/conversation/codexNotificationQueue.js +21 -10
  64. package/src/server/conversation/codexObservationControl.js +105 -89
  65. package/src/server/conversation/codexOutput.js +84 -419
  66. package/src/server/conversation/codexProcess.js +29 -1053
  67. package/src/server/conversation/codexProcessLeader.js +1 -0
  68. package/src/server/conversation/codexPromptDispatch.js +241 -0
  69. package/src/server/conversation/codexProvider.js +147 -1807
  70. package/src/server/conversation/codexProviderAuth.js +348 -0
  71. package/src/server/conversation/codexProviderInvalidation.js +371 -0
  72. package/src/server/conversation/codexProviderInventories.js +437 -0
  73. package/src/server/conversation/codexProviderOwner.js +149 -957
  74. package/src/server/conversation/codexProviderRelease.js +465 -0
  75. package/src/server/conversation/codexProviderSelection.js +26 -15
  76. package/src/server/conversation/codexProviderThreads.js +698 -0
  77. package/src/server/conversation/codexProviderTurns.js +453 -0
  78. package/src/server/conversation/codexReasoning.js +32 -23
  79. package/src/server/conversation/codexRenewalCommands.js +18 -6
  80. package/src/server/conversation/codexRenewalThreads.js +7 -22
  81. package/src/server/conversation/codexResultSettlement.js +70 -88
  82. package/src/server/conversation/codexRunJournal.js +91 -97
  83. package/src/server/conversation/codexRuntime.js +426 -0
  84. package/src/server/conversation/codexRuntimeInventory.js +113 -0
  85. package/src/server/conversation/codexRuntimeLifecycle.js +39 -13
  86. package/src/server/conversation/codexRuntimeStart.js +431 -0
  87. package/src/server/conversation/codexRuntimeStop.js +324 -0
  88. package/src/server/conversation/codexSessionCleanup.js +25 -10
  89. package/src/server/conversation/codexSessionReconciliation.js +21 -7
  90. package/src/server/conversation/codexThreadReadiness.js +49 -52
  91. package/src/server/conversation/codexThreadSnapshot.js +210 -0
  92. package/src/server/conversation/codexThreadStatus.js +48 -62
  93. package/src/server/conversation/codexTurn.js +171 -55
  94. package/src/server/conversation/codexTurnActivity.js +210 -0
  95. package/src/server/conversation/codexTurnControl.js +44 -48
  96. package/src/server/conversation/codexTurnEndings.js +610 -0
  97. package/src/server/conversation/codexTurnRecovery.js +97 -848
  98. package/src/server/conversation/codexTurnState.js +138 -111
  99. package/src/server/conversation/completedResponses.js +227 -0
  100. package/src/server/conversation/configuration.js +2 -2
  101. package/src/server/conversation/continuity.js +43 -6
  102. package/src/server/conversation/conversationDelivery.js +394 -0
  103. package/src/server/conversation/conversationEntries.js +365 -0
  104. package/src/server/conversation/conversationEvents.js +192 -0
  105. package/src/server/conversation/conversationGoals.js +187 -0
  106. package/src/server/conversation/conversationHandles.js +237 -0
  107. package/src/server/conversation/conversationReads.js +206 -0
  108. package/src/server/conversation/conversationRefusals.js +58 -0
  109. package/src/server/conversation/conversationReplacement.js +254 -0
  110. package/src/server/conversation/conversationSending.js +273 -0
  111. package/src/server/conversation/conversationStopping.js +121 -0
  112. package/src/server/conversation/conversationTurnDelivery.js +413 -0
  113. package/src/server/conversation/conversationTurns.js +511 -0
  114. package/src/server/conversation/deliveryTiming.js +25 -3
  115. package/src/server/conversation/fileStorage.js +11 -6
  116. package/src/server/conversation/hookBridge.js +14 -3
  117. package/src/server/conversation/index.js +1 -1
  118. package/src/server/conversation/localExecution.js +82 -625
  119. package/src/server/conversation/nativeCommandCallbacks.js +10 -0
  120. package/src/server/conversation/nativeConversationLifecycle.js +379 -0
  121. package/src/server/conversation/nativeHistoryExport.js +27 -18
  122. package/src/server/conversation/normalize.js +9 -0
  123. package/src/server/conversation/openCodeClient.js +295 -366
  124. package/src/server/conversation/openCodeNativeHistory.js +141 -0
  125. package/src/server/conversation/openCodeNativeSession.js +79 -0
  126. package/src/server/conversation/openCodeProcess.js +109 -53
  127. package/src/server/conversation/openCodeProcessOwner.js +565 -0
  128. package/src/server/conversation/openCodeRuntime.js +111 -1814
  129. package/src/server/conversation/openCodeSessionTurns.js +547 -0
  130. package/src/server/conversation/openCodeTemporaryConversations.js +394 -0
  131. package/src/server/conversation/openCodeTools.js +28 -14
  132. package/src/server/conversation/openCodeTurn.js +80 -74
  133. package/src/server/conversation/openCodeTurnMonitor.js +388 -0
  134. package/src/server/conversation/processIdentity.js +582 -0
  135. package/src/server/conversation/provider.js +21 -6
  136. package/src/server/conversation/providers/api.js +268 -107
  137. package/src/server/conversation/providers/claude.js +29 -6
  138. package/src/server/conversation/providers/claudeDriver.js +325 -250
  139. package/src/server/conversation/providers/codex.js +69 -33
  140. package/src/server/conversation/providers/codexDriver.js +503 -1081
  141. package/src/server/conversation/providers/codexDriverConnection.js +331 -0
  142. package/src/server/conversation/providers/codexDriverTurns.js +464 -0
  143. package/src/server/conversation/providers/opencode.js +30 -4
  144. package/src/server/conversation/providers/opencodeDriver.js +321 -659
  145. package/src/server/conversation/providers/opencodeStandalone.js +475 -0
  146. package/src/server/conversation/providers/scoped.js +64 -19
  147. package/src/server/conversation/runtime.js +171 -2863
  148. package/src/server/conversation/storage.js +91 -50
  149. package/src/server/conversation/streams.js +15 -2
  150. package/src/server/conversation/structuredOutput.js +7 -11
  151. package/src/server/conversation/systemPrompt.js +13 -1
  152. package/src/server/conversation/tools.js +47 -15
  153. package/src/server/conversation/transcript.js +49 -20
  154. package/src/server/hosts/claudeTurn.js +2 -4
  155. package/src/server/hosts/codexConfiguration.js +6 -8
  156. package/src/server/hosts/codexEvents.js +4 -2
  157. package/src/server/hosts/codexProcess.js +1 -1
  158. package/src/server/hosts/codexProvider.js +11 -9
  159. package/src/server/hosts/codexTurn.js +3 -3
  160. package/src/server/hosts/openCodeClient.js +4 -2
  161. package/src/server/index.js +0 -2
  162. package/src/server/lib/aiConnectionClient.js +35 -25
  163. package/src/server/lib/ndjson.js +1 -0
  164. package/src/server/lib/providers/anthropicClient.js +15 -6
  165. package/src/server/lib/providers/common.js +10 -6
  166. package/src/server/lib/providers/openAiCompatibleClient.js +40 -23
  167. package/src/server/lib/serviceToolCatalog.js +29 -283
  168. package/src/server/lib/serviceToolEntries.js +270 -0
  169. package/src/server/types.js +78 -0
  170. package/src/shared/assistantResource.js +0 -23
  171. package/src/shared/conversation/answerChoiceSugar.js +2 -14
  172. package/src/shared/conversation/messageInputSugar.js +18 -0
  173. package/src/shared/conversation/numberedQuestionSugar.js +6 -16
  174. package/src/shared/conversation/pagination.js +1 -1
  175. package/src/shared/conversation/questions.js +1 -0
  176. package/src/shared/conversation/streaming.js +1 -0
  177. package/src/shared/index.js +0 -1
  178. package/src/testing/conversationStorageContract.js +20 -0
  179. package/test/aiConnectionClient.test.js +42 -1
  180. package/test/apiConversationDriver.test.js +217 -38
  181. package/test/assistantBoundedToolLoop.test.js +1 -1
  182. package/test/claudeConversationSession.test.js +15 -11
  183. package/test/claudeInstructionResume.test.js +1 -1
  184. package/test/claudeProcess.test.js +9 -9
  185. package/test/claudeTurn.test.js +21 -8
  186. package/test/codexAccountChange.test.js +5 -3
  187. package/test/codexConversationSession.test.js +22 -21
  188. package/test/codexEvents.test.js +3 -1
  189. package/test/codexHelperDeletion.test.js +3 -7
  190. package/test/codexIsolation.test.js +6 -6
  191. package/test/codexModelCatalog.test.js +6 -7
  192. package/test/codexProcess.test.js +3 -3
  193. package/test/codexThreadSelection.test.js +4 -1
  194. package/test/codexTurn.test.js +29 -20
  195. package/test/conversationApiFacilities.test.js +11 -9
  196. package/test/conversationAttachments.test.js +3 -3
  197. package/test/conversationConfiguration.test.js +4 -4
  198. package/test/conversationNativeStorage.test.js +11 -10
  199. package/test/conversationReplacement.test.js +13 -13
  200. package/test/conversationRuntime.test.js +9 -5
  201. package/test/conversationSession.test.js +78 -22
  202. package/test/conversationTools.test.js +47 -26
  203. package/test/fileConversationStorage.test.js +10 -3
  204. package/test/fixtures/codexHelperThreadLedger.js +3 -3
  205. package/test/frameworkActions.test.js +33 -18
  206. package/test/localConversationExecution.test.js +4 -4
  207. package/test/localExecution.test.js +1 -1
  208. package/test/openCodeConnectionChange.test.js +3 -2
  209. package/test/openCodeRuntime.test.js +8 -7
  210. package/test/openCodeTools.test.js +1 -1
  211. package/test/opencodeConversationSession.test.js +4 -3
  212. package/test/serviceToolCatalog.test.js +3 -8
  213. package/src/server/lib/assistantCompletion.js +0 -190
  214. package/src/server/lib/assistantToolLoop.js +0 -259
@@ -1,31 +1,32 @@
1
1
  import { createCodexAppServerReasoning } from "./codexReasoning.js";
2
+ import { createCodexAppServerLiveItems, codexAppServerLiveProgressCandidate } from "./codexLiveItems.js";
3
+ import { codexAppServerProcessedResultEvent, codexAppServerTurnCanReceiveProviderCompletion, codexAppServerTurnAwaitsProviderIdentity, codexAppServerTurnCanReceiveProviderActivity, codexAppServerTurnKey, CODEX_APP_SERVER_AGENT_RUN_ID, codexAppServerRunInputSource, codexAppServerConversationMessageId } from "./codexTurnState.js";
4
+ import { isRecord, normalizeText } from "@jskit-ai/kernel/shared/support/normalize";
2
5
  import {
3
- normalizeCodexRunText,
4
- codexAppServerProcessedResultEvent,
5
- codexAppServerTurnCanReceiveProviderCompletion,
6
- codexAppServerTurnAwaitsProviderIdentity,
7
- codexAppServerTurnCanReceiveProviderActivity,
8
- codexAppServerTurnKey,
9
- CODEX_APP_SERVER_AGENT_RUN_ID,
10
- codexAppServerRunInputSource
11
- } from "./codexTurnState.js";
12
- import crypto from "node:crypto";
13
- import { isRecord } from "@jskit-ai/kernel/shared/support/normalize";
14
- import {
15
- codexAppServerAgentMessageText,
16
6
  codexAppServerAssistantItemText,
17
- classifyCodexAppServerEvent,
18
- codexAppServerNotificationEvent,
19
- codexAppServerNotificationEventType,
20
- codexAppServerNotificationEventPayload,
21
- codexAppServerNotificationItem,
22
7
  codexAppServerNotificationItemId,
23
- codexAppServerNotificationTurnId,
24
- codexAppServerProviderThreadAssistantSegments
8
+ codexAppServerNotificationTurnId
25
9
  } from "./codexEvents.js";
10
+ import { codexAppServerProviderThreadAssistantSegments } from "./codexThreadSnapshot.js";
26
11
 
27
- // Native output, reasoning persistence and exact-result identity.
28
- // One instance belongs to each retained run owner; its state is shared by reference.
12
+ /**
13
+ * Native output, reasoning persistence and exact-result identity. One instance belongs to each retained run owner;
14
+ * its state is shared by reference.
15
+ * @param {object} dependencies
16
+ * @param {import("./codexTurn.js").CodexSessionNamespace} dependencies.namespace
17
+ * @param {import("./codexTurn.js").CodexCreateRuntime} dependencies.createRuntime
18
+ * @param {import("./codexTurn.js").CodexCreateStore} dependencies.createStore
19
+ * @param {import("./codexTurn.js").CodexPublish} dependencies.publish
20
+ * @param {(input: { sessionId: string, runtime: any, session: object }) => Promise<any>} dependencies.acquireProvider
21
+ * @param {import("./codexTurn.js").CodexTurnStateReader} dependencies.turnState
22
+ * @param {import("./codexTurn.js").CodexAgentRunTurnStateReader} dependencies.turnStateFromAgentRun
23
+ * @param {import("./codexTurn.js").CodexDebugLog} dependencies.debugLog
24
+ * @param {import("./codexTurn.js").CodexDebugError} dependencies.debugError
25
+ * @param {number} dependencies.liveProgressMaxLength
26
+ * @param {boolean} [dependencies.persistCommentary]
27
+ * @param {import("./codexTurn.js").CodexMessageMetadataHooks} dependencies.messageMetadata
28
+ * @param {number} dependencies.snapshotRecoveryItemLimit
29
+ */
29
30
  export function createCodexAppServerOutput({
30
31
  namespace,
31
32
  createRuntime,
@@ -38,7 +39,6 @@ export function createCodexAppServerOutput({
38
39
  debugError,
39
40
  liveProgressMaxLength,
40
41
  persistCommentary = true,
41
- storeReadError,
42
42
  messageMetadata,
43
43
  snapshotRecoveryItemLimit
44
44
  }) {
@@ -59,9 +59,24 @@ export function createCodexAppServerOutput({
59
59
  debugLog,
60
60
  readCodexAppServerAgentRunForSession
61
61
  });
62
- const codexAppServerLiveProgressItems = new Set();
63
- const codexAppServerLiveProgressFingerprints = new Set();
64
- const codexAppServerMirroredTerminalItems = new Set();
62
+ const {
63
+ liveProgressItems: codexAppServerLiveProgressItems,
64
+ liveProgressFingerprints: codexAppServerLiveProgressFingerprints,
65
+ mirroredTerminalItems: codexAppServerMirroredTerminalItems,
66
+ writeLiveProgress: writeCodexAppServerLiveProgress,
67
+ writeMirroredTerminalMessage: writeMirroredCodexAppServerTerminalMessage,
68
+ mirrorTerminalAssistantMessage: mirrorCodexAppServerTerminalAssistantMessage,
69
+ forgetTurnItems: forgetCodexAppServerLiveTurnItems
70
+ } = createCodexAppServerLiveItems({
71
+ createStore,
72
+ publish,
73
+ turnStateFromAgentRun,
74
+ debugLog,
75
+ readCodexAppServerAgentRunForSession,
76
+ messageMetadata,
77
+ persistCommentary,
78
+ liveProgressMaxLength
79
+ });
65
80
 
66
81
  function codexAppServerResultFinalizationKey(sessionId = "", threadId = "", turnId = "") {
67
82
  return [
@@ -70,262 +85,21 @@ export function createCodexAppServerOutput({
70
85
  ].filter(Boolean).join(":");
71
86
  }
72
87
 
73
- function codexAppServerLiveProgressCandidate(notification = {}) {
74
- const method = normalizeCodexRunText(notification.method);
75
- const event = codexAppServerNotificationEvent(notification);
76
- if (isRecord(event)) {
77
- const eventType = codexAppServerNotificationEventType(notification, event);
78
- const payload = codexAppServerNotificationEventPayload(notification, event);
79
- const payloadType = normalizeCodexRunText(payload.type);
80
- const phase = normalizeCodexRunText(payload.phase || event.phase);
81
- if (eventType === "event_msg" && payloadType === "agent_message" && phase && phase !== "final_answer") {
82
- return {
83
- explicit: Boolean(phase),
84
- phase,
85
- source: "event",
86
- text: codexAppServerAgentMessageText(payload)
87
- };
88
- }
89
- }
90
-
91
- if (method !== "item/completed") {
92
- return null;
93
- }
94
- const item = codexAppServerNotificationItem(notification);
95
- const text = codexAppServerAssistantItemText(item);
96
- if (!text) {
97
- return null;
98
- }
99
- const phase = normalizeCodexRunText(item?.phase || item?.purpose || item?.category);
100
- if (phase === "final_answer") {
101
- return null;
102
- }
103
- return {
104
- explicit: ["commentary", "progress", "status", "thinking"].includes(phase),
105
- phase,
106
- source: "item",
107
- text
108
- };
109
- }
110
-
111
- function codexAppServerLiveProgressText(notification = {}) {
112
- const candidate = codexAppServerLiveProgressCandidate(notification);
113
- const text = normalizeCodexRunText(candidate?.text);
114
- if (!text) {
115
- return "";
116
- }
117
- if (candidate?.phase === "commentary") {
118
- return text;
119
- }
120
- if (text.length > liveProgressMaxLength) {
121
- return "";
122
- }
123
- if (text.includes("\n") || text.includes("\r") || text.includes("```")) {
124
- return "";
125
- }
126
- return text;
127
- }
128
-
129
- function codexAppServerLiveProgressKey(sessionId = "", threadId = "", notification = {}) {
130
- const itemId = codexAppServerNotificationItemId(notification);
131
- if (!itemId) {
132
- return "";
133
- }
134
- return [
135
- normalizeCodexRunText(sessionId),
136
- normalizeCodexRunText(threadId),
137
- codexAppServerNotificationTurnId(notification) || "*",
138
- "live-progress",
139
- itemId
140
- ].join(":");
141
- }
142
-
143
- function codexAppServerLiveProgressFingerprintKey(
144
- sessionId = "",
145
- threadId = "",
146
- turnId = "",
147
- text = ""
148
- ) {
149
- const normalizedText = normalizeCodexRunText(text);
150
- if (!normalizedText) {
151
- return "";
152
- }
153
- return [
154
- normalizeCodexRunText(sessionId),
155
- normalizeCodexRunText(threadId),
156
- normalizeCodexRunText(turnId) || "*",
157
- "live-progress-text",
158
- crypto.createHash("sha256").update(normalizedText).digest("hex")
159
- ].join(":");
160
- }
161
-
162
- function codexAppServerConversationMessageId(
163
- threadId = "",
164
- turnId = "",
165
- role = "",
166
- text = ""
167
- ) {
168
- const normalizedText = normalizeCodexRunText(text);
169
- const normalizedThreadId = normalizeCodexRunText(threadId);
170
- if (!normalizedText || !normalizedThreadId) {
171
- return "";
172
- }
173
- const digest = crypto.createHash("sha256")
174
- .update([
175
- normalizedThreadId,
176
- normalizeCodexRunText(turnId) || "*",
177
- normalizeCodexRunText(role),
178
- normalizedText
179
- ].join("\u0000"))
180
- .digest("hex");
181
- return `codex-${digest}`;
182
- }
183
-
184
88
  async function readCodexAppServerAgentRunForSession(store, sessionId = "") {
185
- const normalizedSessionId = normalizeCodexRunText(sessionId);
89
+ const normalizedSessionId = normalizeText(sessionId);
186
90
  if (!normalizedSessionId) {
187
91
  return null;
188
92
  }
189
- if (typeof store?.readAgentRun !== "function") {
190
- throw new Error(storeReadError);
191
- }
192
93
  return store.readAgentRun(
193
94
  normalizedSessionId,
194
95
  CODEX_APP_SERVER_AGENT_RUN_ID
195
96
  );
196
97
  }
197
98
 
198
- function codexAppServerTerminalItemMirrorKey(sessionId = "", threadId = "", notification = {}, role = "") {
199
- const itemId = codexAppServerNotificationItemId(notification);
200
- if (!itemId) {
201
- return "";
202
- }
203
- return [
204
- normalizeCodexRunText(sessionId),
205
- normalizeCodexRunText(threadId),
206
- codexAppServerNotificationTurnId(notification) || "*",
207
- normalizeCodexRunText(role),
208
- itemId
209
- ].join(":");
210
- }
211
-
212
- async function writeMirroredCodexAppServerTerminalMessage({
213
- notification = {},
214
- role = "",
215
- sessionId = "",
216
- text = "",
217
- threadId = ""
218
- } = {}) {
219
- const normalizedRole = normalizeCodexRunText(role);
220
- const normalizedSessionId = normalizeCodexRunText(sessionId);
221
- const normalizedText = normalizeCodexRunText(text);
222
- if (!normalizedSessionId || !normalizedText || !["assistant", "user"].includes(normalizedRole)) {
223
- return null;
224
- }
225
- const key = codexAppServerTerminalItemMirrorKey(
226
- normalizedSessionId,
227
- threadId,
228
- notification,
229
- normalizedRole
230
- );
231
- if (!key) {
232
- return null;
233
- }
234
- if (codexAppServerMirroredTerminalItems.has(key)) {
235
- return null;
236
- }
237
- codexAppServerMirroredTerminalItems.add(key);
238
- let written = null;
239
- try {
240
- const store = await createStore(sessionId);
241
- const writer = normalizedRole === "user"
242
- ? store?.writeConversationUserMessage
243
- : store?.writeConversationAssistantMessage;
244
- if (typeof writer !== "function") {
245
- codexAppServerMirroredTerminalItems.delete(key);
246
- return null;
247
- }
248
- let turnMetadata = null;
249
- if (normalizedRole === "user" && typeof store.readConversationLog === "function") {
250
- turnMetadata = await messageMetadata.terminal?.(store, normalizedSessionId) ?? null;
251
- }
252
- written = await writer.call(store, normalizedSessionId, {
253
- messageId: codexAppServerConversationMessageId(
254
- threadId,
255
- codexAppServerNotificationTurnId(notification),
256
- normalizedRole,
257
- normalizedText
258
- ),
259
- text: normalizedText,
260
- nativeIdentity: { threadId, turnId: codexAppServerNotificationTurnId(notification) },
261
- ...(turnMetadata ? { turnMetadata } : {})
262
- });
263
- if (!written) {
264
- codexAppServerMirroredTerminalItems.delete(key);
265
- return null;
266
- }
267
- const reason = normalizedRole === "user"
268
- ? "codex-app-server-terminal-user-message"
269
- : "codex-app-server-terminal-assistant-message";
270
- await publish(normalizedSessionId, {
271
- payload: {
272
- conversationLogPatch: {
273
- turn: written,
274
- type: "upsert-turn"
275
- }
276
- },
277
- reason
278
- });
279
- debugLog(`appServerTerminal${normalizedRole === "user" ? "User" : "Assistant"}Message.mirrored`, {
280
- itemId: normalizeCodexRunText(codexAppServerNotificationItem(notification)?.id),
281
- sessionId: normalizedSessionId,
282
- threadId: normalizeCodexRunText(threadId),
283
- turnId: codexAppServerNotificationTurnId(notification)
284
- });
285
- return written;
286
- } catch (error) {
287
- if (!written) {
288
- codexAppServerMirroredTerminalItems.delete(key);
289
- }
290
- throw error;
291
- }
292
- }
293
-
294
- async function mirrorCodexAppServerTerminalAssistantMessage(sessionId = "", threadId = "", notification = {}) {
295
- const normalizedSessionId = normalizeCodexRunText(sessionId);
296
- const normalizedThreadId = normalizeCodexRunText(threadId);
297
- if (codexAppServerLiveProgressCandidate(notification)?.explicit === true) {
298
- return;
299
- }
300
- const classification = classifyCodexAppServerEvent(notification);
301
- // Completed finals use the same native-item publication owner as UI chat.
302
- if (classification.kind === "final_assistant_result") {
303
- return;
304
- }
305
- const text = normalizeCodexRunText(
306
- codexAppServerAssistantItemText(codexAppServerNotificationItem(notification))
307
- );
308
- if (!normalizedSessionId || !text) {
309
- return;
310
- }
311
- const store = await createStore(normalizedSessionId);
312
- const run = await readCodexAppServerAgentRunForSession(store, normalizedSessionId);
313
- if (normalizeCodexRunText(run?.inputSource) !== "terminal") {
314
- return;
315
- }
316
- await writeMirroredCodexAppServerTerminalMessage({
317
- notification,
318
- role: "assistant",
319
- sessionId: normalizedSessionId,
320
- text,
321
- threadId: normalizedThreadId
322
- });
323
- }
324
-
325
99
  function readCodexAppServerFinalAssistantResult(sessionId = "", threadId = "", turnId = "") {
326
- const normalizedSessionId = normalizeCodexRunText(sessionId);
327
- const normalizedThreadId = normalizeCodexRunText(threadId);
328
- const normalizedTurnId = normalizeCodexRunText(turnId);
100
+ const normalizedSessionId = normalizeText(sessionId);
101
+ const normalizedThreadId = normalizeText(threadId);
102
+ const normalizedTurnId = normalizeText(turnId);
329
103
  if (!normalizedSessionId || !normalizedThreadId || !normalizedTurnId) {
330
104
  return null;
331
105
  }
@@ -338,7 +112,7 @@ export function createCodexAppServerOutput({
338
112
  if (record.conversationTurn && !streamItemId) {
339
113
  return record.conversationTurn;
340
114
  }
341
- const conversationText = normalizeCodexRunText(record.text);
115
+ const conversationText = normalizeText(record.text);
342
116
  if (!conversationText) {
343
117
  return null;
344
118
  }
@@ -385,11 +159,11 @@ export function createCodexAppServerOutput({
385
159
  });
386
160
  record.conversationTurn = written;
387
161
  debugLog("appServerAssistantResponseBundle.persisted", {
388
- conversationTurnId: normalizeCodexRunText(written.turnId),
389
- sessionId: normalizeCodexRunText(sessionId),
162
+ conversationTurnId: normalizeText(written.turnId),
163
+ sessionId: normalizeText(sessionId),
390
164
  textLength: conversationText.length,
391
- threadId: normalizeCodexRunText(record.threadId),
392
- turnId: normalizeCodexRunText(record.turnId)
165
+ threadId: normalizeText(record.threadId),
166
+ turnId: normalizeText(record.turnId)
393
167
  });
394
168
  return written;
395
169
  }
@@ -405,10 +179,10 @@ export function createCodexAppServerOutput({
405
179
  threadId = "",
406
180
  turnId = ""
407
181
  } = {}) {
408
- const normalizedSessionId = normalizeCodexRunText(sessionId);
409
- const normalizedThreadId = normalizeCodexRunText(threadId);
410
- const assistantText = normalizeCodexRunText(text);
411
- const normalizedItemId = normalizeCodexRunText(itemId) || codexAppServerNotificationItemId(notification);
182
+ const normalizedSessionId = normalizeText(sessionId);
183
+ const normalizedThreadId = normalizeText(threadId);
184
+ const assistantText = normalizeText(text);
185
+ const normalizedItemId = normalizeText(itemId) || codexAppServerNotificationItemId(notification);
412
186
  if (!normalizedSessionId || !normalizedThreadId || !assistantText || !normalizedItemId) {
413
187
  return {
414
188
  recorded: false,
@@ -419,8 +193,8 @@ export function createCodexAppServerOutput({
419
193
  const runtime = await createRuntime();
420
194
  const session = await runtime.getSession(normalizedSessionId);
421
195
  const currentTurn = turnState(session);
422
- const currentTurnId = normalizeCodexRunText(currentTurn.turnId);
423
- const normalizedTurnId = normalizeCodexRunText(turnId) || codexAppServerNotificationTurnId(notification);
196
+ const currentTurnId = normalizeText(currentTurn.turnId);
197
+ const normalizedTurnId = normalizeText(turnId) || codexAppServerNotificationTurnId(notification);
424
198
  if (!normalizedTurnId) {
425
199
  return { recorded: false, reason: "missing_turn_id" };
426
200
  }
@@ -454,7 +228,7 @@ export function createCodexAppServerOutput({
454
228
  currentThreadId: currentTurn.threadId,
455
229
  currentTurnId: currentTurn.turnId,
456
230
  sessionId: normalizedSessionId,
457
- source: normalizeCodexRunText(source),
231
+ source: normalizeText(source),
458
232
  threadId: normalizedThreadId,
459
233
  turnId: normalizedTurnId
460
234
  });
@@ -497,7 +271,7 @@ export function createCodexAppServerOutput({
497
271
  }
498
272
  const record = {
499
273
  itemId: normalizedItemId,
500
- source: normalizeCodexRunText(source),
274
+ source: normalizeText(source),
501
275
  text: assistantText,
502
276
  threadId: normalizedThreadId,
503
277
  turnId: normalizedTurnId
@@ -530,26 +304,7 @@ export function createCodexAppServerOutput({
530
304
 
531
305
  function cleanupCodexAppServerUntrackedTurn(threadId = "", turnId = "") {
532
306
  cleanupCodexAppServerReasoningTurn(threadId, turnId);
533
- const normalizedThreadId = normalizeCodexRunText(threadId);
534
- const normalizedTurnId = normalizeCodexRunText(turnId);
535
- if (!normalizedThreadId) {
536
- return;
537
- }
538
- const markers = [
539
- `:${normalizedThreadId}:*:`,
540
- ...(normalizedTurnId ? [`:${normalizedThreadId}:${normalizedTurnId}:`] : [])
541
- ];
542
- for (const set of [
543
- codexAppServerLiveProgressItems,
544
- codexAppServerLiveProgressFingerprints,
545
- codexAppServerMirroredTerminalItems
546
- ]) {
547
- for (const key of set) {
548
- if (markers.some((marker) => key.includes(marker))) {
549
- set.delete(key);
550
- }
551
- }
552
- }
307
+ forgetCodexAppServerLiveTurnItems(threadId, turnId);
553
308
  }
554
309
 
555
310
  function codexAppServerStreamMessage(classification) {
@@ -583,102 +338,10 @@ export function createCodexAppServerOutput({
583
338
  }
584
339
  }
585
340
 
586
- async function writeCodexAppServerLiveProgress(sessionId = "", threadId = "", notification = {}) {
587
- // Phase-less providers also send short updates as agent messages.
588
- // Reasoning items are recorded separately from these user-facing updates.
589
- const normalizedSessionId = normalizeCodexRunText(sessionId);
590
- const normalizedThreadId = normalizeCodexRunText(threadId);
591
- const candidate = codexAppServerLiveProgressCandidate(notification);
592
- const text = codexAppServerLiveProgressText(notification);
593
- if (!normalizedSessionId || !normalizedThreadId || !text) {
594
- return null;
595
- }
596
- const store = await createStore(normalizedSessionId);
597
- const run = await readCodexAppServerAgentRunForSession(store, normalizedSessionId);
598
- const turn = turnStateFromAgentRun(run || {});
599
- const notificationTurnId = codexAppServerNotificationTurnId(notification);
600
- const ownerTurnId = notificationTurnId || turn.turnId;
601
- if (!codexAppServerTurnCanReceiveProviderActivity(turn, normalizedThreadId, notificationTurnId)) {
602
- return null;
603
- }
604
- const key = codexAppServerLiveProgressKey(normalizedSessionId, normalizedThreadId, notification);
605
- if (!key) {
606
- return null;
607
- }
608
- const fingerprintKey = codexAppServerLiveProgressFingerprintKey(
609
- normalizedSessionId,
610
- normalizedThreadId,
611
- ownerTurnId,
612
- text
613
- );
614
- const streamMessageId = codexAppServerConversationMessageId(
615
- normalizedThreadId, notificationTurnId,
616
- "assistant-item", codexAppServerNotificationItemId(notification)
617
- );
618
- if (
619
- codexAppServerLiveProgressItems.has(key) ||
620
- codexAppServerLiveProgressFingerprints.has(fingerprintKey)
621
- ) {
622
- await publish(normalizedSessionId, {
623
- payload: { conversationStream: store.completeConversationStreamMessage(normalizedSessionId, streamMessageId) },
624
- reason: "assistant-stream"
625
- });
626
- return null;
627
- }
628
- codexAppServerLiveProgressItems.add(key);
629
- codexAppServerLiveProgressFingerprints.add(fingerprintKey);
630
- let written = null;
631
- try {
632
- const role = !candidate.phase || candidate.phase === "commentary" ? "commentary" : "thinking";
633
- const writer = role === "commentary"
634
- ? store.writeConversationCommentaryMessage
635
- : store.writeConversationThinkingMessage;
636
- if (role !== "commentary" || persistCommentary) {
637
- written = await writer.call(store, normalizedSessionId, {
638
- ...(streamMessageId ? { outputId: streamMessageId } : {}),
639
- messageId: codexAppServerConversationMessageId(
640
- normalizedThreadId,
641
- ownerTurnId,
642
- role,
643
- text
644
- ),
645
- requireOpenTurn: false,
646
- nativeIdentity: { threadId: normalizedThreadId, turnId: ownerTurnId },
647
- text
648
- });
649
- if (!written) {
650
- codexAppServerLiveProgressItems.delete(key);
651
- codexAppServerLiveProgressFingerprints.delete(fingerprintKey);
652
- }
653
- }
654
- const payload = {
655
- conversationStream: await store.completeConversationStreamMessage(normalizedSessionId, streamMessageId, {
656
- text, role, nativeIdentity: { threadId: normalizedThreadId, turnId: ownerTurnId }
657
- })
658
- };
659
- if (written) {
660
- payload.conversationLogPatch = { turn: written, type: "upsert-turn" };
661
- }
662
- await publish(normalizedSessionId, {
663
- payload,
664
- reason: role === "commentary"
665
- ? "codex-app-server-commentary"
666
- : "codex-app-server-live-progress"
667
- });
668
- return written;
669
- } catch (error) {
670
- if (!written) {
671
- codexAppServerLiveProgressItems.delete(key);
672
- codexAppServerLiveProgressFingerprints.delete(fingerprintKey);
673
- }
674
- throw error;
675
- }
676
- }
677
-
678
341
  async function recoverCodexAppServerAssistantSegmentsFromProvider(sessionId = "", threadId = "", turnId = "") {
679
- const normalizedSessionId = normalizeCodexRunText(sessionId);
680
- const normalizedThreadId = normalizeCodexRunText(threadId);
681
- const normalizedTurnId = normalizeCodexRunText(turnId);
342
+ const normalizedSessionId = normalizeText(sessionId);
343
+ const normalizedThreadId = normalizeText(threadId);
344
+ const normalizedTurnId = normalizeText(turnId);
682
345
  if (!normalizedSessionId || !normalizedThreadId || !normalizedTurnId) {
683
346
  return [];
684
347
  }
@@ -717,9 +380,9 @@ export function createCodexAppServerOutput({
717
380
  async function submitCodexAppServerAssistantResult(sessionId = "", threadId = "", turnId = "", {
718
381
  recoverFromProvider = false
719
382
  } = {}) {
720
- const normalizedSessionId = normalizeCodexRunText(sessionId);
383
+ const normalizedSessionId = normalizeText(sessionId);
721
384
  let finalResult = readCodexAppServerFinalAssistantResult(normalizedSessionId, threadId, turnId);
722
- let assistantText = normalizeCodexRunText(finalResult?.text);
385
+ let assistantText = normalizeText(finalResult?.text);
723
386
  const reasoningText = readCodexAppServerReasoningText(threadId, turnId);
724
387
  try {
725
388
  if (normalizedSessionId && recoverFromProvider) {
@@ -740,7 +403,7 @@ export function createCodexAppServerOutput({
740
403
  }
741
404
  if (recoveredSegments.length) {
742
405
  finalResult = readCodexAppServerFinalAssistantResult(normalizedSessionId, threadId, turnId);
743
- assistantText = normalizeCodexRunText(finalResult?.text);
406
+ assistantText = normalizeText(finalResult?.text);
744
407
  }
745
408
  }
746
409
  if (!normalizedSessionId || !assistantText && !reasoningText) {
@@ -771,11 +434,11 @@ export function createCodexAppServerOutput({
771
434
  debugLog("appServerAgentResult.error", {
772
435
  error: debugError(error),
773
436
  sessionId: normalizedSessionId,
774
- threadId: normalizeCodexRunText(threadId),
775
- turnId: normalizeCodexRunText(turnId)
437
+ threadId: normalizeText(threadId),
438
+ turnId: normalizeText(turnId)
776
439
  });
777
440
  return {
778
- error: normalizeCodexRunText(error?.error || error?.message || error) || "Codex app-server response could not be processed.",
441
+ error: normalizeText(error?.error || error?.message || error) || "Codex app-server response could not be processed.",
779
442
  ok: false,
780
443
  processed: false,
781
444
  reason: "error"
@@ -785,7 +448,7 @@ export function createCodexAppServerOutput({
785
448
  }
786
449
  }
787
450
 
788
- function codexAppServerSnapshotCursor(run = {}) {
451
+ function codexAppServerSnapshotCursor(run) {
789
452
  const cursor = run?.providerSnapshotCursor;
790
453
  if (!isRecord(cursor)) {
791
454
  return {
@@ -794,8 +457,8 @@ export function createCodexAppServerOutput({
794
457
  };
795
458
  }
796
459
  return {
797
- itemId: normalizeCodexRunText(cursor.itemId),
798
- turnId: normalizeCodexRunText(cursor.turnId)
460
+ itemId: normalizeText(cursor.itemId),
461
+ turnId: normalizeText(cursor.turnId)
799
462
  };
800
463
  }
801
464
 
@@ -803,9 +466,9 @@ export function createCodexAppServerOutput({
803
466
  itemId = "",
804
467
  turnId = ""
805
468
  } = {}) {
806
- const normalizedItemId = normalizeCodexRunText(itemId);
807
- const normalizedSessionId = normalizeCodexRunText(sessionId);
808
- const normalizedTurnId = normalizeCodexRunText(turnId);
469
+ const normalizedItemId = normalizeText(itemId);
470
+ const normalizedSessionId = normalizeText(sessionId);
471
+ const normalizedTurnId = normalizeText(turnId);
809
472
  if (!normalizedItemId || !normalizedSessionId || !normalizedTurnId) {
810
473
  return;
811
474
  }
@@ -836,11 +499,11 @@ export function createCodexAppServerOutput({
836
499
  observedTurn = null,
837
500
  provider = null
838
501
  ) {
839
- const normalizedSessionId = normalizeCodexRunText(sessionId);
840
- const normalizedThreadId = normalizeCodexRunText(threadId);
841
- const normalizedTurnId = normalizeCodexRunText(observedTurn?.id);
502
+ const normalizedSessionId = normalizeText(sessionId);
503
+ const normalizedThreadId = normalizeText(threadId);
504
+ const normalizedTurnId = normalizeText(observedTurn?.id);
842
505
  const items = (Array.isArray(observedTurn?.items) ? observedTurn.items : [])
843
- .filter((item) => isRecord(item) && normalizeCodexRunText(item.id));
506
+ .filter((item) => isRecord(item) && normalizeText(item.id));
844
507
  if (!normalizedSessionId || !normalizedThreadId || !normalizedTurnId || !items.length) {
845
508
  return;
846
509
  }
@@ -861,7 +524,7 @@ export function createCodexAppServerOutput({
861
524
  }
862
525
  const cursor = codexAppServerSnapshotCursor(run);
863
526
  const cursorIndex = cursor.turnId === normalizedTurnId
864
- ? items.findIndex((item) => normalizeCodexRunText(item.id) === cursor.itemId)
527
+ ? items.findIndex((item) => normalizeText(item.id) === cursor.itemId)
865
528
  : -1;
866
529
  const unseenItems = cursorIndex >= 0
867
530
  ? items.slice(cursorIndex + 1)
@@ -890,7 +553,7 @@ export function createCodexAppServerOutput({
890
553
  );
891
554
  }
892
555
  await recordCodexAppServerSnapshotCursor(store, normalizedSessionId, {
893
- itemId: normalizeCodexRunText(items.at(-1)?.id),
556
+ itemId: normalizeText(items.at(-1)?.id),
894
557
  turnId: normalizedTurnId
895
558
  });
896
559
  } catch (error) {
@@ -899,7 +562,7 @@ export function createCodexAppServerOutput({
899
562
  }
900
563
  }
901
564
 
902
- return {
565
+ return Object.freeze({
903
566
  finalizedTurns: codexAppServerFinalizedTurns,
904
567
  finalAssistantResults: codexAppServerFinalAssistantResults,
905
568
  reasoningTurns: codexAppServerReasoningTurns,
@@ -925,5 +588,7 @@ export function createCodexAppServerOutput({
925
588
  writeMirroredTerminalMessage: writeMirroredCodexAppServerTerminalMessage,
926
589
  mirrorTerminalAssistantMessage: mirrorCodexAppServerTerminalAssistantMessage,
927
590
  reconcileObservedTurnItems: reconcileCodexAppServerObservedTurnItems
928
- };
591
+ });
929
592
  }
593
+
594
+ /** @typedef {ReturnType<typeof createCodexAppServerOutput>} CodexAppServerOutput */