@openclaw/codex 2026.7.2-beta.2 → 2026.7.2-beta.4
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/{app-server-policy-Scc-Wevo.js → app-server-policy-BO3jYBkv.js} +1 -1
- package/dist/{attempt-notifications-BFmNhqFl.js → attempt-notifications-DdmnBMUp.js} +1 -1
- package/dist/{media-understanding-provider-D31dOJwb.js → bounded-turn-CaQL96kg.js} +43 -183
- package/dist/capabilities-CLICvTxf.js +36 -0
- package/dist/cli-metadata.js +1 -1
- package/dist/{command-formatters-Dq9InZUK.js → command-formatters-DgADqnHa.js} +4 -34
- package/dist/{command-handlers-IgqmL_kv.js → command-handlers-l_lVPNlB.js} +72 -13
- package/dist/{compact-DCTmg3id.js → compact-CC5KhBzX.js} +5 -4
- package/dist/{computer-use-CPcU8TjG.js → computer-use-Ip1-QGa-.js} +4 -4
- package/dist/{conversation-control-CGkBlfc5.js → conversation-control-sNPsbTCP.js} +6 -5
- package/dist/doctor-contract-api.js +1 -1
- package/dist/{dynamic-tools-C_1tEs34.js → dynamic-tools-CQI3UwqY.js} +117 -2543
- package/dist/event-projector-assistant-message-DTgnPPVF.js +101 -0
- package/dist/event-projector-usage-D6tE7_qD.js +69 -0
- package/dist/harness.js +27 -7
- package/dist/incognito-session-ET_ufDH-.js +2 -0
- package/dist/index.js +60 -26
- package/dist/media-understanding-provider.js +168 -1
- package/dist/{models-uh26C8QU.js → models-BNeMlHgg.js} +2 -2
- package/dist/{notification-correlation-KmfV4EkP.js → notification-correlation-BGLixv5_.js} +3 -3
- package/dist/{plugin-app-cache-key-Ceb-lm2c.js → plugin-app-cache-key-CvzvmBRz.js} +2 -2
- package/dist/{rate-limits-DyXaYAxU.js → rate-limits-D0IJT-a6.js} +3 -1
- package/dist/{request-B_oQsCXy.js → request-BTccUTD3.js} +1 -1
- package/dist/{run-attempt-MLzoMe_m.js → run-attempt--858NXDl.js} +2798 -172
- package/dist/{session-binding-h1mmCGnl.js → session-binding-ZSMX1omP.js} +9 -2
- package/dist/{session-catalog-CEvoXWHA.js → session-catalog-DsKaezgR.js} +119 -96
- package/dist/{session-cli-XsEuWb_C.js → session-cli-CYJTfRLG.js} +2 -2
- package/dist/session-upstream-marker-D7XlI9us.js +82 -0
- package/dist/settled-turn-finalizer-DHltNgtF.js +303 -0
- package/dist/{shared-client-JiAnW6pc.js → shared-client-wmgNFNYp.js} +82 -13
- package/dist/{side-question-DqDvIwSU.js → side-question-BfFZCsJ-.js} +21 -15
- package/dist/{thread-lifecycle-CN_pPtPh.js → thread-lifecycle-cqrOlJkq.js} +157 -32
- package/dist/{transcript-mirror-D9rTxx2P.js → transcript-mirror-2p7kl6e4.js} +433 -145
- package/dist/upstream-session-fork-vPjwkT1i.js +320 -0
- package/dist/{usage-D5Rohxoc.js → usage-DM_I3mPT.js} +3 -3
- package/dist/{web-search-provider.runtime-CKVBn3fP.js → web-search-provider.runtime-Bx6HAc_k.js} +3 -3
- package/npm-shrinkwrap.json +38 -38
- package/openclaw.plugin.json +11 -1
- package/package.json +7 -7
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { formatErrorMessage } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
2
|
+
//#region extensions/codex/src/app-server/local-runtime-attribution.ts
|
|
3
|
+
const OPENAI_PROVIDER_ID = "openai";
|
|
4
|
+
const OPENAI_RESPONSES_API = "openai-responses";
|
|
5
|
+
const OPENAI_CODEX_RESPONSES_API = "openai-chatgpt-responses";
|
|
6
|
+
function normalizeRuntimeId(value) {
|
|
7
|
+
return value?.trim().toLowerCase() ?? "";
|
|
8
|
+
}
|
|
9
|
+
/** Maps local Codex runtime plans onto the provider/api pair exposed to event projection. */
|
|
10
|
+
function resolveCodexLocalRuntimeAttribution(params) {
|
|
11
|
+
const authProfileProvider = normalizeRuntimeId(params.runtimePlan?.auth?.authProfileProviderForAuth);
|
|
12
|
+
if (normalizeRuntimeId(params.runtimePlan?.observability.harnessId) === "codex" && authProfileProvider !== OPENAI_PROVIDER_ID && normalizeRuntimeId(params.model.provider) === OPENAI_PROVIDER_ID && normalizeRuntimeId(params.model.api) === OPENAI_RESPONSES_API) return {
|
|
13
|
+
provider: OPENAI_PROVIDER_ID,
|
|
14
|
+
api: OPENAI_CODEX_RESPONSES_API
|
|
15
|
+
};
|
|
16
|
+
return {
|
|
17
|
+
provider: params.provider,
|
|
18
|
+
api: params.model.api
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region extensions/codex/src/app-server/event-projector-assistant-message.ts
|
|
23
|
+
const ZERO_USAGE = {
|
|
24
|
+
input: 0,
|
|
25
|
+
output: 0,
|
|
26
|
+
cacheRead: 0,
|
|
27
|
+
cacheWrite: 0,
|
|
28
|
+
totalTokens: 0,
|
|
29
|
+
cost: {
|
|
30
|
+
input: 0,
|
|
31
|
+
output: 0,
|
|
32
|
+
cacheRead: 0,
|
|
33
|
+
cacheWrite: 0,
|
|
34
|
+
total: 0
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
function createAssistantMessage(params, text, options) {
|
|
38
|
+
const attribution = resolveCodexLocalRuntimeAttribution(params);
|
|
39
|
+
const usage = options.tokenUsage ? {
|
|
40
|
+
input: options.tokenUsage.input ?? 0,
|
|
41
|
+
output: options.tokenUsage.output ?? 0,
|
|
42
|
+
cacheRead: options.tokenUsage.cacheRead ?? 0,
|
|
43
|
+
cacheWrite: options.tokenUsage.cacheWrite ?? 0,
|
|
44
|
+
...options.tokenUsage.contextUsage ? { contextUsage: options.tokenUsage.contextUsage } : {},
|
|
45
|
+
totalTokens: options.tokenUsage.total ?? (options.tokenUsage.input ?? 0) + (options.tokenUsage.output ?? 0) + (options.tokenUsage.cacheRead ?? 0) + (options.tokenUsage.cacheWrite ?? 0),
|
|
46
|
+
cost: ZERO_USAGE.cost
|
|
47
|
+
} : ZERO_USAGE;
|
|
48
|
+
return {
|
|
49
|
+
role: "assistant",
|
|
50
|
+
content: [{
|
|
51
|
+
type: "text",
|
|
52
|
+
text
|
|
53
|
+
}],
|
|
54
|
+
api: attribution.api ?? "openai-chatgpt-responses",
|
|
55
|
+
provider: attribution.provider,
|
|
56
|
+
model: params.modelId,
|
|
57
|
+
usage,
|
|
58
|
+
stopReason: options.aborted ? "aborted" : options.promptError ? "error" : "stop",
|
|
59
|
+
errorMessage: options.promptError ? formatErrorMessage(options.promptError) : void 0,
|
|
60
|
+
timestamp: Date.now()
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function createAssistantCommentaryMessage(params, text, itemId, timestamp) {
|
|
64
|
+
const attribution = resolveCodexLocalRuntimeAttribution(params);
|
|
65
|
+
return {
|
|
66
|
+
role: "assistant",
|
|
67
|
+
content: [{
|
|
68
|
+
type: "text",
|
|
69
|
+
text
|
|
70
|
+
}],
|
|
71
|
+
api: attribution.api ?? "openai-chatgpt-responses",
|
|
72
|
+
provider: attribution.provider,
|
|
73
|
+
model: params.modelId,
|
|
74
|
+
usage: ZERO_USAGE,
|
|
75
|
+
stopReason: "stop",
|
|
76
|
+
timestamp,
|
|
77
|
+
openclawStreamFallback: {
|
|
78
|
+
replacementText: text,
|
|
79
|
+
source: "segment",
|
|
80
|
+
itemId
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function createAssistantMirrorMessage(params, title, text) {
|
|
85
|
+
const attribution = resolveCodexLocalRuntimeAttribution(params);
|
|
86
|
+
return {
|
|
87
|
+
role: "assistant",
|
|
88
|
+
content: [{
|
|
89
|
+
type: "text",
|
|
90
|
+
text: `${title}:\n${text}`
|
|
91
|
+
}],
|
|
92
|
+
api: attribution.api ?? "openai-chatgpt-responses",
|
|
93
|
+
provider: attribution.provider,
|
|
94
|
+
model: params.modelId,
|
|
95
|
+
usage: ZERO_USAGE,
|
|
96
|
+
stopReason: "stop",
|
|
97
|
+
timestamp: Date.now()
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
//#endregion
|
|
101
|
+
export { resolveCodexLocalRuntimeAttribution as i, createAssistantMessage as n, createAssistantMirrorMessage as r, createAssistantCommentaryMessage as t };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Q as isJsonObject } from "./shared-client-wmgNFNYp.js";
|
|
2
|
+
import { dt as readNonNegativeInteger, pt as readNumber } from "./thread-lifecycle-cqrOlJkq.js";
|
|
3
|
+
import { normalizeUsage } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
4
|
+
//#region extensions/codex/src/app-server/event-projector-usage.ts
|
|
5
|
+
function readTokenCount(record, key) {
|
|
6
|
+
const value = readNonNegativeInteger(record, key);
|
|
7
|
+
return value !== void 0 && Number.isSafeInteger(value) ? value : void 0;
|
|
8
|
+
}
|
|
9
|
+
function readCodexThreadTokenUsage(params) {
|
|
10
|
+
const tokenUsage = isJsonObject(params.tokenUsage) ? params.tokenUsage : void 0;
|
|
11
|
+
const last = tokenUsage && isJsonObject(tokenUsage.last) ? tokenUsage.last : void 0;
|
|
12
|
+
return last ? normalizeCodexThreadTokenUsage(last) : void 0;
|
|
13
|
+
}
|
|
14
|
+
function readCodexThreadContextSnapshot(params) {
|
|
15
|
+
const tokenUsage = isJsonObject(params.tokenUsage) ? params.tokenUsage : void 0;
|
|
16
|
+
const last = tokenUsage && isJsonObject(tokenUsage.last) ? tokenUsage.last : void 0;
|
|
17
|
+
const modelContextWindow = tokenUsage ? readTokenCount(tokenUsage, "modelContextWindow") : void 0;
|
|
18
|
+
const promptTokens = last ? readTokenCount(last, "inputTokens") : void 0;
|
|
19
|
+
return {
|
|
20
|
+
...modelContextWindow && modelContextWindow > 0 ? { modelContextWindow } : {},
|
|
21
|
+
...promptTokens !== void 0 ? { promptTokens } : {}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function projectCodexThreadUsageUpdate(params, currentUsage, applyUsage, emitContext) {
|
|
25
|
+
applyUsage(readCodexThreadTokenUsage(params) ?? currentUsage);
|
|
26
|
+
const context = readCodexThreadContextSnapshot(params);
|
|
27
|
+
if (context.modelContextWindow !== void 0 || context.promptTokens !== void 0) emitContext(context);
|
|
28
|
+
}
|
|
29
|
+
function normalizeCodexThreadTokenUsage(record) {
|
|
30
|
+
const inputTokens = readNumber(record, "inputTokens");
|
|
31
|
+
const cacheRead = readNumber(record, "cachedInputTokens");
|
|
32
|
+
const usage = normalizeUsage({
|
|
33
|
+
input: inputTokens !== void 0 && cacheRead !== void 0 ? Math.max(0, inputTokens - cacheRead) : inputTokens,
|
|
34
|
+
output: readNumber(record, "outputTokens"),
|
|
35
|
+
cacheRead,
|
|
36
|
+
total: readNumber(record, "totalTokens")
|
|
37
|
+
});
|
|
38
|
+
return usage ? {
|
|
39
|
+
...usage,
|
|
40
|
+
contextUsage: { state: "unavailable" }
|
|
41
|
+
} : void 0;
|
|
42
|
+
}
|
|
43
|
+
function normalizeCodexResponseTokenUsage(record) {
|
|
44
|
+
const totalTokens = readTokenCount(record, "totalTokens");
|
|
45
|
+
const inputTokens = readTokenCount(record, "inputTokens");
|
|
46
|
+
const cacheRead = readTokenCount(record, "cachedInputTokens");
|
|
47
|
+
const output = readTokenCount(record, "outputTokens");
|
|
48
|
+
const reasoningOutput = readTokenCount(record, "reasoningOutputTokens");
|
|
49
|
+
const cacheWrite = record.cacheWriteInputTokens === void 0 ? 0 : readTokenCount(record, "cacheWriteInputTokens");
|
|
50
|
+
if (totalTokens === void 0 || inputTokens === void 0 || cacheRead === void 0 || cacheWrite === void 0 || output === void 0 || reasoningOutput === void 0 || cacheRead + cacheWrite > inputTokens || totalTokens !== inputTokens + output) return;
|
|
51
|
+
const usage = normalizeUsage({
|
|
52
|
+
input: inputTokens - cacheRead - cacheWrite,
|
|
53
|
+
output,
|
|
54
|
+
cacheRead,
|
|
55
|
+
cacheWrite,
|
|
56
|
+
total: totalTokens
|
|
57
|
+
});
|
|
58
|
+
if (!usage) return;
|
|
59
|
+
return {
|
|
60
|
+
...usage,
|
|
61
|
+
contextUsage: {
|
|
62
|
+
state: "available",
|
|
63
|
+
promptTokens: inputTokens,
|
|
64
|
+
totalTokens
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
export { projectCodexThreadUsageUpdate as n, normalizeCodexResponseTokenUsage as t };
|
package/dist/harness.js
CHANGED
|
@@ -22,13 +22,29 @@ function createCodexAppServerAgentHarness(options) {
|
|
|
22
22
|
const harnessRuntimeId = options?.id ?? "codex";
|
|
23
23
|
const normalizedHarnessRuntimeId = harnessRuntimeId.trim().toLowerCase();
|
|
24
24
|
const providerIds = new Set([...options?.providerIds ?? DEFAULT_CODEX_HARNESS_PROVIDER_IDS].map((id) => id.trim().toLowerCase()));
|
|
25
|
+
const sessionCatalogControl = options.sessionCatalogControl;
|
|
26
|
+
const sessionRuntime = options.runtime;
|
|
25
27
|
return {
|
|
26
28
|
id: harnessRuntimeId,
|
|
27
29
|
label: options?.label ?? "Codex agent harness",
|
|
30
|
+
autoSelection: { providerIds: [...providerIds] },
|
|
28
31
|
delegatedExecutionPluginIds: ["voice-call"],
|
|
29
32
|
contextEngineHostCapabilities: CODEX_APP_SERVER_CONTEXT_ENGINE_HOST_CAPABILITIES,
|
|
30
|
-
deliveryDefaults: {
|
|
33
|
+
deliveryDefaults: { visibleReplies: "message_tool" },
|
|
31
34
|
authBootstrap: "harness",
|
|
35
|
+
...sessionCatalogControl && sessionRuntime ? { sessionFork: {
|
|
36
|
+
upstreamKinds: ["codex-app-server"],
|
|
37
|
+
fork: async (params) => {
|
|
38
|
+
const { forkCodexUpstreamSession } = await import("./upstream-session-fork-vPjwkT1i.js");
|
|
39
|
+
return await forkCodexUpstreamSession(params, {
|
|
40
|
+
bindingStore: options.bindingStore,
|
|
41
|
+
control: sessionCatalogControl,
|
|
42
|
+
harnessRuntimeId,
|
|
43
|
+
resolveConfig: options.resolveConfig,
|
|
44
|
+
runtime: sessionRuntime
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
} } : {},
|
|
32
48
|
authBinding: { fingerprint: async (params) => {
|
|
33
49
|
const { fingerprintCodexAppServerAuthBinding } = await import("./auth-binding-C1czuHPA.js").then((n) => n.t);
|
|
34
50
|
return fingerprintCodexAppServerAuthBinding(params);
|
|
@@ -38,7 +54,7 @@ function createCodexAppServerAgentHarness(options) {
|
|
|
38
54
|
return validateCodexAppServerRuntimeArtifact(binding);
|
|
39
55
|
} },
|
|
40
56
|
fetchUsageSnapshot: async (ctx) => {
|
|
41
|
-
const { fetchCodexAppServerUsageSnapshot } = await import("./usage-
|
|
57
|
+
const { fetchCodexAppServerUsageSnapshot } = await import("./usage-DM_I3mPT.js");
|
|
42
58
|
return await fetchCodexAppServerUsageSnapshot(ctx, { pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig });
|
|
43
59
|
},
|
|
44
60
|
supports: (ctx) => {
|
|
@@ -79,15 +95,19 @@ function createCodexAppServerAgentHarness(options) {
|
|
|
79
95
|
};
|
|
80
96
|
},
|
|
81
97
|
runAttempt: async (params) => {
|
|
82
|
-
const { runCodexAppServerAttempt } = await import("./run-attempt
|
|
98
|
+
const { runCodexAppServerAttempt } = await import("./run-attempt--858NXDl.js");
|
|
83
99
|
return runCodexAppServerAttempt(params, {
|
|
84
100
|
bindingStore: options.bindingStore,
|
|
85
101
|
pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,
|
|
86
102
|
nativeHookRelay: { enabled: true }
|
|
87
103
|
});
|
|
88
104
|
},
|
|
105
|
+
finalizeSettledTurn: async (params) => {
|
|
106
|
+
const { runCodexSettledTurnFinalization } = await import("./settled-turn-finalizer-DHltNgtF.js");
|
|
107
|
+
return runCodexSettledTurnFinalization(params, { pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig });
|
|
108
|
+
},
|
|
89
109
|
runSideQuestion: async (params) => {
|
|
90
|
-
const { runCodexAppServerSideQuestion } = await import("./side-question-
|
|
110
|
+
const { runCodexAppServerSideQuestion } = await import("./side-question-BfFZCsJ-.js");
|
|
91
111
|
return runCodexAppServerSideQuestion(params, {
|
|
92
112
|
bindingStore: options.bindingStore,
|
|
93
113
|
pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,
|
|
@@ -95,14 +115,14 @@ function createCodexAppServerAgentHarness(options) {
|
|
|
95
115
|
});
|
|
96
116
|
},
|
|
97
117
|
compact: async (params) => {
|
|
98
|
-
const { maybeCompactCodexAppServerSession } = await import("./compact-
|
|
118
|
+
const { maybeCompactCodexAppServerSession } = await import("./compact-CC5KhBzX.js");
|
|
99
119
|
return maybeCompactCodexAppServerSession(params, {
|
|
100
120
|
bindingStore: options.bindingStore,
|
|
101
121
|
pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig
|
|
102
122
|
});
|
|
103
123
|
},
|
|
104
124
|
compactAfterContextEngine: async (params) => {
|
|
105
|
-
const { maybeCompactCodexAppServerSession } = await import("./compact-
|
|
125
|
+
const { maybeCompactCodexAppServerSession } = await import("./compact-CC5KhBzX.js");
|
|
106
126
|
return maybeCompactCodexAppServerSession(params, {
|
|
107
127
|
bindingStore: options.bindingStore,
|
|
108
128
|
pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,
|
|
@@ -111,7 +131,7 @@ function createCodexAppServerAgentHarness(options) {
|
|
|
111
131
|
},
|
|
112
132
|
reset: async (params) => {
|
|
113
133
|
if (params.sessionId) {
|
|
114
|
-
const { reclaimCurrentCodexSessionGeneration, sessionBindingIdentity } = await import("./session-binding-
|
|
134
|
+
const { reclaimCurrentCodexSessionGeneration, sessionBindingIdentity } = await import("./session-binding-ZSMX1omP.js").then((n) => n.u);
|
|
115
135
|
const identity = sessionBindingIdentity({
|
|
116
136
|
agentId: params.agentId,
|
|
117
137
|
sessionId: params.sessionId,
|
package/dist/index.js
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import { registerCodexCliMetadata } from "./cli-metadata.js";
|
|
2
2
|
import { createCodexAppServerAgentHarness } from "./harness.js";
|
|
3
|
-
import { C as resolveCodexAppServerFallbackApiKeyCacheKey,
|
|
4
|
-
import { D as
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
3
|
+
import { C as resolveCodexAppServerFallbackApiKeyCacheKey, Q as isJsonObject, S as resolveCodexAppServerAuthProfileIdForAgent, Y as CODEX_INTERACTIVE_THREAD_SOURCE_KINDS, a as getLeasedSharedCodexAppServerClient, b as resolveCodexAppServerAuthAccountCacheKey, c as releaseLeasedSharedCodexAppServerClient, p as withLeasedCodexAppServerClientStartSelectionRetry, r as clearSharedCodexAppServerClientIfCurrentAndWait, s as releaseCodexAppServerClientLease } from "./shared-client-wmgNFNYp.js";
|
|
4
|
+
import { D as resolveCodexSupervisionAppServerRuntimeOptions, O as resolveOpenClawExecPolicyForCodexAppServer, b as readCodexPluginConfig, d as CODEX_PLUGINS_MARKETPLACE_NAME, g as codexSandboxPolicyForTurn, h as codexAppServerStartOptionsKey, l as sessionBindingIdentity, m as canUseCodexModelBackedApprovalsReviewerForModel, n as assertCodexBindingMayBeReplaced, o as isCodexAppServerNativeAuthProfile, p as assertCodexAppServerConnectionSecurity, s as normalizeCodexAppServerBindingModelProvider, x as resolveCodexAppServerRuntimeOptions } from "./session-binding-ZSMX1omP.js";
|
|
5
|
+
import { N as CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, R as unsubscribeCodexThreadBestEffort, _ as CODEX_NATIVE_PERSONALITY_NONE, c as resumeCodexAppServerThread, et as ensureCodexPluginActivation, tt as pluginReadParams, y as resolveCodexAppServerRequestModelSelection } from "./thread-lifecycle-cqrOlJkq.js";
|
|
6
|
+
import { _ as assertCodexThreadStartResponse } from "./transcript-mirror-2p7kl6e4.js";
|
|
7
|
+
import { i as defaultCodexAppInventoryCache, r as buildCodexPluginAppCacheKey } from "./plugin-app-cache-key-CvzvmBRz.js";
|
|
8
8
|
import { n as CODEX_APP_SERVER_BINDING_NAMESPACE, t as CODEX_APP_SERVER_BINDING_MAX_ENTRIES } from "./session-binding-meta-B7aEMU7g.js";
|
|
9
|
-
import { t as
|
|
10
|
-
import {
|
|
11
|
-
import { t as
|
|
9
|
+
import { t as isIncognitoSessionKey } from "./incognito-session-ET_ufDH-.js";
|
|
10
|
+
import { buildCodexMediaUnderstandingProvider } from "./media-understanding-provider.js";
|
|
11
|
+
import { n as describeControlFailure, t as CODEX_CONTROL_METHODS } from "./capabilities-CLICvTxf.js";
|
|
12
|
+
import { r as formatCodexDisplayText } from "./command-formatters-DgADqnHa.js";
|
|
13
|
+
import { t as resolveCodexAppServerForModelProvider } from "./app-server-policy-BO3jYBkv.js";
|
|
12
14
|
import { n as resolveCodexNativeExecutionBlock, r as resolveCodexNativeSandboxBlock } from "./sandbox-guard-D1Wky__S.js";
|
|
13
|
-
import { d as CODEX_NATIVE_EXECUTION_AUTH_ERROR, f as canMutateCodexHost, u as trackCodexConversationActiveTurn } from "./conversation-control-
|
|
15
|
+
import { d as CODEX_NATIVE_EXECUTION_AUTH_ERROR, f as canMutateCodexHost, u as trackCodexConversationActiveTurn } from "./conversation-control-sNPsbTCP.js";
|
|
14
16
|
import { a as readCodexConversationBindingDataRecord, i as readCodexConversationBindingData, o as resolveCodexDefaultWorkspaceDir, r as createCodexConversationBindingData } from "./conversation-binding-data-BHRpYbX3.js";
|
|
15
|
-
import { a as resolveCodexBindingAppServerConnection, n as readCodexNotificationThreadId, r as readCodexNotificationTurnId } from "./notification-correlation-
|
|
16
|
-
import { d as createCodexCliSessionNodeHostCommands, f as createCodexCliSessionNodeInvokePolicies, g as resumeCodexCliSessionOnNode, h as resolveCodexCliSessionForBindingOnNode, i as createCodexSessionCatalogNodeInvokePolicies, m as listCodexCliSessionsOnNode, n as createCodexSessionCatalogControl, o as codexControlRequest, r as createCodexSessionCatalogNodeHostCommands, t as codexSessionCatalogRuntime, u as assertCodexArchiveDescendantsUnowned } from "./session-catalog-
|
|
17
|
-
import { r as requestCodexAppServerJson } from "./request-
|
|
17
|
+
import { a as resolveCodexBindingAppServerConnection, n as readCodexNotificationThreadId, r as readCodexNotificationTurnId } from "./notification-correlation-BGLixv5_.js";
|
|
18
|
+
import { d as createCodexCliSessionNodeHostCommands, f as createCodexCliSessionNodeInvokePolicies, g as resumeCodexCliSessionOnNode, h as resolveCodexCliSessionForBindingOnNode, i as createCodexSessionCatalogNodeInvokePolicies, m as listCodexCliSessionsOnNode, n as createCodexSessionCatalogControl, o as codexControlRequest, r as createCodexSessionCatalogNodeHostCommands, t as codexSessionCatalogRuntime, u as assertCodexArchiveDescendantsUnowned } from "./session-catalog-DsKaezgR.js";
|
|
19
|
+
import { r as requestCodexAppServerJson } from "./request-BTccUTD3.js";
|
|
18
20
|
import { t as createCodexWebSearchProviderBase } from "./web-search-provider.shared-BrZmlqyR.js";
|
|
19
21
|
import { mutateConfigFile } from "openclaw/plugin-sdk/config-mutation";
|
|
20
22
|
import { normalizePluginsConfig, resolveEffectiveEnableState, resolveLivePluginConfigObject, resolvePluginConfigObject } from "openclaw/plugin-sdk/plugin-config-runtime";
|
|
@@ -34,7 +36,7 @@ import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
|
|
34
36
|
import { canonicalPathFromExistingAncestor, isPathInside, pathExists } from "openclaw/plugin-sdk/security-runtime";
|
|
35
37
|
import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
|
|
36
38
|
import { ModelSelectionLockedError, isModelSelectionLocked } from "openclaw/plugin-sdk/model-session-runtime";
|
|
37
|
-
import { MIGRATION_REASON_TARGET_EXISTS, applyMigrationManualItem, createMigrationItem, createMigrationManualItem, hasMigrationConfigPatchConflict, markMigrationItemConflict, markMigrationItemError, markMigrationItemSkipped, readMigrationConfigPath, summarizeMigrationItems, writeMigrationConfigPath } from "openclaw/plugin-sdk/migration";
|
|
39
|
+
import { MIGRATION_REASON_TARGET_EXISTS, applyMigrationManualItem, createMigrationItem, createMigrationManualItem, hasMigrationConfigPatchConflict, markMigrationItemConflict, markMigrationItemError, markMigrationItemSkipped, readMigrationConfigPath, resolveMigrationConfigRuntime, summarizeMigrationItems, writeMigrationConfigPath } from "openclaw/plugin-sdk/migration";
|
|
38
40
|
import { archiveMigrationItem, copyMemoryMigrationFileItem, copyMigrationFileItem, withCachedMigrationConfigRuntime, writeMigrationReport } from "openclaw/plugin-sdk/migration-runtime";
|
|
39
41
|
import { sleep } from "openclaw/plugin-sdk/runtime-env";
|
|
40
42
|
import { readJsonFileWithFallback } from "openclaw/plugin-sdk/json-store";
|
|
@@ -45,7 +47,7 @@ import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
|
45
47
|
/** Defers schema compilation and auth loading until the first binding operation. */
|
|
46
48
|
function createLazyCodexAppServerBindingStore(state) {
|
|
47
49
|
let resolved;
|
|
48
|
-
const store = () => resolved ??= import("./session-binding-
|
|
50
|
+
const store = () => resolved ??= import("./session-binding-ZSMX1omP.js").then((n) => n.u).then(({ createCodexAppServerBindingStore }) => createCodexAppServerBindingStore(state));
|
|
49
51
|
return {
|
|
50
52
|
read: async (identity) => (await store()).read(identity),
|
|
51
53
|
hasOtherThreadOwner: async (threadId, currentIdentity) => (await store()).hasOtherThreadOwner(threadId, currentIdentity),
|
|
@@ -72,7 +74,7 @@ async function handleCodexCommand(ctx, options) {
|
|
|
72
74
|
}
|
|
73
75
|
}
|
|
74
76
|
async function loadDefaultCodexSubcommandHandler() {
|
|
75
|
-
const { handleCodexSubcommand } = await import("./command-handlers-
|
|
77
|
+
const { handleCodexSubcommand } = await import("./command-handlers-l_lVPNlB.js");
|
|
76
78
|
return handleCodexSubcommand;
|
|
77
79
|
}
|
|
78
80
|
//#endregion
|
|
@@ -569,7 +571,8 @@ async function requestNewConversationBindingThread(params, resolved) {
|
|
|
569
571
|
personality: CODEX_NATIVE_PERSONALITY_NONE,
|
|
570
572
|
...buildThreadRequestRuntimeOptions(params, resolved),
|
|
571
573
|
developerInstructions: CODEX_CONVERSATION_THREAD_DEVELOPER_INSTRUCTIONS,
|
|
572
|
-
experimentalRawEvents: true
|
|
574
|
+
experimentalRawEvents: true,
|
|
575
|
+
...isIncognitoSessionKey(params.sessionKey) ? { ephemeral: true } : {}
|
|
573
576
|
}, requestOptions),
|
|
574
577
|
onClientChange: (client) => {
|
|
575
578
|
resolved.client = client;
|
|
@@ -717,7 +720,8 @@ async function runBoundTurn(params) {
|
|
|
717
720
|
...modelScopedRuntime.networkProxy ? { config: modelScopedRuntime.networkProxy.configPatch } : { sandbox },
|
|
718
721
|
...serviceTier ? { serviceTier } : {},
|
|
719
722
|
developerInstructions: CODEX_CONVERSATION_THREAD_DEVELOPER_INSTRUCTIONS,
|
|
720
|
-
experimentalRawEvents: true
|
|
723
|
+
experimentalRawEvents: true,
|
|
724
|
+
...isIncognitoSessionKey(params.sessionKey) ? { ephemeral: true } : {}
|
|
721
725
|
}, requestOptions),
|
|
722
726
|
onClientChange: (nextClient) => {
|
|
723
727
|
client = nextClient;
|
|
@@ -834,6 +838,19 @@ async function runBoundTurn(params) {
|
|
|
834
838
|
});
|
|
835
839
|
collector.setTurnId(turnId);
|
|
836
840
|
return { reply: { text: (await collector.wait({ timeoutMs: params.timeoutMs ?? DEFAULT_BOUND_TURN_TIMEOUT_MS }).finally(activeCleanup)).replyText.trim() || "Codex completed without a text reply." } };
|
|
841
|
+
} catch (error) {
|
|
842
|
+
if (isIncognitoSessionKey(params.sessionKey)) {
|
|
843
|
+
const bindingReleased = await params.bindingStore.mutate(identity, {
|
|
844
|
+
kind: "clear",
|
|
845
|
+
threadId
|
|
846
|
+
});
|
|
847
|
+
const timedOut = error instanceof Error && error.message === "codex app-server bound turn timed out";
|
|
848
|
+
if (bindingReleased && !timedOut) await unsubscribeCodexThreadBestEffort(client, {
|
|
849
|
+
threadId,
|
|
850
|
+
timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS
|
|
851
|
+
});
|
|
852
|
+
}
|
|
853
|
+
throw error;
|
|
837
854
|
} finally {
|
|
838
855
|
notificationCleanup();
|
|
839
856
|
requestCleanup();
|
|
@@ -1219,7 +1236,7 @@ function hasAuthProfileConfigConflict(config, profile, overwrite) {
|
|
|
1219
1236
|
function hasCurrentAuthProfileConfigConflict(ctx, profile) {
|
|
1220
1237
|
let config = ctx.config;
|
|
1221
1238
|
try {
|
|
1222
|
-
config = ctx
|
|
1239
|
+
config = resolveMigrationConfigRuntime(ctx)?.current?.() ?? config;
|
|
1223
1240
|
} catch {}
|
|
1224
1241
|
return hasAuthProfileConfigConflict(config, profile, Boolean(ctx.overwrite));
|
|
1225
1242
|
}
|
|
@@ -1310,7 +1327,7 @@ function authProfileConfigForCredential(credential, profileId) {
|
|
|
1310
1327
|
return credential.kind === "oauth" ? oauthAuthProfileConfig(credential, profileId) : apiKeyAuthProfileConfig(credential, profileId);
|
|
1311
1328
|
}
|
|
1312
1329
|
async function applyCodexAuthProfileConfig(ctx, profile, applyConfig) {
|
|
1313
|
-
const configApi = ctx
|
|
1330
|
+
const configApi = resolveMigrationConfigRuntime(ctx);
|
|
1314
1331
|
if (!configApi?.current || !configApi.mutateConfigFile) return "unavailable";
|
|
1315
1332
|
try {
|
|
1316
1333
|
await configApi.mutateConfigFile({
|
|
@@ -1386,6 +1403,7 @@ async function applyCodexAuthItem(params) {
|
|
|
1386
1403
|
let wrote = false;
|
|
1387
1404
|
const store = await updateAuthProfileStoreWithLock({
|
|
1388
1405
|
agentDir: targets.agentDir,
|
|
1406
|
+
stateDir: ctx.stateDir,
|
|
1389
1407
|
updater: (freshStore) => {
|
|
1390
1408
|
const existing = freshStore.profiles[profileId];
|
|
1391
1409
|
if (!ctx.overwrite && existing) {
|
|
@@ -2086,6 +2104,7 @@ function buildPluginItems(ctx, plugins) {
|
|
|
2086
2104
|
action: "install",
|
|
2087
2105
|
status: conflict ? "conflict" : "planned",
|
|
2088
2106
|
reason: conflict ? MIGRATION_REASON_PLUGIN_EXISTS : void 0,
|
|
2107
|
+
applyPhase: "after-promotion",
|
|
2089
2108
|
source: plugin.source,
|
|
2090
2109
|
target: `plugins.entries.codex.config.codexPlugins.plugins.${configKey}`,
|
|
2091
2110
|
message: `Install Codex plugin "${plugin.pluginName}" in the OpenClaw-managed Codex app-server runtime.`,
|
|
@@ -2215,6 +2234,7 @@ function buildPluginConfigItem(ctx, pluginItems) {
|
|
|
2215
2234
|
target: "plugins.entries.codex.config.codexPlugins",
|
|
2216
2235
|
status: conflict ? "conflict" : "planned",
|
|
2217
2236
|
reason: conflict ? MIGRATION_REASON_TARGET_EXISTS : void 0,
|
|
2237
|
+
applyPhase: "after-promotion",
|
|
2218
2238
|
message: "Enable OpenClaw's Codex plugin integration and record migrated source-installed curated plugins.",
|
|
2219
2239
|
details: {
|
|
2220
2240
|
path: [...CODEX_PLUGIN_CONFIG_PATH],
|
|
@@ -2542,10 +2562,18 @@ async function buildTargetCodexPluginAppCacheKey(ctx) {
|
|
|
2542
2562
|
});
|
|
2543
2563
|
}
|
|
2544
2564
|
async function applyCodexPluginConfigItem(ctx, item, appliedItems) {
|
|
2565
|
+
if (appliedItems.filter((candidate) => candidate.kind === "plugin" && candidate.action === "install" && readCodexPluginPolicy(candidate) !== void 0 && !isCodexPluginConfigTerminal(candidate)).length > 0) return {
|
|
2566
|
+
...item,
|
|
2567
|
+
status: "warning",
|
|
2568
|
+
reason: "selected Codex plugin activation is incomplete"
|
|
2569
|
+
};
|
|
2545
2570
|
const entries = appliedItems.map(readAppliedPluginConfigEntry).filter((entry) => entry !== void 0);
|
|
2546
|
-
if (entries.length === 0) return
|
|
2571
|
+
if (entries.length === 0) return {
|
|
2572
|
+
...markMigrationItemSkipped(item, "no selected Codex plugins"),
|
|
2573
|
+
deferredCompletion: true
|
|
2574
|
+
};
|
|
2547
2575
|
const returnPatch = shouldReturnCodexPluginConfigPatch(ctx);
|
|
2548
|
-
const configApi = ctx
|
|
2576
|
+
const configApi = resolveMigrationConfigRuntime(ctx);
|
|
2549
2577
|
const currentConfig = returnPatch ? ctx.config : configApi?.current?.();
|
|
2550
2578
|
if (!currentConfig) return markMigrationItemError(item, "config runtime unavailable");
|
|
2551
2579
|
const value = buildCodexPluginsConfigValue(entries, { config: currentConfig });
|
|
@@ -2576,8 +2604,11 @@ async function applyCodexPluginConfigItem(ctx, item, appliedItems) {
|
|
|
2576
2604
|
return markMigrationItemError(item, error instanceof Error ? error.message : String(error));
|
|
2577
2605
|
}
|
|
2578
2606
|
}
|
|
2607
|
+
function isCodexPluginConfigTerminal(item) {
|
|
2608
|
+
return item.status === "migrated" || item.status === "skipped" && (item.deferredCompletion === true || item.reason === CODEX_PLUGIN_NOT_SELECTED_REASON || item.reason === CODEX_PLUGIN_AUTH_REQUIRED_REASON);
|
|
2609
|
+
}
|
|
2579
2610
|
function readAppliedPluginConfigEntry(item) {
|
|
2580
|
-
if (item.status === "migrated") return readCodexPluginMigrationConfigEntry(item, true);
|
|
2611
|
+
if (item.status === "migrated" || item.deferredCompletion === true) return readCodexPluginMigrationConfigEntry(item, true);
|
|
2581
2612
|
if (item.status === "skipped" && item.reason !== CODEX_PLUGIN_NOT_SELECTED_REASON && item.reason === CODEX_PLUGIN_AUTH_REQUIRED_REASON) return readCodexPluginMigrationConfigEntry(item, false);
|
|
2582
2613
|
}
|
|
2583
2614
|
function readCodexPluginPolicy(item) {
|
|
@@ -2620,6 +2651,7 @@ function buildCodexMigrationProvider(params = {}) {
|
|
|
2620
2651
|
};
|
|
2621
2652
|
},
|
|
2622
2653
|
plan: buildCodexMigrationPlan,
|
|
2654
|
+
deferredApply: { retrySafe: true },
|
|
2623
2655
|
prepareApply(ctx) {
|
|
2624
2656
|
if (isMemoryOnlyMigration(ctx)) return;
|
|
2625
2657
|
return prepareTargetCodexAppServer(ctx);
|
|
@@ -3726,7 +3758,7 @@ function createCodexSupervisionTools(options) {
|
|
|
3726
3758
|
}
|
|
3727
3759
|
//#endregion
|
|
3728
3760
|
//#region extensions/codex/src/web-search-provider.ts
|
|
3729
|
-
const loadCodexWebSearchRuntime = createLazyRuntimeModule(() => import("./web-search-provider.runtime-
|
|
3761
|
+
const loadCodexWebSearchRuntime = createLazyRuntimeModule(() => import("./web-search-provider.runtime-Bx6HAc_k.js"));
|
|
3730
3762
|
const CodexWebSearchSchema = {
|
|
3731
3763
|
type: "object",
|
|
3732
3764
|
properties: { query: {
|
|
@@ -3825,8 +3857,10 @@ var codex_default = definePluginEntry({
|
|
|
3825
3857
|
}, { names: [...CODEX_SUPERVISION_COMPAT_TOOL_NAMES] });
|
|
3826
3858
|
api.registerAgentHarness(createCodexAppServerAgentHarness({
|
|
3827
3859
|
bindingStore,
|
|
3860
|
+
sessionCatalogControl,
|
|
3828
3861
|
resolveConfig: resolveCurrentConfig,
|
|
3829
|
-
resolvePluginConfig: resolveCurrentPluginConfig
|
|
3862
|
+
resolvePluginConfig: resolveCurrentPluginConfig,
|
|
3863
|
+
runtime: api.runtime
|
|
3830
3864
|
}));
|
|
3831
3865
|
api.registerMediaUnderstandingProvider(buildCodexMediaUnderstandingProvider({ pluginConfig: api.pluginConfig }));
|
|
3832
3866
|
api.registerWebSearchProvider(createCodexWebSearchProvider({ resolvePluginConfig: resolveCurrentPluginConfig }));
|
|
@@ -3914,7 +3948,7 @@ var codex_default = definePluginEntry({
|
|
|
3914
3948
|
if (!previousSessionId || !sessionId || previousSessionId === sessionId) return;
|
|
3915
3949
|
const config = resolveCurrentConfig();
|
|
3916
3950
|
const sessionKey = ctx.sessionKey?.trim();
|
|
3917
|
-
const { sessionBindingIdentity } = await import("./session-binding-
|
|
3951
|
+
const { sessionBindingIdentity } = await import("./session-binding-ZSMX1omP.js").then((n) => n.u);
|
|
3918
3952
|
const identity = sessionBindingIdentity({
|
|
3919
3953
|
sessionId,
|
|
3920
3954
|
...sessionKey ? { sessionKey } : {},
|
|
@@ -3931,7 +3965,7 @@ var codex_default = definePluginEntry({
|
|
|
3931
3965
|
const nextSessionKey = event.nextSessionKey?.trim();
|
|
3932
3966
|
if (endedSessionKey && nextSessionKey && nextSessionKey !== endedSessionKey) return;
|
|
3933
3967
|
const config = resolveCurrentConfig();
|
|
3934
|
-
const { sessionBindingIdentity } = await import("./session-binding-
|
|
3968
|
+
const { sessionBindingIdentity } = await import("./session-binding-ZSMX1omP.js").then((n) => n.u);
|
|
3935
3969
|
await bindingStore.retireSessionGeneration(sessionBindingIdentity({
|
|
3936
3970
|
sessionId: event.sessionId,
|
|
3937
3971
|
...sessionKey ? { sessionKey } : {},
|
|
@@ -1,2 +1,169 @@
|
|
|
1
|
-
import { t as
|
|
1
|
+
import { t as runBoundedCodexAppServerTurn } from "./bounded-turn-CaQL96kg.js";
|
|
2
|
+
import { validateJsonSchemaValue } from "openclaw/plugin-sdk/json-schema-runtime";
|
|
3
|
+
//#region extensions/codex/media-understanding-provider.ts
|
|
4
|
+
/**
|
|
5
|
+
* Codex-backed media understanding provider for bounded image description and
|
|
6
|
+
* structured extraction turns.
|
|
7
|
+
*/
|
|
8
|
+
const CODEX_MEDIA_PROVIDER_ID = "codex";
|
|
9
|
+
const DEFAULT_CODEX_IMAGE_MODEL = "gpt-5.6-sol";
|
|
10
|
+
const DEFAULT_CODEX_IMAGE_PROMPT = "Describe the image.";
|
|
11
|
+
/**
|
|
12
|
+
* Builds the media-understanding provider that delegates image tasks to an
|
|
13
|
+
* isolated Codex app-server session.
|
|
14
|
+
*/
|
|
15
|
+
function buildCodexMediaUnderstandingProvider(options = {}) {
|
|
16
|
+
return {
|
|
17
|
+
id: CODEX_MEDIA_PROVIDER_ID,
|
|
18
|
+
capabilities: ["image"],
|
|
19
|
+
defaultModels: { image: DEFAULT_CODEX_IMAGE_MODEL },
|
|
20
|
+
describeImage: async (req) => describeCodexImages({
|
|
21
|
+
images: [{
|
|
22
|
+
buffer: req.buffer,
|
|
23
|
+
fileName: req.fileName,
|
|
24
|
+
mime: req.mime
|
|
25
|
+
}],
|
|
26
|
+
provider: req.provider,
|
|
27
|
+
model: req.model,
|
|
28
|
+
prompt: req.prompt,
|
|
29
|
+
maxTokens: req.maxTokens,
|
|
30
|
+
timeoutMs: req.timeoutMs,
|
|
31
|
+
profile: req.profile,
|
|
32
|
+
preferredProfile: req.preferredProfile,
|
|
33
|
+
authStore: req.authStore,
|
|
34
|
+
agentDir: req.agentDir,
|
|
35
|
+
cfg: req.cfg
|
|
36
|
+
}, options),
|
|
37
|
+
describeImages: async (req) => describeCodexImages(req, options),
|
|
38
|
+
extractStructured: async (req) => extractCodexStructured(req, options)
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
async function describeCodexImages(req, options) {
|
|
42
|
+
const model = req.model.trim();
|
|
43
|
+
if (!model) throw new Error("Codex image understanding requires model id.");
|
|
44
|
+
const { text } = await runBoundedCodexAppServerTurn({
|
|
45
|
+
config: req.cfg,
|
|
46
|
+
model: {
|
|
47
|
+
mode: "required",
|
|
48
|
+
id: model
|
|
49
|
+
},
|
|
50
|
+
profile: req.profile,
|
|
51
|
+
timeoutMs: req.timeoutMs,
|
|
52
|
+
agentDir: req.agentDir,
|
|
53
|
+
authProfileStore: req.authStore,
|
|
54
|
+
options,
|
|
55
|
+
taskLabel: "image understanding",
|
|
56
|
+
developerInstructions: "You are OpenClaw's bounded image-understanding worker. Describe only the provided image content. Do not call tools, edit files, or ask follow-up questions.",
|
|
57
|
+
input: [{
|
|
58
|
+
type: "text",
|
|
59
|
+
text: buildCodexImagePrompt(req),
|
|
60
|
+
text_elements: []
|
|
61
|
+
}, ...req.images.map((image) => ({
|
|
62
|
+
type: "image",
|
|
63
|
+
url: `data:${image.mime ?? "image/png"};base64,${image.buffer.toString("base64")}`
|
|
64
|
+
}))],
|
|
65
|
+
requiredModalities: ["text", "image"],
|
|
66
|
+
isolation: "configured-transport"
|
|
67
|
+
});
|
|
68
|
+
return {
|
|
69
|
+
text,
|
|
70
|
+
model
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
async function extractCodexStructured(req, options) {
|
|
74
|
+
const model = req.model.trim();
|
|
75
|
+
if (!model) throw new Error("Codex structured extraction requires model id.");
|
|
76
|
+
if (!req.instructions.trim()) throw new Error("Codex structured extraction requires instructions.");
|
|
77
|
+
if (req.input.length === 0) throw new Error("Codex structured extraction requires at least one input.");
|
|
78
|
+
if (!req.input.some((entry) => entry.type === "image")) throw new Error("Codex structured extraction requires at least one image input.");
|
|
79
|
+
const { text } = await runBoundedCodexAppServerTurn({
|
|
80
|
+
config: req.cfg,
|
|
81
|
+
model: {
|
|
82
|
+
mode: "required",
|
|
83
|
+
id: model
|
|
84
|
+
},
|
|
85
|
+
profile: req.profile,
|
|
86
|
+
timeoutMs: req.timeoutMs,
|
|
87
|
+
agentDir: req.agentDir,
|
|
88
|
+
authProfileStore: req.authStore,
|
|
89
|
+
options,
|
|
90
|
+
taskLabel: "structured extraction",
|
|
91
|
+
developerInstructions: "You are OpenClaw's bounded structured-extraction worker. Return only the requested extraction. Do not call tools, edit files, ask follow-up questions, or include secrets.",
|
|
92
|
+
input: buildCodexStructuredInput(req),
|
|
93
|
+
requiredModalities: requiredStructuredModalities(),
|
|
94
|
+
isolation: "configured-transport"
|
|
95
|
+
});
|
|
96
|
+
return normalizeStructuredExtractionResult({
|
|
97
|
+
text,
|
|
98
|
+
model,
|
|
99
|
+
provider: req.provider,
|
|
100
|
+
req
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
function buildCodexImagePrompt(req) {
|
|
104
|
+
const prompt = req.prompt?.trim() || DEFAULT_CODEX_IMAGE_PROMPT;
|
|
105
|
+
if (req.images.length <= 1) return prompt;
|
|
106
|
+
return `${prompt}\n\nAnalyze all ${req.images.length} images together.`;
|
|
107
|
+
}
|
|
108
|
+
function requiredStructuredModalities() {
|
|
109
|
+
return ["text", "image"];
|
|
110
|
+
}
|
|
111
|
+
function buildCodexStructuredInput(req) {
|
|
112
|
+
return [{
|
|
113
|
+
type: "text",
|
|
114
|
+
text: buildStructuredExtractionPrompt(req),
|
|
115
|
+
text_elements: []
|
|
116
|
+
}, ...req.input.map((entry) => {
|
|
117
|
+
if (entry.type === "text") return {
|
|
118
|
+
type: "text",
|
|
119
|
+
text: entry.text,
|
|
120
|
+
text_elements: []
|
|
121
|
+
};
|
|
122
|
+
return {
|
|
123
|
+
type: "image",
|
|
124
|
+
url: `data:${entry.mime ?? "image/png"};base64,${entry.buffer.toString("base64")}`
|
|
125
|
+
};
|
|
126
|
+
})];
|
|
127
|
+
}
|
|
128
|
+
function buildStructuredExtractionPrompt(req) {
|
|
129
|
+
return [
|
|
130
|
+
req.instructions.trim(),
|
|
131
|
+
req.schemaName ? `Schema name: ${req.schemaName}` : void 0,
|
|
132
|
+
req.jsonSchema ? `JSON schema:\n${JSON.stringify(req.jsonSchema)}` : void 0,
|
|
133
|
+
req.jsonMode === false ? "Return the extraction as concise text." : "Return valid JSON only. Do not wrap the JSON in Markdown fences."
|
|
134
|
+
].filter((part) => Boolean(part)).join("\n\n");
|
|
135
|
+
}
|
|
136
|
+
function isJsonSchemaObject(value) {
|
|
137
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
138
|
+
}
|
|
139
|
+
function normalizeStructuredExtractionResult(params) {
|
|
140
|
+
const result = {
|
|
141
|
+
text: params.text,
|
|
142
|
+
model: params.model,
|
|
143
|
+
provider: params.provider,
|
|
144
|
+
contentType: params.req.jsonMode === false ? "text" : "json"
|
|
145
|
+
};
|
|
146
|
+
if (params.req.jsonMode !== false) {
|
|
147
|
+
try {
|
|
148
|
+
result.parsed = JSON.parse(params.text);
|
|
149
|
+
} catch {
|
|
150
|
+
throw new Error("Codex structured extraction returned invalid JSON.");
|
|
151
|
+
}
|
|
152
|
+
if (isJsonSchemaObject(params.req.jsonSchema)) {
|
|
153
|
+
const validation = validateJsonSchemaValue({
|
|
154
|
+
schema: params.req.jsonSchema,
|
|
155
|
+
cacheKey: "codex.media-understanding.extractStructured",
|
|
156
|
+
value: result.parsed,
|
|
157
|
+
cache: false
|
|
158
|
+
});
|
|
159
|
+
if (!validation.ok) {
|
|
160
|
+
const message = validation.errors.map((error) => error.text).join("; ") || "invalid";
|
|
161
|
+
throw new Error(`Codex structured extraction JSON did not match schema: ${message}`);
|
|
162
|
+
}
|
|
163
|
+
result.parsed = validation.value;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
//#endregion
|
|
2
169
|
export { buildCodexMediaUnderstandingProvider };
|