





















@@ -141,6 +141,7 @@ const CODEX_DYNAMIC_TOOL_MAX_TIMEOUT_MS = 600_000;
141141const CODEX_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS = 60_000;
142142const CODEX_APP_SERVER_STARTUP_CONNECTION_CLOSE_MAX_ATTEMPTS = 3;
143143const CODEX_APP_SERVER_STARTUP_TIMEOUT_FLOOR_MS = 100;
144+const CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS = 5_000;
144145const CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS = 5_000;
145146const CODEX_TURN_COMPLETION_IDLE_TIMEOUT_MS = 60_000;
146147const CODEX_TURN_TERMINAL_IDLE_TIMEOUT_MS = 30 * 60_000;
@@ -1499,10 +1500,19 @@ export async function runCodexAppServerAttempt(
14991500);
1500150115011502const abortListener = () => {
1503+const shouldRetireClient = timedOut;
15021504interruptCodexTurnBestEffort(client, {
15031505threadId: thread.threadId,
15041506turnId: activeTurnId,
1507+timeoutMs: shouldRetireClient ? CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS : undefined,
15051508});
1509+if (shouldRetireClient) {
1510+retireCodexAppServerClientAfterTimedOutTurn(client, {
1511+threadId: thread.threadId,
1512+turnId: activeTurnId,
1513+reason: String(runAbortController.signal.reason ?? "timeout"),
1514+});
1515+}
15061516resolveCompletion?.();
15071517};
15081518runAbortController.signal.addEventListener("abort", abortListener, { once: true });
@@ -1977,13 +1987,47 @@ function interruptCodexTurnBestEffort(
19771987params: {
19781988threadId: string;
19791989turnId: string;
1990+timeoutMs?: number;
19801991},
19811992): void {
1982-void Promise.resolve()
1983-.then(() => client.request("turn/interrupt", params))
1984-.catch((error: unknown) => {
1993+const requestOptions =
1994+params.timeoutMs && Number.isFinite(params.timeoutMs) && params.timeoutMs > 0
1995+ ? { timeoutMs: params.timeoutMs }
1996+ : undefined;
1997+const requestParams = { threadId: params.threadId, turnId: params.turnId };
1998+try {
1999+const interrupt = requestOptions
2000+ ? client.request("turn/interrupt", requestParams, requestOptions)
2001+ : client.request("turn/interrupt", requestParams);
2002+void Promise.resolve(interrupt).catch((error: unknown) => {
19852003embeddedAgentLog.debug("codex app-server turn interrupt failed during abort", { error });
19862004});
2005+} catch (error) {
2006+embeddedAgentLog.debug("codex app-server turn interrupt failed during abort", { error });
2007+}
2008+}
2009+2010+function retireCodexAppServerClientAfterTimedOutTurn(
2011+client: CodexAppServerClient,
2012+params: {
2013+threadId: string;
2014+turnId: string;
2015+reason: string;
2016+},
2017+): void {
2018+const clearedSharedClient = clearSharedCodexAppServerClientIfCurrent(client);
2019+if (!clearedSharedClient) {
2020+const close = (client as { close?: () => void }).close;
2021+if (typeof close === "function") {
2022+close.call(client);
2023+}
2024+}
2025+embeddedAgentLog.warn("codex app-server client retired after timed-out turn", {
2026+threadId: params.threadId,
2027+turnId: params.turnId,
2028+reason: params.reason,
2029+ clearedSharedClient,
2030+});
19872031}
1988203219892033type DynamicToolBuildParams = {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。