@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
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { codexAppServerTurnStatusIsSuccessfulComplete, codexAppServerTurnStatusIsProviderFailure, codexAppServerThreadStatus, normalizeCodexRunText, codexAppServerErrorMessage, codexAppServerSteerFailure, codexAppServerInterruptFailure, codexAppServerConversationTurnIsActive } from "./codexTurnState.js";
|
|
1
|
+
import { codexAppServerTurnStatusIsSuccessfulComplete, codexAppServerTurnStatusIsProviderFailure, codexAppServerThreadStatus, normalizeCodexRunText, codexAppServerErrorMessage, codexAppServerSteerFailure, codexAppServerInterruptFailure, codexAppServerConversationTurnIsActive, codexAppServerNativeOuterTurnId } from "./codexTurnState.js";
|
|
2
2
|
import { CODEX_APP_SERVER_DETACHED_TURN_TIMEOUT_MS, createCodexAppServerDetachedTurnWatcher } from "./codexDetachedTurn.js";
|
|
3
3
|
import { assertCodexAppServerHelperAccountIdentity, readCodexAppServerAccountIdentity, sendPreparedCodexAppServerHelperTurn } from "./codexHelperExecution.js";
|
|
4
|
-
import { codexAppServerRequestIsInvalid, codexAppServerThreadHasReadableHistory, codexAppServerThreadIsMissing, codexLocalImageInput, sendCodexAppServerPrompt } from "./codexProvider.js";
|
|
4
|
+
import { codexAppServerDeliveredTurn, codexAppServerRequestIsInvalid, codexAppServerThreadHasReadableHistory, codexAppServerThreadIsMissing, codexLocalImageInput, sendCodexAppServerPrompt } from "./codexProvider.js";
|
|
5
5
|
import { codexAppServerProjectHookTrustConfig, readCodexToolFreeConfiguration } from "./codexConfiguration.js";
|
|
6
|
-
import { codexAppServerAssistantItemText, codexAppServerContentText, classifyCodexAppServerEvent, codexAppServerNotificationThreadId, codexAppServerNotificationTurnId, codexAppServerNotificationTurnStatus,
|
|
6
|
+
import { codexAppServerAssistantItemText, codexAppServerContentText, classifyCodexAppServerEvent, codexAppServerNotificationThreadId, codexAppServerNotificationTurnId, codexAppServerNotificationTurnStatus, codexAppServerThreadRawValue, codexAppServerProviderThreadAssistantSegments, codexAppServerProviderTurnId, codexAppServerProviderTurnStatus, codexAppServerProviderTurnItems, codexAppServerProviderTurnClientIds, codexAppServerThreadTurnId, codexAppServerThreadError } from "./codexEvents.js";
|
|
7
7
|
|
|
8
8
|
// Internal command facet of the original run owner; the same native conversation
|
|
9
9
|
// and turn-start collections retain their original lifetime and public references.
|
|
@@ -19,7 +19,10 @@ export function createCodexConversationCommands({
|
|
|
19
19
|
interruptFailedCode,
|
|
20
20
|
namespace,
|
|
21
21
|
providerSessions,
|
|
22
|
-
|
|
22
|
+
sessionConnection,
|
|
23
|
+
ensureSessionProvider,
|
|
24
|
+
steerFailedCode,
|
|
25
|
+
turnOutcomes
|
|
23
26
|
}) {
|
|
24
27
|
const codexAppServerConversations = new Map();
|
|
25
28
|
const codexAppServerConversationTurnStarts = new Map();
|
|
@@ -68,7 +71,7 @@ export function createCodexConversationCommands({
|
|
|
68
71
|
let state = conversations.get(conversationId);
|
|
69
72
|
if (state?.provider === provider && state.unsubscribe) return state;
|
|
70
73
|
state?.unsubscribe?.();
|
|
71
|
-
state = { conversationId, provider, persistent: true, status: "ready", runId: "", error: "" };
|
|
74
|
+
state = { conversationId, provider, persistent: true, status: "ready", runId: "", error: "", turnOutcome: "" };
|
|
72
75
|
state.unsubscribe = provider.subscribe((notification) => {
|
|
73
76
|
if (codexAppServerNotificationThreadId(notification) !== conversationId) return;
|
|
74
77
|
const turnId = codexAppServerNotificationTurnId(notification);
|
|
@@ -91,11 +94,15 @@ export function createCodexConversationCommands({
|
|
|
91
94
|
state.onEvent = null;
|
|
92
95
|
const completedTurnId = state.runId;
|
|
93
96
|
const completedStatus = state.status;
|
|
97
|
+
// A turn the person stopped reaches the checkpoint as cancelled, as Main turns do.
|
|
98
|
+
const completedOutcome = state.turnOutcome;
|
|
99
|
+
state.turnOutcome = "";
|
|
94
100
|
void checkpoint(sessionId, {
|
|
95
|
-
outerTurnId:
|
|
101
|
+
outerTurnId: codexAppServerNativeOuterTurnId(conversationId, completedTurnId),
|
|
96
102
|
threadId: conversationId,
|
|
97
103
|
turnId: completedTurnId,
|
|
98
|
-
status: completedStatus
|
|
104
|
+
status: completedStatus,
|
|
105
|
+
turnOutcome: completedOutcome
|
|
99
106
|
}).catch(() => {});
|
|
100
107
|
}
|
|
101
108
|
});
|
|
@@ -229,9 +236,7 @@ export function createCodexConversationCommands({
|
|
|
229
236
|
const { context } = prepared;
|
|
230
237
|
if (context.assistantScope) {
|
|
231
238
|
const providerOptions = prepared.providerOptions;
|
|
232
|
-
const provider = await
|
|
233
|
-
providerSessions.context(normalizeCodexRunText(sessionId), providerOptions)
|
|
234
|
-
);
|
|
239
|
+
const provider = await ensureSessionProvider(sessionId, providerOptions);
|
|
235
240
|
const result = prepared.project(provider);
|
|
236
241
|
result.isolationConfig = await readCodexToolFreeConfiguration(
|
|
237
242
|
provider, context.workdir, conversationPreparation.isolation.assertCompatibility
|
|
@@ -251,21 +256,19 @@ export function createCodexConversationCommands({
|
|
|
251
256
|
}
|
|
252
257
|
}
|
|
253
258
|
const managedIdentity = prepared.managedIdentity;
|
|
254
|
-
const
|
|
255
|
-
|
|
259
|
+
const assertAdmitted = () => {
|
|
260
|
+
const error = conversationPreparation.admissionError(sessionId);
|
|
261
|
+
if (error) throw error;
|
|
262
|
+
};
|
|
263
|
+
assertAdmitted();
|
|
256
264
|
const activeProvider = prepared.helperTurn
|
|
257
265
|
? null
|
|
258
266
|
: await ensureCodexAppServerProviderForActiveTurn(context.session, managedIdentity);
|
|
259
|
-
|
|
260
|
-
if (activeProviderAdmissionError) throw activeProviderAdmissionError;
|
|
267
|
+
assertAdmitted();
|
|
261
268
|
const providerOptions = activeProvider ? null : await prepared.providerOptions;
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
providerSessions.context(normalizeCodexRunText(sessionId), providerOptions)
|
|
266
|
-
);
|
|
267
|
-
const providerAdmissionError = conversationPreparation.admissionError(sessionId);
|
|
268
|
-
if (providerAdmissionError) throw providerAdmissionError;
|
|
269
|
+
assertAdmitted();
|
|
270
|
+
const provider = activeProvider?.provider || await ensureSessionProvider(sessionId, providerOptions);
|
|
271
|
+
assertAdmitted();
|
|
269
272
|
return prepared.project(provider, activeProvider?.providerOptions || providerOptions, helperRestore);
|
|
270
273
|
}
|
|
271
274
|
|
|
@@ -369,11 +372,6 @@ export function createCodexConversationCommands({
|
|
|
369
372
|
if (helperTurn) {
|
|
370
373
|
try {
|
|
371
374
|
await assertCodexAppServerHelperAccountIdentity(provider, input.expectedAccountIdentitySignature, helperOwnershipError);
|
|
372
|
-
} catch (error) {
|
|
373
|
-
await helper.discard();
|
|
374
|
-
throw error;
|
|
375
|
-
}
|
|
376
|
-
try {
|
|
377
375
|
execution.validateOutput(result.text);
|
|
378
376
|
} catch (error) {
|
|
379
377
|
await helper.discard();
|
|
@@ -516,7 +514,9 @@ export function createCodexConversationCommands({
|
|
|
516
514
|
});
|
|
517
515
|
}
|
|
518
516
|
|
|
519
|
-
async function stopCodexAppServerConversation(sessionId, input = {}, options = {}
|
|
517
|
+
async function stopCodexAppServerConversation(sessionId, input = {}, options = {}, {
|
|
518
|
+
turnOutcome = turnOutcomes.USER_CANCELLED
|
|
519
|
+
} = {}) {
|
|
520
520
|
const conversationId = normalizeCodexRunText(input.conversationId);
|
|
521
521
|
const conversationState = codexAppServerConversation(sessionId, conversationId);
|
|
522
522
|
if (conversationState?.provider.observationFailure) {
|
|
@@ -541,7 +541,8 @@ export function createCodexConversationCommands({
|
|
|
541
541
|
return stopPersistentCodexConversation({
|
|
542
542
|
conversationId,
|
|
543
543
|
conversationState,
|
|
544
|
-
provider: context.provider
|
|
544
|
+
provider: context.provider,
|
|
545
|
+
turnOutcome
|
|
545
546
|
});
|
|
546
547
|
}
|
|
547
548
|
const result = await interruptDetachedCodexAppServerConversationTurn(sessionId, {
|
|
@@ -586,7 +587,7 @@ export function createCodexConversationCommands({
|
|
|
586
587
|
if (context.ok === false) {
|
|
587
588
|
return context;
|
|
588
589
|
}
|
|
589
|
-
const connection =
|
|
590
|
+
const connection = sessionConnection(sessionId, context.providerOptions);
|
|
590
591
|
providerExit = await providerSessions.owner.stopProvider(connection.providerKey, context.providerOptions, {
|
|
591
592
|
preserveProcessExitProof: false,
|
|
592
593
|
requireStopped: true,
|
|
@@ -605,7 +606,9 @@ export function createCodexConversationCommands({
|
|
|
605
606
|
const key = namespace(sessionId);
|
|
606
607
|
for (const state of codexAppServerConversations.get(key)?.values() || []) {
|
|
607
608
|
if (state.persistent) {
|
|
608
|
-
|
|
609
|
+
// Closing is not the person stopping the turn; its status alone decides the outcome.
|
|
610
|
+
await stopCodexAppServerConversation(sessionId, { conversationId: state.conversationId, persistent: true },
|
|
611
|
+
{}, { turnOutcome: "" });
|
|
609
612
|
state.unsubscribe?.();
|
|
610
613
|
} else {
|
|
611
614
|
await deleteScopedCodexAppServerConversation(sessionId, { conversationId: state.conversationId }).catch(() => null);
|
|
@@ -771,9 +774,7 @@ export function createCodexConversationCommands({
|
|
|
771
774
|
|
|
772
775
|
async function dispatchCodexAppServerDetachedTurn({ provider, prompt, threadId }, authorized) {
|
|
773
776
|
const delivery = await sendCodexAppServerPrompt({ provider, prompt, threadId }, authorized);
|
|
774
|
-
|
|
775
|
-
const status = normalizeCodexRunText(delivery.turn?.status || delivery.turn?.raw?.status);
|
|
776
|
-
return { delivery, status, turnId };
|
|
777
|
+
return { delivery, ...codexAppServerDeliveredTurn(delivery) };
|
|
777
778
|
}
|
|
778
779
|
|
|
779
780
|
async function runDetachedCodexAppServerTurn({
|
|
@@ -819,12 +820,7 @@ export function createCodexConversationCommands({
|
|
|
819
820
|
type: "turn"
|
|
820
821
|
});
|
|
821
822
|
if (codexAppServerTurnStatusIsProviderFailure(status)) {
|
|
822
|
-
const
|
|
823
|
-
delivery.turn?.raw?.error ||
|
|
824
|
-
delivery.turn?.response?.turn?.error ||
|
|
825
|
-
delivery.turn?.error
|
|
826
|
-
);
|
|
827
|
-
const error = new Error(providerError || `Codex app-server turn ${status}.`);
|
|
823
|
+
const error = new Error(codexAppServerDeliveredTurn(delivery).error || `Codex app-server turn ${status}.`);
|
|
828
824
|
await throwWatcherFailure(error, status, {
|
|
829
825
|
waitForDetail: true
|
|
830
826
|
});
|
|
@@ -915,7 +911,7 @@ export function createCodexConversationCommands({
|
|
|
915
911
|
conversationState.watcher = watcher;
|
|
916
912
|
}
|
|
917
913
|
let delivery = null;
|
|
918
|
-
if (input.persistent && conversationState) conversationState
|
|
914
|
+
if (input.persistent && conversationState) Object.assign(conversationState, { onEvent, turnOutcome: "" });
|
|
919
915
|
try {
|
|
920
916
|
await input.onPromptSending?.({ threadId: conversationId });
|
|
921
917
|
if (executionProfile) {
|
|
@@ -945,8 +941,7 @@ export function createCodexConversationCommands({
|
|
|
945
941
|
}
|
|
946
942
|
throw error;
|
|
947
943
|
}
|
|
948
|
-
const runId =
|
|
949
|
-
const status = normalizeCodexRunText(delivery.turn?.status || delivery.turn?.raw?.status);
|
|
944
|
+
const { turnId: runId, status } = codexAppServerDeliveredTurn(delivery);
|
|
950
945
|
if (!runId) {
|
|
951
946
|
watcher?.failNow(new Error("Codex app-server accepted a conversation turn without returning its id."));
|
|
952
947
|
await waitForResult?.catch(() => null);
|
|
@@ -1083,13 +1078,21 @@ export function createCodexConversationCommands({
|
|
|
1083
1078
|
async function stopPersistentCodexConversation({
|
|
1084
1079
|
conversationId,
|
|
1085
1080
|
conversationState,
|
|
1086
|
-
provider
|
|
1081
|
+
provider,
|
|
1082
|
+
turnOutcome = ""
|
|
1087
1083
|
} = {}) {
|
|
1084
|
+
// Set before stopping: the provider can report turn/completed while it stops.
|
|
1085
|
+
if (conversationState && codexAppServerConversationTurnIsActive(conversationState.status)) {
|
|
1086
|
+
conversationState.turnOutcome = turnOutcome;
|
|
1087
|
+
}
|
|
1088
1088
|
try {
|
|
1089
1089
|
await provider.readThreadStatus(conversationId);
|
|
1090
1090
|
await provider.stopThreadForObservationLoss(conversationId, "");
|
|
1091
1091
|
} catch (error) {
|
|
1092
|
-
if (!codexAppServerThreadIsMissing(error, conversationId) || error.message.toLowerCase().startsWith("thread not loaded:"))
|
|
1092
|
+
if (!codexAppServerThreadIsMissing(error, conversationId) || error.message.toLowerCase().startsWith("thread not loaded:")) {
|
|
1093
|
+
if (conversationState) conversationState.turnOutcome = "";
|
|
1094
|
+
throw error;
|
|
1095
|
+
}
|
|
1093
1096
|
}
|
|
1094
1097
|
if (conversationState) {
|
|
1095
1098
|
conversationState.status = "interrupted";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isRecord } from "@jskit-ai/kernel/shared/support/normalize";
|
|
2
|
+
import { normalizeNullableText } from "./normalize.js";
|
|
2
3
|
import { classifyCodexAppServerEvent, codexAppServerNotificationParams, codexAppServerNotificationThreadId, codexAppServerNotificationTurnId, codexAppServerNotificationTurnStatus, codexAppServerNotificationError, codexAppServerStatusFromValue, codexAppServerProviderThreadAssistantSegments, codexAppServerProviderTurnId, codexAppServerProviderTurnStatus, codexAppServerProviderTurnForOperation, codexAppServerProviderTurnText, codexAppServerProviderTurnError } from "./codexEvents.js";
|
|
3
4
|
import { codexAppServerTurnStatusIsProviderFailure, codexAppServerTurnStatusIsSuccessfulComplete } from "./codexTurnState.js";
|
|
4
5
|
|
|
@@ -6,12 +7,12 @@ const CODEX_APP_SERVER_DETACHED_TURN_TIMEOUT_MS = 180_000;
|
|
|
6
7
|
const CODEX_APP_SERVER_DETACHED_FAILURE_DETAIL_GRACE_MS = 500;
|
|
7
8
|
|
|
8
9
|
function codexAppServerTurnTokenUsage(notification = {}) {
|
|
9
|
-
if (
|
|
10
|
+
if (normalizeNullableText(notification.method) !== "thread/tokenUsage/updated") {
|
|
10
11
|
return null;
|
|
11
12
|
}
|
|
12
13
|
const params = codexAppServerNotificationParams(notification);
|
|
13
|
-
const tokenUsage =
|
|
14
|
-
const turnUsage =
|
|
14
|
+
const tokenUsage = isRecord(params.tokenUsage) ? params.tokenUsage : {};
|
|
15
|
+
const turnUsage = isRecord(tokenUsage.last) ? tokenUsage.last : tokenUsage;
|
|
15
16
|
const snapshot = {};
|
|
16
17
|
for (const field of [
|
|
17
18
|
"cachedInputTokens",
|
|
@@ -35,7 +36,7 @@ function createCodexAppServerDetachedTurnWatcher(provider = null, threadId = "",
|
|
|
35
36
|
onEvent = null,
|
|
36
37
|
timeoutMs = CODEX_APP_SERVER_DETACHED_TURN_TIMEOUT_MS
|
|
37
38
|
} = {}) {
|
|
38
|
-
const normalizedThreadId =
|
|
39
|
+
const normalizedThreadId = normalizeNullableText(threadId);
|
|
39
40
|
let targetTurnId = "";
|
|
40
41
|
let finalText = "";
|
|
41
42
|
let usage = null;
|
|
@@ -106,7 +107,7 @@ function createCodexAppServerDetachedTurnWatcher(provider = null, threadId = "",
|
|
|
106
107
|
const rawStatus = thread.raw?.status || thread.response?.thread?.status;
|
|
107
108
|
return {
|
|
108
109
|
status: codexAppServerStatusFromValue(rawStatus),
|
|
109
|
-
statusType:
|
|
110
|
+
statusType: normalizeNullableText(typeof rawStatus === "string" ? rawStatus : rawStatus?.type),
|
|
110
111
|
text: codexAppServerProviderThreadAssistantSegments(thread, targetTurnId)
|
|
111
112
|
.map((segment) => segment.text)
|
|
112
113
|
.join("\n\n")
|
|
@@ -126,7 +127,7 @@ function createCodexAppServerDetachedTurnWatcher(provider = null, threadId = "",
|
|
|
126
127
|
async function finishFromCompletion(status = "completed") {
|
|
127
128
|
try {
|
|
128
129
|
if (!targetTurnId) {
|
|
129
|
-
pendingCompletionStatus =
|
|
130
|
+
pendingCompletionStatus = normalizeNullableText(status) || "completed";
|
|
130
131
|
return;
|
|
131
132
|
}
|
|
132
133
|
const authoritative = await resultFromThread().catch(() => ({
|
|
@@ -136,7 +137,7 @@ function createCodexAppServerDetachedTurnWatcher(provider = null, threadId = "",
|
|
|
136
137
|
}));
|
|
137
138
|
finalText = authoritative.text || finalText;
|
|
138
139
|
if (!finalText && !allowEmptyResponse) {
|
|
139
|
-
pendingCompletionStatus =
|
|
140
|
+
pendingCompletionStatus = normalizeNullableText(status) || "completed";
|
|
140
141
|
const systemError = authoritative.statusType === "systemError" || authoritative.status === "failed";
|
|
141
142
|
failAfterDetailGrace(new Error(systemError
|
|
142
143
|
? "Codex app-server thread entered a system error before producing an assistant response."
|
|
@@ -175,7 +176,7 @@ function createCodexAppServerDetachedTurnWatcher(provider = null, threadId = "",
|
|
|
175
176
|
failAfterDetailGrace(error);
|
|
176
177
|
},
|
|
177
178
|
setTurnId(turnId = "") {
|
|
178
|
-
targetTurnId =
|
|
179
|
+
targetTurnId = normalizeNullableText(turnId);
|
|
179
180
|
if (pendingFailure) {
|
|
180
181
|
failAfterDetailGrace(pendingFailure);
|
|
181
182
|
return;
|
|
@@ -240,7 +241,7 @@ function createCodexAppServerDetachedTurnWatcher(provider = null, threadId = "",
|
|
|
240
241
|
void finishFromCompletion(status);
|
|
241
242
|
}
|
|
242
243
|
}
|
|
243
|
-
const method =
|
|
244
|
+
const method = normalizeNullableText(notification.method);
|
|
244
245
|
if (method !== "turn/completed" && method !== "thread/status/changed") {
|
|
245
246
|
return;
|
|
246
247
|
}
|
|
@@ -279,7 +280,7 @@ async function waitForCodexAppServerTurn(provider, threadId = "", turn = null, {
|
|
|
279
280
|
timeoutMs = CODEX_APP_SERVER_DETACHED_TURN_TIMEOUT_MS,
|
|
280
281
|
createError = codexAppServerTurnError
|
|
281
282
|
} = {}) {
|
|
282
|
-
const normalizedThreadId =
|
|
283
|
+
const normalizedThreadId = normalizeNullableText(threadId || "");
|
|
283
284
|
const turnId = codexAppServerProviderTurnId(turn || {});
|
|
284
285
|
const status = codexAppServerProviderTurnStatus(turn || {});
|
|
285
286
|
if (!normalizedThreadId || !turnId) {
|