@jskit-ai/assistant-core 0.1.240 → 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 +41 -38
- 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/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 +8 -16
- package/src/server/conversation/providers/codexDriver.js +25 -41
- 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/assistantSettingsResource.test.js +2 -2
- package/test/claudeConversationSession.test.js +11 -1
- package/test/claudeTurn.test.js +27 -7
- package/test/codexClient.test.js +20 -0
- package/test/codexConversationSession.test.js +2 -2
- 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
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
codexAppServerRunInputSource
|
|
11
11
|
} from "./codexTurnState.js";
|
|
12
12
|
import crypto from "node:crypto";
|
|
13
|
-
import {
|
|
13
|
+
import { isRecord } from "@jskit-ai/kernel/shared/support/normalize";
|
|
14
14
|
import {
|
|
15
|
+
codexAppServerAgentMessageText,
|
|
15
16
|
codexAppServerAssistantItemText,
|
|
16
17
|
classifyCodexAppServerEvent,
|
|
17
|
-
codexAppServerContentText,
|
|
18
18
|
codexAppServerNotificationEvent,
|
|
19
19
|
codexAppServerNotificationEventType,
|
|
20
20
|
codexAppServerNotificationEventPayload,
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
codexAppServerProviderThreadAssistantSegments
|
|
25
25
|
} from "./codexEvents.js";
|
|
26
26
|
|
|
27
|
-
//
|
|
27
|
+
// Native output, reasoning persistence and exact-result identity.
|
|
28
28
|
// One instance belongs to each retained run owner; its state is shared by reference.
|
|
29
29
|
export function createCodexAppServerOutput({
|
|
30
30
|
namespace,
|
|
@@ -73,7 +73,7 @@ export function createCodexAppServerOutput({
|
|
|
73
73
|
function codexAppServerLiveProgressCandidate(notification = {}) {
|
|
74
74
|
const method = normalizeCodexRunText(notification.method);
|
|
75
75
|
const event = codexAppServerNotificationEvent(notification);
|
|
76
|
-
if (
|
|
76
|
+
if (isRecord(event)) {
|
|
77
77
|
const eventType = codexAppServerNotificationEventType(notification, event);
|
|
78
78
|
const payload = codexAppServerNotificationEventPayload(notification, event);
|
|
79
79
|
const payloadType = normalizeCodexRunText(payload.type);
|
|
@@ -83,11 +83,7 @@ export function createCodexAppServerOutput({
|
|
|
83
83
|
explicit: Boolean(phase),
|
|
84
84
|
phase,
|
|
85
85
|
source: "event",
|
|
86
|
-
text:
|
|
87
|
-
codexAppServerContentText(payload.message) ||
|
|
88
|
-
codexAppServerContentText(payload.text) ||
|
|
89
|
-
codexAppServerContentText(payload.content)
|
|
90
|
-
)
|
|
86
|
+
text: codexAppServerAgentMessageText(payload)
|
|
91
87
|
};
|
|
92
88
|
}
|
|
93
89
|
}
|
|
@@ -557,15 +553,14 @@ export function createCodexAppServerOutput({
|
|
|
557
553
|
}
|
|
558
554
|
|
|
559
555
|
function codexAppServerStreamMessage(classification) {
|
|
556
|
+
const messageId = codexAppServerConversationMessageId(
|
|
557
|
+
classification.threadId, classification.turnId, "assistant-item", classification.itemId
|
|
558
|
+
);
|
|
560
559
|
return {
|
|
561
560
|
nativeIdentity: { threadId: classification.threadId, turnId: classification.turnId },
|
|
562
561
|
turnId: `${classification.threadId}:${classification.turnId}`,
|
|
563
|
-
outputId:
|
|
564
|
-
|
|
565
|
-
),
|
|
566
|
-
messageId: codexAppServerConversationMessageId(
|
|
567
|
-
classification.threadId, classification.turnId, "assistant-item", classification.itemId
|
|
568
|
-
),
|
|
562
|
+
outputId: messageId,
|
|
563
|
+
messageId,
|
|
569
564
|
role: classification.role,
|
|
570
565
|
delta: classification.delta
|
|
571
566
|
};
|
|
@@ -601,11 +596,9 @@ export function createCodexAppServerOutput({
|
|
|
601
596
|
const store = await createStore(normalizedSessionId);
|
|
602
597
|
const run = await readCodexAppServerAgentRunForSession(store, normalizedSessionId);
|
|
603
598
|
const turn = turnStateFromAgentRun(run || {});
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
codexAppServerNotificationTurnId(notification)
|
|
608
|
-
)) {
|
|
599
|
+
const notificationTurnId = codexAppServerNotificationTurnId(notification);
|
|
600
|
+
const ownerTurnId = notificationTurnId || turn.turnId;
|
|
601
|
+
if (!codexAppServerTurnCanReceiveProviderActivity(turn, normalizedThreadId, notificationTurnId)) {
|
|
609
602
|
return null;
|
|
610
603
|
}
|
|
611
604
|
const key = codexAppServerLiveProgressKey(normalizedSessionId, normalizedThreadId, notification);
|
|
@@ -615,11 +608,11 @@ export function createCodexAppServerOutput({
|
|
|
615
608
|
const fingerprintKey = codexAppServerLiveProgressFingerprintKey(
|
|
616
609
|
normalizedSessionId,
|
|
617
610
|
normalizedThreadId,
|
|
618
|
-
|
|
611
|
+
ownerTurnId,
|
|
619
612
|
text
|
|
620
613
|
);
|
|
621
614
|
const streamMessageId = codexAppServerConversationMessageId(
|
|
622
|
-
normalizedThreadId,
|
|
615
|
+
normalizedThreadId, notificationTurnId,
|
|
623
616
|
"assistant-item", codexAppServerNotificationItemId(notification)
|
|
624
617
|
);
|
|
625
618
|
if (
|
|
@@ -645,12 +638,12 @@ export function createCodexAppServerOutput({
|
|
|
645
638
|
...(streamMessageId ? { outputId: streamMessageId } : {}),
|
|
646
639
|
messageId: codexAppServerConversationMessageId(
|
|
647
640
|
normalizedThreadId,
|
|
648
|
-
|
|
641
|
+
ownerTurnId,
|
|
649
642
|
role,
|
|
650
643
|
text
|
|
651
644
|
),
|
|
652
645
|
requireOpenTurn: false,
|
|
653
|
-
nativeIdentity: { threadId: normalizedThreadId, turnId:
|
|
646
|
+
nativeIdentity: { threadId: normalizedThreadId, turnId: ownerTurnId },
|
|
654
647
|
text
|
|
655
648
|
});
|
|
656
649
|
if (!written) {
|
|
@@ -660,7 +653,7 @@ export function createCodexAppServerOutput({
|
|
|
660
653
|
}
|
|
661
654
|
const payload = {
|
|
662
655
|
conversationStream: await store.completeConversationStreamMessage(normalizedSessionId, streamMessageId, {
|
|
663
|
-
text, role, nativeIdentity: { threadId: normalizedThreadId, turnId:
|
|
656
|
+
text, role, nativeIdentity: { threadId: normalizedThreadId, turnId: ownerTurnId }
|
|
664
657
|
})
|
|
665
658
|
};
|
|
666
659
|
if (written) {
|
|
@@ -794,7 +787,7 @@ export function createCodexAppServerOutput({
|
|
|
794
787
|
|
|
795
788
|
function codexAppServerSnapshotCursor(run = {}) {
|
|
796
789
|
const cursor = run?.providerSnapshotCursor;
|
|
797
|
-
if (!
|
|
790
|
+
if (!isRecord(cursor)) {
|
|
798
791
|
return {
|
|
799
792
|
itemId: "",
|
|
800
793
|
turnId: ""
|
|
@@ -847,7 +840,7 @@ export function createCodexAppServerOutput({
|
|
|
847
840
|
const normalizedThreadId = normalizeCodexRunText(threadId);
|
|
848
841
|
const normalizedTurnId = normalizeCodexRunText(observedTurn?.id);
|
|
849
842
|
const items = (Array.isArray(observedTurn?.items) ? observedTurn.items : [])
|
|
850
|
-
.filter((item) =>
|
|
843
|
+
.filter((item) => isRecord(item) && normalizeCodexRunText(item.id));
|
|
851
844
|
if (!normalizedSessionId || !normalizedThreadId || !normalizedTurnId || !items.length) {
|
|
852
845
|
return;
|
|
853
846
|
}
|
|
@@ -8,8 +8,9 @@ import path from "node:path";
|
|
|
8
8
|
import { setTimeout as delay } from "node:timers/promises";
|
|
9
9
|
import { CodexAppServerJsonRpcClient, socketPathFromCodexAppServerEndpoint } from "./codexClient.js";
|
|
10
10
|
import { createConversationProcessIdentity } from "./localExecution.js";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
11
|
+
import { isRecord, normalizePositiveInteger } from "@jskit-ai/kernel/shared/support/normalize";
|
|
12
|
+
import { normalizeNullableText } from "./normalize.js";
|
|
13
|
+
import { copyCodexProviderHome, prepareCodexModelCatalog } from "./codexConfiguration.js";
|
|
13
14
|
import { startCodexHistoryAdapter } from "./codexHistoryAdapter.js";
|
|
14
15
|
|
|
15
16
|
const CODEX_APP_SERVER_METADATA_FILE = "runtime.json";
|
|
@@ -100,34 +101,34 @@ function codexAppServerLockDir(runtimeDir = "") {
|
|
|
100
101
|
}
|
|
101
102
|
|
|
102
103
|
export function normalizeCodexAppServerMetadata(metadata = {}) {
|
|
103
|
-
const normalized =
|
|
104
|
-
const endpoint =
|
|
104
|
+
const normalized = isRecord(metadata) ? metadata : {};
|
|
105
|
+
const endpoint = normalizeNullableText(normalized.endpoint);
|
|
105
106
|
return {
|
|
106
|
-
accountIdentitySignature:
|
|
107
|
-
attachmentHostRoot:
|
|
108
|
-
authStateSignature:
|
|
107
|
+
accountIdentitySignature: normalizeNullableText(normalized.accountIdentitySignature),
|
|
108
|
+
attachmentHostRoot: normalizeNullableText(normalized.attachmentHostRoot),
|
|
109
|
+
authStateSignature: normalizeNullableText(normalized.authStateSignature),
|
|
109
110
|
endpoint,
|
|
110
|
-
executionId:
|
|
111
|
-
executionMode:
|
|
112
|
-
executionContextHash:
|
|
113
|
-
healthz:
|
|
114
|
-
historyAdapterBaseUrl:
|
|
115
|
-
logPath:
|
|
111
|
+
executionId: normalizeNullableText(normalized.executionId),
|
|
112
|
+
executionMode: normalizeNullableText(normalized.executionMode) || CODEX_APP_SERVER_EXECUTION_MODES.INTERACTIVE,
|
|
113
|
+
executionContextHash: normalizeNullableText(normalized.executionContextHash),
|
|
114
|
+
healthz: normalizeNullableText(normalized.healthz),
|
|
115
|
+
historyAdapterBaseUrl: normalizeNullableText(normalized.historyAdapterBaseUrl),
|
|
116
|
+
logPath: normalizeNullableText(normalized.logPath),
|
|
116
117
|
pid: Number.isSafeInteger(Number(normalized.pid)) ? Number(normalized.pid) : null,
|
|
117
|
-
processCwd:
|
|
118
|
-
processExitVerifiedAt:
|
|
118
|
+
processCwd: normalizeNullableText(normalized.processCwd),
|
|
119
|
+
processExitVerifiedAt: normalizeNullableText(normalized.processExitVerifiedAt),
|
|
119
120
|
processIdentity: runtimeProcessIdentity.normalize(normalized.processIdentity),
|
|
120
|
-
processState:
|
|
121
|
-
provider:
|
|
122
|
-
readyz:
|
|
123
|
-
runtimeDir:
|
|
124
|
-
runtimesHash:
|
|
121
|
+
processState: normalizeNullableText(normalized.processState),
|
|
122
|
+
provider: normalizeNullableText(normalized.provider),
|
|
123
|
+
readyz: normalizeNullableText(normalized.readyz),
|
|
124
|
+
runtimeDir: normalizeNullableText(normalized.runtimeDir),
|
|
125
|
+
runtimesHash: normalizeNullableText(normalized.runtimesHash),
|
|
125
126
|
schemaVersion: Number(normalized.schemaVersion || 0),
|
|
126
|
-
socketPath:
|
|
127
|
-
startedAt:
|
|
128
|
-
terminalEnvHash:
|
|
129
|
-
toolHomeSource:
|
|
130
|
-
transport:
|
|
127
|
+
socketPath: normalizeNullableText(normalized.socketPath),
|
|
128
|
+
startedAt: normalizeNullableText(normalized.startedAt),
|
|
129
|
+
terminalEnvHash: normalizeNullableText(normalized.terminalEnvHash),
|
|
130
|
+
toolHomeSource: normalizeNullableText(normalized.toolHomeSource),
|
|
131
|
+
transport: normalizeNullableText(normalized.transport)
|
|
131
132
|
};
|
|
132
133
|
}
|
|
133
134
|
|
|
@@ -249,7 +250,7 @@ const CODEX_APP_SERVER_READY_TIMEOUT_MS = 60000;
|
|
|
249
250
|
|
|
250
251
|
const CODEX_APP_SERVER_LIVENESS_TIMEOUT_MS = 2000;
|
|
251
252
|
|
|
252
|
-
const CODEX_APP_SERVER_DESKTOP_BUS_ENV_NAMES = new Set([
|
|
253
|
+
export const CODEX_APP_SERVER_DESKTOP_BUS_ENV_NAMES = new Set([
|
|
253
254
|
"DBUS_SESSION_BUS_ADDRESS",
|
|
254
255
|
"DBUS_STARTER_ADDRESS",
|
|
255
256
|
"DBUS_STARTER_BUS_TYPE"
|
|
@@ -289,11 +290,6 @@ const CODEX_APP_SERVER_PROCESS_IDENTITY_STATUS = Object.freeze({
|
|
|
289
290
|
MISMATCH: "mismatch"
|
|
290
291
|
});
|
|
291
292
|
|
|
292
|
-
function normalizePositiveInteger(value, fallback) {
|
|
293
|
-
const number = Number(value);
|
|
294
|
-
return Number.isSafeInteger(number) && number > 0 ? number : fallback;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
293
|
function stableHash(value) {
|
|
298
294
|
return createHash("sha256")
|
|
299
295
|
.update(String(value || ""))
|
|
@@ -302,7 +298,7 @@ function stableHash(value) {
|
|
|
302
298
|
}
|
|
303
299
|
|
|
304
300
|
export function codexAppServerExecutionMode(options = {}) {
|
|
305
|
-
return
|
|
301
|
+
return normalizeNullableText(options.executionMode) === CODEX_APP_SERVER_EXECUTION_MODES.HELPER
|
|
306
302
|
? CODEX_APP_SERVER_EXECUTION_MODES.HELPER
|
|
307
303
|
: CODEX_APP_SERVER_EXECUTION_MODES.INTERACTIVE;
|
|
308
304
|
}
|
|
@@ -312,7 +308,7 @@ export function codexAppServerIsHelper(options = {}) {
|
|
|
312
308
|
}
|
|
313
309
|
|
|
314
310
|
export async function assertExistingDirectory(dirPath = "", label = "directory") {
|
|
315
|
-
const normalizedPath =
|
|
311
|
+
const normalizedPath = normalizeNullableText(dirPath);
|
|
316
312
|
if (!normalizedPath) {
|
|
317
313
|
return;
|
|
318
314
|
}
|
|
@@ -331,7 +327,7 @@ export function codexAppServerHelperWorkspaceDir(runtimeDir = "") {
|
|
|
331
327
|
}
|
|
332
328
|
|
|
333
329
|
function codexAppServerHelperCommandBaseEnv(env = process.env, codexHome = "") {
|
|
334
|
-
const source =
|
|
330
|
+
const source = isRecord(env) ? env : {};
|
|
335
331
|
const cleared = Object.fromEntries(Object.keys({
|
|
336
332
|
...process.env,
|
|
337
333
|
...source
|
|
@@ -377,7 +373,7 @@ function codexAppServerUnixEndpoint(socketPath = "") {
|
|
|
377
373
|
}
|
|
378
374
|
|
|
379
375
|
function codexAppServerProjectTrustOverride(workdir = "") {
|
|
380
|
-
const normalizedWorkdir =
|
|
376
|
+
const normalizedWorkdir = normalizeNullableText(workdir);
|
|
381
377
|
if (!normalizedWorkdir) {
|
|
382
378
|
return "";
|
|
383
379
|
}
|
|
@@ -390,19 +386,19 @@ export function codexAppServerProcessCwd({
|
|
|
390
386
|
runtimeDir = "",
|
|
391
387
|
workdir = ""
|
|
392
388
|
} = {}) {
|
|
393
|
-
const normalizedWorkdir =
|
|
389
|
+
const normalizedWorkdir = normalizeNullableText(workdir) ? path.resolve(workdir) : "";
|
|
394
390
|
if (normalizedWorkdir) {
|
|
395
391
|
return normalizedWorkdir;
|
|
396
392
|
}
|
|
397
|
-
const normalizedExecutionRoot =
|
|
393
|
+
const normalizedExecutionRoot = normalizeNullableText(executionRoot) ? path.resolve(executionRoot) : "";
|
|
398
394
|
if (normalizedExecutionRoot) {
|
|
399
395
|
return normalizedExecutionRoot;
|
|
400
396
|
}
|
|
401
|
-
return
|
|
397
|
+
return normalizeNullableText(runtimeDir) ? path.resolve(runtimeDir) : "";
|
|
402
398
|
}
|
|
403
399
|
|
|
404
400
|
function codexAppServerRuntimeDirIsManaged(runtimeDir = "") {
|
|
405
|
-
const normalizedRuntimeDir =
|
|
401
|
+
const normalizedRuntimeDir = normalizeNullableText(runtimeDir);
|
|
406
402
|
if (!normalizedRuntimeDir) {
|
|
407
403
|
return false;
|
|
408
404
|
}
|
|
@@ -412,7 +408,7 @@ function codexAppServerRuntimeDirIsManaged(runtimeDir = "") {
|
|
|
412
408
|
}
|
|
413
409
|
|
|
414
410
|
async function removeCodexAppServerRuntimeDir(runtimeDir = "") {
|
|
415
|
-
const normalizedRuntimeDir =
|
|
411
|
+
const normalizedRuntimeDir = normalizeNullableText(runtimeDir);
|
|
416
412
|
if (!codexAppServerRuntimeDirIsManaged(normalizedRuntimeDir)) {
|
|
417
413
|
return false;
|
|
418
414
|
}
|
|
@@ -441,26 +437,26 @@ function codexAppServerRuntimeCleanupCanSkip(error) {
|
|
|
441
437
|
|
|
442
438
|
export function codexAppServerRuntimeIdentity(runtime = {}) {
|
|
443
439
|
return [
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
440
|
+
normalizeNullableText(runtime.accountIdentitySignature),
|
|
441
|
+
normalizeNullableText(runtime.authStateSignature),
|
|
442
|
+
normalizeNullableText(runtime.endpoint),
|
|
443
|
+
normalizeNullableText(runtime.executionId),
|
|
444
|
+
normalizeNullableText(runtime.executionMode),
|
|
445
|
+
normalizeNullableText(runtime.runtimesHash),
|
|
446
|
+
normalizeNullableText(runtime.terminalEnvHash),
|
|
447
|
+
normalizeNullableText(runtime.socketPath),
|
|
448
|
+
normalizeNullableText(runtime.startedAt),
|
|
449
|
+
normalizeNullableText(runtime.pid)
|
|
454
450
|
].join("\0");
|
|
455
451
|
}
|
|
456
452
|
|
|
457
453
|
export function normalizeCodexAppServerTerminalEnv(terminalEnv = {}) {
|
|
458
|
-
if (!
|
|
454
|
+
if (!isRecord(terminalEnv)) {
|
|
459
455
|
return {};
|
|
460
456
|
}
|
|
461
457
|
return Object.fromEntries(Object.entries(terminalEnv)
|
|
462
458
|
.map(([name, value]) => [
|
|
463
|
-
|
|
459
|
+
normalizeNullableText(name),
|
|
464
460
|
String(value ?? "")
|
|
465
461
|
])
|
|
466
462
|
.filter(([name, value]) => (
|
|
@@ -485,13 +481,13 @@ export function codexAppServerCommandBaseEnv({
|
|
|
485
481
|
}
|
|
486
482
|
|
|
487
483
|
export function codexAppServerCredentialHome(toolHomeSource = "", baseEnv = {}) {
|
|
488
|
-
const home =
|
|
484
|
+
const home = normalizeNullableText(toolHomeSource);
|
|
489
485
|
if (!home) {
|
|
490
486
|
return {};
|
|
491
487
|
}
|
|
492
488
|
return {
|
|
493
489
|
home,
|
|
494
|
-
username:
|
|
490
|
+
username: normalizeNullableText(baseEnv.USER || baseEnv.LOGNAME)
|
|
495
491
|
};
|
|
496
492
|
}
|
|
497
493
|
|
|
@@ -501,8 +497,9 @@ export function codexAppServerTerminalEnvHash(terminalEnv = {}) {
|
|
|
501
497
|
}
|
|
502
498
|
|
|
503
499
|
function codexHistoryAdapterUrlIsValid(baseUrl, token) {
|
|
504
|
-
//
|
|
505
|
-
// its process identity readable
|
|
500
|
+
// Only this adapter URL shape serves thread-bound compaction recovery. Any
|
|
501
|
+
// other shape keeps its process identity readable but is retired through
|
|
502
|
+
// normal owned cleanup.
|
|
506
503
|
const match = typeof baseUrl === "string" && /^http:\/\/127\.0\.0\.1:([1-9]\d{0,4})\/[0-9a-f-]{36}\/v2$/iu.exec(baseUrl);
|
|
507
504
|
return Boolean(match && Number(match[1]) <= 65535 && baseUrl.endsWith(`/${token}/v2`));
|
|
508
505
|
}
|
|
@@ -510,7 +507,7 @@ function codexHistoryAdapterUrlIsValid(baseUrl, token) {
|
|
|
510
507
|
function codexAppServerLivenessTimeoutMs(options = {}) {
|
|
511
508
|
return normalizePositiveInteger(
|
|
512
509
|
options.livenessTimeoutMs,
|
|
513
|
-
normalizePositiveInteger(options.timeoutMs, CODEX_APP_SERVER_LIVENESS_TIMEOUT_MS)
|
|
510
|
+
{ fallback: normalizePositiveInteger(options.timeoutMs, { fallback: CODEX_APP_SERVER_LIVENESS_TIMEOUT_MS }) }
|
|
514
511
|
);
|
|
515
512
|
}
|
|
516
513
|
|
|
@@ -523,10 +520,10 @@ function codexAppServerProcessCommandHash({
|
|
|
523
520
|
} = {}) {
|
|
524
521
|
return stableHash(JSON.stringify({
|
|
525
522
|
codexArgs,
|
|
526
|
-
codexCommand:
|
|
523
|
+
codexCommand: normalizeNullableText(codexCommand),
|
|
527
524
|
executionMode: codexAppServerExecutionMode({ executionMode }),
|
|
528
|
-
processCwd:
|
|
529
|
-
runtimeDir:
|
|
525
|
+
processCwd: normalizeNullableText(processCwd),
|
|
526
|
+
runtimeDir: normalizeNullableText(runtimeDir)
|
|
530
527
|
}));
|
|
531
528
|
}
|
|
532
529
|
|
|
@@ -535,16 +532,39 @@ const codexAppServerRuntimePreparations = new Map();
|
|
|
535
532
|
/** The production shared runtime: one process owner per stable runtime directory.
|
|
536
533
|
* Execution and credential facilities retain host policy; threads do not own this process.
|
|
537
534
|
*/
|
|
535
|
+
/** Default environment names the runtime and its process leader share. */
|
|
536
|
+
export const CODEX_APP_SERVER_DEFAULT_ENVIRONMENT = Object.freeze({
|
|
537
|
+
runtimeToken: "JSKIT_EXECUTION_RUNTIME_TOKEN",
|
|
538
|
+
modelCatalogSource: "JSKIT_CODEX_MODEL_CATALOG_SOURCE",
|
|
539
|
+
commandHash: "JSKIT_EXECUTION_COMMAND_HASH"
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
/** The PreToolUse hook that routes native Bash commands through the host's wrapper. */
|
|
543
|
+
export function codexCommandHookDefinition(command) {
|
|
544
|
+
return [{ matcher: "^Bash$", hooks: [{ type: "command", command, timeout: 30 }] }];
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// Inline TOML for `-c` overrides: bare keys, JSON-quoted strings.
|
|
548
|
+
function tomlInlineValue(value) {
|
|
549
|
+
if (Array.isArray(value)) {
|
|
550
|
+
return `[${value.map(tomlInlineValue).join(",")}]`;
|
|
551
|
+
}
|
|
552
|
+
if (isRecord(value)) {
|
|
553
|
+
return `{${Object.entries(value).map(([key, item]) => `${key}=${tomlInlineValue(item)}`).join(",")}}`;
|
|
554
|
+
}
|
|
555
|
+
return JSON.stringify(value);
|
|
556
|
+
}
|
|
557
|
+
|
|
538
558
|
export function createCodexAppServerRuntime({ execution, credentials, configuration = {} }) {
|
|
539
559
|
const {
|
|
540
560
|
clientInfo = { name: "jskit", title: "JSKIT", version: "0.1.0" },
|
|
541
561
|
commandHookCommand,
|
|
542
562
|
errorPrefix = "",
|
|
543
|
-
modelCatalogEnvironmentName =
|
|
563
|
+
modelCatalogEnvironmentName = CODEX_APP_SERVER_DEFAULT_ENVIRONMENT.modelCatalogSource,
|
|
544
564
|
processLabel = "jskit-codex-app-server",
|
|
545
565
|
processPath = fileURLToPath(new URL("./codexProcessLeader.js", import.meta.url)),
|
|
546
|
-
runtimeTokenEnvironmentName =
|
|
547
|
-
commandHashEnvironmentName =
|
|
566
|
+
runtimeTokenEnvironmentName = CODEX_APP_SERVER_DEFAULT_ENVIRONMENT.runtimeToken,
|
|
567
|
+
commandHashEnvironmentName = CODEX_APP_SERVER_DEFAULT_ENVIRONMENT.commandHash,
|
|
548
568
|
socketPathHelp = "Configure a shorter host runtime directory.",
|
|
549
569
|
umask = "0007"
|
|
550
570
|
} = configuration;
|
|
@@ -563,8 +583,7 @@ export function createCodexAppServerRuntime({ execution, credentials, configurat
|
|
|
563
583
|
const assertCodexAuthGenerationCurrent = credentials.assertCurrent;
|
|
564
584
|
|
|
565
585
|
function codexAppServerSessionCommandHookConfig() {
|
|
566
|
-
|
|
567
|
-
return `hooks.PreToolUse=[{matcher="^Bash$",hooks=[{type="command",command=${JSON.stringify(command)},timeout=30}]}]`;
|
|
586
|
+
return `hooks.PreToolUse=${tomlInlineValue(codexCommandHookDefinition(commandHookCommand))}`;
|
|
568
587
|
}
|
|
569
588
|
|
|
570
589
|
async function acquireRuntimeLock(runtimeDir = "", options = {}) {
|
|
@@ -573,7 +592,7 @@ export function createCodexAppServerRuntime({ execution, credentials, configurat
|
|
|
573
592
|
}
|
|
574
593
|
|
|
575
594
|
// An empty or null umask inherits the host's own; hosts that share files set one.
|
|
576
|
-
const startupUmask =
|
|
595
|
+
const startupUmask = normalizeNullableText(umask);
|
|
577
596
|
if (startupUmask && !/^[0-7]{3,4}$/u.test(startupUmask)) {
|
|
578
597
|
throw new TypeError(`Codex app-server umask must be octal, not ${JSON.stringify(startupUmask)}.`);
|
|
579
598
|
}
|
|
@@ -598,7 +617,7 @@ export function createCodexAppServerRuntime({ execution, credentials, configurat
|
|
|
598
617
|
].join("\n");
|
|
599
618
|
|
|
600
619
|
function codexAppServerProcessMetadataIsIdentifiable(metadata = {}, runtimeDir = "") {
|
|
601
|
-
const normalizedRuntimeDir =
|
|
620
|
+
const normalizedRuntimeDir = normalizeNullableText(runtimeDir);
|
|
602
621
|
return Boolean(
|
|
603
622
|
Number(metadata.schemaVersion) === CODEX_APP_SERVER_METADATA_SCHEMA_VERSION &&
|
|
604
623
|
metadata.provider === CODEX_APP_SERVER_PROVIDER_ID &&
|
|
@@ -654,7 +673,7 @@ export function createCodexAppServerRuntime({ execution, credentials, configurat
|
|
|
654
673
|
) {
|
|
655
674
|
return stopCodexAppServerProcessGroup(metadata, options);
|
|
656
675
|
}
|
|
657
|
-
const executionId =
|
|
676
|
+
const executionId = normalizeNullableText(metadata.executionId);
|
|
658
677
|
if (executionId) {
|
|
659
678
|
const stopExecution = typeof options.stopExecution === "function"
|
|
660
679
|
? options.stopExecution
|
|
@@ -698,7 +717,7 @@ export function createCodexAppServerRuntime({ execution, credentials, configurat
|
|
|
698
717
|
}
|
|
699
718
|
|
|
700
719
|
async function stopCodexAppServerProcess(runtimeDir = "", options = {}) {
|
|
701
|
-
const normalizedRuntimeDir =
|
|
720
|
+
const normalizedRuntimeDir = normalizeNullableText(runtimeDir);
|
|
702
721
|
if (!normalizedRuntimeDir) {
|
|
703
722
|
return {
|
|
704
723
|
processExitVerified: false,
|
|
@@ -732,12 +751,12 @@ export function createCodexAppServerRuntime({ execution, credentials, configurat
|
|
|
732
751
|
if (!neverStarted) {
|
|
733
752
|
try {
|
|
734
753
|
processStop = await stopOwnedCodexAppServerExecution({
|
|
735
|
-
executionId:
|
|
754
|
+
executionId: normalizeNullableText(executionId),
|
|
736
755
|
pid: Number(pid),
|
|
737
756
|
processIdentity,
|
|
738
757
|
processState: CODEX_APP_SERVER_PROCESS_STATE.RUNNING,
|
|
739
758
|
provider: CODEX_APP_SERVER_PROVIDER_ID,
|
|
740
|
-
runtimeDir:
|
|
759
|
+
runtimeDir: normalizeNullableText(runtimeDir),
|
|
741
760
|
schemaVersion: CODEX_APP_SERVER_METADATA_SCHEMA_VERSION
|
|
742
761
|
}, options);
|
|
743
762
|
} catch {
|
|
@@ -770,7 +789,7 @@ export function createCodexAppServerRuntime({ execution, credentials, configurat
|
|
|
770
789
|
}
|
|
771
790
|
|
|
772
791
|
async function stopCodexAppServerRuntime(options = {}) {
|
|
773
|
-
const runtimeDir =
|
|
792
|
+
const runtimeDir = normalizeNullableText(options.runtimeDir);
|
|
774
793
|
const preserveProcessExitProof = options.preserveProcessExitProof === true;
|
|
775
794
|
if (!runtimeDir || !codexAppServerRuntimeDirIsManaged(runtimeDir)) {
|
|
776
795
|
return {
|
|
@@ -806,7 +825,7 @@ export function createCodexAppServerRuntime({ execution, credentials, configurat
|
|
|
806
825
|
};
|
|
807
826
|
try {
|
|
808
827
|
const existing = await readCodexAppServerMetadata(runtimeDir);
|
|
809
|
-
const expectedAccount =
|
|
828
|
+
const expectedAccount = normalizeNullableText(options.expectedAccountIdentitySignature);
|
|
810
829
|
const ownedRuntime = options.ownedRuntime;
|
|
811
830
|
if (
|
|
812
831
|
ownedRuntime &&
|
|
@@ -831,7 +850,7 @@ export function createCodexAppServerRuntime({ execution, credentials, configurat
|
|
|
831
850
|
? await execution.stopOwned({
|
|
832
851
|
kind: "assistant",
|
|
833
852
|
operationId: "codex-app-server",
|
|
834
|
-
ownerId:
|
|
853
|
+
ownerId: normalizeNullableText(options.ownerId) || stableHash(runtimeDir)
|
|
835
854
|
}, { reason: "codex-app-server-changeover" })
|
|
836
855
|
: null;
|
|
837
856
|
const ownerExitVerified = owned?.supported === true && owned?.ok === true && owned?.scopeEmpty === true;
|
|
@@ -896,9 +915,9 @@ export function createCodexAppServerRuntime({ execution, credentials, configurat
|
|
|
896
915
|
|
|
897
916
|
function codexAppServerMetadataIsWellFormed(metadata = {}, options = {}) {
|
|
898
917
|
const expectedAttachmentHostRoot = options.compatibility.attachmentHostRoot;
|
|
899
|
-
const expectedAccountIdentitySignature =
|
|
918
|
+
const expectedAccountIdentitySignature = normalizeNullableText(options.accountIdentitySignature);
|
|
900
919
|
const expectedExecutionMode = codexAppServerExecutionMode(options);
|
|
901
|
-
const expectedToolHomeSource = codexAppServerIsHelper(options) ? "" :
|
|
920
|
+
const expectedToolHomeSource = codexAppServerIsHelper(options) ? "" : normalizeNullableText(options.toolHomeSource);
|
|
902
921
|
const expectedTerminalEnvHash = codexAppServerTerminalEnvHash(codexAppServerIsHelper(options) ? {} : options.terminalEnv);
|
|
903
922
|
const expectedRuntimesHash = options.compatibility.runtimesHash;
|
|
904
923
|
const expectedExecutionContextHash = options.compatibility.executionContextHash;
|
|
@@ -933,41 +952,43 @@ export function createCodexAppServerRuntime({ execution, credentials, configurat
|
|
|
933
952
|
timeoutMs = CODEX_APP_SERVER_LIVENESS_TIMEOUT_MS,
|
|
934
953
|
WebSocketImpl = WebSocket
|
|
935
954
|
} = {}) {
|
|
936
|
-
const normalizedEndpoint =
|
|
955
|
+
const normalizedEndpoint = normalizeNullableText(endpoint);
|
|
937
956
|
const socketPath = socketPathFromCodexAppServerEndpoint(normalizedEndpoint);
|
|
938
957
|
if (!socketPath || !await fileExists(socketPath)) {
|
|
939
958
|
return {
|
|
940
959
|
status: CODEX_APP_SERVER_ENDPOINT_STATUS.MISSING
|
|
941
960
|
};
|
|
942
961
|
}
|
|
943
|
-
const normalizedTimeoutMs = normalizePositiveInteger(timeoutMs, CODEX_APP_SERVER_LIVENESS_TIMEOUT_MS);
|
|
962
|
+
const normalizedTimeoutMs = normalizePositiveInteger(timeoutMs, { fallback: CODEX_APP_SERVER_LIVENESS_TIMEOUT_MS });
|
|
963
|
+
return {
|
|
964
|
+
status: await probeCodexAppServer(normalizedEndpoint, normalizedTimeoutMs, WebSocketImpl)
|
|
965
|
+
};
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// One bounded connect-and-initialize handshake: responsive, timeout or unreachable.
|
|
969
|
+
async function probeCodexAppServer(endpoint, timeoutMs, WebSocketImpl) {
|
|
944
970
|
const client = new CodexAppServerJsonRpcClient({
|
|
945
|
-
endpoint
|
|
946
|
-
requestTimeoutMs:
|
|
971
|
+
endpoint,
|
|
972
|
+
requestTimeoutMs: timeoutMs,
|
|
947
973
|
WebSocketImpl
|
|
948
974
|
});
|
|
949
975
|
let timeout = null;
|
|
950
976
|
const probe = (async () => {
|
|
951
977
|
await client.connect();
|
|
952
|
-
await client.initialize({ clientInfo
|
|
978
|
+
await client.initialize({ clientInfo });
|
|
953
979
|
return CODEX_APP_SERVER_ENDPOINT_STATUS.RESPONSIVE;
|
|
954
980
|
})();
|
|
955
981
|
probe.catch(() => null);
|
|
956
982
|
try {
|
|
957
|
-
|
|
983
|
+
return await Promise.race([
|
|
958
984
|
probe,
|
|
959
985
|
new Promise((resolve) => {
|
|
960
|
-
timeout = setTimeout(() => resolve(CODEX_APP_SERVER_ENDPOINT_STATUS.TIMEOUT),
|
|
986
|
+
timeout = setTimeout(() => resolve(CODEX_APP_SERVER_ENDPOINT_STATUS.TIMEOUT), timeoutMs);
|
|
961
987
|
timeout.unref?.();
|
|
962
988
|
})
|
|
963
989
|
]);
|
|
964
|
-
return {
|
|
965
|
-
status
|
|
966
|
-
};
|
|
967
990
|
} catch {
|
|
968
|
-
return
|
|
969
|
-
status: CODEX_APP_SERVER_ENDPOINT_STATUS.UNREACHABLE
|
|
970
|
-
};
|
|
991
|
+
return CODEX_APP_SERVER_ENDPOINT_STATUS.UNREACHABLE;
|
|
971
992
|
} finally {
|
|
972
993
|
clearTimeout(timeout);
|
|
973
994
|
client.close();
|
|
@@ -1089,35 +1110,10 @@ export function createCodexAppServerRuntime({ execution, credentials, configurat
|
|
|
1089
1110
|
await delay(100);
|
|
1090
1111
|
}
|
|
1091
1112
|
const remainingMs = Math.max(1, timeoutMs - (Date.now() - startedAt));
|
|
1092
|
-
if (!await fileExists(socketPath)
|
|
1093
|
-
return false;
|
|
1094
|
-
}
|
|
1095
|
-
const client = new CodexAppServerJsonRpcClient({
|
|
1096
|
-
endpoint,
|
|
1097
|
-
requestTimeoutMs: remainingMs,
|
|
1098
|
-
WebSocketImpl
|
|
1099
|
-
});
|
|
1100
|
-
let timeout = null;
|
|
1101
|
-
const handshake = (async () => {
|
|
1102
|
-
await client.connect();
|
|
1103
|
-
await client.initialize({ clientInfo: clientInfo });
|
|
1104
|
-
return true;
|
|
1105
|
-
})();
|
|
1106
|
-
handshake.catch(() => null);
|
|
1107
|
-
try {
|
|
1108
|
-
return await Promise.race([
|
|
1109
|
-
handshake,
|
|
1110
|
-
new Promise((resolve) => {
|
|
1111
|
-
timeout = setTimeout(() => resolve(false), remainingMs);
|
|
1112
|
-
timeout.unref?.();
|
|
1113
|
-
})
|
|
1114
|
-
]);
|
|
1115
|
-
} catch {
|
|
1113
|
+
if (!await fileExists(socketPath)) {
|
|
1116
1114
|
return false;
|
|
1117
|
-
} finally {
|
|
1118
|
-
clearTimeout(timeout);
|
|
1119
|
-
client.close();
|
|
1120
1115
|
}
|
|
1116
|
+
return await probeCodexAppServer(endpoint, remainingMs, WebSocketImpl) === CODEX_APP_SERVER_ENDPOINT_STATUS.RESPONSIVE;
|
|
1121
1117
|
}
|
|
1122
1118
|
|
|
1123
1119
|
async function startCodexAppServerProcess({
|
|
@@ -1153,7 +1149,7 @@ export function createCodexAppServerRuntime({ execution, credentials, configurat
|
|
|
1153
1149
|
await ensureWritablePrivateDirectory(runtimeDir);
|
|
1154
1150
|
const helper = codexAppServerExecutionMode({ executionMode }) ===
|
|
1155
1151
|
CODEX_APP_SERVER_EXECUTION_MODES.HELPER;
|
|
1156
|
-
const normalizedToolHomeSource =
|
|
1152
|
+
const normalizedToolHomeSource = normalizeNullableText(toolHomeSource);
|
|
1157
1153
|
if (normalizedToolHomeSource) {
|
|
1158
1154
|
await assertExistingDirectory(normalizedToolHomeSource, "Codex credential home");
|
|
1159
1155
|
}
|
|
@@ -1177,13 +1173,13 @@ export function createCodexAppServerRuntime({ execution, credentials, configurat
|
|
|
1177
1173
|
if (providerHome) {
|
|
1178
1174
|
// The canonical home contains only our curated provider projection. Copy
|
|
1179
1175
|
// it into the existing isolated helper home; never load OpenAI auth here.
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1176
|
+
try {
|
|
1177
|
+
await copyCodexProviderHome(path.join(normalizedToolHomeSource, ".codex"), helperHome);
|
|
1178
|
+
} catch (cause) {
|
|
1179
|
+
const error = new Error("Codex isolated helper runtime could not copy the provider home.", { cause });
|
|
1180
|
+
error.code = `${errorPrefix}codex_helper_runtime_start_failed`;
|
|
1181
|
+
throw error;
|
|
1182
|
+
}
|
|
1187
1183
|
}
|
|
1188
1184
|
}
|
|
1189
1185
|
const processCwd = helper
|
|
@@ -1280,7 +1276,7 @@ export function createCodexAppServerRuntime({ execution, credentials, configurat
|
|
|
1280
1276
|
label: "Codex assistant",
|
|
1281
1277
|
lifecycle: "service",
|
|
1282
1278
|
operationId: "codex-app-server",
|
|
1283
|
-
ownerId:
|
|
1279
|
+
ownerId: normalizeNullableText(ownerId) || stableHash(runtimeDir)
|
|
1284
1280
|
},
|
|
1285
1281
|
processProfile: profileBinary?.isFile() ? {
|
|
1286
1282
|
command: codexCommand, helper, executionMode,
|
|
@@ -1413,11 +1409,11 @@ export function createCodexAppServerRuntime({ execution, credentials, configurat
|
|
|
1413
1409
|
}
|
|
1414
1410
|
|
|
1415
1411
|
return {
|
|
1416
|
-
accountIdentitySignature:
|
|
1412
|
+
accountIdentitySignature: normalizeNullableText(accountIdentitySignature),
|
|
1417
1413
|
attachmentHostRoot: compatibility.attachmentHostRoot,
|
|
1418
1414
|
authStateSignature: resolvedAuthStateSignature,
|
|
1419
1415
|
endpoint,
|
|
1420
|
-
executionId:
|
|
1416
|
+
executionId: normalizeNullableText(startResult.execution?.id),
|
|
1421
1417
|
executionMode: helper
|
|
1422
1418
|
? CODEX_APP_SERVER_EXECUTION_MODES.HELPER
|
|
1423
1419
|
: CODEX_APP_SERVER_EXECUTION_MODES.INTERACTIVE,
|