@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
@@ -11,7 +11,7 @@ function nonNegativeInteger(value) {
11
11
  return Number.isSafeInteger(number) && number >= 0 ? number : null;
12
12
  }
13
13
 
14
- function codexContextUsageFromNotification(notification = {}) {
14
+ function codexContextUsageFromNotification(notification) {
15
15
  if (normalizeNullableText(notification?.method) !== CODEX_TOKEN_USAGE_METHOD) {
16
16
  return null;
17
17
  }
@@ -104,7 +104,7 @@ function codexAppServerStatusFromValue(status = null) {
104
104
  return type;
105
105
  }
106
106
 
107
- function codexAppServerNotificationParams(notification = {}) {
107
+ function codexAppServerNotificationParams(notification) {
108
108
  return isRecord(notification?.params) ? notification.params : {};
109
109
  }
110
110
 
@@ -604,74 +604,6 @@ function codexAppServerContextRefreshReason(notification = {}) {
604
604
  return "";
605
605
  }
606
606
 
607
- // Like codexAppServerThreadRawValue, but provider results may also wrap the
608
- // thread once more under `thread`, checked after raw and response.thread.
609
- function codexAppServerProviderThread(value = {}) {
610
- if (!isRecord(value?.raw) && !isRecord(value?.response?.thread) && isRecord(value?.thread)) {
611
- return value.thread;
612
- }
613
- return codexAppServerThreadRawValue(value || {});
614
- }
615
-
616
- function codexAppServerProviderTurnId(turn = {}) {
617
- return normalizeNullableText(turn.id || turn.turnId || turn.turn_id || turn.turn?.id || "");
618
- }
619
-
620
- function codexAppServerProviderTurnItems(turn = {}) {
621
- return [
622
- ...(Array.isArray(turn.items) ? turn.items : []),
623
- ...(Array.isArray(turn.itemsView) ? turn.itemsView : [])
624
- ].filter(isRecord);
625
- }
626
-
627
- function codexAppServerProviderThreadTurn(value = {}, turnId = "") {
628
- const normalizedTurnId = normalizeNullableText(turnId);
629
- if (!normalizedTurnId) {
630
- return null;
631
- }
632
- const thread = codexAppServerProviderThread(value);
633
- return (Array.isArray(thread.turns) ? thread.turns : [])
634
- .find((turn) => codexAppServerProviderTurnId(turn) === normalizedTurnId) || null;
635
- }
636
-
637
- function codexAppServerProviderTurnAssistantSegments(turn = {}) {
638
- const seenItemIds = new Set();
639
- const items = codexAppServerProviderTurnItems(turn);
640
- // Providers without phases emit progress as ordinary assistant messages.
641
- // Only the trailing response can be a final; reasoning/tools separate it
642
- // from earlier updates. Explicit finals retain their native attribution.
643
- let responseStart = items.length;
644
- while (responseStart > 0 && codexAppServerAssistantItemText(items[responseStart - 1])) responseStart -= 1;
645
- const active = ["inProgress", "starting"].includes(codexAppServerStatusFromValue(turn.status));
646
- return items
647
- .filter((item, index) => {
648
- const phase = normalizeNullableText(item.phase);
649
- return phase === "final_answer" || (!phase && !active && index >= responseStart);
650
- })
651
- .map((item) => {
652
- const itemId = normalizeNullableText(item.id);
653
- const text = codexAppServerAssistantItemText(item);
654
- if (
655
- !itemId ||
656
- !text ||
657
- seenItemIds.has(itemId)
658
- ) {
659
- return null;
660
- }
661
- seenItemIds.add(itemId);
662
- return {
663
- itemId,
664
- text
665
- };
666
- })
667
- .filter(Boolean);
668
- }
669
-
670
- function codexAppServerProviderThreadAssistantSegments(value = {}, turnId = "") {
671
- const turn = codexAppServerProviderThreadTurn(value, turnId);
672
- return turn ? codexAppServerProviderTurnAssistantSegments(turn) : [];
673
- }
674
-
675
607
  function codexAppServerOutputOwnerTurnId({
676
608
  notificationThreadId = "",
677
609
  notificationTurnId = "",
@@ -693,139 +625,12 @@ function codexAppServerOutputOwnerTurnId({
693
625
  : normalizeNullableText(notificationTurnId);
694
626
  }
695
627
 
696
- function codexAppServerThreadRawValue(thread = {}) {
697
- if (isRecord(thread.raw)) {
698
- return thread.raw;
699
- }
700
- if (isRecord(thread.response?.thread)) {
701
- return thread.response.thread;
702
- }
703
- return isRecord(thread) ? thread : {};
704
- }
705
-
706
- function codexAppServerThreadTurnId(thread = {}) {
707
- const observedTurnId = normalizeNullableText(thread.observedTurn?.id || "");
708
- if (observedTurnId) {
709
- return observedTurnId;
710
- }
711
- const rawThread = codexAppServerThreadRawValue(thread);
712
- const status = isRecord(rawThread.status) ? rawThread.status : {};
713
- return normalizeNullableText(
714
- thread.turnId ||
715
- thread.turn_id ||
716
- thread.turn?.id ||
717
- rawThread.turnId ||
718
- rawThread.turn_id ||
719
- rawThread.turn?.id ||
720
- rawThread.currentTurnId ||
721
- rawThread.current_turn_id ||
722
- rawThread.activeTurnId ||
723
- rawThread.active_turn_id ||
724
- status.turnId ||
725
- status.turn_id ||
726
- status.turn?.id ||
727
- status.currentTurnId ||
728
- status.current_turn_id ||
729
- status.activeTurnId ||
730
- status.active_turn_id ||
731
- ""
732
- );
733
- }
734
-
735
- function codexAppServerThreadError(thread = {}) {
736
- const rawThread = codexAppServerThreadRawValue(thread);
737
- const status = isRecord(rawThread.status) ? rawThread.status : {};
738
- return codexAppServerErrorText(rawThread.error || status.error);
739
- }
740
-
741
- function codexAppServerProviderThreadTurns(thread = null) {
742
- const rawThread = codexAppServerThreadRawValue(thread || {});
743
- return (Array.isArray(rawThread.turns) ? rawThread.turns : [])
744
- .filter((turn) => isRecord(turn));
745
- }
746
-
747
- function codexAppServerProviderTurnStatus(turn = {}) {
748
- return codexAppServerStatusFromValue(turn.status || turn.state);
749
- }
750
-
751
- function codexAppServerProviderTurnClientIds(turn = {}) {
752
- return codexAppServerProviderTurnItems(turn)
753
- .map((item) => normalizeNullableText(
754
- item.clientId ||
755
- item.client_id ||
756
- item.clientUserMessageId ||
757
- item.client_user_message_id ||
758
- ""
759
- ))
760
- .filter(Boolean);
761
- }
762
-
763
- function codexAppServerProviderTurnForOperation(thread = null, {
764
- clientMessageId = "",
765
- turnId = ""
766
- } = {}) {
767
- const normalizedTurnId = normalizeNullableText(turnId || "");
768
- const normalizedClientMessageId = normalizeNullableText(clientMessageId || "");
769
- const turns = codexAppServerProviderThreadTurns(thread);
770
- if (normalizedTurnId) {
771
- return turns.find((turn) => (
772
- codexAppServerProviderTurnId(turn) === normalizedTurnId
773
- )) || null;
774
- }
775
- if (!normalizedClientMessageId) {
776
- return null;
777
- }
778
- return [...turns].reverse().find((turn) => (
779
- codexAppServerProviderTurnClientIds(turn).includes(normalizedClientMessageId)
780
- )) || null;
781
- }
782
-
783
- // Native snapshot matching for renewal handover and seeding.
784
- // The application projects these classifications into its approval/error policy.
785
- function inspectCodexAppServerRenewalThread(thread = null, {
786
- clientMessageId = "",
787
- turnId: expectedTurnId = "",
788
- requireFresh = false
789
- } = {}) {
790
- const snapshotTurns = codexAppServerProviderThreadTurns(thread);
791
- const targetTurn = codexAppServerProviderTurnForOperation(thread, {
792
- clientMessageId,
793
- turnId: expectedTurnId
794
- });
795
- if (expectedTurnId && !targetTurn) return { targetTurn, failure: "turn_missing" };
796
- if (!requireFresh && !targetTurn && snapshotTurns.length === 0) return { targetTurn, failure: "history_missing" };
797
- if (requireFresh && snapshotTurns.some((turn) => (
798
- !targetTurn || codexAppServerProviderTurnId(turn) !== codexAppServerProviderTurnId(targetTurn)
799
- ))) return { targetTurn, failure: "unrelated_history" };
800
- return { targetTurn, failure: "" };
801
- }
802
-
803
- function codexAppServerProviderTurnText(thread = null, turnId = "") {
804
- return codexAppServerProviderThreadAssistantSegments(thread || {}, turnId)
805
- .map((segment) => segment.text)
806
- .join("\n\n")
807
- .trim();
808
- }
809
-
810
- function codexAppServerProviderTurnError(turn = {}) {
811
- return codexAppServerSignedOutText(codexAppServerErrorText(turn.error || turn.status?.error || turn.state?.error));
812
- }
628
+ // The `./server/codex-events` contract forwards this snapshot reader from here.
629
+ export { codexAppServerProviderThreadAssistantSegments } from "./codexThreadSnapshot.js";
813
630
 
814
631
  export {
815
632
  codexContextUsageFromNotification,
816
633
  classifyCodexAppServerEvent,
817
- codexAppServerThreadRawValue,
818
- codexAppServerThreadTurnId,
819
- codexAppServerThreadError,
820
- codexAppServerProviderThreadTurns,
821
- codexAppServerProviderTurnId,
822
- codexAppServerProviderTurnStatus,
823
- codexAppServerProviderTurnItems,
824
- codexAppServerProviderTurnClientIds,
825
- codexAppServerProviderTurnForOperation,
826
- inspectCodexAppServerRenewalThread,
827
- codexAppServerProviderTurnText,
828
- codexAppServerProviderTurnError,
829
634
  codexAppServerAgentMessageText,
830
635
  codexAppServerAssistantItemText,
831
636
  codexAppServerContentText,
@@ -842,8 +647,8 @@ export {
842
647
  codexAppServerNotificationTurnId,
843
648
  codexAppServerNotificationTurnStatus,
844
649
  codexAppServerNotificationUsageLimitExceeded,
845
- codexAppServerProviderThreadAssistantSegments,
846
650
  codexAppServerOutputOwnerTurnId,
651
+ codexAppServerSignedOutText,
847
652
  codexAppServerStatusFromValue,
848
653
  codexAppServerUserMessageText
849
654
  };
@@ -1,6 +1,17 @@
1
1
  import { CODEX_APP_SERVER_AGENT_RUN_ID } from "./codexTurnState.js";
2
2
 
3
- // Private composition of unchanged operations from the original run owner.
3
+ /**
4
+ * The run owner's native goal commands: preparing a goal's context, validating its input and updating it.
5
+ * @param {object} dependencies
6
+ * @param {import("./codexConversations.js").CodexConversationCommands["codexAppServerConversationContext"]} dependencies.conversationContext
7
+ * @param {import("./codexThreadReadiness.js").CodexThreadReadiness["ensureThreadReady"]} dependencies.ensureThreadReady
8
+ * @param {import("./codexTurn.js").CodexPublish} dependencies.publish
9
+ * @param {import("./codexOutput.js").CodexAppServerOutput["readAgentRunForSession"]} dependencies.readCodexAppServerAgentRunForSession
10
+ * @param {import("./codexNotificationObserver.js").CodexNotificationObserver["reconcileGoalUpdated"]} dependencies.reconcileCodexAppServerGoalUpdated
11
+ * @param {import("./codexOutput.js").CodexAppServerOutput["submitAssistantResult"]} dependencies.submitCodexAppServerAssistantResult
12
+ * @param {import("./codexNotificationObserver.js").CodexNotificationObserver["subscribeEvents"]} dependencies.subscribeCodexAppServerEvents
13
+ * @param {import("./codexTurn.js").CodexTurnStateReader} dependencies.turnState
14
+ */
4
15
  export function createCodexGoalCommands({
5
16
  conversationContext,
6
17
  ensureThreadReady,
@@ -120,10 +131,9 @@ export function createCodexGoalCommands({
120
131
  return { ok: true, status: "available", threadId, goal: result.goal || null };
121
132
  }
122
133
 
123
-
124
- return {
134
+ return Object.freeze({
125
135
  prepareCodexAppServerGoalContext,
126
136
  validateCodexAppServerGoalInput,
127
137
  updateCodexAppServerGoal
128
- };
138
+ });
129
139
  }
@@ -1,34 +1,31 @@
1
- import { codexAppServerDeliveredTurn, deleteCodexAppServerThread } from "./codexProvider.js";
2
- import { CODEX_HELPER_THREAD_LIFECYCLES } from "./codexHelperThreadLedger.js";
3
- import { codexAppServerErrorMessage as errorMessage, normalizeCodexRunText as normalizeText } from "./codexTurnState.js";
1
+ import { AppError } from "@jskit-ai/kernel/server/runtime/errors";
2
+ import { codexAppServerDeliveredTurn } from "./codexProviderTurns.js";
3
+ import { deleteCodexAppServerThread } from "./codexProviderThreads.js";
4
+ import { CODEX_HELPER_THREAD_LIFECYCLES } from "./codexHelperThreadRecord.js";
5
+ import { codexAppServerErrorMessage as errorMessage } from "./codexTurnState.js";
6
+ import { normalizeText } from "@jskit-ai/kernel/shared/support/normalize";
4
7
 
5
8
  export function createCodexHelperOwnershipError({ applicationName = "Application", errorPrefix = "" } = {}) {
6
9
  return function codexAppServerHelperOwnershipError(message = "", details = {}) {
7
- const error = new Error(
8
- normalizeText(message) ||
9
- `${applicationName} could not prove ownership of a persisted low-cost assistant thread.`
10
+ const retryable = details.retryable !== false;
11
+ const error = new AppError(409,
12
+ normalizeText(message) || `${applicationName} could not prove ownership of a persisted low-cost assistant thread.`,
13
+ {
14
+ code: `${errorPrefix}codex_helper_ownership_blocked`,
15
+ details: { ...details, retryable },
16
+ ...(normalizeText(message) ? {} : { messageCode: "assistant.codex.helperOwnershipBlocked", messageParams: { applicationName } })
17
+ }
10
18
  );
11
- error.code = `${errorPrefix}codex_helper_ownership_blocked`;
12
- error.statusCode = 409;
13
- if (!normalizeText(message)) {
14
- error.messageCode = "assistant.codex.helperOwnershipBlocked";
15
- error.messageParams = { applicationName };
16
- }
17
- error.retryable = details.retryable !== false;
18
- error.details = {
19
- ...details,
20
- retryable: error.retryable
21
- };
19
+ error.retryable = retryable;
22
20
  return error;
23
21
  };
24
22
  }
25
23
 
24
+ /**
25
+ * @param {import("./codexProvider.js").CodexAppServerAgentProvider} provider
26
+ * @param {ReturnType<typeof createCodexHelperOwnershipError>} codexAppServerHelperOwnershipError
27
+ */
26
28
  export async function readCodexAppServerAccountIdentity(provider, codexAppServerHelperOwnershipError) {
27
- if (typeof provider.currentRuntimeInfo !== "function") {
28
- throw codexAppServerHelperOwnershipError(
29
- "The Codex provider cannot identify the selected account."
30
- );
31
- }
32
29
  const runtimeInfo = await provider.currentRuntimeInfo();
33
30
  const accountIdentitySignature = normalizeText(runtimeInfo?.accountIdentitySignature);
34
31
  if (!/^sha256:[a-f0-9]{64}$/u.test(accountIdentitySignature)) {
@@ -39,12 +36,17 @@ export async function readCodexAppServerAccountIdentity(provider, codexAppServer
39
36
  return accountIdentitySignature;
40
37
  }
41
38
 
39
+ /**
40
+ * @param {import("./codexProvider.js").CodexAppServerAgentProvider | null} provider
41
+ * @param {string} expectedSignature
42
+ * @param {ReturnType<typeof createCodexHelperOwnershipError>} codexAppServerHelperOwnershipError
43
+ */
42
44
  export async function assertCodexAppServerHelperAccountIdentity(provider, expectedSignature = "", codexAppServerHelperOwnershipError) {
43
45
  const expected = normalizeText(expectedSignature);
44
46
  if (!expected) {
45
47
  return;
46
48
  }
47
- if (!/^sha256:[a-f0-9]{64}$/u.test(expected) || typeof provider?.currentRuntimeInfo !== "function") {
49
+ if (!/^sha256:[a-f0-9]{64}$/u.test(expected) || !provider) {
48
50
  throw codexAppServerHelperOwnershipError(
49
51
  "The requested low-cost assistant account identity is invalid. Refresh the task and retry."
50
52
  );
@@ -65,25 +67,18 @@ export async function sendPreparedCodexAppServerHelperTurn(provider, prepared, h
65
67
  prepared.input,
66
68
  prepared.turnSettings((await helperIsolation.executionContext(provider)).cwd)
67
69
  );
68
- return Object.freeze({ executionProfile: prepared.executionProfile, input: prepared.input, turn });
70
+ return Object.freeze({
71
+ executionProfile: prepared.executionProfile,
72
+ input: prepared.input,
73
+ turn
74
+ });
69
75
  }
70
76
 
71
- // One invocation retains its original mutable record while the shared ownership
72
- // facet retains all durable state, locks and cross-operation coordination.
77
+ // One invocation holds its own mutable record; the shared owner holds all
78
+ // durable state, locks and cross-operation coordination.
73
79
  export async function prepareDetachedCodexHelperThread(owner, scope, preparation, {
74
80
  applicationName = "Application"
75
81
  } = {}) {
76
- const {
77
- withProjectOperation: withCodexAppServerHelperProjectOperation,
78
- remember: rememberCodexAppServerHelperThread,
79
- update: updateCodexAppServerHelperThread,
80
- remove: removeCodexAppServerHelperThread,
81
- retire: retireCodexAppServerHelperThread,
82
- ownershipError: codexAppServerHelperOwnershipError,
83
- cleanupError: codexAppServerHelperThreadCleanupError,
84
- key: codexAppServerHelperThreadKey,
85
- turnStarts: codexAppServerHelperTurnStarts
86
- } = owner;
87
82
  const {
88
83
  executionProfile, onRetired, projectRuntimeRoot, provider, sessionId,
89
84
  requestedThreadId, workdir
@@ -100,7 +95,7 @@ export async function prepareDetachedCodexHelperThread(owner, scope, preparation
100
95
  sessionId = "",
101
96
  workdir = ""
102
97
  } = {}) {
103
- return withCodexAppServerHelperProjectOperation(projectRuntimeRoot, async () => {
98
+ return owner.withProjectOperation(projectRuntimeRoot, async () => {
104
99
  const projectContextRoot = normalizeText(scope.projectContextRoot);
105
100
  let thread = null;
106
101
  try {
@@ -116,7 +111,7 @@ export async function prepareDetachedCodexHelperThread(owner, scope, preparation
116
111
  error?.codexAppServerHelperThreadCleanupRequired === true &&
117
112
  failedThreadId
118
113
  ) {
119
- await rememberCodexAppServerHelperThread({
114
+ await owner.remember({
120
115
  executionProfile,
121
116
  lifecycle: CODEX_HELPER_THREAD_LIFECYCLES.CLEANUP_REQUIRED,
122
117
  projectContextRoot,
@@ -134,7 +129,7 @@ export async function prepareDetachedCodexHelperThread(owner, scope, preparation
134
129
  throw new Error("Codex app-server did not return a helper thread id.");
135
130
  }
136
131
  try {
137
- const record = await rememberCodexAppServerHelperThread({
132
+ const record = await owner.remember({
138
133
  executionProfile,
139
134
  lifecycle: CODEX_HELPER_THREAD_LIFECYCLES.STARTING_TURN,
140
135
  onRetired,
@@ -150,7 +145,7 @@ export async function prepareDetachedCodexHelperThread(owner, scope, preparation
150
145
  try {
151
146
  await deleteCodexAppServerThread({ provider, threadId });
152
147
  } catch (cleanupError) {
153
- const failure = codexAppServerHelperOwnershipError(
148
+ const failure = owner.ownershipError(
154
149
  `${applicationName} could not persist or retire a newly created low-cost assistant thread.`,
155
150
  {
156
151
  cleanupError: errorMessage(cleanupError),
@@ -169,7 +164,7 @@ export async function prepareDetachedCodexHelperThread(owner, scope, preparation
169
164
 
170
165
  if (requestedThreadId) {
171
166
  try {
172
- helperThreadRecord = await updateCodexAppServerHelperThread(
167
+ helperThreadRecord = await owner.update(
173
168
  helperThreadRecord,
174
169
  {
175
170
  lifecycle: CODEX_HELPER_THREAD_LIFECYCLES.STARTING_TURN,
@@ -186,30 +181,30 @@ export async function prepareDetachedCodexHelperThread(owner, scope, preparation
186
181
  } catch (error) {
187
182
  if (error?.codexAppServerHelperThreadRetired === true) {
188
183
  try {
189
- await removeCodexAppServerHelperThread(helperThreadRecord);
184
+ await owner.remove(helperThreadRecord);
190
185
  } catch (ledgerError) {
191
- throw codexAppServerHelperThreadCleanupError(
186
+ throw owner.cleanupError(
192
187
  helperThreadRecord,
193
188
  ledgerError
194
189
  );
195
190
  }
196
191
  } else if (error?.codexAppServerHelperThreadCleanupRequired === true) {
197
192
  try {
198
- helperThreadRecord = await updateCodexAppServerHelperThread(
193
+ helperThreadRecord = await owner.update(
199
194
  helperThreadRecord,
200
195
  {
201
196
  lifecycle: CODEX_HELPER_THREAD_LIFECYCLES.CLEANUP_REQUIRED
202
197
  }
203
198
  );
204
199
  } catch (ledgerError) {
205
- throw codexAppServerHelperThreadCleanupError(
200
+ throw owner.cleanupError(
206
201
  helperThreadRecord,
207
202
  ledgerError
208
203
  );
209
204
  }
210
205
  } else {
211
206
  try {
212
- await retireCodexAppServerHelperThread(helperThreadRecord);
207
+ await owner.retire(helperThreadRecord);
213
208
  } catch (cleanupError) {
214
209
  cleanupError.cause = error;
215
210
  throw cleanupError;
@@ -236,7 +231,7 @@ export async function prepareDetachedCodexHelperThread(owner, scope, preparation
236
231
  if (!helperThreadRecord) {
237
232
  return;
238
233
  }
239
- await retireCodexAppServerHelperThread(helperThreadRecord);
234
+ await owner.retire(helperThreadRecord);
240
235
  };
241
236
 
242
237
  async function dispatch(threadId, failDispatch) {
@@ -245,13 +240,13 @@ export async function prepareDetachedCodexHelperThread(owner, scope, preparation
245
240
  let status = "";
246
241
  let helperTurnStart = null;
247
242
  try {
248
- const helperThreadKey = codexAppServerHelperThreadKey(helperThreadRecord);
243
+ const helperThreadKey = owner.key(helperThreadRecord);
249
244
  helperTurnStart = (async () => {
250
245
  const currentDelivery = await sendPreparedCodexAppServerHelperTurn(
251
246
  provider, preparation.turn(threadId), preparation.isolation
252
247
  );
253
248
  const { turnId: currentTurnId, status: currentStatus } = codexAppServerDeliveredTurn(currentDelivery);
254
- helperThreadRecord = await updateCodexAppServerHelperThread(
249
+ helperThreadRecord = await owner.update(
255
250
  helperThreadRecord,
256
251
  {
257
252
  lifecycle: CODEX_HELPER_THREAD_LIFECYCLES.ACTIVE,
@@ -264,15 +259,15 @@ export async function prepareDetachedCodexHelperThread(owner, scope, preparation
264
259
  turnId: currentTurnId
265
260
  };
266
261
  })();
267
- codexAppServerHelperTurnStarts.set(helperThreadKey, helperTurnStart);
262
+ owner.turnStarts.set(helperThreadKey, helperTurnStart);
268
263
  ({ delivery, status, turnId } = await helperTurnStart);
269
264
  } catch (error) {
270
265
  await failDispatch(error);
271
266
  } finally {
272
267
  if (helperTurnStart) {
273
- const helperThreadKey = codexAppServerHelperThreadKey(helperThreadRecord);
274
- if (codexAppServerHelperTurnStarts.get(helperThreadKey) === helperTurnStart) {
275
- codexAppServerHelperTurnStarts.delete(helperThreadKey);
268
+ const helperThreadKey = owner.key(helperThreadRecord);
269
+ if (owner.turnStarts.get(helperThreadKey) === helperTurnStart) {
270
+ owner.turnStarts.delete(helperThreadKey);
276
271
  }
277
272
  }
278
273
  }
@@ -281,13 +276,13 @@ export async function prepareDetachedCodexHelperThread(owner, scope, preparation
281
276
 
282
277
  async function complete() {
283
278
  try {
284
- helperThreadRecord = await updateCodexAppServerHelperThread(helperThreadRecord, {
279
+ helperThreadRecord = await owner.update(helperThreadRecord, {
285
280
  lifecycle: CODEX_HELPER_THREAD_LIFECYCLES.READY,
286
281
  turnId: ""
287
282
  });
288
283
  } catch (error) {
289
284
  try {
290
- await retireCodexAppServerHelperThread(helperThreadRecord);
285
+ await owner.retire(helperThreadRecord);
291
286
  } catch (cleanupError) {
292
287
  cleanupError.cause = error;
293
288
  throw cleanupError;
@@ -296,5 +291,10 @@ export async function prepareDetachedCodexHelperThread(owner, scope, preparation
296
291
  }
297
292
  }
298
293
 
299
- return Object.freeze({ thread, dispatch, discard: discardHelperThread, complete });
294
+ return Object.freeze({
295
+ thread,
296
+ dispatch,
297
+ discard: discardHelperThread,
298
+ complete
299
+ });
300
300
  }