






















@@ -10,8 +10,11 @@ import { CODEX_CONTROL_METHODS } from "./app-server/capabilities.js";
1010import {
1111codexSandboxPolicyForTurn,
1212resolveCodexAppServerRuntimeOptions,
13+type CodexAppServerApprovalPolicy,
14+type CodexAppServerSandboxMode,
1315} from "./app-server/config.js";
1416import {
17+type CodexServiceTier,
1518type CodexThreadResumeResponse,
1619type CodexThreadStartResponse,
1720type CodexTurnStartResponse,
@@ -59,6 +62,9 @@ type CodexConversationStartParams = {
5962model?: string;
6063modelProvider?: string;
6164authProfileId?: string;
65+approvalPolicy?: CodexAppServerApprovalPolicy;
66+sandbox?: CodexAppServerSandboxMode;
67+serviceTier?: CodexServiceTier;
6268};
63696470type BoundTurnResult = {
@@ -100,6 +106,9 @@ export async function startCodexConversationThread(
100106model: params.model,
101107modelProvider: params.modelProvider,
102108 authProfileId,
109+approvalPolicy: params.approvalPolicy,
110+sandbox: params.sandbox,
111+serviceTier: params.serviceTier,
103112config: params.config,
104113});
105114} else {
@@ -110,6 +119,9 @@ export async function startCodexConversationThread(
110119model: params.model,
111120modelProvider: params.modelProvider,
112121 authProfileId,
122+approvalPolicy: params.approvalPolicy,
123+sandbox: params.sandbox,
124+serviceTier: params.serviceTier,
113125config: params.config,
114126});
115127}
@@ -137,7 +149,7 @@ export async function handleCodexConversationInboundClaim(
137149}
138150try {
139151const result = await enqueueBoundTurn(data.sessionFile, () =>
140-runBoundTurn({
152+runBoundTurnWithMissingThreadRecovery({
141153 data,
142154 prompt,
143155 event,
@@ -177,9 +189,14 @@ async function attachExistingThread(params: {
177189model?: string;
178190modelProvider?: string;
179191authProfileId?: string;
192+approvalPolicy?: CodexAppServerApprovalPolicy;
193+sandbox?: CodexAppServerSandboxMode;
194+serviceTier?: CodexServiceTier;
180195config?: CodexAppServerAuthProfileLookup["config"];
181196}): Promise<void> {
182-const runtime = resolveCodexAppServerRuntimeOptions({ pluginConfig: params.pluginConfig });
197+const runtime = resolveCodexAppServerRuntimeOptions({
198+pluginConfig: params.pluginConfig,
199+});
183200const modelProvider = resolveThreadRequestModelProvider({
184201authProfileId: params.authProfileId,
185202modelProvider: params.modelProvider,
@@ -196,10 +213,12 @@ async function attachExistingThread(params: {
196213threadId: params.threadId,
197214 ...(params.model ? { model: params.model } : {}),
198215 ...(modelProvider ? { modelProvider } : {}),
199-approvalPolicy: runtime.approvalPolicy,
216+approvalPolicy: params.approvalPolicy ?? runtime.approvalPolicy,
200217approvalsReviewer: runtime.approvalsReviewer,
201-sandbox: runtime.sandbox,
202- ...(runtime.serviceTier ? { serviceTier: runtime.serviceTier } : {}),
218+sandbox: params.sandbox ?? runtime.sandbox,
219+ ...((params.serviceTier ?? runtime.serviceTier)
220+ ? { serviceTier: params.serviceTier ?? runtime.serviceTier }
221+ : {}),
203222persistExtendedHistory: true,
204223},
205224{ timeoutMs: runtime.requestTimeoutMs },
@@ -217,9 +236,9 @@ async function attachExistingThread(params: {
217236authProfileId: params.authProfileId,
218237modelProvider: response.modelProvider ?? params.modelProvider,
219238}),
220-approvalPolicy: runtime.approvalPolicy,
221-sandbox: runtime.sandbox,
222-serviceTier: runtime.serviceTier,
239+approvalPolicy: params.approvalPolicy ?? runtime.approvalPolicy,
240+sandbox: params.sandbox ?? runtime.sandbox,
241+serviceTier: params.serviceTier ?? runtime.serviceTier,
223242},
224243{
225244config: params.config,
@@ -234,9 +253,14 @@ async function createThread(params: {
234253model?: string;
235254modelProvider?: string;
236255authProfileId?: string;
256+approvalPolicy?: CodexAppServerApprovalPolicy;
257+sandbox?: CodexAppServerSandboxMode;
258+serviceTier?: CodexServiceTier;
237259config?: CodexAppServerAuthProfileLookup["config"];
238260}): Promise<void> {
239-const runtime = resolveCodexAppServerRuntimeOptions({ pluginConfig: params.pluginConfig });
261+const runtime = resolveCodexAppServerRuntimeOptions({
262+pluginConfig: params.pluginConfig,
263+});
240264const modelProvider = resolveThreadRequestModelProvider({
241265authProfileId: params.authProfileId,
242266modelProvider: params.modelProvider,
@@ -253,10 +277,12 @@ async function createThread(params: {
253277cwd: params.workspaceDir,
254278 ...(params.model ? { model: params.model } : {}),
255279 ...(modelProvider ? { modelProvider } : {}),
256-approvalPolicy: runtime.approvalPolicy,
280+approvalPolicy: params.approvalPolicy ?? runtime.approvalPolicy,
257281approvalsReviewer: runtime.approvalsReviewer,
258-sandbox: runtime.sandbox,
259- ...(runtime.serviceTier ? { serviceTier: runtime.serviceTier } : {}),
282+sandbox: params.sandbox ?? runtime.sandbox,
283+ ...((params.serviceTier ?? runtime.serviceTier)
284+ ? { serviceTier: params.serviceTier ?? runtime.serviceTier }
285+ : {}),
260286developerInstructions:
261287"This Codex thread is bound to an OpenClaw conversation. Answer normally; OpenClaw will deliver your final response back to the conversation.",
262288experimentalRawEvents: true,
@@ -276,9 +302,9 @@ async function createThread(params: {
276302authProfileId: params.authProfileId,
277303modelProvider: response.modelProvider ?? params.modelProvider,
278304}),
279-approvalPolicy: runtime.approvalPolicy,
280-sandbox: runtime.sandbox,
281-serviceTier: runtime.serviceTier,
305+approvalPolicy: params.approvalPolicy ?? runtime.approvalPolicy,
306+sandbox: params.sandbox ?? runtime.sandbox,
307+serviceTier: params.serviceTier ?? runtime.serviceTier,
282308},
283309{
284310config: params.config,
@@ -293,7 +319,9 @@ async function runBoundTurn(params: {
293319pluginConfig?: unknown;
294320timeoutMs?: number;
295321}): Promise<BoundTurnResult> {
296-const runtime = resolveCodexAppServerRuntimeOptions({ pluginConfig: params.pluginConfig });
322+const runtime = resolveCodexAppServerRuntimeOptions({
323+pluginConfig: params.pluginConfig,
324+});
297325const binding = await readCodexAppServerBinding(params.data.sessionFile);
298326const threadId = binding?.threadId;
299327if (!threadId) {
@@ -350,7 +378,10 @@ async function runBoundTurn(params: {
350378"turn/start",
351379{
352380 threadId,
353-input: buildCodexConversationTurnInput({ prompt: params.prompt, event: params.event }),
381+input: buildCodexConversationTurnInput({
382+prompt: params.prompt,
383+event: params.event,
384+}),
354385cwd: binding.cwd || params.data.workspaceDir,
355386approvalPolicy: binding.approvalPolicy ?? runtime.approvalPolicy,
356387approvalsReviewer: runtime.approvalsReviewer,
@@ -389,6 +420,39 @@ async function runBoundTurn(params: {
389420}
390421}
391422423+async function runBoundTurnWithMissingThreadRecovery(params: {
424+data: CodexConversationBindingData;
425+prompt: string;
426+event: PluginHookInboundClaimEvent;
427+pluginConfig?: unknown;
428+timeoutMs?: number;
429+}): Promise<BoundTurnResult> {
430+try {
431+return await runBoundTurn(params);
432+} catch (error) {
433+if (!isCodexThreadNotFoundError(error)) {
434+throw error;
435+}
436+const binding = await readCodexAppServerBinding(params.data.sessionFile);
437+await startCodexConversationThread({
438+pluginConfig: params.pluginConfig,
439+sessionFile: params.data.sessionFile,
440+workspaceDir: binding?.cwd || params.data.workspaceDir,
441+model: binding?.model,
442+modelProvider: binding?.modelProvider,
443+authProfileId: binding?.authProfileId,
444+approvalPolicy: binding?.approvalPolicy,
445+sandbox: binding?.sandbox,
446+serviceTier: binding?.serviceTier,
447+});
448+return await runBoundTurn(params);
449+}
450+}
451+452+function isCodexThreadNotFoundError(error: unknown): boolean {
453+return /\bthread not found:/iu.test(formatErrorMessage(error));
454+}
455+392456function enqueueBoundTurn<T>(key: string, run: () => Promise<T>): Promise<T> {
393457const state = getGlobalState();
394458const previous = state.queues.get(key) ?? Promise.resolve();
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。