@jskit-ai/assistant-core 0.2.7 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +13 -10
- 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,14 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
normalizeCodexRunText
|
|
6
|
-
} from "./codexTurnState.js";
|
|
7
|
-
import { codexAppServerThreadIsMissing, ensureCodexAppServerThread } from "./codexProvider.js";
|
|
8
|
-
import { codexAppServerThreadRawValue, codexAppServerThreadTurnId } from "./codexEvents.js";
|
|
1
|
+
import { codexAppServerTurnStatusIsActive, codexAppServerThreadStatus, codexAppServerReadThreadStatus } from "./codexTurnState.js";
|
|
2
|
+
import { codexAppServerThreadIsMissing, ensureCodexAppServerThread } from "./codexProviderThreads.js";
|
|
3
|
+
import { codexAppServerThreadRawValue, codexAppServerThreadTurnId } from "./codexThreadSnapshot.js";
|
|
4
|
+
import { normalizeText } from "@jskit-ai/kernel/shared/support/normalize";
|
|
9
5
|
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Native thread readiness, loaded-thread restoration and reconciliation drain. Its one Map lives as long as the run
|
|
8
|
+
* owner and is shared with shutdown.
|
|
9
|
+
* @param {object} dependencies
|
|
10
|
+
* @param {import("./codexTurn.js").CodexProviderSessions} [dependencies.providerSessions]
|
|
11
|
+
* @param {import("./codexProviderSelection.js").CodexProviderSelection} dependencies.selection
|
|
12
|
+
* @param {import("./codexNotificationObserver.js").CodexNotificationObserver} dependencies.observer
|
|
13
|
+
* @param {import("./codexThreadStatus.js").CodexThreadStatus} dependencies.threadStatus
|
|
14
|
+
* @param {import("./codexTurnRecovery.js").CodexTurnRecovery} dependencies.recovery
|
|
15
|
+
* @param {import("./codexTurn.js").CodexTurnStateReader} dependencies.turnState
|
|
16
|
+
* @param {import("./codexTurn.js").CodexDebugLog} dependencies.debugLog
|
|
17
|
+
* @param {import("./codexTurn.js").CodexDebugError} dependencies.debugError
|
|
18
|
+
*/
|
|
12
19
|
export function createCodexThreadReadiness({
|
|
13
20
|
providerSessions,
|
|
14
21
|
selection,
|
|
@@ -27,23 +34,11 @@ export function createCodexThreadReadiness({
|
|
|
27
34
|
ensureSessionProvider,
|
|
28
35
|
rememberManagedSession
|
|
29
36
|
} = selection;
|
|
30
|
-
const {
|
|
31
|
-
eventSubscriptionKey: codexAppServerEventSubscriptionKey,
|
|
32
|
-
eventSubscriptionIsCurrent: codexAppServerEventSubscriptionIsCurrent,
|
|
33
|
-
subscribeEvents: subscribeCodexAppServerEvents
|
|
34
|
-
} = observer;
|
|
35
|
-
const {
|
|
36
|
-
reconcileThreadStatus: reconcileCodexAppServerThreadStatus,
|
|
37
|
-
reconcileLoadedThreadStatus: reconcileCodexAppServerLoadedThreadStatus
|
|
38
|
-
} = threadStatus;
|
|
39
|
-
const {
|
|
40
|
-
recoverActiveTurn: recoverCodexAppServerActiveTurn
|
|
41
|
-
} = recovery;
|
|
42
37
|
|
|
43
38
|
async function ensureCodexAppServerThreadReady(sessionId, context, preparation) {
|
|
44
39
|
const { runtime, session, workdir } = context;
|
|
45
40
|
// Runtime recovery may await a disconnect callback that writes session
|
|
46
|
-
// state. This acquisition stays outside the
|
|
41
|
+
// state. This acquisition stays outside the startup gate.
|
|
47
42
|
const activeProvider = await ensureCodexAppServerProviderForActiveTurn(session, preparation.managedIdentity);
|
|
48
43
|
let providerOptions = activeProvider?.providerOptions;
|
|
49
44
|
if (!providerOptions) {
|
|
@@ -54,19 +49,19 @@ export function createCodexThreadReadiness({
|
|
|
54
49
|
const { currentSession: preparedSession, thread } = await preparation.gate(async currentSession => {
|
|
55
50
|
const thread = await ensureCodexAppServerThread({
|
|
56
51
|
...preparation.preparation(currentSession),
|
|
57
|
-
observeThread: threadId =>
|
|
52
|
+
observeThread: threadId => observer.subscribeEvents(sessionId, provider, threadId,
|
|
58
53
|
codexAppServerSessionObserverOptions(sessionId, providerOptions)),
|
|
59
54
|
provider,
|
|
60
55
|
workdir
|
|
61
56
|
});
|
|
62
57
|
return { currentSession, thread };
|
|
63
58
|
});
|
|
64
|
-
|
|
59
|
+
observer.subscribeEvents(sessionId, provider, thread.threadId,
|
|
65
60
|
codexAppServerSessionObserverOptions(sessionId, providerOptions));
|
|
66
61
|
rememberManagedSession(sessionId, providerOptions, {
|
|
67
62
|
executionRoot: context.executionRoot, workdir: context.workdir, threadId: thread.threadId
|
|
68
63
|
});
|
|
69
|
-
await
|
|
64
|
+
await threadStatus.reconcileThreadStatus(sessionId, provider, thread.threadId, {
|
|
70
65
|
failUnconfirmedTrackedTurn: true,
|
|
71
66
|
observeLatestTurn: true,
|
|
72
67
|
requireTrackedTurn: true,
|
|
@@ -75,7 +70,7 @@ export function createCodexThreadReadiness({
|
|
|
75
70
|
const ready = await preparation.ready(preparedSession);
|
|
76
71
|
let currentSession = await runtime.getSession(sessionId);
|
|
77
72
|
if (turnState(currentSession).state === "starting") {
|
|
78
|
-
currentSession = await
|
|
73
|
+
currentSession = await recovery.recoverActiveTurn(sessionId, {
|
|
79
74
|
provider,
|
|
80
75
|
retryOnError: false,
|
|
81
76
|
runtime
|
|
@@ -153,12 +148,12 @@ export function createCodexThreadReadiness({
|
|
|
153
148
|
}
|
|
154
149
|
debugLog("appServerThread.reconcile.pruneWait.start", {
|
|
155
150
|
pendingCount: pending.length,
|
|
156
|
-
projectContextRoot:
|
|
151
|
+
projectContextRoot: normalizeText(projectContextRoot)
|
|
157
152
|
});
|
|
158
153
|
await Promise.allSettled(pending.map(([, reconciliation]) => reconciliation));
|
|
159
154
|
debugLog("appServerThread.reconcile.pruneWait.done", {
|
|
160
155
|
pendingCount: pending.length,
|
|
161
|
-
projectContextRoot:
|
|
156
|
+
projectContextRoot: normalizeText(projectContextRoot)
|
|
162
157
|
});
|
|
163
158
|
}
|
|
164
159
|
|
|
@@ -166,11 +161,11 @@ export function createCodexThreadReadiness({
|
|
|
166
161
|
reconnect = true
|
|
167
162
|
} = {}) {
|
|
168
163
|
providerSessions.assertOpen();
|
|
169
|
-
const normalizedProviderKey =
|
|
164
|
+
const normalizedProviderKey = normalizeText(providerKey);
|
|
170
165
|
const managed = providerSessions.managed.get(normalizedProviderKey);
|
|
171
166
|
const provider = providerSessions.owner.providers.get(normalizedProviderKey);
|
|
172
|
-
const sessionId =
|
|
173
|
-
const threadId =
|
|
167
|
+
const sessionId = normalizeText(managed?.sessionId);
|
|
168
|
+
const threadId = normalizeText(managed?.threadId);
|
|
174
169
|
if (!managed || !provider || !sessionId) {
|
|
175
170
|
throw new Error("Codex app-server managed connection is incomplete.");
|
|
176
171
|
}
|
|
@@ -186,7 +181,7 @@ export function createCodexThreadReadiness({
|
|
|
186
181
|
|
|
187
182
|
if (reconnect) {
|
|
188
183
|
await providerSessions.owner.acquireRuntime({
|
|
189
|
-
operation: () => provider.ensureAvailable
|
|
184
|
+
operation: () => provider.ensureAvailable(),
|
|
190
185
|
provider,
|
|
191
186
|
providerKey: normalizedProviderKey,
|
|
192
187
|
providerOptions: managed.providerOptions || {}
|
|
@@ -220,38 +215,38 @@ export function createCodexThreadReadiness({
|
|
|
220
215
|
const session = await current.readSession();
|
|
221
216
|
current.assertCurrent(session);
|
|
222
217
|
try {
|
|
223
|
-
const controls = await provider.ensureThreadControls
|
|
218
|
+
const controls = await provider.ensureThreadControls(threadId);
|
|
224
219
|
if (controls?.recovered) providerThread = await codexAppServerReadThreadStatus(provider, threadId);
|
|
225
220
|
} catch (error) {
|
|
226
221
|
current.assertCurrent(session);
|
|
227
|
-
//
|
|
222
|
+
// The stop owner keeps its visible recovery state. This does not
|
|
228
223
|
// spend automatic goal turns or repeatedly probe a known failed binding.
|
|
229
|
-
void Promise.resolve(provider.failObservation
|
|
224
|
+
void Promise.resolve(provider.failObservation(error)).catch(() => null);
|
|
230
225
|
throw error;
|
|
231
226
|
}
|
|
232
227
|
current.assertCurrent(session);
|
|
233
228
|
const nativeStatus = codexAppServerThreadRawValue(providerThread).status;
|
|
234
|
-
const subscriptionKey =
|
|
229
|
+
const subscriptionKey = observer.eventSubscriptionKey(
|
|
235
230
|
providerKey,
|
|
236
231
|
threadId
|
|
237
232
|
);
|
|
238
|
-
const subscriptionIsCurrent =
|
|
233
|
+
const subscriptionIsCurrent = observer.eventSubscriptionIsCurrent(subscriptionKey, provider);
|
|
239
234
|
if (!reconnect && (
|
|
240
235
|
nativeStatus === "notLoaded" || nativeStatus?.type === "notLoaded" || !subscriptionIsCurrent
|
|
241
236
|
)) {
|
|
242
237
|
return { ok: true, requiresPreparation: true };
|
|
243
238
|
}
|
|
244
239
|
if (!subscriptionIsCurrent) {
|
|
245
|
-
|
|
240
|
+
observer.subscribeEvents(
|
|
246
241
|
sessionId,
|
|
247
242
|
provider,
|
|
248
243
|
threadId,
|
|
249
244
|
subscriptionOptions
|
|
250
245
|
);
|
|
251
|
-
await provider.resumeThread
|
|
252
|
-
cwd:
|
|
246
|
+
await provider.resumeThread(threadId, {
|
|
247
|
+
cwd: normalizeText(connection.workdir)
|
|
253
248
|
});
|
|
254
|
-
return
|
|
249
|
+
return threadStatus.reconcileLoadedThreadStatus(
|
|
255
250
|
sessionId,
|
|
256
251
|
provider,
|
|
257
252
|
threadId,
|
|
@@ -277,7 +272,7 @@ export function createCodexThreadReadiness({
|
|
|
277
272
|
)) ||
|
|
278
273
|
(!providerIsActive && trackedTurn.active)
|
|
279
274
|
) {
|
|
280
|
-
return
|
|
275
|
+
return threadStatus.reconcileThreadStatus(
|
|
281
276
|
sessionId,
|
|
282
277
|
provider,
|
|
283
278
|
threadId,
|
|
@@ -295,7 +290,7 @@ export function createCodexThreadReadiness({
|
|
|
295
290
|
}
|
|
296
291
|
|
|
297
292
|
async function codexAppServerLoadedThreadIds(provider = null) {
|
|
298
|
-
if (
|
|
293
|
+
if (!provider) {
|
|
299
294
|
return null;
|
|
300
295
|
}
|
|
301
296
|
const threadIds = new Set();
|
|
@@ -306,12 +301,12 @@ export function createCodexThreadReadiness({
|
|
|
306
301
|
limit: 100
|
|
307
302
|
});
|
|
308
303
|
for (const threadId of Array.isArray(response?.data) ? response.data : []) {
|
|
309
|
-
const normalizedThreadId =
|
|
304
|
+
const normalizedThreadId = normalizeText(threadId);
|
|
310
305
|
if (normalizedThreadId) {
|
|
311
306
|
threadIds.add(normalizedThreadId);
|
|
312
307
|
}
|
|
313
308
|
}
|
|
314
|
-
cursor =
|
|
309
|
+
cursor = normalizeText(response?.nextCursor);
|
|
315
310
|
} while (cursor);
|
|
316
311
|
return threadIds;
|
|
317
312
|
}
|
|
@@ -320,18 +315,18 @@ export function createCodexThreadReadiness({
|
|
|
320
315
|
const { runtime, provider, providerKey, threadId } = context;
|
|
321
316
|
const loadedThreadIds = await codexAppServerLoadedThreadIds(provider);
|
|
322
317
|
if (!loadedThreadIds?.has(threadId)) return null;
|
|
323
|
-
const subscription =
|
|
318
|
+
const subscription = observer.subscribeEvents(
|
|
324
319
|
sessionId,
|
|
325
320
|
provider,
|
|
326
321
|
threadId,
|
|
327
322
|
context.subscriptionOptions
|
|
328
323
|
);
|
|
329
|
-
const subscriptionStatus =
|
|
324
|
+
const subscriptionStatus = normalizeText(subscription?.status) || "subscribed";
|
|
330
325
|
if (subscriptionStatus !== "alreadySubscribed") {
|
|
331
326
|
await provider.resumeThread(threadId, context.resumeOptions);
|
|
332
327
|
}
|
|
333
328
|
context.remember();
|
|
334
|
-
await
|
|
329
|
+
await threadStatus.reconcileLoadedThreadStatus(
|
|
335
330
|
sessionId,
|
|
336
331
|
provider,
|
|
337
332
|
threadId,
|
|
@@ -347,7 +342,7 @@ export function createCodexThreadReadiness({
|
|
|
347
342
|
});
|
|
348
343
|
let loadedSession = await runtime.getSession(sessionId);
|
|
349
344
|
if (turnState(loadedSession).state === "starting") {
|
|
350
|
-
loadedSession = await
|
|
345
|
+
loadedSession = await recovery.recoverActiveTurn(sessionId, {
|
|
351
346
|
provider,
|
|
352
347
|
retryOnError: false,
|
|
353
348
|
runtime
|
|
@@ -372,12 +367,14 @@ export function createCodexThreadReadiness({
|
|
|
372
367
|
};
|
|
373
368
|
}
|
|
374
369
|
|
|
375
|
-
return {
|
|
370
|
+
return Object.freeze({
|
|
376
371
|
threadReconciliations: codexAppServerThreadReconciliations,
|
|
377
372
|
ensureThreadReady: ensureCodexAppServerThreadReady,
|
|
378
373
|
reconcileThread: reconcileCodexAppServerThreadForSession,
|
|
379
374
|
waitForThreadReconciliations: waitForOtherCodexAppServerThreadReconciliations,
|
|
380
375
|
checkManagedConnection,
|
|
381
376
|
restoreLoadedThread: restoreCodexAppServerLoadedThread
|
|
382
|
-
};
|
|
377
|
+
});
|
|
383
378
|
}
|
|
379
|
+
|
|
380
|
+
/** @typedef {ReturnType<typeof createCodexThreadReadiness>} CodexThreadReadiness */
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { isRecord } from "@jskit-ai/kernel/shared/support/normalize";
|
|
2
|
+
import { normalizeNullableText } from "./normalize.js";
|
|
3
|
+
import {
|
|
4
|
+
codexAppServerAssistantItemText,
|
|
5
|
+
codexAppServerErrorText,
|
|
6
|
+
codexAppServerSignedOutText,
|
|
7
|
+
codexAppServerStatusFromValue
|
|
8
|
+
} from "./codexEvents.js";
|
|
9
|
+
|
|
10
|
+
// Like codexAppServerThreadRawValue, but provider results may also wrap the
|
|
11
|
+
// thread once more under `thread`, checked after raw and response.thread.
|
|
12
|
+
function codexAppServerProviderThread(value) {
|
|
13
|
+
if (!isRecord(value?.raw) && !isRecord(value?.response?.thread) && isRecord(value?.thread)) {
|
|
14
|
+
return value.thread;
|
|
15
|
+
}
|
|
16
|
+
return codexAppServerThreadRawValue(value || {});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function codexAppServerProviderTurnId(turn = {}) {
|
|
20
|
+
return normalizeNullableText(turn.id || turn.turnId || turn.turn_id || turn.turn?.id || "");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function codexAppServerProviderTurnItems(turn = {}) {
|
|
24
|
+
return [
|
|
25
|
+
...(Array.isArray(turn.items) ? turn.items : []),
|
|
26
|
+
...(Array.isArray(turn.itemsView) ? turn.itemsView : [])
|
|
27
|
+
].filter(isRecord);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function codexAppServerProviderThreadTurn(value = {}, turnId = "") {
|
|
31
|
+
const normalizedTurnId = normalizeNullableText(turnId);
|
|
32
|
+
if (!normalizedTurnId) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const thread = codexAppServerProviderThread(value);
|
|
36
|
+
return (Array.isArray(thread.turns) ? thread.turns : [])
|
|
37
|
+
.find((turn) => codexAppServerProviderTurnId(turn) === normalizedTurnId) || null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function codexAppServerProviderTurnAssistantSegments(turn = {}) {
|
|
41
|
+
const seenItemIds = new Set();
|
|
42
|
+
const items = codexAppServerProviderTurnItems(turn);
|
|
43
|
+
// Providers without phases emit progress as ordinary assistant messages.
|
|
44
|
+
// Only the trailing response can be a final; reasoning/tools separate it
|
|
45
|
+
// from earlier updates. Explicit finals retain their native attribution.
|
|
46
|
+
let responseStart = items.length;
|
|
47
|
+
while (responseStart > 0 && codexAppServerAssistantItemText(items[responseStart - 1])) responseStart -= 1;
|
|
48
|
+
const active = ["inProgress", "starting"].includes(codexAppServerStatusFromValue(turn.status));
|
|
49
|
+
return items
|
|
50
|
+
.filter((item, index) => {
|
|
51
|
+
const phase = normalizeNullableText(item.phase);
|
|
52
|
+
return phase === "final_answer" || (!phase && !active && index >= responseStart);
|
|
53
|
+
})
|
|
54
|
+
.map((item) => {
|
|
55
|
+
const itemId = normalizeNullableText(item.id);
|
|
56
|
+
const text = codexAppServerAssistantItemText(item);
|
|
57
|
+
if (
|
|
58
|
+
!itemId ||
|
|
59
|
+
!text ||
|
|
60
|
+
seenItemIds.has(itemId)
|
|
61
|
+
) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
seenItemIds.add(itemId);
|
|
65
|
+
return {
|
|
66
|
+
itemId,
|
|
67
|
+
text
|
|
68
|
+
};
|
|
69
|
+
})
|
|
70
|
+
.filter(Boolean);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function codexAppServerProviderThreadAssistantSegments(value = {}, turnId = "") {
|
|
74
|
+
const turn = codexAppServerProviderThreadTurn(value, turnId);
|
|
75
|
+
return turn ? codexAppServerProviderTurnAssistantSegments(turn) : [];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function codexAppServerThreadRawValue(thread = {}) {
|
|
79
|
+
if (isRecord(thread.raw)) {
|
|
80
|
+
return thread.raw;
|
|
81
|
+
}
|
|
82
|
+
if (isRecord(thread.response?.thread)) {
|
|
83
|
+
return thread.response.thread;
|
|
84
|
+
}
|
|
85
|
+
return isRecord(thread) ? thread : {};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function codexAppServerThreadTurnId(thread = {}) {
|
|
89
|
+
const observedTurnId = normalizeNullableText(thread.observedTurn?.id || "");
|
|
90
|
+
if (observedTurnId) {
|
|
91
|
+
return observedTurnId;
|
|
92
|
+
}
|
|
93
|
+
const rawThread = codexAppServerThreadRawValue(thread);
|
|
94
|
+
const status = isRecord(rawThread.status) ? rawThread.status : {};
|
|
95
|
+
return normalizeNullableText(
|
|
96
|
+
thread.turnId ||
|
|
97
|
+
thread.turn_id ||
|
|
98
|
+
thread.turn?.id ||
|
|
99
|
+
rawThread.turnId ||
|
|
100
|
+
rawThread.turn_id ||
|
|
101
|
+
rawThread.turn?.id ||
|
|
102
|
+
rawThread.currentTurnId ||
|
|
103
|
+
rawThread.current_turn_id ||
|
|
104
|
+
rawThread.activeTurnId ||
|
|
105
|
+
rawThread.active_turn_id ||
|
|
106
|
+
status.turnId ||
|
|
107
|
+
status.turn_id ||
|
|
108
|
+
status.turn?.id ||
|
|
109
|
+
status.currentTurnId ||
|
|
110
|
+
status.current_turn_id ||
|
|
111
|
+
status.activeTurnId ||
|
|
112
|
+
status.active_turn_id ||
|
|
113
|
+
""
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function codexAppServerThreadError(thread = {}) {
|
|
118
|
+
const rawThread = codexAppServerThreadRawValue(thread);
|
|
119
|
+
const status = isRecord(rawThread.status) ? rawThread.status : {};
|
|
120
|
+
return codexAppServerErrorText(rawThread.error || status.error);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function codexAppServerProviderThreadTurns(thread = null) {
|
|
124
|
+
const rawThread = codexAppServerThreadRawValue(thread || {});
|
|
125
|
+
return (Array.isArray(rawThread.turns) ? rawThread.turns : [])
|
|
126
|
+
.filter((turn) => isRecord(turn));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function codexAppServerProviderTurnStatus(turn = {}) {
|
|
130
|
+
return codexAppServerStatusFromValue(turn.status || turn.state);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function codexAppServerProviderTurnClientIds(turn = {}) {
|
|
134
|
+
return codexAppServerProviderTurnItems(turn)
|
|
135
|
+
.map((item) => normalizeNullableText(
|
|
136
|
+
item.clientId ||
|
|
137
|
+
item.client_id ||
|
|
138
|
+
item.clientUserMessageId ||
|
|
139
|
+
item.client_user_message_id ||
|
|
140
|
+
""
|
|
141
|
+
))
|
|
142
|
+
.filter(Boolean);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function codexAppServerProviderTurnForOperation(thread = null, {
|
|
146
|
+
clientMessageId = "",
|
|
147
|
+
turnId = ""
|
|
148
|
+
} = {}) {
|
|
149
|
+
const normalizedTurnId = normalizeNullableText(turnId || "");
|
|
150
|
+
const normalizedClientMessageId = normalizeNullableText(clientMessageId || "");
|
|
151
|
+
const turns = codexAppServerProviderThreadTurns(thread);
|
|
152
|
+
if (normalizedTurnId) {
|
|
153
|
+
return turns.find((turn) => (
|
|
154
|
+
codexAppServerProviderTurnId(turn) === normalizedTurnId
|
|
155
|
+
)) || null;
|
|
156
|
+
}
|
|
157
|
+
if (!normalizedClientMessageId) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
return [...turns].reverse().find((turn) => (
|
|
161
|
+
codexAppServerProviderTurnClientIds(turn).includes(normalizedClientMessageId)
|
|
162
|
+
)) || null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Native snapshot matching for renewal handover and seeding.
|
|
166
|
+
// The application projects these classifications into its approval/error policy.
|
|
167
|
+
function inspectCodexAppServerRenewalThread(thread = null, {
|
|
168
|
+
clientMessageId = "",
|
|
169
|
+
turnId: expectedTurnId = "",
|
|
170
|
+
requireFresh = false
|
|
171
|
+
} = {}) {
|
|
172
|
+
const snapshotTurns = codexAppServerProviderThreadTurns(thread);
|
|
173
|
+
const targetTurn = codexAppServerProviderTurnForOperation(thread, {
|
|
174
|
+
clientMessageId,
|
|
175
|
+
turnId: expectedTurnId
|
|
176
|
+
});
|
|
177
|
+
if (expectedTurnId && !targetTurn) return { targetTurn, failure: "turn_missing" };
|
|
178
|
+
if (!requireFresh && !targetTurn && snapshotTurns.length === 0) return { targetTurn, failure: "history_missing" };
|
|
179
|
+
if (requireFresh && snapshotTurns.some((turn) => (
|
|
180
|
+
!targetTurn || codexAppServerProviderTurnId(turn) !== codexAppServerProviderTurnId(targetTurn)
|
|
181
|
+
))) return { targetTurn, failure: "unrelated_history" };
|
|
182
|
+
return { targetTurn, failure: "" };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function codexAppServerProviderTurnText(thread = null, turnId = "") {
|
|
186
|
+
return codexAppServerProviderThreadAssistantSegments(thread || {}, turnId)
|
|
187
|
+
.map((segment) => segment.text)
|
|
188
|
+
.join("\n\n")
|
|
189
|
+
.trim();
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function codexAppServerProviderTurnError(turn = {}) {
|
|
193
|
+
return codexAppServerSignedOutText(codexAppServerErrorText(turn.error || turn.status?.error || turn.state?.error));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export {
|
|
197
|
+
codexAppServerThreadRawValue,
|
|
198
|
+
codexAppServerThreadTurnId,
|
|
199
|
+
codexAppServerThreadError,
|
|
200
|
+
codexAppServerProviderThreadTurns,
|
|
201
|
+
codexAppServerProviderTurnId,
|
|
202
|
+
codexAppServerProviderTurnStatus,
|
|
203
|
+
codexAppServerProviderTurnItems,
|
|
204
|
+
codexAppServerProviderTurnClientIds,
|
|
205
|
+
codexAppServerProviderTurnForOperation,
|
|
206
|
+
inspectCodexAppServerRenewalThread,
|
|
207
|
+
codexAppServerProviderTurnText,
|
|
208
|
+
codexAppServerProviderTurnError,
|
|
209
|
+
codexAppServerProviderThreadAssistantSegments
|
|
210
|
+
};
|