@jskit-ai/assistant-core 0.2.6 → 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.
- package/examples/conversation/package.json +5 -5
- package/package.json +18 -7
- package/src/client/browser.js +21 -0
- package/src/client/conversation/AssistantAttachmentQueue.vue +25 -108
- package/src/client/conversation/AssistantComposerActions.vue +1 -1
- package/src/client/conversation/AssistantConversationElement.vue +14 -52
- package/src/client/conversation/AssistantGoalControl.vue +18 -12
- package/src/client/conversation/AssistantPromptInput.vue +6 -91
- package/src/client/conversation/AssistantTranscript.css +505 -0
- package/src/client/conversation/AssistantTranscript.vue +24 -1197
- package/src/client/conversation/attachmentFiles.js +158 -0
- package/src/client/conversation/attachmentQueueItems.js +121 -0
- package/src/client/conversation/attachmentUploadRows.js +265 -0
- package/src/client/conversation/conversationDisplay.js +54 -0
- package/src/client/conversation/messageDelivery.js +13 -9
- package/src/client/conversation/retainedConversation.js +14 -3
- package/src/client/conversation/submitText.js +13 -2
- package/src/client/conversation/transcriptEntries.js +225 -0
- package/src/client/conversation/useAssistantAttachments.js +86 -388
- package/src/client/conversation/useAssistantQuestions.js +16 -3
- package/src/client/conversation/useAssistantSuggestions.js +16 -2
- package/src/client/conversation/useScrollToBottom.js +17 -19
- package/src/client/conversation/useTextareaAutoGrow.js +115 -0
- package/src/client/conversation/useTranscriptScrollFollow.js +525 -0
- package/src/client/lib/assistantApi.js +192 -161
- package/src/client/types.js +110 -0
- package/src/server/conversation/attachments.js +21 -6
- package/src/server/conversation/boundedToolLoop.js +1 -0
- package/src/server/conversation/claudeClient.js +71 -20
- package/src/server/conversation/claudeCommandRun.js +191 -0
- package/src/server/conversation/claudeHistory.js +7 -0
- package/src/server/conversation/claudeNativeTurn.js +708 -0
- package/src/server/conversation/claudeProcess.js +186 -112
- package/src/server/conversation/claudeProcessStart.js +214 -0
- package/src/server/conversation/claudePromptDelivery.js +183 -0
- package/src/server/conversation/claudeSessionCleanup.js +248 -0
- package/src/server/conversation/claudeTools.js +15 -3
- package/src/server/conversation/claudeTurn.js +212 -1388
- package/src/server/conversation/codexAccountReader.js +168 -0
- package/src/server/conversation/codexAuthPreflight.js +5 -4
- package/src/server/conversation/codexClient.js +18 -6
- package/src/server/conversation/codexConfiguration.js +8 -844
- package/src/server/conversation/codexConversationStops.js +377 -0
- package/src/server/conversation/codexConversationStore.js +119 -85
- package/src/server/conversation/codexConversationTurns.js +378 -0
- package/src/server/conversation/codexConversations.js +134 -866
- package/src/server/conversation/codexDetachedConversation.js +203 -0
- package/src/server/conversation/codexDetachedTurn.js +145 -104
- package/src/server/conversation/codexEvents.js +5 -200
- package/src/server/conversation/codexGoalCommands.js +14 -4
- package/src/server/conversation/codexHelperExecution.js +57 -57
- package/src/server/conversation/codexHelperThreadLedger.js +30 -288
- package/src/server/conversation/codexHelperThreadRecord.js +304 -0
- package/src/server/conversation/codexHelperThreadRecovery.js +54 -76
- package/src/server/conversation/codexHelperThreads.js +94 -93
- package/src/server/conversation/codexHistoryAdapter.js +13 -8
- package/src/server/conversation/codexIsolation.js +672 -0
- package/src/server/conversation/codexLiveItems.js +379 -0
- package/src/server/conversation/codexMessageCommands.js +68 -286
- package/src/server/conversation/codexMessageDelivery.js +46 -37
- package/src/server/conversation/codexModelCatalog.js +86 -7
- package/src/server/conversation/codexNotificationObserver.js +81 -88
- package/src/server/conversation/codexNotificationQueue.js +21 -10
- package/src/server/conversation/codexObservationControl.js +105 -89
- package/src/server/conversation/codexOutput.js +84 -419
- package/src/server/conversation/codexProcess.js +29 -1053
- package/src/server/conversation/codexProcessLeader.js +1 -0
- package/src/server/conversation/codexPromptDispatch.js +241 -0
- package/src/server/conversation/codexProvider.js +147 -1807
- package/src/server/conversation/codexProviderAuth.js +348 -0
- package/src/server/conversation/codexProviderInvalidation.js +371 -0
- package/src/server/conversation/codexProviderInventories.js +437 -0
- package/src/server/conversation/codexProviderOwner.js +149 -957
- package/src/server/conversation/codexProviderRelease.js +465 -0
- package/src/server/conversation/codexProviderSelection.js +26 -15
- package/src/server/conversation/codexProviderThreads.js +698 -0
- package/src/server/conversation/codexProviderTurns.js +453 -0
- package/src/server/conversation/codexReasoning.js +32 -23
- package/src/server/conversation/codexRenewalCommands.js +18 -6
- package/src/server/conversation/codexRenewalThreads.js +7 -22
- package/src/server/conversation/codexResultSettlement.js +70 -88
- package/src/server/conversation/codexRunJournal.js +91 -97
- package/src/server/conversation/codexRuntime.js +426 -0
- package/src/server/conversation/codexRuntimeInventory.js +113 -0
- package/src/server/conversation/codexRuntimeLifecycle.js +39 -13
- package/src/server/conversation/codexRuntimeStart.js +431 -0
- package/src/server/conversation/codexRuntimeStop.js +324 -0
- package/src/server/conversation/codexSessionCleanup.js +25 -10
- package/src/server/conversation/codexSessionReconciliation.js +21 -7
- package/src/server/conversation/codexThreadReadiness.js +49 -52
- package/src/server/conversation/codexThreadSnapshot.js +210 -0
- package/src/server/conversation/codexThreadStatus.js +48 -62
- package/src/server/conversation/codexTurn.js +171 -55
- package/src/server/conversation/codexTurnActivity.js +210 -0
- package/src/server/conversation/codexTurnControl.js +44 -48
- package/src/server/conversation/codexTurnEndings.js +610 -0
- package/src/server/conversation/codexTurnRecovery.js +97 -848
- package/src/server/conversation/codexTurnState.js +138 -111
- package/src/server/conversation/completedResponses.js +227 -0
- package/src/server/conversation/configuration.js +2 -2
- package/src/server/conversation/continuity.js +43 -6
- package/src/server/conversation/conversationDelivery.js +394 -0
- package/src/server/conversation/conversationEntries.js +365 -0
- package/src/server/conversation/conversationEvents.js +192 -0
- package/src/server/conversation/conversationGoals.js +187 -0
- package/src/server/conversation/conversationHandles.js +237 -0
- package/src/server/conversation/conversationReads.js +206 -0
- package/src/server/conversation/conversationRefusals.js +58 -0
- package/src/server/conversation/conversationReplacement.js +254 -0
- package/src/server/conversation/conversationSending.js +273 -0
- package/src/server/conversation/conversationStopping.js +121 -0
- package/src/server/conversation/conversationTurnDelivery.js +413 -0
- package/src/server/conversation/conversationTurns.js +511 -0
- package/src/server/conversation/deliveryTiming.js +25 -3
- package/src/server/conversation/fileStorage.js +11 -6
- package/src/server/conversation/hookBridge.js +14 -3
- package/src/server/conversation/index.js +1 -1
- package/src/server/conversation/localExecution.js +82 -625
- package/src/server/conversation/nativeCommandCallbacks.js +10 -0
- package/src/server/conversation/nativeConversationLifecycle.js +379 -0
- package/src/server/conversation/nativeHistoryExport.js +27 -18
- package/src/server/conversation/normalize.js +9 -0
- package/src/server/conversation/openCodeClient.js +295 -366
- package/src/server/conversation/openCodeNativeHistory.js +141 -0
- package/src/server/conversation/openCodeNativeSession.js +79 -0
- package/src/server/conversation/openCodeProcess.js +109 -53
- package/src/server/conversation/openCodeProcessOwner.js +565 -0
- package/src/server/conversation/openCodeRuntime.js +111 -1814
- package/src/server/conversation/openCodeSessionTurns.js +547 -0
- package/src/server/conversation/openCodeTemporaryConversations.js +394 -0
- package/src/server/conversation/openCodeTools.js +28 -14
- package/src/server/conversation/openCodeTurn.js +80 -74
- package/src/server/conversation/openCodeTurnMonitor.js +388 -0
- package/src/server/conversation/processIdentity.js +582 -0
- package/src/server/conversation/provider.js +21 -6
- package/src/server/conversation/providers/api.js +268 -107
- package/src/server/conversation/providers/claude.js +29 -6
- package/src/server/conversation/providers/claudeDriver.js +325 -250
- package/src/server/conversation/providers/codex.js +69 -33
- package/src/server/conversation/providers/codexDriver.js +503 -1081
- package/src/server/conversation/providers/codexDriverConnection.js +331 -0
- package/src/server/conversation/providers/codexDriverTurns.js +464 -0
- package/src/server/conversation/providers/opencode.js +30 -4
- package/src/server/conversation/providers/opencodeDriver.js +321 -659
- package/src/server/conversation/providers/opencodeStandalone.js +475 -0
- package/src/server/conversation/providers/scoped.js +64 -19
- package/src/server/conversation/runtime.js +171 -2863
- package/src/server/conversation/storage.js +91 -50
- package/src/server/conversation/streams.js +15 -2
- package/src/server/conversation/structuredOutput.js +7 -11
- package/src/server/conversation/systemPrompt.js +13 -1
- package/src/server/conversation/tools.js +47 -15
- package/src/server/conversation/transcript.js +49 -20
- package/src/server/hosts/claudeTurn.js +2 -4
- package/src/server/hosts/codexConfiguration.js +6 -8
- package/src/server/hosts/codexEvents.js +4 -2
- package/src/server/hosts/codexProcess.js +1 -1
- package/src/server/hosts/codexProvider.js +11 -9
- package/src/server/hosts/codexTurn.js +3 -3
- package/src/server/hosts/openCodeClient.js +4 -2
- package/src/server/index.js +0 -2
- package/src/server/lib/aiConnectionClient.js +35 -25
- package/src/server/lib/ndjson.js +1 -0
- package/src/server/lib/providers/anthropicClient.js +15 -6
- package/src/server/lib/providers/common.js +10 -6
- package/src/server/lib/providers/openAiCompatibleClient.js +40 -23
- package/src/server/lib/serviceToolCatalog.js +29 -283
- package/src/server/lib/serviceToolEntries.js +270 -0
- package/src/server/types.js +78 -0
- package/src/shared/assistantResource.js +0 -23
- package/src/shared/conversation/answerChoiceSugar.js +2 -14
- package/src/shared/conversation/messageInputSugar.js +18 -0
- package/src/shared/conversation/numberedQuestionSugar.js +6 -16
- package/src/shared/conversation/pagination.js +1 -1
- package/src/shared/conversation/questions.js +1 -0
- package/src/shared/conversation/streaming.js +1 -0
- package/src/shared/index.js +0 -1
- package/src/testing/conversationStorageContract.js +20 -0
- package/test/aiConnectionClient.test.js +42 -1
- package/test/apiConversationDriver.test.js +217 -38
- package/test/assistantBoundedToolLoop.test.js +1 -1
- package/test/claudeConversationSession.test.js +15 -11
- package/test/claudeInstructionResume.test.js +1 -1
- package/test/claudeProcess.test.js +9 -9
- package/test/claudeTurn.test.js +21 -8
- package/test/codexAccountChange.test.js +5 -3
- package/test/codexConversationSession.test.js +22 -21
- package/test/codexEvents.test.js +3 -1
- package/test/codexHelperDeletion.test.js +3 -7
- package/test/codexIsolation.test.js +6 -6
- package/test/codexModelCatalog.test.js +6 -7
- package/test/codexProcess.test.js +3 -3
- package/test/codexThreadSelection.test.js +4 -1
- package/test/codexTurn.test.js +29 -20
- package/test/conversationApiFacilities.test.js +11 -9
- package/test/conversationAttachments.test.js +3 -3
- package/test/conversationConfiguration.test.js +4 -4
- package/test/conversationNativeStorage.test.js +11 -10
- package/test/conversationReplacement.test.js +13 -13
- package/test/conversationRuntime.test.js +9 -5
- package/test/conversationSession.test.js +78 -22
- package/test/conversationTools.test.js +47 -26
- package/test/fileConversationStorage.test.js +10 -3
- package/test/fixtures/codexHelperThreadLedger.js +3 -3
- package/test/frameworkActions.test.js +33 -18
- package/test/localConversationExecution.test.js +4 -4
- package/test/localExecution.test.js +1 -1
- package/test/openCodeConnectionChange.test.js +3 -2
- package/test/openCodeRuntime.test.js +8 -7
- package/test/openCodeTools.test.js +1 -1
- package/test/opencodeConversationSession.test.js +4 -3
- package/test/serviceToolCatalog.test.js +3 -8
- package/src/server/lib/assistantCompletion.js +0 -190
- package/src/server/lib/assistantToolLoop.js +0 -259
|
@@ -1,12 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
codexAppServerTurnStatusIsActive,
|
|
3
|
-
codexAppServerTurnStatusIsSuccessfulComplete,
|
|
4
|
-
codexAppServerTurnStatusIsProviderFailure,
|
|
5
|
-
normalizeCodexRunText,
|
|
6
|
-
CODEX_APP_SERVER_AGENT_RUN_ID,
|
|
7
|
-
CODEX_AGENT_PROVIDER,
|
|
8
|
-
CODEX_APP_SERVER_RUN_STATE
|
|
9
|
-
} from "./codexTurnState.js";
|
|
1
|
+
import { codexAppServerTurnStatusIsActive, codexAppServerTurnStatusIsSuccessfulComplete, codexAppServerTurnStatusIsProviderFailure, CODEX_APP_SERVER_AGENT_RUN_ID, CODEX_AGENT_PROVIDER, CODEX_APP_SERVER_RUN_STATE } from "./codexTurnState.js";
|
|
10
2
|
import { codexAppServerProviderConnectionGeneration } from "./codexModelCatalog.js";
|
|
11
3
|
import {
|
|
12
4
|
codexAppServerAssistantItemText,
|
|
@@ -23,9 +15,27 @@ import {
|
|
|
23
15
|
codexAppServerContextRefreshReason,
|
|
24
16
|
codexAppServerNotificationUsageLimitExceeded
|
|
25
17
|
} from "./codexEvents.js";
|
|
18
|
+
import { normalizeText } from "@jskit-ai/kernel/shared/support/normalize";
|
|
26
19
|
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Native notification routing, goal updates and provider-generation subscriptions. Ordering belongs to the
|
|
22
|
+
* notification queue; state belongs to the operation owners.
|
|
23
|
+
* @param {object} dependencies
|
|
24
|
+
* @param {import("./codexRunJournal.js").CodexRunJournal} dependencies.journal
|
|
25
|
+
* @param {import("./codexTurnRecovery.js").CodexTurnRecovery} dependencies.recovery
|
|
26
|
+
* @param {import("./codexThreadStatus.js").CodexThreadStatus} dependencies.threadStatus
|
|
27
|
+
* @param {import("./codexOutput.js").CodexAppServerOutput} dependencies.output
|
|
28
|
+
* @param {import("./codexMessageDelivery.js").CodexAppServerMessageDelivery} dependencies.delivery
|
|
29
|
+
* @param {import("./codexNotificationQueue.js").CodexAppServerNotificationQueue} dependencies.notificationQueue
|
|
30
|
+
* @param {import("./codexTurn.js").CodexSessionNamespace} dependencies.namespace
|
|
31
|
+
* @param {import("./codexTurn.js").CodexCreateRuntime} dependencies.createRuntime
|
|
32
|
+
* @param {import("./codexTurn.js").CodexCreateStore} dependencies.createStore
|
|
33
|
+
* @param {import("./codexTurn.js").CodexPublish} dependencies.publish
|
|
34
|
+
* @param {import("./codexTurn.js").CodexCaptureContext} dependencies.captureContext
|
|
35
|
+
* @param {import("./codexTurn.js").CodexDebugLog} dependencies.debugLog
|
|
36
|
+
* @param {(kind: string, details: object) => Promise<unknown>} dependencies.onNotificationSignal
|
|
37
|
+
* @param {import("./codexTurn.js").CodexAgentRunTurnStateReader} dependencies.turnStateFromAgentRun
|
|
38
|
+
*/
|
|
29
39
|
export function createCodexNotificationObserver({
|
|
30
40
|
journal,
|
|
31
41
|
recovery,
|
|
@@ -42,25 +52,6 @@ export function createCodexNotificationObserver({
|
|
|
42
52
|
onNotificationSignal,
|
|
43
53
|
turnStateFromAgentRun
|
|
44
54
|
}) {
|
|
45
|
-
const { resolveTurnId: resolveCodexAppServerTurnId } = journal;
|
|
46
|
-
const {
|
|
47
|
-
recoverFinalizingTurn: recoverCodexAppServerFinalizingTurn,
|
|
48
|
-
markTurnActive: markCodexAppServerTurnActive,
|
|
49
|
-
markProviderTurnActive: markCodexAppServerProviderTurnActive,
|
|
50
|
-
stopTurnWithProviderFailure: stopCodexAppServerTurnWithProviderFailure,
|
|
51
|
-
completeTurn: completeCodexAppServerTurn
|
|
52
|
-
} = recovery;
|
|
53
|
-
const { reconcileThreadStatus: reconcileCodexAppServerThreadStatus } = threadStatus;
|
|
54
|
-
const {
|
|
55
|
-
readAgentRunForSession: readCodexAppServerAgentRunForSession,
|
|
56
|
-
recordReasoningForSession: recordCodexAppServerReasoningForSession,
|
|
57
|
-
writeStream: writeCodexAppServerStream,
|
|
58
|
-
recordFinalAssistantResult: recordCodexAppServerFinalAssistantResult,
|
|
59
|
-
writeLiveProgress: writeCodexAppServerLiveProgress,
|
|
60
|
-
mirrorTerminalAssistantMessage: mirrorCodexAppServerTerminalAssistantMessage
|
|
61
|
-
} = output;
|
|
62
|
-
const { mirrorTerminalUserMessage: mirrorCodexAppServerTerminalUserMessage } = delivery;
|
|
63
|
-
const { run: runCodexAppServerNotificationTask } = notificationQueue;
|
|
64
55
|
const CODEX_APP_SERVER_GOAL_STATUSES = new Set([
|
|
65
56
|
"active", "blocked", "budgetLimited", "complete", "paused", "usageLimited"
|
|
66
57
|
]);
|
|
@@ -68,7 +59,7 @@ export function createCodexNotificationObserver({
|
|
|
68
59
|
const codexAppServerAutomaticHookThreads = new Set();
|
|
69
60
|
|
|
70
61
|
function codexAppServerEventSubscriptionKey(providerKey = "", threadId = "") {
|
|
71
|
-
return `${
|
|
62
|
+
return `${normalizeText(providerKey)}:${normalizeText(threadId)}`;
|
|
72
63
|
}
|
|
73
64
|
|
|
74
65
|
function codexAppServerEventSubscriptionIsCurrent(key = "", provider = null) {
|
|
@@ -82,16 +73,16 @@ export function createCodexNotificationObserver({
|
|
|
82
73
|
|
|
83
74
|
function unsubscribeCodexAppServerEventSubscription(key = "") {
|
|
84
75
|
const record = codexAppServerEventSubscriptions.get(key);
|
|
85
|
-
record?.unsubscribe
|
|
76
|
+
record?.unsubscribe();
|
|
86
77
|
codexAppServerEventSubscriptions.delete(key);
|
|
87
78
|
}
|
|
88
79
|
|
|
89
80
|
function queueCodexAppServerReasoning(context, notification) {
|
|
90
|
-
return notificationQueue.reasoning(context, notification,
|
|
81
|
+
return notificationQueue.reasoning(context, notification, output.recordReasoningForSession);
|
|
91
82
|
}
|
|
92
83
|
|
|
93
84
|
function queueCodexAppServerStream(context, classification) {
|
|
94
|
-
return notificationQueue.stream(context, classification,
|
|
85
|
+
return notificationQueue.stream(context, classification, output.writeStream);
|
|
95
86
|
}
|
|
96
87
|
|
|
97
88
|
async function reconcileCodexAppServerGoalUpdated(
|
|
@@ -100,26 +91,26 @@ export function createCodexNotificationObserver({
|
|
|
100
91
|
threadId = "",
|
|
101
92
|
notification = {}
|
|
102
93
|
) {
|
|
103
|
-
const normalizedSessionId =
|
|
104
|
-
const normalizedThreadId =
|
|
94
|
+
const normalizedSessionId = normalizeText(sessionId);
|
|
95
|
+
const normalizedThreadId = normalizeText(threadId);
|
|
105
96
|
const notificationTurnId = codexAppServerNotificationTurnId(notification);
|
|
106
|
-
const goalStatus =
|
|
97
|
+
const goalStatus = normalizeText(notification.params?.goal?.status);
|
|
107
98
|
const goalCleared = notification.method === "thread/goal/cleared";
|
|
108
99
|
const runtime = await createRuntime();
|
|
109
|
-
let run = await
|
|
100
|
+
let run = await output.readAgentRunForSession(
|
|
110
101
|
runtime.store,
|
|
111
102
|
normalizedSessionId
|
|
112
103
|
);
|
|
113
104
|
if (run?.providerStatus === "observation_lost") return { ok: true, processed: false, reason: "observation_lost" };
|
|
114
|
-
const currentThreadId =
|
|
105
|
+
const currentThreadId = normalizeText(run?.providerThreadId);
|
|
115
106
|
if (currentThreadId && currentThreadId !== normalizedThreadId) {
|
|
116
107
|
return { ok: true, processed: false, reason: "goal_thread_changed" };
|
|
117
108
|
}
|
|
118
109
|
if (
|
|
119
110
|
(goalCleared || CODEX_APP_SERVER_GOAL_STATUSES.has(goalStatus)) &&
|
|
120
111
|
(
|
|
121
|
-
|
|
122
|
-
|
|
112
|
+
normalizeText(run?.providerGoalStatus) !== goalStatus ||
|
|
113
|
+
normalizeText(run?.providerGoalThreadId) !== normalizedThreadId
|
|
123
114
|
)
|
|
124
115
|
) {
|
|
125
116
|
const updatedAt = new Date().toISOString();
|
|
@@ -142,7 +133,7 @@ export function createCodexNotificationObserver({
|
|
|
142
133
|
providerGoalUpdatedAt: updatedAt
|
|
143
134
|
}
|
|
144
135
|
});
|
|
145
|
-
run = await
|
|
136
|
+
run = await output.readAgentRunForSession(
|
|
146
137
|
runtime.store,
|
|
147
138
|
normalizedSessionId
|
|
148
139
|
);
|
|
@@ -169,7 +160,7 @@ export function createCodexNotificationObserver({
|
|
|
169
160
|
turn.threadId === normalizedThreadId &&
|
|
170
161
|
(!notificationTurnId || turn.turnId === notificationTurnId)
|
|
171
162
|
) {
|
|
172
|
-
return
|
|
163
|
+
return recovery.recoverFinalizingTurn(
|
|
173
164
|
normalizedSessionId,
|
|
174
165
|
normalizedThreadId,
|
|
175
166
|
turn.turnId,
|
|
@@ -178,7 +169,7 @@ export function createCodexNotificationObserver({
|
|
|
178
169
|
}
|
|
179
170
|
);
|
|
180
171
|
}
|
|
181
|
-
return
|
|
172
|
+
return threadStatus.reconcileThreadStatus(
|
|
182
173
|
normalizedSessionId,
|
|
183
174
|
provider,
|
|
184
175
|
normalizedThreadId,
|
|
@@ -190,14 +181,14 @@ export function createCodexNotificationObserver({
|
|
|
190
181
|
}
|
|
191
182
|
|
|
192
183
|
function subscribeCodexAppServerEvents(sessionId = "", provider = null, threadId = "", options = {}) {
|
|
193
|
-
const normalizedSessionId =
|
|
194
|
-
const normalizedThreadId =
|
|
195
|
-
if (!normalizedSessionId || !normalizedThreadId ||
|
|
184
|
+
const normalizedSessionId = normalizeText(sessionId);
|
|
185
|
+
const normalizedThreadId = normalizeText(threadId);
|
|
186
|
+
if (!normalizedSessionId || !normalizedThreadId || !provider) {
|
|
196
187
|
throw new Error("Codex thread observation requires a session, thread and provider subscription.");
|
|
197
188
|
}
|
|
198
189
|
const projectContext = captureContext();
|
|
199
190
|
const sessionKey = namespace(normalizedSessionId);
|
|
200
|
-
const providerKey =
|
|
191
|
+
const providerKey = normalizeText(options.providerKey);
|
|
201
192
|
const key = codexAppServerEventSubscriptionKey(providerKey, normalizedThreadId);
|
|
202
193
|
const existing = codexAppServerEventSubscriptions.get(key);
|
|
203
194
|
if (existing && codexAppServerEventSubscriptionIsCurrent(key, provider)) {
|
|
@@ -211,27 +202,27 @@ export function createCodexNotificationObserver({
|
|
|
211
202
|
}
|
|
212
203
|
// A new observer cannot confirm a previously active phase. Fresh native
|
|
213
204
|
// events restore it; a stored phase alone must not animate activity.
|
|
214
|
-
|
|
205
|
+
notificationQueue.run({ projectContext, provider, sessionId: normalizedSessionId, sessionKey }, async () => {
|
|
215
206
|
const store = await createStore(normalizedSessionId);
|
|
216
|
-
const run = await
|
|
207
|
+
const run = await output.readAgentRunForSession(store, normalizedSessionId);
|
|
217
208
|
if (!run?.providerPhase || run.providerThreadId !== normalizedThreadId) return;
|
|
218
|
-
await
|
|
209
|
+
await recovery.markTurnActive(normalizedSessionId, {
|
|
219
210
|
phase: "", requireTrackedTurn: true,
|
|
220
211
|
threadId: normalizedThreadId, turnId: run.providerTurnId
|
|
221
212
|
});
|
|
222
213
|
});
|
|
223
214
|
const onNotification = (notification = {}) => {
|
|
224
|
-
const runProviderFailure = (context, turnId, status) =>
|
|
225
|
-
|
|
215
|
+
const runProviderFailure = (context, turnId, status) => notificationQueue.run(context, () =>
|
|
216
|
+
recovery.stopTurnWithProviderFailure(normalizedSessionId, normalizedThreadId, turnId, {
|
|
226
217
|
error: codexAppServerNotificationError(notification),
|
|
227
218
|
provider,
|
|
228
219
|
status,
|
|
229
220
|
usageLimitExceeded: codexAppServerNotificationUsageLimitExceeded(notification),
|
|
230
221
|
deferFailureDetails: true
|
|
231
222
|
}));
|
|
232
|
-
const method =
|
|
223
|
+
const method = normalizeText(notification.method);
|
|
233
224
|
if (method === "account/rateLimits/updated" || method === "account/updated") {
|
|
234
|
-
|
|
225
|
+
notificationQueue.run({ method, projectContext, provider, sessionId: normalizedSessionId, sessionKey }, () =>
|
|
235
226
|
publish(normalizedSessionId, { reason: "codex-plan-usage" }));
|
|
236
227
|
return;
|
|
237
228
|
}
|
|
@@ -249,7 +240,7 @@ export function createCodexNotificationObserver({
|
|
|
249
240
|
turnId: codexAppServerNotificationTurnId(notification)
|
|
250
241
|
};
|
|
251
242
|
if (method === "thread/tokenUsage/updated") {
|
|
252
|
-
|
|
243
|
+
notificationQueue.run(notificationContext, async () => {
|
|
253
244
|
const store = await createStore(normalizedSessionId);
|
|
254
245
|
return onNotificationSignal("usage", {
|
|
255
246
|
store, sessionId: normalizedSessionId, threadId: normalizedThreadId, notification
|
|
@@ -259,10 +250,10 @@ export function createCodexNotificationObserver({
|
|
|
259
250
|
const classification = classifyCodexAppServerEvent(notification);
|
|
260
251
|
if (classification.kind === "provider_error" && classification.text &&
|
|
261
252
|
codexAppServerNotificationParams(notification).willRetry !== true) {
|
|
262
|
-
|
|
253
|
+
notificationQueue.run(notificationContext, async () => {
|
|
263
254
|
return onNotificationSignal("provider_error", {
|
|
264
255
|
sessionId: normalizedSessionId, threadId: normalizedThreadId, provider,
|
|
265
|
-
turnId: await
|
|
256
|
+
turnId: await journal.resolveTurnId(normalizedSessionId, normalizedThreadId,
|
|
266
257
|
codexAppServerNotificationTurnId(notification)),
|
|
267
258
|
error: classification.text
|
|
268
259
|
});
|
|
@@ -279,14 +270,14 @@ export function createCodexNotificationObserver({
|
|
|
279
270
|
const retrying = classification.phase === "retrying";
|
|
280
271
|
if (!hookOwned &&
|
|
281
272
|
(retrying || method === "item/started" || method === "item/completed" && ["contextCompaction", "reasoning"].includes(itemType))) {
|
|
282
|
-
|
|
273
|
+
notificationQueue.run(notificationContext, async () => {
|
|
283
274
|
const phase = retrying ? "retrying" : method === "item/started"
|
|
284
275
|
? ({ contextCompaction: "compacting", reasoning: "reasoning" })[itemType] || ""
|
|
285
276
|
: "";
|
|
286
277
|
const store = await createStore(normalizedSessionId);
|
|
287
|
-
const run = await
|
|
288
|
-
if (
|
|
289
|
-
return
|
|
278
|
+
const run = await output.readAgentRunForSession(store, normalizedSessionId);
|
|
279
|
+
if (normalizeText(run?.providerPhase) === phase) return;
|
|
280
|
+
return recovery.markTurnActive(normalizedSessionId, {
|
|
290
281
|
phase, requireTrackedTurn: true,
|
|
291
282
|
threadId: normalizedThreadId,
|
|
292
283
|
turnId: codexAppServerNotificationTurnId(notification)
|
|
@@ -294,7 +285,7 @@ export function createCodexNotificationObserver({
|
|
|
294
285
|
});
|
|
295
286
|
}
|
|
296
287
|
if (contextRefreshReason) {
|
|
297
|
-
|
|
288
|
+
notificationQueue.run(notificationContext, () => {
|
|
298
289
|
return onNotificationSignal("context_refresh", {
|
|
299
290
|
sessionId: normalizedSessionId, threadId: normalizedThreadId,
|
|
300
291
|
notification, reason: contextRefreshReason
|
|
@@ -302,14 +293,14 @@ export function createCodexNotificationObserver({
|
|
|
302
293
|
});
|
|
303
294
|
}
|
|
304
295
|
if (method === "thread/goal/cleared") {
|
|
305
|
-
|
|
296
|
+
notificationQueue.run(notificationContext, async () => {
|
|
306
297
|
await reconcileCodexAppServerGoalUpdated(normalizedSessionId, provider, normalizedThreadId, notification);
|
|
307
298
|
await publish(normalizedSessionId, { reason: "codex-goal", nativeGoal: { threadId: normalizedThreadId, goal: null } });
|
|
308
299
|
});
|
|
309
300
|
return;
|
|
310
301
|
}
|
|
311
302
|
if (method === "thread/goal/updated") {
|
|
312
|
-
|
|
303
|
+
notificationQueue.run(notificationContext, async () => {
|
|
313
304
|
await publish(normalizedSessionId, { reason: "codex-goal", nativeGoal: { threadId: normalizedThreadId, goal: notification.params.goal } });
|
|
314
305
|
return reconcileCodexAppServerGoalUpdated(
|
|
315
306
|
normalizedSessionId,
|
|
@@ -333,8 +324,8 @@ export function createCodexNotificationObserver({
|
|
|
333
324
|
if (classification.kind === "final_assistant_result") {
|
|
334
325
|
const event = codexAppServerNotificationEvent(notification);
|
|
335
326
|
const payload = codexAppServerNotificationEventPayload(notification, event);
|
|
336
|
-
|
|
337
|
-
return
|
|
327
|
+
notificationQueue.run(notificationContext, () => {
|
|
328
|
+
return output.recordFinalAssistantResult({
|
|
338
329
|
itemId: classification.itemId,
|
|
339
330
|
notification,
|
|
340
331
|
sessionId: normalizedSessionId,
|
|
@@ -345,11 +336,11 @@ export function createCodexNotificationObserver({
|
|
|
345
336
|
});
|
|
346
337
|
});
|
|
347
338
|
debugLog("appServerFinalAssistantResult.received", {
|
|
348
|
-
eventId:
|
|
339
|
+
eventId: normalizeText(event?.id),
|
|
349
340
|
eventType: codexAppServerNotificationEventType(notification, event),
|
|
350
|
-
itemId:
|
|
341
|
+
itemId: normalizeText(codexAppServerNotificationItem(notification)?.id),
|
|
351
342
|
method,
|
|
352
|
-
payloadId:
|
|
343
|
+
payloadId: normalizeText(payload?.id),
|
|
353
344
|
stableItemId: classification.itemId,
|
|
354
345
|
source: classification.source,
|
|
355
346
|
sessionId: normalizedSessionId,
|
|
@@ -361,28 +352,28 @@ export function createCodexNotificationObserver({
|
|
|
361
352
|
if (hookOwned) {
|
|
362
353
|
return;
|
|
363
354
|
}
|
|
364
|
-
|
|
365
|
-
return
|
|
355
|
+
notificationQueue.run(notificationContext, () => {
|
|
356
|
+
return output.writeLiveProgress(normalizedSessionId, normalizedThreadId, notification);
|
|
366
357
|
});
|
|
367
358
|
}
|
|
368
359
|
if (method === "item/completed") {
|
|
369
360
|
const item = codexAppServerNotificationItem(notification);
|
|
370
|
-
if (
|
|
371
|
-
|
|
372
|
-
return
|
|
361
|
+
if (normalizeText(item?.type) === "userMessage") {
|
|
362
|
+
notificationQueue.run(notificationContext, () => {
|
|
363
|
+
return delivery.mirrorTerminalUserMessage(normalizedSessionId, normalizedThreadId, notification);
|
|
373
364
|
});
|
|
374
365
|
return;
|
|
375
366
|
}
|
|
376
367
|
if (codexAppServerAssistantItemText(item)) {
|
|
377
|
-
|
|
378
|
-
return
|
|
368
|
+
notificationQueue.run(notificationContext, () => {
|
|
369
|
+
return output.mirrorTerminalAssistantMessage(normalizedSessionId, normalizedThreadId, notification);
|
|
379
370
|
});
|
|
380
371
|
return;
|
|
381
372
|
}
|
|
382
373
|
}
|
|
383
374
|
if (method === "turn/started") {
|
|
384
375
|
codexAppServerAutomaticHookThreads.delete(normalizedThreadId);
|
|
385
|
-
|
|
376
|
+
notificationQueue.run(notificationContext, () => recovery.markProviderTurnActive(normalizedSessionId, {
|
|
386
377
|
source: "turn_started",
|
|
387
378
|
status: codexAppServerNotificationTurnStatus(notification) || "inProgress",
|
|
388
379
|
threadId: normalizedThreadId,
|
|
@@ -399,8 +390,8 @@ export function createCodexNotificationObserver({
|
|
|
399
390
|
return;
|
|
400
391
|
}
|
|
401
392
|
if (codexAppServerTurnStatusIsSuccessfulComplete(status)) {
|
|
402
|
-
|
|
403
|
-
return
|
|
393
|
+
notificationQueue.run(notificationContext, () => {
|
|
394
|
+
return recovery.completeTurn(normalizedSessionId, normalizedThreadId, turnId, {
|
|
404
395
|
provider,
|
|
405
396
|
status
|
|
406
397
|
});
|
|
@@ -411,13 +402,13 @@ export function createCodexNotificationObserver({
|
|
|
411
402
|
if (method === "thread/status/changed") {
|
|
412
403
|
const status = codexAppServerNotificationTurnStatus(notification);
|
|
413
404
|
if (codexAppServerTurnStatusIsActive(status)) {
|
|
414
|
-
|
|
415
|
-
const turnId = await
|
|
405
|
+
notificationQueue.run(notificationContext, async () => {
|
|
406
|
+
const turnId = await journal.resolveTurnId(
|
|
416
407
|
normalizedSessionId,
|
|
417
408
|
normalizedThreadId,
|
|
418
409
|
codexAppServerNotificationTurnId(notification)
|
|
419
410
|
);
|
|
420
|
-
await
|
|
411
|
+
await recovery.markProviderTurnActive(normalizedSessionId, {
|
|
421
412
|
source: "thread_status_changed",
|
|
422
413
|
status,
|
|
423
414
|
threadId: normalizedThreadId,
|
|
@@ -433,13 +424,13 @@ export function createCodexNotificationObserver({
|
|
|
433
424
|
return;
|
|
434
425
|
}
|
|
435
426
|
if (codexAppServerTurnStatusIsSuccessfulComplete(status)) {
|
|
436
|
-
|
|
437
|
-
const resolvedTurnId = await
|
|
427
|
+
notificationQueue.run(notificationContext, async () => {
|
|
428
|
+
const resolvedTurnId = await journal.resolveTurnId(
|
|
438
429
|
normalizedSessionId,
|
|
439
430
|
normalizedThreadId,
|
|
440
431
|
turnId
|
|
441
432
|
);
|
|
442
|
-
return
|
|
433
|
+
return recovery.completeTurn(normalizedSessionId, normalizedThreadId, resolvedTurnId, {
|
|
443
434
|
provider,
|
|
444
435
|
status
|
|
445
436
|
});
|
|
@@ -467,7 +458,7 @@ export function createCodexNotificationObserver({
|
|
|
467
458
|
};
|
|
468
459
|
}
|
|
469
460
|
|
|
470
|
-
return {
|
|
461
|
+
return Object.freeze({
|
|
471
462
|
eventSubscriptions: codexAppServerEventSubscriptions,
|
|
472
463
|
automaticHookThreads: codexAppServerAutomaticHookThreads,
|
|
473
464
|
eventSubscriptionKey: codexAppServerEventSubscriptionKey,
|
|
@@ -475,5 +466,7 @@ export function createCodexNotificationObserver({
|
|
|
475
466
|
unsubscribeEventSubscription: unsubscribeCodexAppServerEventSubscription,
|
|
476
467
|
reconcileGoalUpdated: reconcileCodexAppServerGoalUpdated,
|
|
477
468
|
subscribeEvents: subscribeCodexAppServerEvents
|
|
478
|
-
};
|
|
469
|
+
});
|
|
479
470
|
}
|
|
471
|
+
|
|
472
|
+
/** @typedef {ReturnType<typeof createCodexNotificationObserver>} CodexNotificationObserver */
|
|
@@ -1,12 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { normalizeText } from "@jskit-ai/kernel/shared/support/normalize";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
function ignoreNotificationTaskError() {}
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Per-session ordered notification tasks. Coalesces only fragments still
|
|
7
|
+
* waiting behind a running write; running batches are never merged or delayed.
|
|
8
|
+
* @param {object} [options]
|
|
9
|
+
* @param {import("./codexTurn.js").CodexSessionNamespace} [options.namespace]
|
|
10
|
+
* @param {() => boolean} [options.isClosing]
|
|
11
|
+
* @param {import("./codexTurn.js").CodexRunInContext} [options.runInContext]
|
|
12
|
+
* @param {(error: unknown, context: object) => void} [options.reportError]
|
|
13
|
+
*/
|
|
5
14
|
export function createCodexAppServerNotificationQueue({
|
|
6
|
-
namespace =
|
|
15
|
+
namespace = normalizeText,
|
|
7
16
|
isClosing = () => false,
|
|
8
17
|
runInContext = (_context, operation) => operation(),
|
|
9
|
-
reportError =
|
|
18
|
+
reportError = ignoreNotificationTaskError
|
|
10
19
|
} = {}) {
|
|
11
20
|
const codexAppServerNotificationTasks = new Map();
|
|
12
21
|
const codexAppServerPendingStreams = new Map();
|
|
@@ -16,8 +25,8 @@ export function createCodexAppServerNotificationQueue({
|
|
|
16
25
|
if (isClosing()) {
|
|
17
26
|
return;
|
|
18
27
|
}
|
|
19
|
-
const taskSessionId =
|
|
20
|
-
const taskSessionKey =
|
|
28
|
+
const taskSessionId = normalizeText(context.sessionId);
|
|
29
|
+
const taskSessionKey = normalizeText(context.sessionKey) ||
|
|
21
30
|
namespace(taskSessionId);
|
|
22
31
|
// Other notifications end the pending stream batch so completion, reasoning
|
|
23
32
|
// and turn changes retain their position in the provider's event order.
|
|
@@ -28,7 +37,7 @@ export function createCodexAppServerNotificationQueue({
|
|
|
28
37
|
.catch(() => null)
|
|
29
38
|
.then(() => runInContext(context.projectContext, operation))
|
|
30
39
|
.catch((error) => {
|
|
31
|
-
context.provider?.failObservation
|
|
40
|
+
context.provider?.failObservation(error);
|
|
32
41
|
reportError(error, context);
|
|
33
42
|
});
|
|
34
43
|
codexAppServerNotificationTasks.set(taskSessionKey, task);
|
|
@@ -98,7 +107,7 @@ export function createCodexAppServerNotificationQueue({
|
|
|
98
107
|
codexAppServerPendingReasoning.set(context.sessionKey, batch);
|
|
99
108
|
}
|
|
100
109
|
|
|
101
|
-
return {
|
|
110
|
+
return Object.freeze({
|
|
102
111
|
tasks: codexAppServerNotificationTasks,
|
|
103
112
|
pendingStreams: codexAppServerPendingStreams,
|
|
104
113
|
pendingReasoning: codexAppServerPendingReasoning,
|
|
@@ -107,5 +116,7 @@ export function createCodexAppServerNotificationQueue({
|
|
|
107
116
|
captureDrain: captureCodexAppServerNotificationDrain,
|
|
108
117
|
stream: queueCodexAppServerStream,
|
|
109
118
|
reasoning: queueCodexAppServerReasoning
|
|
110
|
-
};
|
|
119
|
+
});
|
|
111
120
|
}
|
|
121
|
+
|
|
122
|
+
/** @typedef {ReturnType<typeof createCodexAppServerNotificationQueue>} CodexAppServerNotificationQueue */
|