@openclaw/codex 2026.9.1-beta.1 → 2026.9.1
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/dist/api.js +5 -6
- package/dist/{attempt-client-cleanup-bfsmcQ6m.js → attempt-client-cleanup-DYHcRQAa.js} +31 -45
- package/dist/attempt-context-DmQUNWwT.js +634 -0
- package/dist/{auth-binding-B4FfbcCg.js → auth-binding-Ds_QVm-X.js} +18 -3
- package/dist/{binding-connection-BMvPX73o.js → binding-connection-E6uDsPlx.js} +2 -2
- package/dist/{bounded-turn-B7iBUcuP.js → bounded-turn-wzJrwKKe.js} +15 -20
- package/dist/{capabilities-BRMh0aIq.js → capabilities-dIjNVCYH.js} +1 -1
- package/dist/cli-metadata.js +1 -1
- package/dist/{command-formatters-DEsIufkt.js → command-formatters-CLHhEB1Q.js} +5 -4
- package/dist/{command-handlers-D_-1_qRp.js → command-handlers-CTGb2csu.js} +124 -101
- package/dist/{compact-BglNFZrQ.js → compact-_t0HQrUS.js} +38 -29
- package/dist/{config-giW8X0QA.js → config-BhmfC1s6.js} +294 -282
- package/dist/{context-compaction-activity-BOeJf7yo.js → context-compaction-activity-CMla5FPJ.js} +4 -1
- package/dist/{conversation-binding-data-CW2GuupV.js → conversation-binding-data-BiodpIzq.js} +2 -1
- package/dist/doctor-contract-api.js +143 -12
- package/dist/{dynamic-tools-Dnlfa--w.js → dynamic-tools-BU9tmlYm.js} +599 -655
- package/dist/{effective-mcp-catalog-CTeGrnfO.js → effective-mcp-catalog-DzYBW4h1.js} +2 -2
- package/dist/{event-projector-assistant-message-C5-Ds8mA.js → event-projector-assistant-message-DHRFXKbS.js} +4 -4
- package/dist/{event-projector-usage-Bk1I90Bg.js → event-projector-usage-C5mcrGjp.js} +15 -148
- package/dist/{harness-Csz0F-DK.js → harness-DXVZ5II5.js} +42 -52
- package/dist/harness.js +1 -1
- package/dist/index.js +458 -404
- package/dist/{isolated-completion-Cv6FqygM.js → isolated-completion-kg9kv4iH.js} +4 -4
- package/dist/launch-args-RXQwn8zV.js +90 -0
- package/dist/{managed-binary-DFYK4DWq.js → managed-binary-4-Vjz5GH.js} +14 -9
- package/dist/media-understanding-provider.js +1 -1
- package/dist/model-catalog-CUM68Hkl.js +101 -0
- package/dist/{models-TS3HBU-q.js → models-sYnEc0gd.js} +25 -28
- package/dist/{native-subagent-monitor-4Mfq2HDs.js → native-subagent-monitor-CnH147jH.js} +55 -115
- package/dist/{node-exec-server.runtime-BpWqJO1V.js → node-exec-server.runtime-CstNHCmC.js} +9 -6
- package/dist/{plugin-approval-roundtrip-bUm777tR.js → plugin-approval-roundtrip-CNe-Xrjx.js} +30 -3
- package/dist/{plugin-marketplace-discovery-B9DvaAG-.js → plugin-marketplace-discovery-CfFlKqDl.js} +15 -14
- package/dist/{plugin-metadata-cache-CTCT3w5L.js → plugin-metadata-cache-BFrPhb2c.js} +6 -6
- package/dist/provider-capabilities-DW5p4k9w.js +101 -0
- package/dist/{rate-limits-C5_D8Gmb.js → rate-limits-CawQJfUS.js} +3 -2
- package/dist/{sandbox-guard-kuWTn9C5.js → request-DYAI5FQE.js} +195 -2
- package/dist/{run-attempt-DYc0QCBF.js → run-attempt-D1hJO4fX.js} +828 -2100
- package/dist/{runtime-artifact-BvyT1uyd.js → runtime-artifact-C3jVimFn.js} +21 -14
- package/dist/{session-binding-Bcynfd-_.js → session-binding-BHuTCRZQ.js} +198 -127
- package/dist/{session-catalog-DaLKVtpH.js → session-catalog-yyvTWFOw.js} +564 -408
- package/dist/{session-cli-DMc4oS2w.js → session-cli-CmFEXMAM.js} +1 -1
- package/dist/session-history-C5J1AKzG.js +87 -0
- package/dist/session-initialization-BeWzjGiR.js +74 -0
- package/dist/{session-permission-policy-BrNH1bjy.js → session-permission-policy-DeWVTCMj.js} +2 -2
- package/dist/session-retirement-BujDjXVF.js +97 -0
- package/dist/{session-upstream-marker-BIkusb95.js → session-upstream-marker-C351-5Qw.js} +19 -4
- package/dist/settled-turn-context-D3SNWtUn.js +268 -0
- package/dist/settled-turn-finalizer-BVJx4yoc.js +104 -0
- package/dist/{shared-client-DKz23hHY.js → shared-client-DxcfF9KX.js} +3480 -679
- package/dist/{side-question-DjA_jsNe.js → side-question-BTZAII4l.js} +108 -70
- package/dist/{thread-lifecycle-L7oEkTlq.js → thread-lifecycle-DAcEJ_Om.js} +2188 -1915
- package/dist/{thread-ownership-DZeuKH1j.js → thread-ownership-zGokd8i1.js} +25 -14
- package/dist/thread-policy-g4KbJPzp.js +54 -0
- package/dist/{plugin-app-cache-key-C1CAdfcP.js → thread-resume-C7pyVKeW.js} +59 -7
- package/dist/{transcript-mirror-DsCMWBca.js → transcript-mirror-DTUxFWa_.js} +79 -17
- package/dist/transport-stdio-CyPldczm.js +726 -0
- package/dist/{upstream-prompt-provenance-CFmsKwr9.js → upstream-prompt-provenance-LphB8slG.js} +8 -4
- package/dist/upstream-session-fork-CYlBIGVt.js +966 -0
- package/dist/{usage-ROIaW3wo.js → usage-Bj-rrzkR.js} +3 -3
- package/dist/{web-search-provider.runtime-ClaNPV7N.js → web-search-provider.runtime-D2FWSK4w.js} +3 -3
- package/openclaw.plugin.json +1 -30
- package/package.json +6 -6
- package/dist/command-rpc-CCeCkf_v.js +0 -90
- package/dist/incognito-session-ET_ufDH-.js +0 -2
- package/dist/model-catalog-i9rNBthX.js +0 -48
- package/dist/protocol-validators-VeJxxJ0U.js +0 -2421
- package/dist/request-DXXGHko0.js +0 -157
- package/dist/session-catalog-home-id-BNwAJ9D7.js +0 -18
- package/dist/session-retirement-CcNC3YSY.js +0 -36
- package/dist/settled-turn-finalizer-Dc3ApjU4.js +0 -328
- package/dist/thread-resume-BE9qNEW0.js +0 -30
- package/dist/transport-stdio-DhoGy33Z.js +0 -99
- package/dist/upstream-session-fork-DlaHxSLC.js +0 -326
package/dist/index.js
CHANGED
|
@@ -1,30 +1,26 @@
|
|
|
1
1
|
import { registerCodexCliMetadata } from "./cli-metadata.js";
|
|
2
|
-
import { n as createCodexAppServerNativeCompaction, t as createCodexAppServerAgentHarness } from "./harness-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { n as createCodexAppServerNativeCompaction, t as createCodexAppServerAgentHarness } from "./harness-DXVZ5II5.js";
|
|
3
|
+
import { $t as isJsonObject, B as isCodexAppServerIndeterminateRequestCancellationError, Bt as resolveCodexAppServerAuthProfileIdForAgent, C as withLeasedCodexAppServerClientStartSelectionRetry, Et as isCodexAppServerLiveThreadClaimed, G as isUnsupportedCodexAppServerVersionError, H as isCodexAppServerOverloadError, Ht as resolveCodexAppServerFallbackApiKeyCacheKey, J as CodexThreadDirectInputError, O as createCodexDesktopGenerationService, Rt as resolveCodexAppServerAuthAccountCacheKey, St as consumeCodexAppServerLiveThread, Tt as isCodexAppServerClientRuntimeLive, X as assertCodexThreadAcceptsDirectInput, Xt as CODEX_INTERACTIVE_THREAD_SOURCE_KINDS, _ as retainSharedCodexAppServerClientByInstanceId, b as retireSharedCodexAppServerClientsBeforeDesktopGeneration, c as getLeasedSharedCodexAppServerClient, et as assertCodexThreadStartResponse, h as releaseLeasedSharedCodexAppServerClient, kt as releaseCodexAppServerLiveThread, m as releaseCodexAppServerClientLease, o as clearSharedCodexAppServerClientIfCurrentAndWait, wt as hasCodexAppServerLiveThread } from "./shared-client-DxcfF9KX.js";
|
|
4
|
+
import { E as readCodexPluginConfig, M as CODEX_PLUGINS_MARKETPLACE_NAME, O as resolveOpenClawExecPolicyForCodexAppServer, c as assertCodexAppServerConnectionSecurity, i as resolveCodexAppServerRuntimeOptions, m as canUseCodexModelBackedApprovalsReviewerForModel, n as codexSandboxPolicyForTurn, s as resolveCodexSupervisionAppServerRuntimeOptions, t as codexAppServerStartOptionsKey, y as readCodexRequirementsToml } from "./config-BhmfC1s6.js";
|
|
5
|
+
import { a as setManagedCodexPluginRoot } from "./managed-binary-4-Vjz5GH.js";
|
|
6
6
|
import { n as CODEX_APP_SERVER_BINDING_NAMESPACE, t as CODEX_APP_SERVER_BINDING_MAX_ENTRIES } from "./session-binding-meta-B7aEMU7g.js";
|
|
7
|
-
import { d as sessionBindingIdentity, n as assertCodexBindingMayBeReplaced, o as isCodexAppServerNativeAuthProfile, s as normalizeCodexAppServerBindingModelProvider } from "./session-binding-
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
7
|
+
import { d as sessionBindingIdentity, n as assertCodexBindingMayBeReplaced, o as isCodexAppServerNativeAuthProfile, s as normalizeCodexAppServerBindingModelProvider } from "./session-binding-BHuTCRZQ.js";
|
|
8
|
+
import { o as createCodexAppServerProcessReaperService } from "./transport-stdio-CyPldczm.js";
|
|
9
|
+
import { a as closeCodexStartupClientBestEffort, c as isCodexAppServerUnsafeSubscriptionError, d as unsubscribeCodexThreadBestEffort, h as isCodexNotificationForTurn, l as retireUnsafeCodexTurnClientBestEffort, o as interruptCodexTurnAndWaitBestEffort, p as getCodexAppServerTurnRouter } from "./attempt-client-cleanup-DYHcRQAa.js";
|
|
10
|
+
import { o as isAssistantCommentaryCompletionNotification } from "./event-projector-usage-C5mcrGjp.js";
|
|
11
|
+
import { i as buildCodexPluginAppCacheKey, s as defaultCodexAppInventoryCache, t as resumeCodexAppServerThread } from "./thread-resume-C7pyVKeW.js";
|
|
12
|
+
import { Dt as mergeCodexThreadConfigs, E as resolveCodexAppServerRequestModelSelection, Et as buildDisabledAppsConfigPatch, J as createCodexManagedThreadStore, K as CODEX_MANAGED_THREAD_MAX_ENTRIES, Nt as pluginReadParams, jt as isOpenAiCuratedMarketplace, k as buildCodexProjectDocThreadConfig, kt as ensureCodexPluginActivation, q as CODEX_MANAGED_THREAD_NAMESPACE, w as CODEX_NATIVE_PERSONALITY_NONE } from "./thread-lifecycle-DAcEJ_Om.js";
|
|
13
|
+
import { a as rollbackCodexAppServerBindingSubscription, c as withExclusiveCodexAppServerThread, i as retireCodexConversationThreadBinding, l as isIncognitoSessionKey, n as releaseCodexAppServerBindingSubscription, r as retainCodexAppServerBindingSubscription, s as withCodexConversationThreadActivity, t as isSameCodexAppServerThreadOwner } from "./thread-ownership-zGokd8i1.js";
|
|
14
|
+
import { p as projectBoundedCodexVisibleSessionHistory } from "./transcript-mirror-DTUxFWa_.js";
|
|
15
|
+
import { c as resolveCodexNativeSandboxBlock, i as requestCodexAppServerJson, o as withCodexAppServerJsonClient, s as resolveCodexNativeExecutionBlock } from "./request-DYAI5FQE.js";
|
|
16
16
|
import { buildCodexMediaUnderstandingProvider } from "./media-understanding-provider.js";
|
|
17
|
-
import { n as describeControlFailure, t as CODEX_CONTROL_METHODS } from "./capabilities-
|
|
18
|
-
import {
|
|
19
|
-
import { a as resolveCodexAppServerForModelProvider, i as resolveCodexSessionPermissionCwd, n as applyCodexSessionPermissionPolicy, t as CODEX_SESSION_PERMISSION_EXEC_MODES } from "./session-permission-policy-
|
|
20
|
-
import {
|
|
21
|
-
import { a as
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import { n as resolveCodexBindingAppServerConnection } from "./binding-connection-BMvPX73o.js";
|
|
25
|
-
import { c as createCodexCliSessionNodeInvokePolicies, d as resolveCodexCliSessionForBindingOnNode, f as resumeCodexCliSessionOnNode, i as createCodexSessionCatalogNodeHostCommands, n as createCodexSessionCatalogNodeInvokePolicies, o as assertCodexArchiveDescendantsUnowned, r as createCodexSessionCatalogControl, s as createCodexCliSessionNodeHostCommands, t as codexSessionCatalogRuntime, u as listCodexCliSessionsOnNode } from "./session-catalog-DaLKVtpH.js";
|
|
26
|
-
import { i as withCodexAppServerJsonClient, r as requestCodexAppServerJson } from "./request-DXXGHko0.js";
|
|
27
|
-
import { t as codexControlRequest } from "./command-rpc-CCeCkf_v.js";
|
|
17
|
+
import { n as describeControlFailure, t as CODEX_CONTROL_METHODS } from "./capabilities-dIjNVCYH.js";
|
|
18
|
+
import { a as formatCodexDisplayText } from "./command-formatters-CLHhEB1Q.js";
|
|
19
|
+
import { a as resolveCodexAppServerForModelProvider, i as resolveCodexSessionPermissionCwd, n as applyCodexSessionPermissionPolicy, t as CODEX_SESSION_PERMISSION_EXEC_MODES } from "./session-permission-policy-DeWVTCMj.js";
|
|
20
|
+
import { f as trackCodexConversationActiveTurn, g as canMutateCodexHost, h as CODEX_NATIVE_EXECUTION_AUTH_ERROR, t as discoverCodexMarketplacePlugins } from "./plugin-marketplace-discovery-CfFlKqDl.js";
|
|
21
|
+
import { a as readCodexConversationBindingDataRecord, i as readCodexConversationBindingData, o as resolveCodexDefaultWorkspaceDir, r as createCodexConversationBindingData } from "./conversation-binding-data-BiodpIzq.js";
|
|
22
|
+
import { n as resolveCodexBindingAppServerConnection } from "./binding-connection-E6uDsPlx.js";
|
|
23
|
+
import { d as createCodexCliSessionNodeHostCommands, f as createCodexCliSessionNodeInvokePolicies, g as resumeCodexCliSessionOnNode, h as resolveCodexCliSessionForBindingOnNode, i as createCodexSessionCatalogNodeHostCommands, m as listCodexCliSessionsOnNode, n as createCodexSessionCatalogNodeInvokePolicies, o as assertCodexArchiveDescendantsUnowned, r as createCodexSessionCatalogControl, s as codexControlRequest, t as codexSessionCatalogRuntime } from "./session-catalog-yyvTWFOw.js";
|
|
28
24
|
import { t as createCodexWebSearchProviderBase } from "./web-search-provider.shared-BrZmlqyR.js";
|
|
29
25
|
import { mutateConfigFile } from "openclaw/plugin-sdk/config-mutation";
|
|
30
26
|
import { normalizePluginsConfig, resolveEffectiveEnableState, resolveLivePluginConfigObject, resolvePluginConfigObject } from "openclaw/plugin-sdk/plugin-config-runtime";
|
|
@@ -34,20 +30,20 @@ import fs from "node:fs/promises";
|
|
|
34
30
|
import path from "node:path";
|
|
35
31
|
import { parseStrictNonNegativeInteger, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
36
32
|
import { embeddedAgentLog, formatErrorMessage, resolveActiveEmbeddedRunSessionId, resolveSandboxContext } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
33
|
+
import { canonicalPathFromExistingAncestor, isPathInside } from "openclaw/plugin-sdk/file-access-runtime";
|
|
37
34
|
import os from "node:os";
|
|
38
35
|
import { loadAuthProfileStoreWithoutExternalProfiles, resolveAgentConfig, resolveAgentWorkspaceDir, resolveDefaultAgentDir, resolveDefaultAgentId } from "openclaw/plugin-sdk/agent-runtime";
|
|
39
36
|
import { applyAuthProfileConfig, buildApiKeyCredential, buildOauthProviderAuthResult, buildOpenAICodexCredentialExtra, readCodexCliCredentialsCached, resolveOpenAICodexAuthIdentity, resolveOpenAICodexImportProfileName, updateAuthProfileStoreWithLock } from "openclaw/plugin-sdk/provider-auth";
|
|
40
|
-
import { resolveSessionAgentIds as resolveSessionAgentIds$2 } from "openclaw/plugin-sdk/agent-scope-runtime";
|
|
41
|
-
import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
|
|
42
37
|
import { extractErrorCode, pathExists } from "openclaw/plugin-sdk/security-runtime";
|
|
38
|
+
import { resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
|
|
39
|
+
import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
|
|
43
40
|
import { getSessionEntry, resolveStorePath, resolveTranscriptSessionKeyBySessionId } from "openclaw/plugin-sdk/session-store-runtime";
|
|
44
41
|
import { coerceErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
45
42
|
import { fileURLToPath } from "node:url";
|
|
46
43
|
import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
|
47
|
-
import {
|
|
44
|
+
import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
|
|
48
45
|
import { readVisibleSessionTranscriptMessageEntries } from "openclaw/plugin-sdk/session-transcript-runtime";
|
|
49
46
|
import { getSessionBindingService } from "openclaw/plugin-sdk/conversation-binding-runtime";
|
|
50
|
-
import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
|
|
51
47
|
import { ModelSelectionLockedError, isModelSelectionLocked } from "openclaw/plugin-sdk/model-session-runtime";
|
|
52
48
|
import { MIGRATION_REASON_TARGET_EXISTS, applyMigrationManualItem, createMigrationItem, createMigrationManualItem, hasMigrationConfigPatchConflict, markMigrationItemConflict, markMigrationItemError, markMigrationItemSkipped, mergeMigrationConfigValue, readMigrationConfigPath, resolveMigrationConfigRuntime, summarizeMigrationItems, writeMigrationConfigPath } from "openclaw/plugin-sdk/migration";
|
|
53
49
|
import { archiveMigrationItem, copyMemoryMigrationFileItem, copyMigrationFileItem, withCachedMigrationConfigRuntime, writeMigrationReport } from "openclaw/plugin-sdk/migration-runtime";
|
|
@@ -184,17 +180,18 @@ function waitForReconnect(delayMs, signal) {
|
|
|
184
180
|
/** Defers schema compilation and auth loading until the first binding operation. */
|
|
185
181
|
function createLazyCodexAppServerBindingStore(state, managedThreadState) {
|
|
186
182
|
let resolved;
|
|
187
|
-
const store = () => resolved ??= import("./session-binding-
|
|
183
|
+
const store = () => resolved ??= import("./session-binding-BHuTCRZQ.js").then((n) => n.f).then(({ createCodexAppServerBindingStore }) => createCodexAppServerBindingStore(state));
|
|
188
184
|
const managedThreads = managedThreadState ? createCodexManagedThreadStore(managedThreadState) : void 0;
|
|
189
185
|
return {
|
|
190
186
|
...managedThreads ? { managedThreads } : {},
|
|
191
187
|
read: async (identity) => (await store()).read(identity),
|
|
192
188
|
hasOtherThreadOwner: async (threadId, currentIdentity) => (await store()).hasOtherThreadOwner(threadId, currentIdentity),
|
|
193
|
-
mutate: async (identity, mutation) => (await store()).mutate(identity, mutation),
|
|
189
|
+
mutate: async (identity, mutation, assertCurrent) => (await store()).mutate(identity, mutation, assertCurrent),
|
|
194
190
|
prepareSessionGenerationReclaim: async (identity) => (await store()).prepareSessionGenerationReclaim(identity),
|
|
195
191
|
adoptSessionGeneration: async (identity, previousSessionId) => (await store()).adoptSessionGeneration(identity, previousSessionId),
|
|
196
192
|
resetSessionGeneration: async (identity) => (await store()).resetSessionGeneration(identity),
|
|
197
193
|
retireSessionGeneration: async (identity) => (await store()).retireSessionGeneration(identity),
|
|
194
|
+
withSessionDeletion: async (identity, assertCurrent, run) => (await store()).withSessionDeletion(identity, assertCurrent, run),
|
|
198
195
|
withThreadArchiveFence: async (run) => (await store()).withThreadArchiveFence(run),
|
|
199
196
|
withLease: async (identity, run) => (await store()).withLease(identity, run)
|
|
200
197
|
};
|
|
@@ -214,7 +211,7 @@ async function handleCodexCommand(ctx, options) {
|
|
|
214
211
|
}
|
|
215
212
|
}
|
|
216
213
|
async function loadDefaultCodexSubcommandHandler() {
|
|
217
|
-
const { handleCodexSubcommand } = await import("./command-handlers-
|
|
214
|
+
const { handleCodexSubcommand } = await import("./command-handlers-CTGb2csu.js");
|
|
218
215
|
return handleCodexSubcommand;
|
|
219
216
|
}
|
|
220
217
|
//#endregion
|
|
@@ -396,7 +393,7 @@ function isImageMedia(media) {
|
|
|
396
393
|
return IMAGE_EXTENSIONS.has(path.extname(candidate.split(/[?#]/, 1)[0] ?? "").toLowerCase());
|
|
397
394
|
}
|
|
398
395
|
function normalizeFileUrl(value) {
|
|
399
|
-
if (
|
|
396
|
+
if (!/^file:\/\//iu.test(value)) return value;
|
|
400
397
|
try {
|
|
401
398
|
return fileURLToPath(value);
|
|
402
399
|
} catch {
|
|
@@ -405,18 +402,18 @@ function normalizeFileUrl(value) {
|
|
|
405
402
|
}
|
|
406
403
|
function readLocalMediaPath(value) {
|
|
407
404
|
if (!value) return;
|
|
408
|
-
if (
|
|
405
|
+
if (/^file:\/\//iu.test(value)) return value;
|
|
409
406
|
if (value.startsWith("//")) return;
|
|
410
407
|
if (path.isAbsolute(value) || path.win32.isAbsolute(value)) return value;
|
|
411
408
|
return /^[a-z][a-z0-9+.-]*:/i.test(value) ? void 0 : value;
|
|
412
409
|
}
|
|
413
410
|
//#endregion
|
|
414
411
|
//#region extensions/codex/src/conversation-binding.ts
|
|
415
|
-
const DEFAULT_BOUND_TURN_TIMEOUT_MS =
|
|
412
|
+
const DEFAULT_BOUND_TURN_TIMEOUT_MS = 12e5;
|
|
416
413
|
const NATIVE_CONVERSATION_INTERACTIVE_APPROVALS_UNAVAILABLE = "OpenClaw native Codex conversation binding cannot route interactive approvals yet; use the Codex harness or explicit /acp spawn codex for that workflow.";
|
|
417
414
|
async function resolveConversationAppServerRuntime(params) {
|
|
418
415
|
const source = params.source;
|
|
419
|
-
const agentId = source?.agentId ?? params.agentId ?? (params.config ?
|
|
416
|
+
const agentId = source?.agentId ?? params.agentId ?? (params.config ? resolveSessionAgentIdsStrict({
|
|
420
417
|
sessionKey: params.sessionKey,
|
|
421
418
|
config: params.config
|
|
422
419
|
}).sessionAgentId : void 0);
|
|
@@ -511,12 +508,10 @@ async function startCodexConversationThread(params) {
|
|
|
511
508
|
authProfileId: params.authProfileId ?? existingBinding?.authProfileId,
|
|
512
509
|
...agentLookup
|
|
513
510
|
});
|
|
514
|
-
const
|
|
515
|
-
if (params.threadId?.trim()) await attachExistingThread({
|
|
511
|
+
const bindingParams = {
|
|
516
512
|
pluginConfig: params.pluginConfig,
|
|
517
513
|
bindingStore: params.bindingStore,
|
|
518
514
|
identity,
|
|
519
|
-
threadId: params.threadId.trim(),
|
|
520
515
|
workspaceDir,
|
|
521
516
|
...agentDir ? { agentDir } : {},
|
|
522
517
|
model: params.model,
|
|
@@ -525,24 +520,19 @@ async function startCodexConversationThread(params) {
|
|
|
525
520
|
serviceTier: params.serviceTier,
|
|
526
521
|
config: params.config,
|
|
527
522
|
sessionKey: params.sessionKey,
|
|
528
|
-
incognito,
|
|
523
|
+
incognito: isIncognitoSessionKey(params.sessionKey),
|
|
529
524
|
agentId: params.agentId
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
|
|
525
|
+
};
|
|
526
|
+
const threadId = params.threadId?.trim();
|
|
527
|
+
const bind = () => params.bindingStore.withLease(identity, () => bindThread(bindingParams, threadId));
|
|
528
|
+
const ownedThreadId = threadId ?? existingBinding?.threadId;
|
|
529
|
+
if (ownedThreadId) await withExclusiveCodexAppServerThread({
|
|
533
530
|
bindingStore: params.bindingStore,
|
|
534
531
|
identity,
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
model: params.model,
|
|
538
|
-
modelProvider: params.modelProvider,
|
|
539
|
-
authProfileId,
|
|
540
|
-
serviceTier: params.serviceTier,
|
|
541
|
-
config: params.config,
|
|
542
|
-
sessionKey: params.sessionKey,
|
|
543
|
-
incognito,
|
|
544
|
-
agentId: params.agentId
|
|
532
|
+
threadId: ownedThreadId,
|
|
533
|
+
run: bind
|
|
545
534
|
});
|
|
535
|
+
else await bind();
|
|
546
536
|
const storedBinding = await params.bindingStore.read(identity);
|
|
547
537
|
if (!storedBinding) throw new Error("Codex session binding disappeared while starting its conversation thread.");
|
|
548
538
|
return createCodexConversationBindingData({
|
|
@@ -707,21 +697,21 @@ async function resolveThreadBindingRuntime(params) {
|
|
|
707
697
|
authProfileId: params.authProfileId,
|
|
708
698
|
...agentLookup
|
|
709
699
|
};
|
|
710
|
-
const client = await getLeasedSharedCodexAppServerClient(clientOptions);
|
|
711
700
|
return {
|
|
712
701
|
runtime: modelScopedRuntime,
|
|
713
702
|
workspaceDir,
|
|
714
703
|
agentLookup,
|
|
715
704
|
model: modelSelection?.model,
|
|
716
705
|
modelProvider: modelSelection?.modelProvider ?? modelProvider,
|
|
717
|
-
client,
|
|
718
|
-
clientLease: { client },
|
|
719
706
|
clientOptions
|
|
720
707
|
};
|
|
721
708
|
}
|
|
722
|
-
function
|
|
723
|
-
const serviceTier = params.serviceTier ?? resolved.runtime.serviceTier;
|
|
709
|
+
function buildConversationThreadRequest(resolved, serviceTier) {
|
|
724
710
|
return {
|
|
711
|
+
cwd: resolved.workspaceDir,
|
|
712
|
+
...resolved.model ? { model: resolved.model } : {},
|
|
713
|
+
...resolved.modelProvider ? { modelProvider: resolved.modelProvider } : {},
|
|
714
|
+
personality: CODEX_NATIVE_PERSONALITY_NONE,
|
|
725
715
|
approvalPolicy: resolved.runtime.approvalPolicy,
|
|
726
716
|
approvalsReviewer: resolved.runtime.approvalsReviewer,
|
|
727
717
|
...resolved.runtime.sessionRoot ? { runtimeWorkspaceRoots: [resolved.runtime.sessionRoot] } : {},
|
|
@@ -738,45 +728,33 @@ function codexConversationSandboxOrPermissions(runtime, sandbox) {
|
|
|
738
728
|
config
|
|
739
729
|
};
|
|
740
730
|
}
|
|
741
|
-
async function
|
|
742
|
-
return await withLeasedCodexAppServerClientStartSelectionRetry({
|
|
743
|
-
lease: resolved.clientLease,
|
|
744
|
-
options: resolved.clientOptions,
|
|
745
|
-
run: async (client, requestOptions) => await client.request("thread/start", {
|
|
746
|
-
cwd: resolved.workspaceDir,
|
|
747
|
-
...resolved.model ? { model: resolved.model } : {},
|
|
748
|
-
...resolved.modelProvider ? { modelProvider: resolved.modelProvider } : {},
|
|
749
|
-
personality: CODEX_NATIVE_PERSONALITY_NONE,
|
|
750
|
-
...buildThreadRequestRuntimeOptions(params, resolved),
|
|
751
|
-
developerInstructions: CODEX_CONVERSATION_THREAD_DEVELOPER_INSTRUCTIONS,
|
|
752
|
-
experimentalRawEvents: true,
|
|
753
|
-
...params.incognito ? { ephemeral: true } : {}
|
|
754
|
-
}, requestOptions),
|
|
755
|
-
onClientChange: (client) => {
|
|
756
|
-
resolved.client = client;
|
|
757
|
-
}
|
|
758
|
-
});
|
|
759
|
-
}
|
|
760
|
-
async function writeThreadBindingFromResponse(params, resolved, response) {
|
|
761
|
-
const current = await params.bindingStore.read(params.identity);
|
|
762
|
-
assertCodexBindingMayBeReplaced(current, "storing a conversation-bound Codex thread");
|
|
763
|
-
const trackSubscription = !params.incognito && isCodexAppServerClientRuntimeLive(resolved.client);
|
|
764
|
-
const sameOwner = isSameCodexAppServerThreadOwner(current, {
|
|
765
|
-
threadId: response.thread.id,
|
|
766
|
-
clientId: resolved.client.getInstanceId()
|
|
767
|
-
});
|
|
731
|
+
async function writeThreadBindingFromResponse(params, resolved, client, response, requestOptions) {
|
|
768
732
|
let retained = false;
|
|
733
|
+
let sameOwner = false;
|
|
769
734
|
try {
|
|
735
|
+
const current = await params.bindingStore.read(params.identity);
|
|
736
|
+
assertCodexBindingMayBeReplaced(current, "storing a conversation-bound Codex thread");
|
|
737
|
+
const trackSubscription = !params.incognito && isCodexAppServerClientRuntimeLive(client);
|
|
738
|
+
sameOwner = isSameCodexAppServerThreadOwner(current, {
|
|
739
|
+
threadId: response.thread.id,
|
|
740
|
+
clientId: client.getInstanceId()
|
|
741
|
+
});
|
|
742
|
+
requestOptions();
|
|
743
|
+
assertCodexThreadAcceptsDirectInput(response.thread);
|
|
770
744
|
if (trackSubscription) {
|
|
771
|
-
retained = await retainCodexAppServerBindingSubscription(
|
|
745
|
+
retained = await retainCodexAppServerBindingSubscription(client, response.thread.id);
|
|
772
746
|
if (!retained) throw new Error("Codex conversation thread lost its native subscription owner.");
|
|
773
747
|
}
|
|
774
|
-
if (current && !sameOwner)
|
|
748
|
+
if (current && !sameOwner) {
|
|
749
|
+
const { assertCurrent } = requestOptions();
|
|
750
|
+
await releaseCodexAppServerBindingSubscription(current, { assertCurrent });
|
|
751
|
+
}
|
|
752
|
+
requestOptions();
|
|
775
753
|
if (!await params.bindingStore.mutate(params.identity, {
|
|
776
754
|
kind: "set",
|
|
777
755
|
binding: {
|
|
778
756
|
threadId: response.thread.id,
|
|
779
|
-
clientId:
|
|
757
|
+
clientId: client.getInstanceId(),
|
|
780
758
|
cwd: resolved.workspaceDir,
|
|
781
759
|
authProfileId: params.authProfileId,
|
|
782
760
|
model: response.model ?? resolved.model ?? params.model,
|
|
@@ -789,56 +767,54 @@ async function writeThreadBindingFromResponse(params, resolved, response) {
|
|
|
789
767
|
networkProxyProfileName: resolved.runtime.networkProxy?.profileName,
|
|
790
768
|
networkProxyConfigFingerprint: resolved.runtime.networkProxy?.configFingerprint
|
|
791
769
|
}
|
|
792
|
-
})) throw new Error("Codex conversation binding changed while storing its thread.");
|
|
770
|
+
}, requestOptions)) throw new Error("Codex conversation binding changed while storing its thread.");
|
|
793
771
|
} catch (error) {
|
|
794
|
-
if (
|
|
772
|
+
if (retained && !sameOwner || !hasCodexAppServerLiveThread(client, response.thread.id)) await rollbackCodexAppServerBindingSubscription(client, response.thread.id, retained);
|
|
795
773
|
throw error;
|
|
796
774
|
}
|
|
797
775
|
}
|
|
798
|
-
async function
|
|
799
|
-
await
|
|
800
|
-
|
|
801
|
-
identity: params.identity,
|
|
802
|
-
threadId: params.threadId,
|
|
803
|
-
run: async () => {
|
|
804
|
-
assertCodexBindingMayBeReplaced(await params.bindingStore.read(params.identity), "attaching a conversation-bound Codex thread");
|
|
805
|
-
const resolved = await resolveThreadBindingRuntime(params);
|
|
806
|
-
try {
|
|
807
|
-
const response = resolved.runtime.networkProxy ? await requestNewConversationBindingThread(params, resolved) : await withLeasedCodexAppServerClientStartSelectionRetry({
|
|
808
|
-
lease: resolved.clientLease,
|
|
809
|
-
options: resolved.clientOptions,
|
|
810
|
-
run: async (client, requestOptions) => {
|
|
811
|
-
if (isCodexAppServerLiveThreadClaimed(client, params.threadId)) throw new Error(`Codex thread ${params.threadId} has an active run; stop it before binding its conversation.`);
|
|
812
|
-
await releaseCodexAppServerLiveThread(client, params.threadId);
|
|
813
|
-
if (isCodexAppServerLiveThreadClaimed(client, params.threadId)) throw new Error(`Codex thread ${params.threadId} has an active run; stop it before binding its conversation.`);
|
|
814
|
-
return await client.request(CODEX_CONTROL_METHODS.resumeThread, {
|
|
815
|
-
threadId: params.threadId,
|
|
816
|
-
cwd: resolved.workspaceDir,
|
|
817
|
-
...resolved.model ? { model: resolved.model } : {},
|
|
818
|
-
...resolved.modelProvider ? { modelProvider: resolved.modelProvider } : {},
|
|
819
|
-
personality: CODEX_NATIVE_PERSONALITY_NONE,
|
|
820
|
-
...buildThreadRequestRuntimeOptions(params, resolved)
|
|
821
|
-
}, requestOptions);
|
|
822
|
-
},
|
|
823
|
-
onClientChange: (client) => {
|
|
824
|
-
resolved.client = client;
|
|
825
|
-
}
|
|
826
|
-
});
|
|
827
|
-
if (!resolved.runtime.networkProxy && response.thread.id !== params.threadId) throw new Error(`Codex conversation resume returned ${response.thread.id} for ${params.threadId}.`);
|
|
828
|
-
await writeThreadBindingFromResponse(params, resolved, response);
|
|
829
|
-
} finally {
|
|
830
|
-
releaseCodexAppServerClientLease(resolved.clientLease);
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
});
|
|
834
|
-
}
|
|
835
|
-
async function createThread(params) {
|
|
836
|
-
assertCodexBindingMayBeReplaced(await params.bindingStore.read(params.identity), "creating a conversation-bound Codex thread");
|
|
776
|
+
async function bindThread(params, threadId) {
|
|
777
|
+
const current = await params.bindingStore.read(params.identity);
|
|
778
|
+
assertCodexBindingMayBeReplaced(current, "binding a conversation-bound Codex thread");
|
|
837
779
|
const resolved = await resolveThreadBindingRuntime(params);
|
|
780
|
+
const clientLease = { client: await getLeasedSharedCodexAppServerClient(resolved.clientOptions) };
|
|
838
781
|
try {
|
|
839
|
-
await
|
|
782
|
+
await withLeasedCodexAppServerClientStartSelectionRetry({
|
|
783
|
+
lease: clientLease,
|
|
784
|
+
options: resolved.clientOptions,
|
|
785
|
+
run: async (client, requestOptions) => {
|
|
786
|
+
const request = buildConversationThreadRequest(resolved, params.serviceTier ?? resolved.runtime.serviceTier);
|
|
787
|
+
let response;
|
|
788
|
+
if (threadId && !resolved.runtime.networkProxy) {
|
|
789
|
+
if (isCodexAppServerLiveThreadClaimed(client, threadId)) throw new Error(`Codex thread ${threadId} has an active run; stop it before binding its conversation.`);
|
|
790
|
+
const { thread } = await client.request("thread/read", {
|
|
791
|
+
threadId,
|
|
792
|
+
includeTurns: false
|
|
793
|
+
}, requestOptions());
|
|
794
|
+
assertCodexThreadAcceptsDirectInput(thread);
|
|
795
|
+
const { assertCurrent } = requestOptions();
|
|
796
|
+
await releaseCodexAppServerLiveThread(client, threadId, assertCurrent);
|
|
797
|
+
if (isCodexAppServerLiveThreadClaimed(client, threadId)) throw new Error(`Codex thread ${threadId} has an active run; stop it before binding its conversation.`);
|
|
798
|
+
response = await resumeCodexAppServerThread({
|
|
799
|
+
client,
|
|
800
|
+
abandonClient: () => closeCodexStartupClientBestEffort(client),
|
|
801
|
+
request: {
|
|
802
|
+
...request,
|
|
803
|
+
threadId
|
|
804
|
+
},
|
|
805
|
+
requestResume: (resumeRequest) => client.request("thread/resume", resumeRequest, requestOptions())
|
|
806
|
+
});
|
|
807
|
+
} else response = await client.request("thread/start", {
|
|
808
|
+
...request,
|
|
809
|
+
developerInstructions: CODEX_CONVERSATION_THREAD_DEVELOPER_INSTRUCTIONS,
|
|
810
|
+
experimentalRawEvents: true,
|
|
811
|
+
...params.incognito ? { ephemeral: true } : {}
|
|
812
|
+
}, requestOptions());
|
|
813
|
+
await writeThreadBindingFromResponse(params, resolved, client, response, requestOptions);
|
|
814
|
+
}
|
|
815
|
+
});
|
|
840
816
|
} finally {
|
|
841
|
-
releaseCodexAppServerClientLease(
|
|
817
|
+
releaseCodexAppServerClientLease(clientLease);
|
|
842
818
|
}
|
|
843
819
|
}
|
|
844
820
|
async function runBoundTurn(params) {
|
|
@@ -849,264 +825,286 @@ async function runBoundTurn(params) {
|
|
|
849
825
|
const identity = conversationBindingIdentity(params.data);
|
|
850
826
|
const binding = await params.bindingStore.read(identity);
|
|
851
827
|
if (!binding?.threadId) throw new Error("bound Codex conversation has no thread binding");
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
828
|
+
return await withExclusiveCodexAppServerThread({
|
|
829
|
+
bindingStore: params.bindingStore,
|
|
830
|
+
identity,
|
|
831
|
+
threadId: binding.threadId,
|
|
832
|
+
run: async () => {
|
|
833
|
+
const current = await params.bindingStore.read(identity);
|
|
834
|
+
if (!isSameCodexAppServerThreadOwner(current, binding)) throw new Error("Codex conversation binding changed before its turn.");
|
|
835
|
+
assertCodexBindingMayBeReplaced(binding, "running a conversation-bound Codex thread");
|
|
836
|
+
let threadId = binding.threadId;
|
|
837
|
+
const requestedWorkspaceDir = binding.cwd || params.data.workspaceDir;
|
|
838
|
+
const reviewerModelProvider = resolveModelBackedReviewerPolicyProvider({
|
|
839
|
+
authProfileId: binding.authProfileId,
|
|
840
|
+
modelProvider: binding.modelProvider,
|
|
841
|
+
...agentLookup
|
|
842
|
+
});
|
|
843
|
+
const { runtime, workspaceDir } = await resolveConversationAppServerRuntime({
|
|
844
|
+
pluginConfig: params.pluginConfig,
|
|
845
|
+
config: params.config,
|
|
846
|
+
agentId: params.data.source?.agentId ?? params.data.agentId,
|
|
847
|
+
sessionKey: params.data.legacyBinding ? params.sessionKey : params.data.source?.sessionKey,
|
|
848
|
+
source: params.data.source,
|
|
849
|
+
workspaceDir: requestedWorkspaceDir,
|
|
850
|
+
modelProvider: reviewerModelProvider,
|
|
851
|
+
model: binding.model,
|
|
852
|
+
agentDir: params.data.agentDir
|
|
853
|
+
});
|
|
854
|
+
const modelScopedRuntime = resolveCodexAppServerForModelProvider({
|
|
855
|
+
appServer: runtime,
|
|
856
|
+
provider: reviewerModelProvider,
|
|
857
|
+
model: binding.model,
|
|
858
|
+
config: params.config,
|
|
859
|
+
env: process.env,
|
|
860
|
+
agentDir: params.data.agentDir
|
|
861
|
+
});
|
|
862
|
+
const sessionRoot = modelScopedRuntime.sessionRoot;
|
|
863
|
+
const approvalPolicy = modelScopedRuntime.approvalPolicy;
|
|
864
|
+
const sandbox = modelScopedRuntime.sandbox;
|
|
865
|
+
const permissionProfile = modelScopedRuntime.networkProxy?.profileName;
|
|
866
|
+
const networkProxyConfigFingerprint = modelScopedRuntime.networkProxy?.configFingerprint;
|
|
867
|
+
const networkProxyBindingChanged = binding.networkProxyProfileName !== permissionProfile || binding.networkProxyConfigFingerprint !== networkProxyConfigFingerprint;
|
|
868
|
+
const serviceTier = binding.serviceTier ?? runtime.serviceTier;
|
|
869
|
+
let useStickyNetworkProfile = permissionProfile !== void 0 && binding.networkProxyProfileName === permissionProfile && binding.networkProxyConfigFingerprint === networkProxyConfigFingerprint;
|
|
870
|
+
assertNativeConversationApprovalPolicySupported(modelScopedRuntime);
|
|
871
|
+
const modelSelection = binding.model ? resolveCodexAppServerRequestModelSelection({
|
|
872
|
+
model: binding.model,
|
|
873
|
+
modelProvider: binding.modelProvider,
|
|
874
|
+
authProfileId: binding.authProfileId,
|
|
875
|
+
...agentLookup
|
|
876
|
+
}) : void 0;
|
|
877
|
+
const threadRequestRuntime = {
|
|
878
|
+
runtime: modelScopedRuntime,
|
|
879
|
+
workspaceDir,
|
|
880
|
+
...modelSelection
|
|
881
|
+
};
|
|
882
|
+
const clientOptions = {
|
|
883
|
+
startOptions: runtime.start,
|
|
884
|
+
timeoutMs: runtime.requestTimeoutMs,
|
|
885
|
+
authProfileId: binding.authProfileId,
|
|
886
|
+
...agentLookup
|
|
887
|
+
};
|
|
888
|
+
let client = await getLeasedSharedCodexAppServerClient(clientOptions);
|
|
889
|
+
const clientLease = { client };
|
|
890
|
+
let activeTurnId;
|
|
891
|
+
let activeTurnCleanup = () => void 0;
|
|
892
|
+
let isolatedSubscriptionClient;
|
|
893
|
+
let turnRoute;
|
|
894
|
+
let liveThreadOwnership;
|
|
895
|
+
let ownsNativeSubscription = false;
|
|
896
|
+
let turnSucceeded = false;
|
|
897
|
+
const assertResumeInputAllowed = async () => {
|
|
898
|
+
const { thread } = await client.request("thread/read", {
|
|
915
899
|
threadId,
|
|
916
|
-
|
|
917
|
-
};
|
|
918
|
-
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
900
|
+
includeTurns: false
|
|
901
|
+
}, { timeoutMs: runtime.requestTimeoutMs });
|
|
902
|
+
assertCodexThreadAcceptsDirectInput(thread);
|
|
903
|
+
};
|
|
904
|
+
try {
|
|
905
|
+
if (!networkProxyBindingChanged && binding.clientId !== client.getInstanceId()) await assertResumeInputAllowed();
|
|
906
|
+
if (!params.incognito && isCodexAppServerClientRuntimeLive(client)) {
|
|
907
|
+
const ownership = await consumeCodexAppServerLiveThread(client, threadId);
|
|
908
|
+
if (ownership) {
|
|
909
|
+
liveThreadOwnership = {
|
|
910
|
+
client,
|
|
911
|
+
threadId,
|
|
912
|
+
ownership
|
|
913
|
+
};
|
|
914
|
+
ownsNativeSubscription = true;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
if (networkProxyBindingChanged) {
|
|
918
|
+
const response = assertCodexThreadStartResponse(await withLeasedCodexAppServerClientStartSelectionRetry({
|
|
919
|
+
lease: clientLease,
|
|
920
|
+
options: clientOptions,
|
|
921
|
+
run: async (requestClient, requestOptions) => await requestClient.request("thread/start", {
|
|
922
|
+
...buildConversationThreadRequest(threadRequestRuntime, serviceTier),
|
|
923
|
+
developerInstructions: CODEX_CONVERSATION_THREAD_DEVELOPER_INSTRUCTIONS,
|
|
924
|
+
experimentalRawEvents: true,
|
|
925
|
+
...params.incognito ? { ephemeral: true } : {}
|
|
926
|
+
}, requestOptions()),
|
|
927
|
+
onClientChange: (nextClient) => {
|
|
928
|
+
client = nextClient;
|
|
929
|
+
}
|
|
930
|
+
}));
|
|
931
|
+
threadId = response.thread.id;
|
|
932
|
+
ownsNativeSubscription = true;
|
|
933
|
+
assertCodexThreadAcceptsDirectInput(response.thread);
|
|
934
|
+
if (liveThreadOwnership && (liveThreadOwnership.threadId !== threadId || liveThreadOwnership.client !== client)) {
|
|
935
|
+
const previousOwnership = liveThreadOwnership;
|
|
936
|
+
try {
|
|
937
|
+
await previousOwnership.ownership.release(previousOwnership.threadId);
|
|
938
|
+
} catch (error) {
|
|
939
|
+
if (!(isCodexAppServerClientRuntimeLive(previousOwnership.client) && await retainCodexAppServerBindingSubscription(previousOwnership.client, previousOwnership.threadId, previousOwnership.ownership).catch(() => false))) await closeCodexStartupClientBestEffort(previousOwnership.client);
|
|
940
|
+
liveThreadOwnership = void 0;
|
|
941
|
+
throw error;
|
|
942
|
+
}
|
|
943
|
+
liveThreadOwnership = void 0;
|
|
944
|
+
} else if (binding.threadId !== threadId) await releaseCodexAppServerBindingSubscription(binding);
|
|
945
|
+
if (!await params.bindingStore.mutate(identity, {
|
|
946
|
+
kind: "set",
|
|
947
|
+
binding: {
|
|
948
|
+
threadId,
|
|
949
|
+
clientId: client.getInstanceId(),
|
|
950
|
+
cwd: response.thread.cwd ?? workspaceDir,
|
|
951
|
+
authProfileId: binding.authProfileId,
|
|
952
|
+
model: response.model ?? modelSelection?.model ?? binding.model,
|
|
953
|
+
modelProvider: normalizeCodexAppServerBindingModelProvider({
|
|
954
|
+
authProfileId: binding.authProfileId,
|
|
955
|
+
modelProvider: response.modelProvider ?? modelSelection?.modelProvider ?? binding.modelProvider,
|
|
956
|
+
...agentLookup
|
|
957
|
+
}),
|
|
958
|
+
serviceTier: serviceTier ?? void 0,
|
|
959
|
+
networkProxyProfileName: modelScopedRuntime.networkProxy?.profileName,
|
|
960
|
+
networkProxyConfigFingerprint: modelScopedRuntime.networkProxy?.configFingerprint,
|
|
961
|
+
conversationStartId: binding.conversationStartId,
|
|
962
|
+
conversationSourceTransferComplete: binding.conversationSourceTransferComplete,
|
|
963
|
+
historyCoveredThrough: binding.historyCoveredThrough
|
|
964
|
+
}
|
|
965
|
+
})) throw new Error("Codex conversation binding changed while rotating its thread.");
|
|
966
|
+
useStickyNetworkProfile = modelScopedRuntime.networkProxy !== void 0;
|
|
967
|
+
} else if (binding.clientId !== client.getInstanceId() || isCodexAppServerClientRuntimeLive(client) && !params.incognito && !liveThreadOwnership) {
|
|
968
|
+
if (binding.clientId === client.getInstanceId()) await assertResumeInputAllowed();
|
|
969
|
+
const response = await withLeasedCodexAppServerClientStartSelectionRetry({
|
|
970
|
+
lease: clientLease,
|
|
971
|
+
options: clientOptions,
|
|
972
|
+
run: async (requestClient, requestOptions) => await resumeCodexAppServerThread({
|
|
973
|
+
client: requestClient,
|
|
974
|
+
onSubscriptionReleased: () => {
|
|
975
|
+
isolatedSubscriptionClient = requestClient;
|
|
976
|
+
},
|
|
977
|
+
abandonClient: async () => {
|
|
978
|
+
await closeCodexStartupClientBestEffort(requestClient);
|
|
979
|
+
isolatedSubscriptionClient = requestClient;
|
|
980
|
+
},
|
|
981
|
+
request: {
|
|
982
|
+
threadId,
|
|
983
|
+
...buildConversationThreadRequest(threadRequestRuntime, serviceTier)
|
|
984
|
+
},
|
|
985
|
+
requestResume: (request) => requestClient.request("thread/resume", request, requestOptions())
|
|
986
|
+
}),
|
|
987
|
+
onClientChange: (nextClient) => {
|
|
988
|
+
client = nextClient;
|
|
989
|
+
}
|
|
990
|
+
});
|
|
991
|
+
threadId = response.thread.id;
|
|
992
|
+
ownsNativeSubscription = true;
|
|
993
|
+
assertCodexThreadAcceptsDirectInput(response.thread);
|
|
994
|
+
if (!isSameCodexAppServerThreadOwner(binding, {
|
|
995
|
+
threadId,
|
|
996
|
+
clientId: client.getInstanceId()
|
|
997
|
+
})) await releaseCodexAppServerBindingSubscription(binding);
|
|
998
|
+
if (!await params.bindingStore.mutate(identity, {
|
|
999
|
+
kind: "patch",
|
|
1000
|
+
threadId: binding.threadId,
|
|
1001
|
+
patch: {
|
|
1002
|
+
clientId: client.getInstanceId(),
|
|
1003
|
+
cwd: response.thread.cwd ?? binding.cwd,
|
|
1004
|
+
model: response.model ?? modelSelection?.model ?? binding.model,
|
|
1005
|
+
modelProvider: normalizeCodexAppServerBindingModelProvider({
|
|
1006
|
+
authProfileId: binding.authProfileId,
|
|
1007
|
+
modelProvider: response.modelProvider ?? modelSelection?.modelProvider ?? binding.modelProvider,
|
|
1008
|
+
...agentLookup
|
|
1009
|
+
})
|
|
1010
|
+
}
|
|
1011
|
+
})) throw new Error("Codex conversation binding changed while resuming on a new client.");
|
|
1012
|
+
}
|
|
1013
|
+
const turnCollector = createCodexConversationTurnCollector(threadId);
|
|
1014
|
+
turnRoute = getCodexAppServerTurnRouter(client).reserveThread({
|
|
1015
|
+
threadId,
|
|
1016
|
+
onNotification: turnCollector.handleNotification
|
|
1017
|
+
});
|
|
1018
|
+
turnRoute.armTurn();
|
|
1019
|
+
activeTurnId = (await client.request("turn/start", {
|
|
1020
|
+
threadId,
|
|
1021
|
+
input: buildCodexConversationTurnInput({
|
|
1022
|
+
prompt: params.prompt,
|
|
1023
|
+
event: params.event
|
|
1024
|
+
}),
|
|
926
1025
|
cwd: workspaceDir,
|
|
927
1026
|
...sessionRoot ? { runtimeWorkspaceRoots: [sessionRoot] } : {},
|
|
928
|
-
...modelSelection?.model ? { model: modelSelection.model } : {},
|
|
929
|
-
...modelSelection?.modelProvider ? { modelProvider: modelSelection.modelProvider } : {},
|
|
930
|
-
personality: CODEX_NATIVE_PERSONALITY_NONE,
|
|
931
1027
|
approvalPolicy,
|
|
932
1028
|
approvalsReviewer: modelScopedRuntime.approvalsReviewer,
|
|
933
|
-
...
|
|
934
|
-
...
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
client
|
|
941
|
-
}
|
|
942
|
-
}));
|
|
943
|
-
threadId = response.thread.id;
|
|
944
|
-
ownsNativeSubscription = true;
|
|
945
|
-
if (liveThreadOwnership && (liveThreadOwnership.threadId !== threadId || liveThreadOwnership.client !== client)) {
|
|
946
|
-
const previousOwnership = liveThreadOwnership;
|
|
947
|
-
try {
|
|
948
|
-
await previousOwnership.ownership.release(previousOwnership.threadId);
|
|
949
|
-
} catch (error) {
|
|
950
|
-
if (!(isCodexAppServerClientRuntimeLive(previousOwnership.client) && await retainCodexAppServerBindingSubscription(previousOwnership.client, previousOwnership.threadId, previousOwnership.ownership).catch(() => false))) await closeCodexStartupClientBestEffort(previousOwnership.client);
|
|
951
|
-
liveThreadOwnership = void 0;
|
|
952
|
-
throw error;
|
|
953
|
-
}
|
|
954
|
-
liveThreadOwnership = void 0;
|
|
955
|
-
} else if (binding.threadId !== threadId) await releaseCodexAppServerBindingSubscription(binding);
|
|
956
|
-
if (!await params.bindingStore.mutate(identity, {
|
|
957
|
-
kind: "set",
|
|
958
|
-
binding: {
|
|
1029
|
+
...useStickyNetworkProfile ? {} : { sandboxPolicy: codexSandboxPolicyForTurn(sandbox, sessionRoot ?? workspaceDir) },
|
|
1030
|
+
...modelSelection?.model ? { model: modelSelection.model } : {},
|
|
1031
|
+
personality: CODEX_NATIVE_PERSONALITY_NONE,
|
|
1032
|
+
...serviceTier ? { serviceTier } : {}
|
|
1033
|
+
}, { timeoutMs: runtime.requestTimeoutMs })).turn.id;
|
|
1034
|
+
activeTurnCleanup = trackCodexConversationActiveTurn({
|
|
1035
|
+
identity,
|
|
1036
|
+
client,
|
|
959
1037
|
threadId,
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1038
|
+
turnId: activeTurnId
|
|
1039
|
+
});
|
|
1040
|
+
turnCollector.setTurnId(activeTurnId);
|
|
1041
|
+
await turnRoute.bindTurn(activeTurnId);
|
|
1042
|
+
const replyText = (await turnCollector.wait({ timeoutMs: params.timeoutMs ?? DEFAULT_BOUND_TURN_TIMEOUT_MS })).replyText.trim();
|
|
1043
|
+
turnSucceeded = true;
|
|
1044
|
+
return { reply: { text: replyText || "Codex completed without a text reply." } };
|
|
1045
|
+
} catch (error) {
|
|
1046
|
+
if (isCodexAppServerOverloadError(error) && error.method === "thread/resume") throw error;
|
|
1047
|
+
if (error instanceof CodexThreadDirectInputError) {
|
|
1048
|
+
if (params.incognito && ownsNativeSubscription) {
|
|
1049
|
+
if (!await unsubscribeCodexThreadBestEffort(client, {
|
|
1050
|
+
threadId,
|
|
1051
|
+
timeoutMs: 5e3
|
|
1052
|
+
})) await retireUnsafeCodexTurnClientBestEffort(client, "parent-owned thread unsubscribe");
|
|
1053
|
+
}
|
|
1054
|
+
throw error;
|
|
975
1055
|
}
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
} else if (binding.clientId !== client.getInstanceId() || isCodexAppServerClientRuntimeLive(client) && !params.incognito && !liveThreadOwnership) {
|
|
979
|
-
const response = await withLeasedCodexAppServerClientStartSelectionRetry({
|
|
980
|
-
lease: clientLease,
|
|
981
|
-
options: clientOptions,
|
|
982
|
-
run: async (requestClient, requestOptions) => await resumeCodexAppServerThread({
|
|
983
|
-
client: requestClient,
|
|
984
|
-
abandonClient: async () => {
|
|
985
|
-
retiredUnsafeClient = requestClient;
|
|
986
|
-
await closeCodexStartupClientBestEffort(requestClient);
|
|
987
|
-
},
|
|
988
|
-
request: {
|
|
1056
|
+
if (error instanceof CodexConversationTurnTimeoutError && activeTurnId || turnRoute && isCodexAppServerIndeterminateRequestCancellationError(error)) {
|
|
1057
|
+
if (!await interruptCodexTurnAndWaitBestEffort(client, {
|
|
989
1058
|
threadId,
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
approvalPolicy,
|
|
996
|
-
approvalsReviewer: modelScopedRuntime.approvalsReviewer,
|
|
997
|
-
...codexConversationSandboxOrPermissions(modelScopedRuntime, sandbox),
|
|
998
|
-
...serviceTier ? { serviceTier } : {}
|
|
999
|
-
},
|
|
1000
|
-
...requestOptions
|
|
1001
|
-
}),
|
|
1002
|
-
onClientChange: (nextClient) => {
|
|
1003
|
-
client = nextClient;
|
|
1059
|
+
turnId: activeTurnId ?? ""
|
|
1060
|
+
})) {
|
|
1061
|
+
await retireUnsafeCodexTurnClientBestEffort(client, "turn interrupt");
|
|
1062
|
+
isolatedSubscriptionClient = client;
|
|
1063
|
+
}
|
|
1004
1064
|
}
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
patch: {
|
|
1016
|
-
clientId: client.getInstanceId(),
|
|
1017
|
-
cwd: response.thread.cwd ?? binding.cwd,
|
|
1018
|
-
model: response.model ?? modelSelection?.model ?? binding.model,
|
|
1019
|
-
modelProvider: normalizeCodexAppServerBindingModelProvider({
|
|
1020
|
-
authProfileId: binding.authProfileId,
|
|
1021
|
-
modelProvider: response.modelProvider ?? modelSelection?.modelProvider ?? binding.modelProvider,
|
|
1022
|
-
...agentLookup
|
|
1023
|
-
})
|
|
1065
|
+
if (params.incognito) {
|
|
1066
|
+
if (await params.bindingStore.mutate(identity, {
|
|
1067
|
+
kind: "clear",
|
|
1068
|
+
threadId
|
|
1069
|
+
}) && isolatedSubscriptionClient !== client) {
|
|
1070
|
+
if (!await unsubscribeCodexThreadBestEffort(client, {
|
|
1071
|
+
threadId,
|
|
1072
|
+
timeoutMs: 5e3
|
|
1073
|
+
})) await retireUnsafeCodexTurnClientBestEffort(client, "thread unsubscribe");
|
|
1074
|
+
}
|
|
1024
1075
|
}
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
}, { timeoutMs: runtime.requestTimeoutMs })).turn.id;
|
|
1048
|
-
activeTurnCleanup = trackCodexConversationActiveTurn({
|
|
1049
|
-
identity,
|
|
1050
|
-
client,
|
|
1051
|
-
threadId,
|
|
1052
|
-
turnId: activeTurnId
|
|
1053
|
-
});
|
|
1054
|
-
turnCollector.setTurnId(activeTurnId);
|
|
1055
|
-
await turnRoute.bindTurn(activeTurnId);
|
|
1056
|
-
const replyText = (await turnCollector.wait({ timeoutMs: params.timeoutMs ?? DEFAULT_BOUND_TURN_TIMEOUT_MS })).replyText.trim();
|
|
1057
|
-
turnSucceeded = true;
|
|
1058
|
-
return { reply: { text: replyText || "Codex completed without a text reply." } };
|
|
1059
|
-
} catch (error) {
|
|
1060
|
-
if (error instanceof CodexConversationTurnTimeoutError && activeTurnId || turnRoute && isCodexAppServerIndeterminateRequestCancellationError(error)) {
|
|
1061
|
-
if (!await interruptCodexTurnAndWaitBestEffort(client, {
|
|
1062
|
-
threadId,
|
|
1063
|
-
turnId: activeTurnId ?? ""
|
|
1064
|
-
})) {
|
|
1065
|
-
retiredUnsafeClient = client;
|
|
1066
|
-
await retireUnsafeCodexTurnClientBestEffort(client, "turn interrupt");
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
1069
|
-
if (params.incognito) {
|
|
1070
|
-
if (await params.bindingStore.mutate(identity, {
|
|
1071
|
-
kind: "clear",
|
|
1072
|
-
threadId
|
|
1073
|
-
}) && retiredUnsafeClient !== client) {
|
|
1074
|
-
if (!await unsubscribeCodexThreadBestEffort(client, {
|
|
1075
|
-
threadId,
|
|
1076
|
-
timeoutMs: 5e3
|
|
1077
|
-
})) await retireUnsafeCodexTurnClientBestEffort(client, "thread unsubscribe");
|
|
1078
|
-
}
|
|
1079
|
-
}
|
|
1080
|
-
throw error;
|
|
1081
|
-
} finally {
|
|
1082
|
-
activeTurnCleanup();
|
|
1083
|
-
turnRoute?.release();
|
|
1084
|
-
try {
|
|
1085
|
-
if (ownsNativeSubscription && retiredUnsafeClient !== client && !params.incognito && isCodexAppServerClientRuntimeLive(client)) {
|
|
1086
|
-
const currentLiveThreadOwnership = liveThreadOwnership?.client === client && liveThreadOwnership.threadId === threadId ? liveThreadOwnership.ownership : void 0;
|
|
1087
|
-
let retained = false;
|
|
1088
|
-
if (turnSucceeded) retained = await params.bindingStore.withLease(identity, async () => {
|
|
1089
|
-
const current = await params.bindingStore.read(identity);
|
|
1090
|
-
if (current?.threadId !== threadId || current.clientId !== client.getInstanceId()) return false;
|
|
1091
|
-
return await retainCodexAppServerBindingSubscription(client, threadId, currentLiveThreadOwnership);
|
|
1092
|
-
});
|
|
1093
|
-
if (!retained) {
|
|
1094
|
-
if (!(currentLiveThreadOwnership ? await currentLiveThreadOwnership.release(threadId).then(() => true) : await unsubscribeCodexThreadBestEffort(client, {
|
|
1076
|
+
throw error;
|
|
1077
|
+
} finally {
|
|
1078
|
+
activeTurnCleanup();
|
|
1079
|
+
turnRoute?.release();
|
|
1080
|
+
try {
|
|
1081
|
+
if (ownsNativeSubscription && isolatedSubscriptionClient !== client && !params.incognito && isCodexAppServerClientRuntimeLive(client)) {
|
|
1082
|
+
const currentLiveThreadOwnership = liveThreadOwnership?.client === client && liveThreadOwnership.threadId === threadId ? liveThreadOwnership.ownership : void 0;
|
|
1083
|
+
let retained = false;
|
|
1084
|
+
if (turnSucceeded) retained = await params.bindingStore.withLease(identity, async () => {
|
|
1085
|
+
const latest = await params.bindingStore.read(identity);
|
|
1086
|
+
if (latest?.threadId !== threadId || latest.clientId !== client.getInstanceId()) return false;
|
|
1087
|
+
return await retainCodexAppServerBindingSubscription(client, threadId, currentLiveThreadOwnership);
|
|
1088
|
+
});
|
|
1089
|
+
if (!retained) {
|
|
1090
|
+
if (!(currentLiveThreadOwnership ? await currentLiveThreadOwnership.release(threadId).then(() => true) : await unsubscribeCodexThreadBestEffort(client, {
|
|
1091
|
+
threadId,
|
|
1092
|
+
timeoutMs: 5e3
|
|
1093
|
+
}))) await closeCodexStartupClientBestEffort(client);
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
} catch (error) {
|
|
1097
|
+
embeddedAgentLog.warn("codex conversation subscription cleanup failed", {
|
|
1095
1098
|
threadId,
|
|
1096
|
-
|
|
1097
|
-
})
|
|
1099
|
+
reason: formatErrorMessage(error)
|
|
1100
|
+
});
|
|
1101
|
+
await closeCodexStartupClientBestEffort(client);
|
|
1102
|
+
} finally {
|
|
1103
|
+
releaseCodexAppServerClientLease(clientLease);
|
|
1098
1104
|
}
|
|
1099
1105
|
}
|
|
1100
|
-
} catch (error) {
|
|
1101
|
-
embeddedAgentLog.warn("codex conversation subscription cleanup failed", {
|
|
1102
|
-
threadId,
|
|
1103
|
-
reason: formatErrorMessage(error)
|
|
1104
|
-
});
|
|
1105
|
-
await closeCodexStartupClientBestEffort(client);
|
|
1106
|
-
} finally {
|
|
1107
|
-
releaseCodexAppServerClientLease(clientLease);
|
|
1108
1106
|
}
|
|
1109
|
-
}
|
|
1107
|
+
});
|
|
1110
1108
|
}
|
|
1111
1109
|
function assertNativeConversationApprovalPolicySupported(runtime) {
|
|
1112
1110
|
if (runtime.approvalPolicy !== "never" && runtime.approvalsReviewer === "user") throw new Error(NATIVE_CONVERSATION_INTERACTIVE_APPROVALS_UNAVAILABLE);
|
|
@@ -1123,8 +1121,10 @@ async function runBoundTurnWithMissingThreadRecovery(params) {
|
|
|
1123
1121
|
}
|
|
1124
1122
|
async function prepareConversationBinding(params, options = {}) {
|
|
1125
1123
|
const identity = conversationBindingIdentity(params.data);
|
|
1126
|
-
await params.bindingStore.
|
|
1124
|
+
const snapshot = await params.bindingStore.read(identity);
|
|
1125
|
+
const run = () => params.bindingStore.withLease(identity, async () => {
|
|
1127
1126
|
const current = await params.bindingStore.read(identity);
|
|
1127
|
+
if (current?.threadId !== snapshot?.threadId || current?.clientId !== snapshot?.clientId) throw new Error("Codex conversation binding changed before preparation.");
|
|
1128
1128
|
const requested = params.data.start && current?.conversationStartId !== params.data.start.id ? params.data.start : void 0;
|
|
1129
1129
|
if (current && !requested && !options.forceNew) return;
|
|
1130
1130
|
const sourceIdentity = params.data.source ? sessionBindingIdentity({
|
|
@@ -1158,11 +1158,7 @@ async function prepareConversationBinding(params, options = {}) {
|
|
|
1158
1158
|
agentId: params.data.source?.agentId ?? params.data.agentId
|
|
1159
1159
|
};
|
|
1160
1160
|
const threadId = requested?.threadId;
|
|
1161
|
-
|
|
1162
|
-
...bindingParams,
|
|
1163
|
-
threadId
|
|
1164
|
-
});
|
|
1165
|
-
else await createThread(bindingParams);
|
|
1161
|
+
await bindThread(bindingParams, options.forceNew ? void 0 : threadId);
|
|
1166
1162
|
const stored = await params.bindingStore.read(identity);
|
|
1167
1163
|
if (!stored) throw new Error("Codex conversation binding disappeared while initializing its thread.");
|
|
1168
1164
|
if (sourceIdentity && params.data.source && !current?.conversationSourceTransferComplete) await params.bindingStore.withLease(sourceIdentity, async () => {
|
|
@@ -1193,6 +1189,14 @@ async function prepareConversationBinding(params, options = {}) {
|
|
|
1193
1189
|
}
|
|
1194
1190
|
})) throw new Error("Codex conversation binding changed while initializing its thread.");
|
|
1195
1191
|
});
|
|
1192
|
+
const threadId = params.data.start?.threadId ?? snapshot?.threadId;
|
|
1193
|
+
if (threadId) await withExclusiveCodexAppServerThread({
|
|
1194
|
+
bindingStore: params.bindingStore,
|
|
1195
|
+
identity,
|
|
1196
|
+
threadId,
|
|
1197
|
+
run
|
|
1198
|
+
});
|
|
1199
|
+
else await run();
|
|
1196
1200
|
}
|
|
1197
1201
|
async function projectConversationSourceHistory(source, target, config) {
|
|
1198
1202
|
const storePath = resolveStorePath(config?.session?.store, { agentId: source.agentId });
|
|
@@ -1202,12 +1206,13 @@ async function projectConversationSourceHistory(source, target, config) {
|
|
|
1202
1206
|
storePath
|
|
1203
1207
|
});
|
|
1204
1208
|
if (!sessionKey) return;
|
|
1205
|
-
const
|
|
1209
|
+
const entries = await readVisibleSessionTranscriptMessageEntries({
|
|
1206
1210
|
agentId: source.agentId,
|
|
1207
1211
|
sessionId: source.sessionId,
|
|
1208
1212
|
sessionKey,
|
|
1209
1213
|
storePath
|
|
1210
|
-
})
|
|
1214
|
+
});
|
|
1215
|
+
const history = projectBoundedCodexVisibleSessionHistory(entries);
|
|
1211
1216
|
if (history.length === 0) return;
|
|
1212
1217
|
const clientLease = retainSharedCodexAppServerClientByInstanceId(target.clientId);
|
|
1213
1218
|
if (!clientLease) throw new Error("Codex conversation source history lost its bound client owner.");
|
|
@@ -1221,6 +1226,7 @@ async function projectConversationSourceHistory(source, target, config) {
|
|
|
1221
1226
|
}
|
|
1222
1227
|
}
|
|
1223
1228
|
function isCodexThreadNotFoundError(error) {
|
|
1229
|
+
if (isCodexAppServerOverloadError(error) || isCodexAppServerUnsafeSubscriptionError(error)) return false;
|
|
1224
1230
|
const message = formatErrorMessage(error);
|
|
1225
1231
|
return /\bthread not found:/iu.test(message) || /\bbound Codex conversation has no thread binding\b/u.test(message);
|
|
1226
1232
|
}
|
|
@@ -1391,7 +1397,8 @@ async function buildCodexOAuthCredential(source) {
|
|
|
1391
1397
|
} : null;
|
|
1392
1398
|
}
|
|
1393
1399
|
async function buildCodexApiKeyCredential(source) {
|
|
1394
|
-
const
|
|
1400
|
+
const raw = await readJsonObject(source.authPath);
|
|
1401
|
+
const key = normalizeOptionalString(raw.OPENAI_API_KEY);
|
|
1395
1402
|
if (!key) return null;
|
|
1396
1403
|
return {
|
|
1397
1404
|
kind: "api_key",
|
|
@@ -2699,7 +2706,8 @@ async function requestTargetCodexAppServerJson(params) {
|
|
|
2699
2706
|
});
|
|
2700
2707
|
if (hasOpenAiCuratedMarketplace(lastResponse)) return lastResponse;
|
|
2701
2708
|
if (Date.now() >= discoveryDeadline) return lastResponse;
|
|
2702
|
-
|
|
2709
|
+
const waitMs = Math.min(TARGET_CODEX_MARKETPLACE_DISCOVERY_POLL_MS, discoveryDeadline - Date.now());
|
|
2710
|
+
await sleep(waitMs);
|
|
2703
2711
|
} while (Date.now() < discoveryDeadline);
|
|
2704
2712
|
return lastResponse;
|
|
2705
2713
|
}
|
|
@@ -3254,7 +3262,8 @@ function createCodexNodeExecServerCommand() {
|
|
|
3254
3262
|
} catch {
|
|
3255
3263
|
throw new Error("Codex node exec-server requires a valid workspace request.");
|
|
3256
3264
|
}
|
|
3257
|
-
|
|
3265
|
+
if (!isRecord(request) || Object.keys(request).length !== 2 || request.authorization !== "human-approved" && request.authorization !== "session-full") throw new Error("Codex node exec-server requires an authorized managed placement workspace launch.");
|
|
3266
|
+
const placement = parseCodexNodePlacementWorkspace(request.placement);
|
|
3258
3267
|
if (!context?.acquireManagedWorkspace || context.sessionKey !== placement.sessionKey || io.signal.aborted) throw new Error("Codex node exec-server requires active managed placement authority.");
|
|
3259
3268
|
const workspace = context.acquireManagedWorkspace({
|
|
3260
3269
|
workspaceDir: placement.cwd,
|
|
@@ -3266,11 +3275,14 @@ function createCodexNodeExecServerCommand() {
|
|
|
3266
3275
|
const frames = io.frames;
|
|
3267
3276
|
let unsubscribe;
|
|
3268
3277
|
try {
|
|
3269
|
-
|
|
3278
|
+
if (!context.prepareExecAuthorization) throw new Error("Codex node execution requires node-local exec policy support; update the node.");
|
|
3279
|
+
const assertExecAuthorized = context.prepareExecAuthorization(request.authorization);
|
|
3280
|
+
const { runCodexNodeExecServer } = await import("./node-exec-server.runtime-CstNHCmC.js");
|
|
3270
3281
|
return await runCodexNodeExecServer({
|
|
3271
3282
|
workspaceDir: workspace.workspaceDir,
|
|
3272
3283
|
io,
|
|
3273
3284
|
activeProcesses,
|
|
3285
|
+
assertExecAuthorized,
|
|
3274
3286
|
onFrameReceiver: (receiver) => {
|
|
3275
3287
|
unsubscribe = frames.onMessage(receiver);
|
|
3276
3288
|
}
|
|
@@ -3285,17 +3297,21 @@ function createCodexNodeExecServerCommand() {
|
|
|
3285
3297
|
}
|
|
3286
3298
|
};
|
|
3287
3299
|
}
|
|
3288
|
-
/** Keeps node
|
|
3300
|
+
/** Keeps node launch behind command opt-in and a live Full owner or human decision. */
|
|
3289
3301
|
function createCodexNodeExecServerInvokePolicy() {
|
|
3290
3302
|
return {
|
|
3291
3303
|
commands: [CODEX_NODE_EXEC_SERVER_COMMAND],
|
|
3292
3304
|
dangerous: true,
|
|
3305
|
+
standingApproval: {
|
|
3306
|
+
kind: "placement",
|
|
3307
|
+
scope: CODEX_NODE_EXEC_SERVER_CAPABILITY
|
|
3308
|
+
},
|
|
3293
3309
|
classifyRisk: () => ({
|
|
3294
3310
|
level: "high",
|
|
3295
3311
|
family: CODEX_NODE_EXEC_SERVER_CAPABILITY
|
|
3296
3312
|
}),
|
|
3297
3313
|
handle: async (context) => {
|
|
3298
|
-
if (
|
|
3314
|
+
if (context.risk?.level !== "high") return {
|
|
3299
3315
|
ok: false,
|
|
3300
3316
|
code: "CODEX_NODE_EXEC_APPROVAL_REQUIRED",
|
|
3301
3317
|
message: "Codex node execution requires an available approval reviewer."
|
|
@@ -3310,18 +3326,52 @@ function createCodexNodeExecServerInvokePolicy() {
|
|
|
3310
3326
|
message: "Codex node execution requires an exact managed placement workspace."
|
|
3311
3327
|
};
|
|
3312
3328
|
}
|
|
3313
|
-
const
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
}
|
|
3329
|
+
const workspace = {
|
|
3330
|
+
workspaceDir: placement.cwd,
|
|
3331
|
+
environmentId: placement.environmentId,
|
|
3332
|
+
sessionId: placement.sessionId,
|
|
3333
|
+
ownerEpoch: placement.ownerEpoch,
|
|
3334
|
+
sessionKey: placement.sessionKey
|
|
3335
|
+
};
|
|
3336
|
+
const fullLaunch = await context.invokeNodeWithSessionFull?.({
|
|
3337
|
+
workspace,
|
|
3338
|
+
createParams: () => ({
|
|
3339
|
+
placement,
|
|
3340
|
+
authorization: "session-full"
|
|
3341
|
+
})
|
|
3342
|
+
});
|
|
3343
|
+
if (fullLaunch) return fullLaunch;
|
|
3344
|
+
if (!context.approvals) return {
|
|
3320
3345
|
ok: false,
|
|
3321
|
-
code: "
|
|
3322
|
-
message: "Codex node execution requires
|
|
3346
|
+
code: "CODEX_NODE_EXEC_APPROVAL_REQUIRED",
|
|
3347
|
+
message: "Codex node execution requires an available approval reviewer."
|
|
3323
3348
|
};
|
|
3324
|
-
|
|
3349
|
+
const nodeName = context.node?.displayName ?? context.nodeId;
|
|
3350
|
+
const approval = await context.approvals.request({
|
|
3351
|
+
title: "Run Codex on this node placement",
|
|
3352
|
+
description: `Allows arbitrary processes and filesystem access across the node account, not only this workspace. Allow always applies only while this exact placement remains active. ${nodeName}: ${placement.cwd}`,
|
|
3353
|
+
severity: "critical",
|
|
3354
|
+
allowedDecisions: ["allow-once", "allow-always"]
|
|
3355
|
+
});
|
|
3356
|
+
if (approval.decision !== "allow-once" && approval.decision !== "allow-always") {
|
|
3357
|
+
if (approval.decision === "deny") return {
|
|
3358
|
+
ok: false,
|
|
3359
|
+
code: "CODEX_NODE_EXEC_APPROVAL_DENIED",
|
|
3360
|
+
message: "Codex node execution was denied. Retry the action and choose Allow once or Allow always to continue."
|
|
3361
|
+
};
|
|
3362
|
+
return {
|
|
3363
|
+
ok: false,
|
|
3364
|
+
code: "CODEX_NODE_EXEC_APPROVAL_EXPIRED",
|
|
3365
|
+
message: "Codex node execution approval expired before a decision. Retry the action and approve the new request."
|
|
3366
|
+
};
|
|
3367
|
+
}
|
|
3368
|
+
return await context.invokeNode({
|
|
3369
|
+
workspace,
|
|
3370
|
+
params: {
|
|
3371
|
+
placement,
|
|
3372
|
+
authorization: "human-approved"
|
|
3373
|
+
}
|
|
3374
|
+
});
|
|
3325
3375
|
}
|
|
3326
3376
|
};
|
|
3327
3377
|
}
|
|
@@ -4107,7 +4157,7 @@ function createCodexSupervisionTools(options) {
|
|
|
4107
4157
|
}
|
|
4108
4158
|
//#endregion
|
|
4109
4159
|
//#region extensions/codex/src/web-search-provider.ts
|
|
4110
|
-
const loadCodexWebSearchRuntime = createLazyRuntimeModule(() => import("./web-search-provider.runtime-
|
|
4160
|
+
const loadCodexWebSearchRuntime = createLazyRuntimeModule(() => import("./web-search-provider.runtime-D2FWSK4w.js"));
|
|
4111
4161
|
const CodexWebSearchSchema = {
|
|
4112
4162
|
type: "object",
|
|
4113
4163
|
properties: { query: {
|
|
@@ -4143,13 +4193,13 @@ const ENDED_SESSION_REASONS = /* @__PURE__ */ new Set([
|
|
|
4143
4193
|
"new",
|
|
4144
4194
|
"reset",
|
|
4145
4195
|
"idle",
|
|
4146
|
-
"daily"
|
|
4147
|
-
"deleted"
|
|
4196
|
+
"daily"
|
|
4148
4197
|
]);
|
|
4149
4198
|
var codex_default = definePluginEntry({
|
|
4150
4199
|
id: "codex",
|
|
4151
4200
|
name: "Codex",
|
|
4152
4201
|
description: "Codex app-server harness and native session supervision.",
|
|
4202
|
+
reload: { noopPrefixes: ["plugins.entries.codex.config.codexPlugins"] },
|
|
4153
4203
|
register(api) {
|
|
4154
4204
|
setManagedCodexPluginRoot(api.rootDir);
|
|
4155
4205
|
const resolveCurrentConfig = () => api.runtime.config?.current ? api.runtime.config.current() : void 0;
|
|
@@ -4169,6 +4219,7 @@ var codex_default = definePluginEntry({
|
|
|
4169
4219
|
const resolveCurrentPluginConfig = () => resolvePluginConfig(resolveCurrentConfig);
|
|
4170
4220
|
const appServerConfig = readCodexPluginConfig(resolveCurrentPluginConfig()).appServer;
|
|
4171
4221
|
api.registerService(createCodexDesktopGenerationService({ onGenerationChange: retireSharedCodexAppServerClientsBeforeDesktopGeneration }));
|
|
4222
|
+
api.registerService(createCodexAppServerProcessReaperService());
|
|
4172
4223
|
if (appServerConfig?.transport === "websocket") api.registerService(createCodexAppServerConnectionHealthService({
|
|
4173
4224
|
getPluginConfig: resolveCurrentPluginConfig,
|
|
4174
4225
|
getRuntimeConfig: resolveCurrentConfig
|
|
@@ -4181,9 +4232,10 @@ var codex_default = definePluginEntry({
|
|
|
4181
4232
|
overflowPolicy: "reject-new"
|
|
4182
4233
|
});
|
|
4183
4234
|
const lazyBindingStateStore = {
|
|
4184
|
-
|
|
4235
|
+
deleteIf: (key, predicate) => openBindingStateStore().deleteIf(key, predicate),
|
|
4185
4236
|
entries: () => openBindingStateStore().entries(),
|
|
4186
4237
|
lookup: (key) => openBindingStateStore().lookup(key),
|
|
4238
|
+
registerIfAbsent: (key, value, options) => openBindingStateStore().registerIfAbsent(key, value, options),
|
|
4187
4239
|
get update() {
|
|
4188
4240
|
const store = openBindingStateStore();
|
|
4189
4241
|
return store.update?.bind(store);
|
|
@@ -4196,10 +4248,12 @@ var codex_default = definePluginEntry({
|
|
|
4196
4248
|
});
|
|
4197
4249
|
const bindingStore = createLazyCodexAppServerBindingStore(lazyBindingStateStore, {
|
|
4198
4250
|
entries: () => openManagedThreadStateStore().entries(),
|
|
4251
|
+
lookup: (key) => openManagedThreadStateStore().lookup(key),
|
|
4199
4252
|
registerIfAbsent: (key, value) => openManagedThreadStateStore().registerIfAbsent(key, value)
|
|
4200
4253
|
});
|
|
4201
4254
|
registerCodexCliMetadata(api);
|
|
4202
4255
|
const sessionCatalogControlFactory = createCodexSessionCatalogControl({
|
|
4256
|
+
managedThreads: bindingStore.managedThreads,
|
|
4203
4257
|
config: api.config,
|
|
4204
4258
|
getPluginConfig: resolveCurrentPluginConfig,
|
|
4205
4259
|
getRuntimeConfig: resolveCurrentConfig
|
|
@@ -4339,7 +4393,7 @@ var codex_default = definePluginEntry({
|
|
|
4339
4393
|
if (!previousSessionId || !sessionId || previousSessionId === sessionId) return;
|
|
4340
4394
|
const config = resolveCurrentConfig();
|
|
4341
4395
|
const sessionKey = ctx.sessionKey?.trim();
|
|
4342
|
-
const { sessionBindingIdentity } = await import("./session-binding-
|
|
4396
|
+
const { sessionBindingIdentity } = await import("./session-binding-BHuTCRZQ.js").then((n) => n.f);
|
|
4343
4397
|
const identity = sessionBindingIdentity({
|
|
4344
4398
|
sessionId,
|
|
4345
4399
|
...sessionKey ? { sessionKey } : {},
|
|
@@ -4357,7 +4411,7 @@ var codex_default = definePluginEntry({
|
|
|
4357
4411
|
if (endedSessionKey && nextSessionKey && nextSessionKey !== endedSessionKey) return;
|
|
4358
4412
|
if (event.nextSessionId?.trim() === event.sessionId.trim()) return;
|
|
4359
4413
|
const config = resolveCurrentConfig();
|
|
4360
|
-
const [{ sessionBindingIdentity }, { retireCodexAppServerSessionGeneration }] = await Promise.all([import("./session-binding-
|
|
4414
|
+
const [{ sessionBindingIdentity }, { retireCodexAppServerSessionGeneration }] = await Promise.all([import("./session-binding-BHuTCRZQ.js").then((n) => n.f), import("./session-retirement-BujDjXVF.js")]);
|
|
4361
4415
|
await retireCodexAppServerSessionGeneration({
|
|
4362
4416
|
bindingStore,
|
|
4363
4417
|
identity: sessionBindingIdentity({
|