@jskit-ai/assistant-core 0.1.199 → 0.1.201
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/README.md +8 -1
- package/examples/conversation/package.json +5 -5
- package/fixtures/responsive-assistant/App.vue +4 -1
- package/package.json +99 -36
- package/src/client/conversation/AssistantConversationElement.vue +27 -4
- package/src/client/conversation/AssistantConversationStatus.vue +24 -0
- package/src/client/conversation/AssistantGoalControl.vue +8 -5
- package/src/client/conversation/AssistantTranscript.vue +10 -3
- package/src/client/conversation/index.js +2 -0
- package/src/client/conversation/messageDelivery.js +115 -32
- package/src/client/conversation/retainedConversation.js +32 -0
- package/src/client/conversation/useAssistantQuestions.js +76 -0
- package/src/client/lib/assistantApi.js +72 -2
- package/src/server/conversation/agentRun.js +222 -0
- package/src/server/conversation/attachments.js +93 -0
- package/src/server/conversation/claudeClient.js +221 -0
- package/src/server/conversation/claudeHistory.js +256 -0
- package/src/server/conversation/claudeProcess.js +327 -0
- package/src/server/conversation/claudeTools.js +42 -0
- package/src/server/conversation/claudeTurn.js +1082 -0
- package/src/server/conversation/codexConfiguration.js +1183 -0
- package/src/server/conversation/codexConversations.js +1082 -0
- package/src/server/conversation/codexDetachedTurn.js +332 -0
- package/src/server/conversation/codexEvents.js +194 -1
- package/src/server/conversation/codexGoalCommands.js +124 -0
- package/src/server/conversation/codexHelperExecution.js +306 -0
- package/src/server/conversation/codexHelperThreadLedger.js +804 -0
- package/src/server/conversation/codexHelperThreadRecovery.js +395 -0
- package/src/server/conversation/codexHelperThreads.js +638 -0
- package/src/server/conversation/codexHistoryAdapter.js +369 -0
- package/src/server/conversation/codexMessageCommands.js +663 -0
- package/src/server/conversation/codexMessageDelivery.js +211 -0
- package/src/server/conversation/codexNativeHistoryExport.js +95 -0
- package/src/server/conversation/codexNotificationObserver.js +482 -0
- package/src/server/conversation/codexNotificationQueue.js +103 -0
- package/src/server/conversation/codexObservationControl.js +174 -0
- package/src/server/conversation/codexOutput.js +931 -0
- package/src/server/conversation/codexProcess.js +1559 -0
- package/src/server/conversation/codexProcessLeader.js +14 -0
- package/src/server/conversation/codexProvider.js +2710 -0
- package/src/server/conversation/codexProviderOwner.js +1058 -0
- package/src/server/conversation/codexProviderSelection.js +218 -0
- package/src/server/conversation/codexReasoning.js +314 -0
- package/src/server/conversation/codexRenewalCommands.js +290 -0
- package/src/server/conversation/codexResultSettlement.js +409 -0
- package/src/server/conversation/codexRunJournal.js +658 -0
- package/src/server/conversation/codexRuntimeLifecycle.js +288 -0
- package/src/server/conversation/codexSessionCleanup.js +96 -0
- package/src/server/conversation/codexSessionReconciliation.js +284 -0
- package/src/server/conversation/codexThreadReadiness.js +397 -0
- package/src/server/conversation/codexThreadStatus.js +354 -0
- package/src/server/conversation/codexTurn.js +701 -255
- package/src/server/conversation/codexTurnControl.js +317 -0
- package/src/server/conversation/codexTurnRecovery.js +990 -0
- package/src/server/conversation/codexTurnState.js +549 -0
- package/src/server/conversation/commandHook.js +18 -0
- package/src/server/conversation/commandWrapper.js +37 -0
- package/src/server/conversation/configuration.js +43 -0
- package/src/server/conversation/continuity.js +289 -0
- package/src/server/conversation/fileStorage.js +55 -0
- package/src/server/conversation/hookBridge.js +19 -0
- package/src/server/conversation/index.js +13 -0
- package/src/server/conversation/localExecution.js +665 -0
- package/src/server/conversation/memoryStorage.js +7 -72
- package/src/server/conversation/nativeHistoryExport.js +90 -0
- package/src/server/conversation/nativeStorage.js +23 -0
- package/src/server/conversation/openCodeClient.js +209 -19
- package/src/server/conversation/openCodePlugin.js +84 -0
- package/src/server/conversation/openCodeProcess.js +476 -0
- package/src/server/conversation/openCodeRuntime.js +1578 -0
- package/src/server/conversation/openCodeTools.js +60 -0
- package/src/server/conversation/openCodeTurn.js +557 -0
- package/src/server/conversation/provider.js +30 -0
- package/src/server/conversation/providers/api.js +136 -0
- package/src/server/conversation/providers/claude.js +63 -0
- package/src/server/conversation/providers/claudeDriver.js +425 -0
- package/src/server/conversation/providers/codex.js +248 -0
- package/src/server/conversation/providers/codexDriver.js +1078 -0
- package/src/server/conversation/providers/opencode.js +49 -0
- package/src/server/conversation/providers/opencodeDriver.js +650 -0
- package/src/server/conversation/providers/scoped.js +312 -0
- package/src/server/conversation/runtime.js +2220 -0
- package/src/server/conversation/runtimeStateUpgrade.js +125 -0
- package/src/server/conversation/storage.js +184 -0
- package/src/server/conversation/streams.js +7 -2
- package/src/server/conversation/structuredOutput.js +240 -0
- package/src/server/conversation/systemPrompt.js +54 -0
- package/src/server/conversation/tools.js +84 -0
- package/src/server/conversation/transcript.js +5 -4
- package/src/server/hosts/claudeHistory.js +5 -0
- package/src/server/hosts/claudeProcess.js +11 -0
- package/src/server/hosts/claudeTurn.js +4 -0
- package/src/server/hosts/codexConfiguration.js +20 -0
- package/src/server/hosts/codexEvents.js +13 -0
- package/src/server/hosts/codexProcess.js +12 -0
- package/src/server/hosts/codexProvider.js +23 -0
- package/src/server/hosts/codexTurn.js +20 -0
- package/src/server/hosts/nativeHistory.js +3 -0
- package/src/server/hosts/openCodeClient.js +3 -0
- package/src/server/hosts/openCodeProcess.js +23 -0
- package/src/server/hosts/openCodeTurn.js +7 -0
- package/src/server/index.js +2 -0
- package/src/server/lib/aiConnectionClient.js +13 -6
- package/src/server/lib/assistantCompletion.js +190 -0
- package/src/server/lib/assistantToolLoop.js +314 -0
- package/src/server/lib/serviceToolCatalog.js +25 -10
- package/src/shared/assistantResponseText.js +29 -0
- package/src/shared/conversation/attachments.js +19 -0
- package/src/shared/conversation/index.js +3 -0
- package/src/shared/conversation/pagination.js +78 -0
- package/src/shared/conversation/patches.js +150 -0
- package/src/shared/conversation/questions.js +48 -0
- package/src/shared/conversation/streaming.js +7 -4
- package/src/shared/index.js +2 -0
- package/src/shared/nativeProviders.js +45 -0
- package/src/testing/conversationStorageContract.js +31 -1
- package/src/testing/nativeCodex.js +11 -0
- package/src/testing/nativeOpenCode.js +3 -0
- package/test/aiConnectionClient.test.js +2 -0
- package/test/apiConversationDriver.test.js +73 -0
- package/test/assistantApiSurfaceHeader.test.js +85 -0
- package/test/assistantBoundedToolLoop.test.js +285 -0
- package/test/assistantScroll.browser.test.js +16 -0
- package/test/claudeClient.test.js +189 -0
- package/test/claudeConversationSession.test.js +1173 -0
- package/test/claudeInstructionResume.test.js +82 -0
- package/test/claudeProcess.test.js +204 -0
- package/test/claudeTurn.test.js +253 -0
- package/test/codexConversationSession.test.js +2122 -0
- package/test/codexGoal.test.js +37 -0
- package/test/codexHelperDeletion.test.js +163 -0
- package/test/codexHelperThreadLedger.test.js +494 -0
- package/test/codexHistoryAdapter.test.js +541 -0
- package/test/codexInteractiveArguments.test.js +30 -0
- package/test/codexIsolation.test.js +756 -0
- package/test/codexModelCatalog.test.js +362 -0
- package/test/codexNativeHistoryExport.test.js +81 -0
- package/test/codexThreadSelection.test.js +136 -0
- package/test/codexTurn.test.js +2158 -0
- package/test/conversation.test.js +110 -0
- package/test/conversationAgentRun.test.js +326 -0
- package/test/conversationApiFacilities.test.js +90 -0
- package/test/conversationAttachments.test.js +238 -0
- package/test/conversationCommandWrapper.test.js +48 -0
- package/test/conversationConfiguration.test.js +174 -0
- package/test/conversationNativeStorage.test.js +25 -0
- package/test/conversationReplacement.test.js +172 -0
- package/test/conversationRuntime.test.js +241 -0
- package/test/conversationRuntimeStateUpgrade.test.js +144 -0
- package/test/conversationSession.test.js +1080 -0
- package/test/conversationStreaming.test.js +68 -0
- package/test/conversationSystemPrompt.test.js +84 -0
- package/test/conversationTools.test.js +416 -0
- package/test/fileConversationStorage.test.js +73 -0
- package/test/fixtures/codexHelperThreadLedger.js +39 -0
- package/test/localConversationExecution.test.js +90 -0
- package/test/messageDelivery.test.js +234 -1
- package/test/nativeConversationRetirement.test.js +215 -0
- package/test/openCodeClient.test.js +515 -0
- package/test/openCodeProcess.test.js +177 -0
- package/test/openCodeRuntime.test.js +322 -0
- package/test/openCodeTools.test.js +287 -0
- package/test/opencodeConversationSession.test.js +789 -0
- package/test/serviceToolCatalog.test.js +24 -0
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
import {
|
|
2
|
+
codexAppServerTurnStatusIsActive,
|
|
3
|
+
codexAppServerThreadStatus,
|
|
4
|
+
codexAppServerReadThreadStatus,
|
|
5
|
+
normalizeCodexRunText
|
|
6
|
+
} from "./codexTurnState.js";
|
|
7
|
+
import { codexAppServerThreadIsMissing, ensureCodexAppServerThread } from "./codexProvider.js";
|
|
8
|
+
import { codexAppServerThreadRawValue, codexAppServerThreadTurnId } from "./codexEvents.js";
|
|
9
|
+
|
|
10
|
+
// Original native readiness, loaded-thread restoration and reconciliation drain.
|
|
11
|
+
// One Map retains the original run-owner lifetime and is shared with shutdown.
|
|
12
|
+
export function createCodexThreadReadiness({
|
|
13
|
+
providerSessions,
|
|
14
|
+
selection,
|
|
15
|
+
observer,
|
|
16
|
+
threadStatus,
|
|
17
|
+
recovery,
|
|
18
|
+
turnState,
|
|
19
|
+
debugLog,
|
|
20
|
+
debugError
|
|
21
|
+
}) {
|
|
22
|
+
const codexAppServerThreadReconciliations = new Map();
|
|
23
|
+
const {
|
|
24
|
+
ensureCodexAppServerProviderForActiveTurn,
|
|
25
|
+
codexAppServerSessionObserverOptions,
|
|
26
|
+
rememberCodexAppServerPreparedThread
|
|
27
|
+
} = selection;
|
|
28
|
+
const {
|
|
29
|
+
eventSubscriptionKey: codexAppServerEventSubscriptionKey,
|
|
30
|
+
eventSubscriptionIsCurrent: codexAppServerEventSubscriptionIsCurrent,
|
|
31
|
+
subscribeEvents: subscribeCodexAppServerEvents
|
|
32
|
+
} = observer;
|
|
33
|
+
const {
|
|
34
|
+
reconcileThreadStatus: reconcileCodexAppServerThreadStatus,
|
|
35
|
+
reconcileLoadedThreadStatus: reconcileCodexAppServerLoadedThreadStatus
|
|
36
|
+
} = threadStatus;
|
|
37
|
+
const {
|
|
38
|
+
recoverActiveTurn: recoverCodexAppServerActiveTurn
|
|
39
|
+
} = recovery;
|
|
40
|
+
|
|
41
|
+
async function ensureCodexAppServerThreadReady(sessionId, context, preparation) {
|
|
42
|
+
const { runtime, session, workdir } = context;
|
|
43
|
+
// Runtime recovery may await a disconnect callback that writes session
|
|
44
|
+
// state. This acquisition stays outside the original startup gate.
|
|
45
|
+
const activeProvider = await ensureCodexAppServerProviderForActiveTurn(session, preparation.managedIdentity);
|
|
46
|
+
let providerOptions = activeProvider?.providerOptions;
|
|
47
|
+
if (!providerOptions) {
|
|
48
|
+
providerOptions = await preparation.providerOptions(session);
|
|
49
|
+
}
|
|
50
|
+
const provider = activeProvider?.provider || await providerSessions.owner.ensureSession(
|
|
51
|
+
providerSessions.context(normalizeCodexRunText(sessionId), providerOptions),
|
|
52
|
+
preparation.threadId(session)
|
|
53
|
+
);
|
|
54
|
+
const { currentSession: preparedSession, thread } = await preparation.gate(async currentSession => {
|
|
55
|
+
const thread = await ensureCodexAppServerThread({
|
|
56
|
+
...preparation.preparation(currentSession),
|
|
57
|
+
observeThread: threadId => subscribeCodexAppServerEvents(sessionId, provider, threadId,
|
|
58
|
+
codexAppServerSessionObserverOptions(sessionId, providerOptions)),
|
|
59
|
+
provider,
|
|
60
|
+
workdir
|
|
61
|
+
});
|
|
62
|
+
return { currentSession, thread };
|
|
63
|
+
});
|
|
64
|
+
subscribeCodexAppServerEvents(sessionId, provider, thread.threadId,
|
|
65
|
+
codexAppServerSessionObserverOptions(sessionId, providerOptions));
|
|
66
|
+
rememberCodexAppServerPreparedThread(sessionId, providerOptions, context, thread);
|
|
67
|
+
await reconcileCodexAppServerThreadStatus(sessionId, provider, thread.threadId, {
|
|
68
|
+
failUnconfirmedTrackedTurn: true,
|
|
69
|
+
observeLatestTurn: true,
|
|
70
|
+
requireTrackedTurn: true,
|
|
71
|
+
source: "thread_ready"
|
|
72
|
+
});
|
|
73
|
+
const ready = await preparation.ready(preparedSession);
|
|
74
|
+
let currentSession = await runtime.getSession(sessionId);
|
|
75
|
+
if (turnState(currentSession).state === "starting") {
|
|
76
|
+
currentSession = await recoverCodexAppServerActiveTurn(sessionId, {
|
|
77
|
+
provider,
|
|
78
|
+
retryOnError: false,
|
|
79
|
+
runtime
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
return { ...ready, currentSession, thread };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function reconcileCodexAppServerThreadForSession(normalizedSessionId, context, preparation) {
|
|
86
|
+
const { runtime, session, executionRoot, workdir } = context;
|
|
87
|
+
const threadId = preparation.threadId(session);
|
|
88
|
+
if (!threadId) {
|
|
89
|
+
const providerOptions = await preparation.providerOptions(session);
|
|
90
|
+
const providerKey = providerSessions.context(normalizedSessionId, providerOptions).providerKey;
|
|
91
|
+
await providerSessions.owner.ensureSession(providerSessions.context(normalizedSessionId, providerOptions));
|
|
92
|
+
providerSessions.context(normalizedSessionId, providerOptions).runOwner.runtimeLifecycle.rememberManagedSession(providerKey, {
|
|
93
|
+
providerOptions,
|
|
94
|
+
sessionId: normalizedSessionId,
|
|
95
|
+
executionRoot,
|
|
96
|
+
workdir
|
|
97
|
+
});
|
|
98
|
+
return {
|
|
99
|
+
ok: true,
|
|
100
|
+
providerKey,
|
|
101
|
+
sessionId: normalizedSessionId,
|
|
102
|
+
status: "notStarted",
|
|
103
|
+
threadId: ""
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
const activeProvider = await ensureCodexAppServerProviderForActiveTurn(session, preparation.managedIdentity);
|
|
107
|
+
const providerOptions = activeProvider?.providerOptions || await preparation.providerOptions(session);
|
|
108
|
+
const providerKey = activeProvider?.providerKey || providerSessions.context(normalizedSessionId, providerOptions).providerKey;
|
|
109
|
+
const existing = codexAppServerThreadReconciliations.get(providerKey);
|
|
110
|
+
if (existing) {
|
|
111
|
+
return existing;
|
|
112
|
+
}
|
|
113
|
+
const reconciliation = (async () => {
|
|
114
|
+
const provider = activeProvider?.provider || await providerSessions.owner.ensureSession(
|
|
115
|
+
providerSessions.context(normalizedSessionId, providerOptions), threadId
|
|
116
|
+
);
|
|
117
|
+
try {
|
|
118
|
+
const restored = await restoreCodexAppServerLoadedThread(normalizedSessionId, {
|
|
119
|
+
runtime, provider, providerKey, threadId,
|
|
120
|
+
subscriptionOptions: {
|
|
121
|
+
get providerKey() { return providerSessions.context(normalizeCodexRunText(normalizedSessionId), providerOptions).providerKey; }
|
|
122
|
+
},
|
|
123
|
+
get resumeOptions() {
|
|
124
|
+
return preparation.resumeOptions;
|
|
125
|
+
},
|
|
126
|
+
remember() {
|
|
127
|
+
providerSessions.context(normalizedSessionId, providerOptions).runOwner.runtimeLifecycle.rememberManagedSession(providerKey, {
|
|
128
|
+
providerOptions,
|
|
129
|
+
sessionId: normalizedSessionId,
|
|
130
|
+
executionRoot,
|
|
131
|
+
threadId,
|
|
132
|
+
workdir
|
|
133
|
+
});
|
|
134
|
+
},
|
|
135
|
+
ready() { return preparation.ready(); }
|
|
136
|
+
});
|
|
137
|
+
if (restored) return restored;
|
|
138
|
+
} catch (error) {
|
|
139
|
+
debugLog("appServerThread.loadedList.error", {
|
|
140
|
+
error: debugError(error),
|
|
141
|
+
sessionId: normalizedSessionId,
|
|
142
|
+
threadId
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
const prepared = await preparation.readiness(ensureCodexAppServerThreadReady);
|
|
146
|
+
return {
|
|
147
|
+
...prepared,
|
|
148
|
+
providerKey
|
|
149
|
+
};
|
|
150
|
+
})().finally(() => {
|
|
151
|
+
codexAppServerThreadReconciliations.delete(providerKey);
|
|
152
|
+
});
|
|
153
|
+
codexAppServerThreadReconciliations.set(providerKey, reconciliation);
|
|
154
|
+
return reconciliation;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async function waitForOtherCodexAppServerThreadReconciliations({
|
|
158
|
+
keepProviderKeys = new Set(),
|
|
159
|
+
projectContextRoot = ""
|
|
160
|
+
} = {}) {
|
|
161
|
+
const pending = [...codexAppServerThreadReconciliations.entries()]
|
|
162
|
+
.filter(([providerKey]) => !keepProviderKeys.has(providerKey));
|
|
163
|
+
if (pending.length === 0) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
debugLog("appServerThread.reconcile.pruneWait.start", {
|
|
167
|
+
pendingCount: pending.length,
|
|
168
|
+
projectContextRoot: normalizeCodexRunText(projectContextRoot)
|
|
169
|
+
});
|
|
170
|
+
await Promise.allSettled(pending.map(([, reconciliation]) => reconciliation));
|
|
171
|
+
debugLog("appServerThread.reconcile.pruneWait.done", {
|
|
172
|
+
pendingCount: pending.length,
|
|
173
|
+
projectContextRoot: normalizeCodexRunText(projectContextRoot)
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async function checkManagedConnection(providerKey = "", {
|
|
178
|
+
reconnect = true
|
|
179
|
+
} = {}) {
|
|
180
|
+
providerSessions.assertOpen();
|
|
181
|
+
const normalizedProviderKey = normalizeCodexRunText(providerKey);
|
|
182
|
+
const managed = providerSessions.managed.get(normalizedProviderKey);
|
|
183
|
+
const provider = providerSessions.owner.providers.get(normalizedProviderKey);
|
|
184
|
+
const sessionId = normalizeCodexRunText(managed?.sessionId);
|
|
185
|
+
const threadId = normalizeCodexRunText(managed?.threadId);
|
|
186
|
+
if (!managed || !provider || !sessionId) {
|
|
187
|
+
throw new Error("Codex app-server managed connection is incomplete.");
|
|
188
|
+
}
|
|
189
|
+
const current = providerSessions.connectionPolicy(sessionId, {
|
|
190
|
+
threadId,
|
|
191
|
+
get workdir() { return managed.workdir; },
|
|
192
|
+
get current() {
|
|
193
|
+
return providerSessions.managed.get(normalizedProviderKey) === managed &&
|
|
194
|
+
providerSessions.owner.providers.get(normalizedProviderKey) === provider;
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
current.assertCurrent();
|
|
198
|
+
|
|
199
|
+
if (reconnect) {
|
|
200
|
+
await providerSessions.owner.acquireRuntime({
|
|
201
|
+
operation: () => provider.ensureAvailable?.(),
|
|
202
|
+
provider,
|
|
203
|
+
providerKey: normalizedProviderKey,
|
|
204
|
+
providerOptions: managed.providerOptions || {}
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
return maintainCodexAppServerManagedConnection(sessionId, {
|
|
208
|
+
provider, providerKey: normalizedProviderKey, threadId, reconnect,
|
|
209
|
+
get workdir() { return managed.workdir; },
|
|
210
|
+
subscriptionOptions: {
|
|
211
|
+
get providerKey() { return providerSessions.context(normalizeCodexRunText(sessionId), managed.providerOptions || {}).providerKey; }
|
|
212
|
+
}
|
|
213
|
+
}, current);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
async function maintainCodexAppServerManagedConnection(sessionId, connection, current) {
|
|
217
|
+
const { provider, providerKey, threadId, subscriptionOptions, reconnect = true } = connection;
|
|
218
|
+
if (!threadId) {
|
|
219
|
+
return {
|
|
220
|
+
ok: true,
|
|
221
|
+
status: "available"
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
let providerThread;
|
|
225
|
+
try {
|
|
226
|
+
providerThread = await codexAppServerReadThreadStatus(provider, threadId);
|
|
227
|
+
} catch (error) {
|
|
228
|
+
if (reconnect || !codexAppServerThreadIsMissing(error, threadId)) {
|
|
229
|
+
throw error;
|
|
230
|
+
}
|
|
231
|
+
providerThread = { status: "notLoaded" };
|
|
232
|
+
}
|
|
233
|
+
// The host rejects a late result after closure, renewal or lost admission.
|
|
234
|
+
const session = await current.readSession();
|
|
235
|
+
current.assertCurrent(session);
|
|
236
|
+
try {
|
|
237
|
+
const controls = await provider.ensureThreadControls?.(threadId);
|
|
238
|
+
if (controls?.recovered) providerThread = await codexAppServerReadThreadStatus(provider, threadId);
|
|
239
|
+
} catch (error) {
|
|
240
|
+
current.assertCurrent(session);
|
|
241
|
+
// Retain the existing stop owner and its visible recovery state. Do not
|
|
242
|
+
// spend automatic goal turns or repeatedly probe a known failed binding.
|
|
243
|
+
void Promise.resolve(provider.failObservation?.(error)).catch(() => null);
|
|
244
|
+
throw error;
|
|
245
|
+
}
|
|
246
|
+
current.assertCurrent(session);
|
|
247
|
+
const nativeStatus = codexAppServerThreadRawValue(providerThread).status;
|
|
248
|
+
const subscriptionKey = codexAppServerEventSubscriptionKey(
|
|
249
|
+
providerKey,
|
|
250
|
+
threadId
|
|
251
|
+
);
|
|
252
|
+
const subscriptionIsCurrent = codexAppServerEventSubscriptionIsCurrent(subscriptionKey, provider);
|
|
253
|
+
if (!reconnect && (
|
|
254
|
+
nativeStatus === "notLoaded" || nativeStatus?.type === "notLoaded" || !subscriptionIsCurrent
|
|
255
|
+
)) {
|
|
256
|
+
return { ok: true, requiresPreparation: true };
|
|
257
|
+
}
|
|
258
|
+
if (!subscriptionIsCurrent) {
|
|
259
|
+
subscribeCodexAppServerEvents(
|
|
260
|
+
sessionId,
|
|
261
|
+
provider,
|
|
262
|
+
threadId,
|
|
263
|
+
subscriptionOptions
|
|
264
|
+
);
|
|
265
|
+
await provider.resumeThread?.(threadId, {
|
|
266
|
+
cwd: normalizeCodexRunText(connection.workdir)
|
|
267
|
+
});
|
|
268
|
+
return reconcileCodexAppServerLoadedThreadStatus(
|
|
269
|
+
sessionId,
|
|
270
|
+
provider,
|
|
271
|
+
threadId,
|
|
272
|
+
{
|
|
273
|
+
observeLatestTurn: true
|
|
274
|
+
}
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const trackedTurn = turnState(session);
|
|
279
|
+
const providerStatus = codexAppServerThreadStatus(providerThread);
|
|
280
|
+
const providerTurnId = codexAppServerThreadTurnId(providerThread);
|
|
281
|
+
const providerIsActive = codexAppServerTurnStatusIsActive(providerStatus);
|
|
282
|
+
const trackedIdentityMatches = (
|
|
283
|
+
trackedTurn.threadId === threadId &&
|
|
284
|
+
(!providerTurnId || trackedTurn.turnId === providerTurnId)
|
|
285
|
+
);
|
|
286
|
+
if (
|
|
287
|
+
(providerIsActive && (
|
|
288
|
+
!trackedTurn.active ||
|
|
289
|
+
trackedTurn.state !== "active" ||
|
|
290
|
+
!trackedIdentityMatches
|
|
291
|
+
)) ||
|
|
292
|
+
(!providerIsActive && trackedTurn.active)
|
|
293
|
+
) {
|
|
294
|
+
return reconcileCodexAppServerThreadStatus(
|
|
295
|
+
sessionId,
|
|
296
|
+
provider,
|
|
297
|
+
threadId,
|
|
298
|
+
{
|
|
299
|
+
observeLatestTurn: true,
|
|
300
|
+
source: "wellbeing"
|
|
301
|
+
}
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
return {
|
|
305
|
+
ok: true,
|
|
306
|
+
status: "healthy",
|
|
307
|
+
threadId
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
async function codexAppServerLoadedThreadIds(provider = null) {
|
|
312
|
+
if (typeof provider?.listLoadedThreads !== "function") {
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
const threadIds = new Set();
|
|
316
|
+
let cursor = null;
|
|
317
|
+
do {
|
|
318
|
+
const response = await provider.listLoadedThreads({
|
|
319
|
+
...(cursor ? { cursor } : {}),
|
|
320
|
+
limit: 100
|
|
321
|
+
});
|
|
322
|
+
for (const threadId of Array.isArray(response?.data) ? response.data : []) {
|
|
323
|
+
const normalizedThreadId = normalizeCodexRunText(threadId);
|
|
324
|
+
if (normalizedThreadId) {
|
|
325
|
+
threadIds.add(normalizedThreadId);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
cursor = normalizeCodexRunText(response?.nextCursor);
|
|
329
|
+
} while (cursor);
|
|
330
|
+
return threadIds;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
async function restoreCodexAppServerLoadedThread(sessionId, context) {
|
|
334
|
+
const { runtime, provider, providerKey, threadId } = context;
|
|
335
|
+
const loadedThreadIds = await codexAppServerLoadedThreadIds(provider);
|
|
336
|
+
if (!loadedThreadIds?.has(threadId)) return null;
|
|
337
|
+
const subscription = subscribeCodexAppServerEvents(
|
|
338
|
+
sessionId,
|
|
339
|
+
provider,
|
|
340
|
+
threadId,
|
|
341
|
+
context.subscriptionOptions
|
|
342
|
+
);
|
|
343
|
+
const subscriptionStatus = normalizeCodexRunText(subscription?.status) || "subscribed";
|
|
344
|
+
if (subscriptionStatus !== "alreadySubscribed") {
|
|
345
|
+
await provider.resumeThread(threadId, context.resumeOptions);
|
|
346
|
+
}
|
|
347
|
+
context.remember();
|
|
348
|
+
await reconcileCodexAppServerLoadedThreadStatus(
|
|
349
|
+
sessionId,
|
|
350
|
+
provider,
|
|
351
|
+
threadId,
|
|
352
|
+
{
|
|
353
|
+
observeLatestTurn: subscriptionStatus !== "alreadySubscribed"
|
|
354
|
+
}
|
|
355
|
+
).catch((error) => {
|
|
356
|
+
debugLog("appServerThread.statusReconcile.error", {
|
|
357
|
+
error: debugError(error),
|
|
358
|
+
sessionId: sessionId,
|
|
359
|
+
threadId
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
let loadedSession = await runtime.getSession(sessionId);
|
|
363
|
+
if (turnState(loadedSession).state === "starting") {
|
|
364
|
+
loadedSession = await recoverCodexAppServerActiveTurn(sessionId, {
|
|
365
|
+
provider,
|
|
366
|
+
retryOnError: false,
|
|
367
|
+
runtime
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
await context.ready();
|
|
371
|
+
if (subscriptionStatus === "alreadySubscribed") {
|
|
372
|
+
return {
|
|
373
|
+
ok: true,
|
|
374
|
+
providerKey,
|
|
375
|
+
sessionId: sessionId,
|
|
376
|
+
status: "alreadySubscribed",
|
|
377
|
+
threadId
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
return {
|
|
381
|
+
ok: true,
|
|
382
|
+
providerKey,
|
|
383
|
+
sessionId: sessionId,
|
|
384
|
+
status: subscriptionStatus === "resubscribed" ? "resubscribed" : "loaded",
|
|
385
|
+
threadId
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return {
|
|
390
|
+
threadReconciliations: codexAppServerThreadReconciliations,
|
|
391
|
+
ensureThreadReady: ensureCodexAppServerThreadReady,
|
|
392
|
+
reconcileThread: reconcileCodexAppServerThreadForSession,
|
|
393
|
+
waitForThreadReconciliations: waitForOtherCodexAppServerThreadReconciliations,
|
|
394
|
+
checkManagedConnection,
|
|
395
|
+
restoreLoadedThread: restoreCodexAppServerLoadedThread
|
|
396
|
+
};
|
|
397
|
+
}
|