Skip to content

Commit 7139f47

Browse files
committed
docs: document codex dynamic tool bridge
1 parent 381a51b commit 7139f47

4 files changed

Lines changed: 51 additions & 0 deletions

File tree

extensions/codex/src/app-server/dynamic-tool-diagnostics.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
/**
2+
* Trusted diagnostics emitted around Codex dynamic tool execution lifecycle.
3+
*/
14
import { emitTrustedDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
25
import type { CodexDynamicToolCallParams, CodexDynamicToolCallResponse } from "./protocol.js";
36

@@ -8,6 +11,7 @@ type DynamicToolDiagnosticContext = {
811
sessionKey?: string | undefined;
912
};
1013

14+
/** Emits a start event for one Codex dynamic tool call. */
1115
export function emitDynamicToolStartedDiagnostic(params: DynamicToolDiagnosticContext): void {
1216
emitTrustedDiagnosticEvent({
1317
type: "tool.execution.started",
@@ -19,6 +23,7 @@ export function emitDynamicToolStartedDiagnostic(params: DynamicToolDiagnosticCo
1923
});
2024
}
2125

26+
/** Emits an error event for one Codex dynamic tool call. */
2227
export function emitDynamicToolErrorDiagnostic(
2328
params: DynamicToolDiagnosticContext & {
2429
durationMs: number;
@@ -36,6 +41,7 @@ export function emitDynamicToolErrorDiagnostic(
3641
});
3742
}
3843

44+
/** Emits the terminal event matching a dynamic tool response's diagnostic type. */
3945
export function emitDynamicToolTerminalDiagnostic(
4046
params: DynamicToolDiagnosticContext & {
4147
response: CodexDynamicToolCallResponse;

extensions/codex/src/app-server/dynamic-tool-execution.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
/**
2+
* Timeout, terminal-release, and diagnostic helpers for Codex dynamic tool
3+
* calls.
4+
*/
15
import {
26
embeddedAgentLog,
37
type EmbeddedRunAttemptParams,
@@ -15,10 +19,14 @@ import {
1519
type JsonValue,
1620
} from "./protocol.js";
1721

22+
/** Default timeout for Codex dynamic tool calls. */
1823
export const CODEX_DYNAMIC_TOOL_TIMEOUT_MS = 90_000;
24+
/** Hard cap for per-call Codex dynamic tool timeout overrides. */
1925
export const CODEX_DYNAMIC_TOOL_MAX_TIMEOUT_MS = 600_000;
2026
const CODEX_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS = 120_000;
27+
/** Timeout for image-understanding style dynamic tool calls. */
2128
export const CODEX_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS = 60_000;
29+
/** Timeout for message-delivery dynamic tool calls. */
2230
export const CODEX_DYNAMIC_MESSAGE_TOOL_TIMEOUT_MS = 120_000;
2331
const LOG_FIELD_MAX_LENGTH = 160;
2432

@@ -109,6 +117,10 @@ function formatDynamicToolTimeoutDetails(params: {
109117
};
110118
}
111119

120+
/**
121+
* Runs a dynamic tool call with run-abort and per-call timeout handling,
122+
* returning a Codex protocol response instead of throwing.
123+
*/
112124
export async function handleDynamicToolCallWithTimeout(params: {
113125
call: CodexDynamicToolCallParams;
114126
toolBridge: Pick<CodexDynamicToolBridge, "handleToolCall">;
@@ -199,6 +211,7 @@ function failedDynamicToolResponse(
199211
return response;
200212
}
201213

214+
/** Strips OpenClaw-only metadata before sending a dynamic tool response to Codex. */
202215
export function toCodexDynamicToolProtocolResponse(
203216
response: CodexDynamicToolCallResponse,
204217
): CodexDynamicToolCallResponse {
@@ -208,6 +221,7 @@ export function toCodexDynamicToolProtocolResponse(
208221
};
209222
}
210223

224+
/** Adds async-started progress details when a tool result continues out of band. */
211225
export function toCodexDynamicToolProgressResponse(
212226
response: CodexDynamicToolCallResponse,
213227
protocolResponse: CodexDynamicToolCallResponse,
@@ -236,6 +250,7 @@ type TerminalDynamicToolReleaseState = {
236250
pendingOpenClawDynamicToolCompletionIdsCount: number;
237251
};
238252

253+
/** Decides whether a terminal dynamic tool response can release the Codex turn. */
239254
export function shouldReleaseTurnAfterTerminalDynamicTool(
240255
state: TerminalDynamicToolReleaseState,
241256
): boolean {
@@ -250,12 +265,14 @@ export function shouldReleaseTurnAfterTerminalDynamicTool(
250265
);
251266
}
252267

268+
/** Returns true when a non-async result should block terminal-release shortcuts. */
253269
export function shouldBlockTerminalReleaseForNonTerminalDynamicToolResult(
254270
response: CodexDynamicToolCallResponse,
255271
): boolean {
256272
return response.asyncStarted !== true;
257273
}
258274

275+
/** Action chosen after checking terminal dynamic-tool diagnostics. */
259276
export type TerminalDynamicToolBatchAction =
260277
| "idle"
261278
| "wait"
@@ -270,6 +287,7 @@ type TerminalDynamicToolBatchState = {
270287
hasPendingTerminalDynamicToolRelease: boolean;
271288
};
272289

290+
/** Resolves whether terminal diagnostic state should release, wait, or stay idle. */
273291
export function resolveTerminalDynamicToolBatchAction(
274292
state: TerminalDynamicToolBatchState,
275293
): TerminalDynamicToolBatchAction {
@@ -289,6 +307,7 @@ export function resolveTerminalDynamicToolBatchAction(
289307
return "idle";
290308
}
291309

310+
/** Returns true for diagnostic events that terminate a dynamic tool call. */
292311
export function isDynamicToolTerminalDiagnosticEvent(
293312
event: DiagnosticEventPayload,
294313
): event is TerminalToolExecutionDiagnostic {
@@ -299,6 +318,7 @@ export function isDynamicToolTerminalDiagnosticEvent(
299318
);
300319
}
301320

321+
/** Matches terminal diagnostics to a specific dynamic tool call id/name. */
302322
export function isMatchingDynamicToolTerminalDiagnostic(params: {
303323
event: TerminalToolExecutionDiagnostic;
304324
call: CodexDynamicToolCallParams;
@@ -328,6 +348,7 @@ export function isMatchingDynamicToolTerminalDiagnostic(params: {
328348
);
329349
}
330350

351+
/** Checks pending diagnostics for a terminal event matching a tool call. */
331352
export function hasPendingDynamicToolTerminalDiagnostic(params: {
332353
call: CodexDynamicToolCallParams;
333354
runId?: string;
@@ -348,6 +369,7 @@ export function hasPendingDynamicToolTerminalDiagnostic(params: {
348369
});
349370
}
350371

372+
/** Resolves per-tool timeout, applying media/message defaults and hard caps. */
351373
export function resolveDynamicToolCallTimeoutMs(params: {
352374
call: CodexDynamicToolCallParams;
353375
config: EmbeddedRunAttemptParams["config"];

extensions/codex/src/app-server/dynamic-tool-profile.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
/**
2+
* Dynamic tool profile rules for Codex app-server tool loading and filtering.
3+
*/
14
import type { CodexDynamicToolsLoading, CodexPluginConfig } from "./config.js";
25

6+
/** Tool names owned by Codex app-server and normally excluded from OpenClaw dynamic tools. */
37
export const CODEX_APP_SERVER_OWNED_DYNAMIC_TOOL_EXCLUDES = [
48
"read",
59
"write",
@@ -24,11 +28,13 @@ type CodexDynamicToolProfileEnv = {
2428
OPENCLAW_QA_FORCE_RUNTIME?: string;
2529
};
2630

31+
/** Normalizes OpenClaw/Codex tool names before filtering and allowlist checks. */
2732
export function normalizeCodexDynamicToolName(name: string): string {
2833
const normalized = name.trim().toLowerCase();
2934
return DYNAMIC_TOOL_NAME_ALIASES[normalized] ?? normalized;
3035
}
3136

37+
/** Returns true for private QA runs that force the Codex runtime profile. */
3238
export function isForcedPrivateQaCodexRuntime(
3339
env: CodexDynamicToolProfileEnv = process.env,
3440
): boolean {
@@ -38,6 +44,7 @@ export function isForcedPrivateQaCodexRuntime(
3844
);
3945
}
4046

47+
/** Resolves whether dynamic tools load directly or through Codex tool search. */
4148
export function resolveCodexDynamicToolsLoading(
4249
config: Pick<CodexPluginConfig, "codexDynamicToolsLoading">,
4350
env: CodexDynamicToolProfileEnv = process.env,
@@ -55,14 +62,17 @@ function normalizeCodexModelId(modelId: string | undefined): string {
5562
return normalized.includes("/") ? normalized.split("/").at(-1)! : normalized;
5663
}
5764

65+
/** Returns true when model behavior requires direct dynamic-tool registration. */
5866
export function shouldUseDirectCodexDynamicToolsForModel(modelId: string | undefined): boolean {
5967
return shouldDisableCodexToolSearchForModel(modelId);
6068
}
6169

70+
/** Returns true for models whose tool-search path is unsupported or inefficient. */
6271
export function shouldDisableCodexToolSearchForModel(modelId: string | undefined): boolean {
6372
return normalizeCodexModelId(modelId) === "gpt-5.4-nano";
6473
}
6574

75+
/** Resolves dynamic-tool loading after applying model-specific restrictions. */
6676
export function resolveCodexDynamicToolsLoadingForModel(
6777
config: Pick<CodexPluginConfig, "codexDynamicToolsLoading">,
6878
modelId: string | undefined,
@@ -74,6 +84,7 @@ export function resolveCodexDynamicToolsLoadingForModel(
7484
: loading;
7585
}
7686

87+
/** Filters OpenClaw tools that Codex owns natively or config explicitly excludes. */
7788
export function filterCodexDynamicTools<T extends { name: string }>(
7889
tools: T[],
7990
config: Pick<CodexPluginConfig, "codexDynamicToolsExclude">,

extensions/codex/src/app-server/dynamic-tools.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
/**
2+
* Bridges OpenClaw runtime tools into Codex app-server dynamic tool specs and
3+
* tool-call responses.
4+
*/
15
import type { AgentToolResult } from "openclaw/plugin-sdk/agent-core";
26
import {
37
createAgentToolResultMiddlewareRunner,
@@ -59,6 +63,7 @@ type CodexDynamicToolSchemaQuarantine = {
5963
violations: readonly string[];
6064
};
6165

66+
/** Runtime bridge returned to Codex app-server attempt code. */
6267
export type CodexDynamicToolBridge = {
6368
availableSpecs: CodexDynamicToolSpec[];
6469
specs: CodexDynamicToolSpec[];
@@ -80,13 +85,18 @@ export type CodexDynamicToolBridge = {
8085
};
8186
};
8287

88+
/** Namespace attached to OpenClaw-owned dynamic tools exposed to Codex. */
8389
export const CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE = "openclaw";
8490

8591
// Keep OpenClaw session spawning searchable in Codex mode so Codex's native
8692
// spawn_agent remains the primary Codex subagent surface.
8793
const ALWAYS_DIRECT_DYNAMIC_TOOL_NAMES = new Set(["sessions_yield"]);
8894
const DEFAULT_CODEX_DYNAMIC_TOOL_RESULT_MAX_CHARS = 16_000;
8995

96+
/**
97+
* Creates dynamic tool specs and a call handler that executes OpenClaw tools,
98+
* applies hooks/middleware, and records delivery/media telemetry.
99+
*/
90100
export function createCodexDynamicToolBridge(params: {
91101
tools: AnyAgentTool[];
92102
registeredTools?: AnyAgentTool[];
@@ -183,6 +193,8 @@ export function createCodexDynamicToolBridge(params: {
183193
const signal = composeAbortSignals(params.signal, options?.signal);
184194
let didStartExecution = false;
185195
try {
196+
// Prepare before marking side-effect evidence; argument preparation can
197+
// fail without the target tool actually starting.
186198
const preparedArgs = tool.prepareArguments ? tool.prepareArguments(args) : args;
187199
didStartExecution = true;
188200
const rawResult = await tool.execute(call.callId, preparedArgs, signal);

0 commit comments

Comments
 (0)