@jskit-ai/assistant-core 0.1.239 → 0.1.241
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 +5 -5
- package/src/client/conversation/AssistantTranscript.vue +26 -29
- package/src/client/conversation/LongTextPreviewBlocks.vue +11 -0
- package/src/client/conversation/messageDelivery.js +8 -2
- package/src/client/conversation/useAssistantAttachments.js +1 -1
- package/src/server/conversation/agentRun.js +12 -198
- package/src/server/conversation/attachments.js +6 -5
- package/src/server/conversation/boundedToolLoop.js +160 -0
- package/src/server/conversation/claudeHistory.js +20 -16
- package/src/server/conversation/claudeProcess.js +2 -2
- package/src/server/conversation/claudeTurn.js +51 -40
- package/src/server/conversation/codexAuthPreflight.js +104 -0
- package/src/server/conversation/codexClient.js +11 -16
- package/src/server/conversation/codexConfiguration.js +112 -98
- package/src/server/conversation/codexConversationStore.js +189 -0
- package/src/server/conversation/codexConversations.js +47 -44
- package/src/server/conversation/codexDetachedTurn.js +12 -11
- package/src/server/conversation/codexEvents.js +95 -99
- package/src/server/conversation/codexGoalCommands.js +1 -1
- package/src/server/conversation/codexHelperExecution.js +3 -13
- package/src/server/conversation/codexHelperThreadLedger.js +7 -13
- package/src/server/conversation/codexHelperThreadRecovery.js +2 -16
- package/src/server/conversation/codexHelperThreads.js +5 -6
- package/src/server/conversation/codexHistoryAdapter.js +32 -26
- package/src/server/conversation/codexMessageCommands.js +22 -22
- package/src/server/conversation/codexMessageDelivery.js +12 -7
- package/src/server/conversation/codexModelCatalog.js +97 -0
- package/src/server/conversation/codexNotificationObserver.js +24 -40
- package/src/server/conversation/codexNotificationQueue.js +2 -3
- package/src/server/conversation/codexOutput.js +20 -27
- package/src/server/conversation/codexProcess.js +123 -127
- package/src/server/conversation/codexProcessLeader.js +3 -3
- package/src/server/conversation/codexProvider.js +31 -614
- package/src/server/conversation/codexProviderOwner.js +2 -2
- package/src/server/conversation/codexProviderSelection.js +38 -40
- package/src/server/conversation/codexRenewalCommands.js +13 -10
- package/src/server/conversation/codexRenewalThreads.js +412 -0
- package/src/server/conversation/codexRunJournal.js +24 -42
- package/src/server/conversation/codexRuntimeLifecycle.js +19 -15
- package/src/server/conversation/codexSessionCleanup.js +11 -10
- package/src/server/conversation/codexSessionReconciliation.js +6 -6
- package/src/server/conversation/codexThreadReadiness.js +19 -33
- package/src/server/conversation/codexThreadStatus.js +3 -3
- package/src/server/conversation/codexTurn.js +124 -297
- package/src/server/conversation/codexTurnRecovery.js +49 -28
- package/src/server/conversation/codexTurnState.js +34 -13
- package/src/server/conversation/commandWrapper.js +3 -0
- package/src/server/conversation/deliveryTiming.js +14 -5
- package/src/server/conversation/index.js +1 -0
- package/src/server/conversation/localExecution.js +13 -17
- package/src/server/conversation/normalize.js +8 -3
- package/src/server/conversation/openCodeClient.js +9 -10
- package/src/server/conversation/openCodeProcess.js +9 -5
- package/src/server/conversation/openCodeRuntime.js +10 -11
- package/src/server/conversation/openCodeTurn.js +43 -29
- package/src/server/conversation/providers/claudeDriver.js +10 -16
- package/src/server/conversation/providers/codexDriver.js +27 -43
- package/src/server/conversation/providers/opencodeDriver.js +17 -42
- package/src/server/conversation/providers/scoped.js +48 -4
- package/src/server/conversation/runtime.js +50 -49
- package/src/server/conversation/runtimeStateUpgrade.js +34 -22
- package/src/server/conversation/transcript.js +10 -10
- package/src/server/hosts/codexConfiguration.js +1 -0
- package/src/server/hosts/codexProvider.js +8 -6
- package/src/server/index.js +2 -1
- package/src/server/lib/assistantToolLoop.js +1 -153
- package/src/server/lib/serviceToolCatalog.js +17 -42
- package/src/shared/assistantResource.js +4 -2
- package/src/shared/conversation/attachments.js +4 -0
- package/src/shared/conversation/longTextBlocks.js +54 -19
- package/src/shared/conversation/numberedQuestionSugar.js +17 -10
- package/src/shared/conversation/pagination.js +4 -6
- package/src/shared/conversation/patches.js +1 -4
- package/src/shared/conversation/streaming.js +3 -11
- package/src/shared/conversation/turns.js +11 -0
- package/src/shared/index.js +1 -0
- package/test/assistantBoundedToolLoop.test.js +2 -2
- package/test/assistantResource.test.js +4 -4
- package/test/assistantScroll.browser.test.js +29 -6
- package/test/assistantSettingsResource.test.js +2 -2
- package/test/claudeConversationSession.test.js +20 -3
- package/test/claudeTurn.test.js +27 -7
- package/test/codexClient.test.js +20 -0
- package/test/codexConversationSession.test.js +5 -3
- package/test/codexConversationsCheckpoint.test.js +51 -0
- package/test/codexModelCatalog.test.js +1 -1
- package/test/codexProviderHome.test.js +51 -0
- package/test/codexProviderSelection.test.js +71 -0
- package/test/codexTurn.test.js +222 -6
- package/test/conversationAgentRun.test.js +2 -1
- package/test/conversationAttachments.test.js +27 -2
- package/test/conversationDeliveryTiming.test.js +21 -0
- package/test/conversationNormalize.test.js +11 -0
- package/test/fixtures/nestedListQuestionMessage.md +37 -0
- package/test/frameworkActions.test.js +2 -2
- package/test/longTextBlocks.test.js +102 -0
- package/test/messageDelivery.test.js +7 -1
- package/test/openCodeClient.test.js +20 -0
- package/test/openCodeRuntime.test.js +1 -1
- package/test/openCodeTurn.test.js +90 -0
- package/test/opencodeConversationSession.test.js +1 -1
- package/test/serviceToolCatalog.test.js +27 -0
|
@@ -9,14 +9,15 @@ import {
|
|
|
9
9
|
codexAppServerAgentRunPatch,
|
|
10
10
|
codexAppServerRunIdentityForPatch,
|
|
11
11
|
codexAppServerRunPatchIsStaleAfterTerminalState,
|
|
12
|
+
codexAppServerRunPatchSettlesOtherActiveTurn,
|
|
12
13
|
CODEX_APP_SERVER_AGENT_RUN_ID,
|
|
13
14
|
CODEX_AGENT_PROVIDER,
|
|
14
15
|
CODEX_APP_SERVER_RUN_STATE,
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
codexAppServerRunInputSource,
|
|
17
|
+
codexAppServerTurnStateFromAgentRun
|
|
17
18
|
} from "./codexTurnState.js";
|
|
18
19
|
import crypto from "node:crypto";
|
|
19
|
-
import {
|
|
20
|
+
import { isRecord } from "@jskit-ai/kernel/shared/support/normalize";
|
|
20
21
|
|
|
21
22
|
const CODEX_APP_SERVER_PROMPT_CLAIM_GRACE_MS = 15000;
|
|
22
23
|
|
|
@@ -207,12 +208,18 @@ export function createCodexRunJournal({
|
|
|
207
208
|
currentTurn.threadId === runPatch.providerThreadId &&
|
|
208
209
|
currentTurn.turnId === runPatch.providerTurnId &&
|
|
209
210
|
runPatch.state === CODEX_APP_SERVER_RUN_STATE.ACTIVE;
|
|
211
|
+
const observationLostBlocks = currentTurn.status === "observation_lost" && status !== "observation_lost";
|
|
212
|
+
const phaseTargetsOtherTurn = phase !== undefined && (!normalizeCodexRunText(turnId) ||
|
|
213
|
+
!codexAppServerTurnCanReceiveProviderActivity(currentTurn, threadId, turnId));
|
|
214
|
+
const observationExpired = Boolean(observedRun) && !canRecoverStoppedTurn;
|
|
215
|
+
const terminalAlreadyRecorded = !canRecoverStoppedTurn && runPatchIsStaleAfterTerminalState(currentTurn, runPatch);
|
|
216
|
+
const settlesOtherActiveTurn = codexAppServerRunPatchSettlesOtherActiveTurn(currentTurn, runPatch);
|
|
210
217
|
if (
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
218
|
+
observationLostBlocks ||
|
|
219
|
+
phaseTargetsOtherTurn ||
|
|
220
|
+
observationExpired ||
|
|
221
|
+
terminalAlreadyRecorded ||
|
|
222
|
+
settlesOtherActiveTurn
|
|
216
223
|
) {
|
|
217
224
|
stale = {
|
|
218
225
|
currentState: currentTurn.state,
|
|
@@ -260,9 +267,9 @@ export function createCodexRunJournal({
|
|
|
260
267
|
|
|
261
268
|
function clearCodexAppServerFinalizingTimer(sessionId = "", threadId = "", turnId = "") {
|
|
262
269
|
const key = codexAppServerResultFinalizationKey(sessionId, threadId, turnId);
|
|
263
|
-
const
|
|
264
|
-
if (
|
|
265
|
-
clearTimeout(timer);
|
|
270
|
+
const entry = codexAppServerFinalizingTimers.get(key);
|
|
271
|
+
if (entry) {
|
|
272
|
+
clearTimeout(entry.timer);
|
|
266
273
|
codexAppServerFinalizingTimers.delete(key);
|
|
267
274
|
}
|
|
268
275
|
}
|
|
@@ -271,9 +278,9 @@ export function createCodexRunJournal({
|
|
|
271
278
|
const normalizedSessionId = normalizeCodexRunText(sessionId);
|
|
272
279
|
clearCodexAppServerActiveTimer(normalizedSessionId);
|
|
273
280
|
const finalizingKeyPrefix = `${namespace(normalizedSessionId)}:`;
|
|
274
|
-
for (const [key,
|
|
281
|
+
for (const [key, entry] of codexAppServerFinalizingTimers.entries()) {
|
|
275
282
|
if (key.startsWith(finalizingKeyPrefix)) {
|
|
276
|
-
clearTimeout(timer);
|
|
283
|
+
clearTimeout(entry.timer);
|
|
277
284
|
codexAppServerFinalizingTimers.delete(key);
|
|
278
285
|
}
|
|
279
286
|
}
|
|
@@ -291,34 +298,10 @@ export function createCodexRunJournal({
|
|
|
291
298
|
}
|
|
292
299
|
|
|
293
300
|
function codexAppServerAgentRunRealtimePayload(runPatch = {}) {
|
|
294
|
-
const
|
|
295
|
-
const active = codexAppServerRunStateIsActive(runState);
|
|
296
|
-
const state = runState === CODEX_APP_SERVER_RUN_STATE.FINALIZING
|
|
297
|
-
? "finalizing"
|
|
298
|
-
: runState === CODEX_APP_SERVER_RUN_STATE.STARTING
|
|
299
|
-
? "starting"
|
|
300
|
-
: active
|
|
301
|
-
? "active"
|
|
302
|
-
: "idle";
|
|
303
|
-
const turn = {
|
|
304
|
-
active,
|
|
305
|
-
completedAt: normalizeCodexRunText(runPatch.finishedAt),
|
|
306
|
-
error: normalizeCodexRunText(runPatch.error),
|
|
307
|
-
inputSource: normalizeCodexRunText(runPatch.inputSource),
|
|
308
|
-
outerTurnId: normalizeCodexRunText(runPatch.outerTurnId),
|
|
309
|
-
phase: active && runPatch.providerStatus !== "observation_lost" ? normalizeCodexRunText(runPatch.providerPhase) : "",
|
|
310
|
-
runId: CODEX_APP_SERVER_AGENT_RUN_ID,
|
|
311
|
-
runState,
|
|
312
|
-
startedAt: normalizeCodexRunText(runPatch.startedAt),
|
|
313
|
-
state,
|
|
314
|
-
status: normalizeCodexRunText(runPatch.providerStatus || runState),
|
|
315
|
-
threadId: normalizeCodexRunText(runPatch.providerThreadId),
|
|
316
|
-
turnId: normalizeCodexRunText(runPatch.providerTurnId),
|
|
317
|
-
updatedAt: normalizeCodexRunText(runPatch.updatedAt)
|
|
318
|
-
};
|
|
301
|
+
const turn = codexAppServerTurnStateFromAgentRun({ ...runPatch, id: CODEX_APP_SERVER_AGENT_RUN_ID }, normalizeRunState);
|
|
319
302
|
return {
|
|
320
303
|
agentRun: {
|
|
321
|
-
active,
|
|
304
|
+
active: turn.active,
|
|
322
305
|
id: CODEX_APP_SERVER_AGENT_RUN_ID,
|
|
323
306
|
inputSource: turn.inputSource,
|
|
324
307
|
outerTurnId: turn.outerTurnId,
|
|
@@ -327,7 +310,7 @@ export function createCodexRunJournal({
|
|
|
327
310
|
providerStatus: turn.status,
|
|
328
311
|
providerThreadId: turn.threadId,
|
|
329
312
|
providerTurnId: turn.turnId,
|
|
330
|
-
state: runState,
|
|
313
|
+
state: turn.runState,
|
|
331
314
|
updatedAt: turn.updatedAt
|
|
332
315
|
},
|
|
333
316
|
agentSession: {
|
|
@@ -390,7 +373,7 @@ export function createCodexRunJournal({
|
|
|
390
373
|
payload: {
|
|
391
374
|
...codexAppServerAgentRunRealtimePayload(runPatch),
|
|
392
375
|
...(conversationStream ? { conversationStream } : {}),
|
|
393
|
-
...(
|
|
376
|
+
...(isRecord(publishPayload) ? publishPayload : {})
|
|
394
377
|
},
|
|
395
378
|
reason: publishReason || "codex-app-server-turn-state",
|
|
396
379
|
session: updatedSession
|
|
@@ -584,7 +567,6 @@ export function createCodexRunJournal({
|
|
|
584
567
|
nowMs - runUpdatedMs >= CODEX_APP_SERVER_PROMPT_CLAIM_GRACE_MS
|
|
585
568
|
);
|
|
586
569
|
return (
|
|
587
|
-
(run.active === true || CODEX_APP_SERVER_ACTIVE_RUN_STATES.has(normalizeRunState(run.state))) &&
|
|
588
570
|
normalizeCodexRunText(run.state) === CODEX_APP_SERVER_RUN_STATE.STARTING &&
|
|
589
571
|
!normalizeCodexRunText(run.providerThreadId) &&
|
|
590
572
|
!normalizeCodexRunText(run.providerTurnId) &&
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { normalizeCodexRunText as normalizeText } from "./codexTurnState.js";
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
//
|
|
3
|
+
// Shutdown, wellbeing timers and managed-session records for shared Codex
|
|
4
|
+
// runtimes. It works on the run/provider owners' collections; it owns no servers.
|
|
5
|
+
// `pendingWork` names the run owner's in-flight task collections that shutdown
|
|
6
|
+
// drains; `observer` owns the event subscriptions a released provider ends.
|
|
5
7
|
export function createCodexRuntimeLifecycle({
|
|
6
|
-
|
|
8
|
+
pendingWork,
|
|
9
|
+
observer,
|
|
10
|
+
checkManagedConnection,
|
|
7
11
|
providerSessions,
|
|
8
12
|
helperLifecycle,
|
|
9
13
|
captureContext,
|
|
@@ -58,16 +62,16 @@ export function createCodexRuntimeLifecycle({
|
|
|
58
62
|
function codexAppServerProviderResources(providerKey) {
|
|
59
63
|
const normalizedProviderKey = normalizeText(providerKey);
|
|
60
64
|
return {
|
|
61
|
-
retire:
|
|
62
|
-
reconcileRetirement:
|
|
65
|
+
retire: helperLifecycle.retireProvider,
|
|
66
|
+
reconcileRetirement: helperLifecycle.reconcileProviderRetirement,
|
|
63
67
|
release(provider) {
|
|
64
|
-
|
|
68
|
+
helperLifecycle.assertProviderReleased(provider);
|
|
65
69
|
stopCodexAppServerWellbeing(normalizedProviderKey);
|
|
66
70
|
providerSessions.managed.delete(normalizedProviderKey);
|
|
67
71
|
const subscriptionPrefix = `${normalizedProviderKey}:`;
|
|
68
|
-
for (const key of [...
|
|
72
|
+
for (const key of [...observer.eventSubscriptions.keys()]) {
|
|
69
73
|
if (key.startsWith(subscriptionPrefix)) {
|
|
70
|
-
|
|
74
|
+
observer.unsubscribeEventSubscription(key);
|
|
71
75
|
}
|
|
72
76
|
}
|
|
73
77
|
}
|
|
@@ -156,21 +160,21 @@ export function createCodexRuntimeLifecycle({
|
|
|
156
160
|
async function drainCodexAppServerControllerTasks() {
|
|
157
161
|
while (true) {
|
|
158
162
|
const pending = new Set([
|
|
159
|
-
...
|
|
163
|
+
...pendingWork.conversationTurnStarts.values(),
|
|
160
164
|
...helperLifecycle.projectOperations.values(),
|
|
161
165
|
...helperLifecycle.cleanups.values(),
|
|
162
166
|
...helperLifecycle.mutations.values(),
|
|
163
167
|
...helperLifecycle.restores.values(),
|
|
164
168
|
...helperLifecycle.turnStarts.values(),
|
|
165
|
-
...
|
|
166
|
-
...
|
|
167
|
-
...
|
|
169
|
+
...pendingWork.messageDeliveries.values(),
|
|
170
|
+
...pendingWork.reasoningPersistQueues.values(),
|
|
171
|
+
...pendingWork.resultFinalizations.values(),
|
|
168
172
|
...providerSessions.owner.lifecycleTasks,
|
|
169
173
|
...providerSessions.owner.runtimeAcquisitions,
|
|
170
174
|
...codexAppServerReconcileTasks,
|
|
171
175
|
...codexAppServerSessionClosures.values(),
|
|
172
|
-
...
|
|
173
|
-
...
|
|
176
|
+
...pendingWork.threadReconciliations.values(),
|
|
177
|
+
...pendingWork.notificationTasks.values()
|
|
174
178
|
]);
|
|
175
179
|
if (pending.size === 0) {
|
|
176
180
|
return;
|
|
@@ -194,7 +198,7 @@ export function createCodexRuntimeLifecycle({
|
|
|
194
198
|
return;
|
|
195
199
|
}
|
|
196
200
|
await runInContext(current.projectContext, async () => {
|
|
197
|
-
await
|
|
201
|
+
await checkManagedConnection(normalizedProviderKey);
|
|
198
202
|
});
|
|
199
203
|
})()
|
|
200
204
|
.catch((error) => {
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
import { normalizeCodexRunText } from "./codexTurnState.js";
|
|
2
2
|
|
|
3
3
|
// Cleanup of the existing run/provider/Helper owners. The application keeps
|
|
4
|
-
// its authority and storage projections; all native coordination stays here
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
// its authority and storage projections; all native coordination stays here:
|
|
5
|
+
// one closure per session key (shared with the runtime lifecycle, which drains
|
|
6
|
+
// them on shutdown) and the private record of which closures are restricted.
|
|
7
|
+
export function createCodexSessionCleanup({ namespace, runOwner, providerSessions, sessionClosures, helperLifecycle,
|
|
8
|
+
journal, conversations, debugLog, debugError }) {
|
|
7
9
|
const providerOwner = providerSessions?.owner;
|
|
10
|
+
const restrictedClosures = new WeakSet();
|
|
8
11
|
|
|
9
12
|
async function closeSession(sessionId, cleanup) {
|
|
10
13
|
const normalizedSessionId = normalizeCodexRunText(sessionId);
|
|
11
14
|
const sessionKey = cleanup.sessionKey;
|
|
12
|
-
|
|
13
|
-
const restrictedClosures = cleanup.restrictedPending;
|
|
14
|
-
let pending = pendingClosures.get(sessionKey);
|
|
15
|
+
let pending = sessionClosures.get(sessionKey);
|
|
15
16
|
while (pending) {
|
|
16
17
|
const pendingIsRestricted = restrictedClosures.has(pending);
|
|
17
18
|
if (cleanup.restricted && !pendingIsRestricted) {
|
|
18
19
|
await pending.catch(() => null);
|
|
19
|
-
pending =
|
|
20
|
+
pending = sessionClosures.get(sessionKey);
|
|
20
21
|
continue;
|
|
21
22
|
}
|
|
22
23
|
if (!cleanup.restricted && pendingIsRestricted) {
|
|
@@ -58,15 +59,15 @@ export function createCodexSessionCleanup({ namespace, runOwner, providerSession
|
|
|
58
59
|
});
|
|
59
60
|
await prepared.complete(exitFailure);
|
|
60
61
|
})();
|
|
61
|
-
|
|
62
|
+
sessionClosures.set(sessionKey, closing);
|
|
62
63
|
if (cleanup.restricted) {
|
|
63
64
|
restrictedClosures.add(closing);
|
|
64
65
|
}
|
|
65
66
|
try {
|
|
66
67
|
return await closing;
|
|
67
68
|
} finally {
|
|
68
|
-
if (
|
|
69
|
-
|
|
69
|
+
if (sessionClosures.get(sessionKey) === closing) {
|
|
70
|
+
sessionClosures.delete(sessionKey);
|
|
70
71
|
}
|
|
71
72
|
}
|
|
72
73
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { normalizeCodexRunText as normalizeText, codexAppServerErrorMessage as errorMessage } from "./codexTurnState.js";
|
|
2
|
-
import {
|
|
2
|
+
import { isRecord } from "@jskit-ai/kernel/shared/support/normalize";
|
|
3
3
|
|
|
4
4
|
// Original batch restoration, prune and startup unsubscribe. The run owner's
|
|
5
5
|
// existing lifecycle and per-thread readiness retain all state and coordination.
|
|
6
6
|
export function createCodexSessionReconciliation({
|
|
7
|
-
|
|
7
|
+
readiness, recoverSessionObservationLoss, providerSessions, helperLifecycle, lifecycle, createRuntime,
|
|
8
8
|
namespace, turnState, sessionIdRequiredError, debugLog, debugError
|
|
9
9
|
}) {
|
|
10
10
|
async function pruneCodexAppServerManagedSessions({
|
|
@@ -72,7 +72,7 @@ export function createCodexSessionReconciliation({
|
|
|
72
72
|
const failed = [];
|
|
73
73
|
const seenSessionIds = new Set();
|
|
74
74
|
for (const session of Array.isArray(sessions) ? sessions : []) {
|
|
75
|
-
const sessionId =
|
|
75
|
+
const sessionId = codexAppServerReconcileSessionId(session);
|
|
76
76
|
if (!sessionId || seenSessionIds.has(sessionId)) {
|
|
77
77
|
continue;
|
|
78
78
|
}
|
|
@@ -131,7 +131,7 @@ export function createCodexSessionReconciliation({
|
|
|
131
131
|
if (prepared.result) return prepared.result;
|
|
132
132
|
const { context } = prepared;
|
|
133
133
|
if (turnState(context.session).status === "observation_lost") {
|
|
134
|
-
const recovered = await prepared.recover(
|
|
134
|
+
const recovered = await prepared.recover(recoverSessionObservationLoss);
|
|
135
135
|
const turn = turnState(recovered);
|
|
136
136
|
return prepared.stopped({
|
|
137
137
|
ok: !turn.active,
|
|
@@ -140,7 +140,7 @@ export function createCodexSessionReconciliation({
|
|
|
140
140
|
threadId: turn.threadId
|
|
141
141
|
}, recovered);
|
|
142
142
|
}
|
|
143
|
-
return
|
|
143
|
+
return readiness.reconcileThread(normalizedSessionId, context, prepared.thread);
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
async function reconcileCodexAppServerThreads(sessions = [], {
|
|
@@ -227,7 +227,7 @@ export function createCodexSessionReconciliation({
|
|
|
227
227
|
}
|
|
228
228
|
}
|
|
229
229
|
if (reconcileGeneration === lifecycle.reconcileGeneration) {
|
|
230
|
-
await
|
|
230
|
+
await readiness.waitForThreadReconciliations({
|
|
231
231
|
keepProviderKeys,
|
|
232
232
|
projectContextRoot
|
|
233
233
|
});
|
|
@@ -7,8 +7,8 @@ import {
|
|
|
7
7
|
import { codexAppServerThreadIsMissing, ensureCodexAppServerThread } from "./codexProvider.js";
|
|
8
8
|
import { codexAppServerThreadRawValue, codexAppServerThreadTurnId } from "./codexEvents.js";
|
|
9
9
|
|
|
10
|
-
//
|
|
11
|
-
//
|
|
10
|
+
// Native thread readiness, loaded-thread restoration and reconciliation drain.
|
|
11
|
+
// Its one Map lives as long as the run owner and is shared with shutdown.
|
|
12
12
|
export function createCodexThreadReadiness({
|
|
13
13
|
providerSessions,
|
|
14
14
|
selection,
|
|
@@ -23,7 +23,9 @@ export function createCodexThreadReadiness({
|
|
|
23
23
|
const {
|
|
24
24
|
ensureCodexAppServerProviderForActiveTurn,
|
|
25
25
|
codexAppServerSessionObserverOptions,
|
|
26
|
-
|
|
26
|
+
sessionConnection,
|
|
27
|
+
ensureSessionProvider,
|
|
28
|
+
rememberManagedSession
|
|
27
29
|
} = selection;
|
|
28
30
|
const {
|
|
29
31
|
eventSubscriptionKey: codexAppServerEventSubscriptionKey,
|
|
@@ -47,10 +49,8 @@ export function createCodexThreadReadiness({
|
|
|
47
49
|
if (!providerOptions) {
|
|
48
50
|
providerOptions = await preparation.providerOptions(session);
|
|
49
51
|
}
|
|
50
|
-
const provider = activeProvider?.provider ||
|
|
51
|
-
|
|
52
|
-
preparation.threadId(session)
|
|
53
|
-
);
|
|
52
|
+
const provider = activeProvider?.provider ||
|
|
53
|
+
await ensureSessionProvider(sessionId, providerOptions, preparation.threadId(session));
|
|
54
54
|
const { currentSession: preparedSession, thread } = await preparation.gate(async currentSession => {
|
|
55
55
|
const thread = await ensureCodexAppServerThread({
|
|
56
56
|
...preparation.preparation(currentSession),
|
|
@@ -63,7 +63,9 @@ export function createCodexThreadReadiness({
|
|
|
63
63
|
});
|
|
64
64
|
subscribeCodexAppServerEvents(sessionId, provider, thread.threadId,
|
|
65
65
|
codexAppServerSessionObserverOptions(sessionId, providerOptions));
|
|
66
|
-
|
|
66
|
+
rememberManagedSession(sessionId, providerOptions, {
|
|
67
|
+
executionRoot: context.executionRoot, workdir: context.workdir, threadId: thread.threadId
|
|
68
|
+
});
|
|
67
69
|
await reconcileCodexAppServerThreadStatus(sessionId, provider, thread.threadId, {
|
|
68
70
|
failUnconfirmedTrackedTurn: true,
|
|
69
71
|
observeLatestTurn: true,
|
|
@@ -87,14 +89,9 @@ export function createCodexThreadReadiness({
|
|
|
87
89
|
const threadId = preparation.threadId(session);
|
|
88
90
|
if (!threadId) {
|
|
89
91
|
const providerOptions = await preparation.providerOptions(session);
|
|
90
|
-
const providerKey =
|
|
91
|
-
await
|
|
92
|
-
|
|
93
|
-
providerOptions,
|
|
94
|
-
sessionId: normalizedSessionId,
|
|
95
|
-
executionRoot,
|
|
96
|
-
workdir
|
|
97
|
-
});
|
|
92
|
+
const { providerKey } = sessionConnection(normalizedSessionId, providerOptions);
|
|
93
|
+
await ensureSessionProvider(normalizedSessionId, providerOptions);
|
|
94
|
+
rememberManagedSession(normalizedSessionId, providerOptions, { executionRoot, workdir });
|
|
98
95
|
return {
|
|
99
96
|
ok: true,
|
|
100
97
|
providerKey,
|
|
@@ -105,32 +102,23 @@ export function createCodexThreadReadiness({
|
|
|
105
102
|
}
|
|
106
103
|
const activeProvider = await ensureCodexAppServerProviderForActiveTurn(session, preparation.managedIdentity);
|
|
107
104
|
const providerOptions = activeProvider?.providerOptions || await preparation.providerOptions(session);
|
|
108
|
-
const providerKey = activeProvider?.providerKey ||
|
|
105
|
+
const providerKey = activeProvider?.providerKey || sessionConnection(normalizedSessionId, providerOptions).providerKey;
|
|
109
106
|
const existing = codexAppServerThreadReconciliations.get(providerKey);
|
|
110
107
|
if (existing) {
|
|
111
108
|
return existing;
|
|
112
109
|
}
|
|
113
110
|
const reconciliation = (async () => {
|
|
114
|
-
const provider = activeProvider?.provider ||
|
|
115
|
-
|
|
116
|
-
);
|
|
111
|
+
const provider = activeProvider?.provider ||
|
|
112
|
+
await ensureSessionProvider(normalizedSessionId, providerOptions, threadId);
|
|
117
113
|
try {
|
|
118
114
|
const restored = await restoreCodexAppServerLoadedThread(normalizedSessionId, {
|
|
119
115
|
runtime, provider, providerKey, threadId,
|
|
120
|
-
subscriptionOptions:
|
|
121
|
-
get providerKey() { return providerSessions.context(normalizeCodexRunText(normalizedSessionId), providerOptions).providerKey; }
|
|
122
|
-
},
|
|
116
|
+
subscriptionOptions: codexAppServerSessionObserverOptions(normalizedSessionId, providerOptions),
|
|
123
117
|
get resumeOptions() {
|
|
124
118
|
return preparation.resumeOptions;
|
|
125
119
|
},
|
|
126
120
|
remember() {
|
|
127
|
-
|
|
128
|
-
providerOptions,
|
|
129
|
-
sessionId: normalizedSessionId,
|
|
130
|
-
executionRoot,
|
|
131
|
-
threadId,
|
|
132
|
-
workdir
|
|
133
|
-
});
|
|
121
|
+
rememberManagedSession(normalizedSessionId, providerOptions, { executionRoot, threadId, workdir });
|
|
134
122
|
},
|
|
135
123
|
ready() { return preparation.ready(); }
|
|
136
124
|
});
|
|
@@ -207,9 +195,7 @@ export function createCodexThreadReadiness({
|
|
|
207
195
|
return maintainCodexAppServerManagedConnection(sessionId, {
|
|
208
196
|
provider, providerKey: normalizedProviderKey, threadId, reconnect,
|
|
209
197
|
get workdir() { return managed.workdir; },
|
|
210
|
-
subscriptionOptions: {
|
|
211
|
-
get providerKey() { return providerSessions.context(normalizeCodexRunText(sessionId), managed.providerOptions || {}).providerKey; }
|
|
212
|
-
}
|
|
198
|
+
subscriptionOptions: codexAppServerSessionObserverOptions(sessionId, managed.providerOptions || {})
|
|
213
199
|
}, current);
|
|
214
200
|
}
|
|
215
201
|
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
codexAppServerTurnCanAdoptSuccessor,
|
|
12
12
|
codexAppServerErrorMessage
|
|
13
13
|
} from "./codexTurnState.js";
|
|
14
|
-
import {
|
|
14
|
+
import { isRecord } from "@jskit-ai/kernel/shared/support/normalize";
|
|
15
15
|
import {
|
|
16
16
|
codexAppServerStatusFromValue,
|
|
17
17
|
codexAppServerThreadRawValue,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
codexAppServerThreadError
|
|
20
20
|
} from "./codexEvents.js";
|
|
21
21
|
|
|
22
|
-
//
|
|
22
|
+
// Native thread snapshot reconciliation; it holds no state of its own.
|
|
23
23
|
export function createCodexThreadStatus({ journal, settlement, recovery, output, createRuntime, turnState, turnOutcomes, debugLog, debugError }) {
|
|
24
24
|
const { turnResultWasProcessed: codexAppServerTurnResultWasProcessed } = journal;
|
|
25
25
|
const {
|
|
@@ -278,7 +278,7 @@ export function createCodexThreadStatus({ journal, settlement, recovery, output,
|
|
|
278
278
|
}
|
|
279
279
|
if (
|
|
280
280
|
codexAppServerTurnStatusIsComplete(status) &&
|
|
281
|
-
|
|
281
|
+
isRecord(thread?.observedTurn) &&
|
|
282
282
|
turnId
|
|
283
283
|
) {
|
|
284
284
|
const currentSession = await runtime.getSession(normalizedSessionId);
|