diff --git a/extensions/codex/src/app-server/thread-lifecycle.test.ts b/extensions/codex/src/app-server/thread-lifecycle.test.ts index d3b7890c9a16..66a4f1748228 100644 --- a/extensions/codex/src/app-server/thread-lifecycle.test.ts +++ b/extensions/codex/src/app-server/thread-lifecycle.test.ts @@ -478,6 +478,26 @@ describe("Codex app-server native code mode config", () => { dynamicTools: [], }, ); + const withWrongNamespace = buildDeveloperInstructions( + createAttemptParams({ provider: "openai" }), + { + dynamicTools: [ + { + type: "namespace", + name: "openclaw", + description: "", + tools: [ + { + type: "function", + name: "sessions_yield", + description: "Different tool with the same leaf name", + inputSchema: { type: "object" }, + }, + ], + }, + ], + }, + ); expect(withSessionsYield).toContain( "end the current turn with `openclaw_direct.sessions_yield`", @@ -488,6 +508,8 @@ describe("Codex app-server native code mode config", () => { expect(withSessionsYield).toContain("Never loop-poll for native child completion."); expect(withoutSessionsYield).not.toContain("`openclaw_direct.sessions_yield`"); expect(withoutSessionsYield).not.toContain("native `wait_agent`"); + expect(withWrongNamespace).not.toContain("`openclaw_direct.sessions_yield`"); + expect(withWrongNamespace).not.toContain("native `wait_agent`"); }); it("summarizes deferred dynamic tool names in developer instructions", () => { diff --git a/extensions/codex/src/app-server/thread-prompt.ts b/extensions/codex/src/app-server/thread-prompt.ts index faa6b19e6cf9..79d41063409d 100644 --- a/extensions/codex/src/app-server/thread-prompt.ts +++ b/extensions/codex/src/app-server/thread-prompt.ts @@ -4,7 +4,11 @@ import { type EmbeddedRunAttemptParams, } from "openclaw/plugin-sdk/agent-harness-runtime"; import { listRegisteredPluginAgentPromptGuidance } from "openclaw/plugin-sdk/plugin-runtime"; -import { flattenCodexDynamicToolFunctions, type CodexDynamicToolSpec } from "./protocol.js"; +import { + CODEX_OPENCLAW_DIRECT_DYNAMIC_TOOL_NAMESPACE, + flattenCodexDynamicToolFunctions, + type CodexDynamicToolSpec, +} from "./protocol.js"; export function buildDeveloperInstructions( params: EmbeddedRunAttemptParams, @@ -33,9 +37,14 @@ export function buildDeveloperInstructions( function buildNativeSubagentCompletionInstruction( dynamicTools: readonly CodexDynamicToolSpec[] | undefined, ): string | undefined { - const hasSessionsYield = flattenCodexDynamicToolFunctions(dynamicTools).some( - (tool) => tool.name.trim() === "sessions_yield", + const directNamespace = dynamicTools?.find( + (tool) => + tool.type === "namespace" && + tool.name.trim() === CODEX_OPENCLAW_DIRECT_DYNAMIC_TOOL_NAMESPACE, ); + const hasSessionsYield = + directNamespace?.type === "namespace" && + directNamespace.tools.some((tool) => tool.name.trim() === "sessions_yield"); if (!hasSessionsYield) { return undefined; }