diff --git a/extensions/codex/src/app-server/run-attempt.test.ts b/extensions/codex/src/app-server/run-attempt.test.ts index 15aa9ccb580..2fb9dabb547 100644 --- a/extensions/codex/src/app-server/run-attempt.test.ts +++ b/extensions/codex/src/app-server/run-attempt.test.ts @@ -368,6 +368,46 @@ describe("runCodexAppServerAttempt", () => { ).toEqual(["read", "exec", "message"]); }); + it("starts Codex threads without duplicate OpenClaw workspace tools by default", async () => { + const sessionFile = path.join(tempDir, "session.jsonl"); + const workspaceDir = path.join(tempDir, "workspace"); + const harness = createStartedThreadHarness(); + const params = { + ...createParams(sessionFile, workspaceDir), + disableTools: false, + provider: "openai", + modelId: "gpt-5.5", + model: createCodexTestModel("openai"), + agentDir: tempDir, + senderIsOwner: true, + } as EmbeddedRunAttemptParams; + + const run = runCodexAppServerAttempt(params); + await harness.waitForMethod("turn/start"); + await harness.completeTurn({ threadId: "thread-1", turnId: "turn-1" }); + await run; + + const startRequest = harness.requests.find((request) => request.method === "thread/start"); + const dynamicToolNames = ( + (startRequest?.params as { dynamicTools?: Array<{ name: string }> } | undefined) + ?.dynamicTools ?? [] + ).map((tool) => tool.name); + + expect(dynamicToolNames).toContain("message"); + expect(dynamicToolNames).toContain("web_search"); + expect(dynamicToolNames).not.toEqual( + expect.arrayContaining([ + "read", + "write", + "edit", + "apply_patch", + "exec", + "process", + "update_plan", + ]), + ); + }); + it("returns a failed dynamic tool response when an app-server tool call exceeds the deadline", async () => { vi.useFakeTimers(); let capturedSignal: AbortSignal | undefined; diff --git a/extensions/codex/src/app-server/thread-lifecycle.ts b/extensions/codex/src/app-server/thread-lifecycle.ts index 0f0bd6a9968..a60fdf89299 100644 --- a/extensions/codex/src/app-server/thread-lifecycle.ts +++ b/extensions/codex/src/app-server/thread-lifecycle.ts @@ -222,7 +222,7 @@ function stabilizeJsonValue(value: JsonValue): JsonValue { export function buildDeveloperInstructions(params: EmbeddedRunAttemptParams): string { const promptOverlay = renderCodexRuntimePromptOverlay(params); const sections = [ - "You are running inside OpenClaw. Use OpenClaw dynamic tools for messaging, cron, sessions, and host actions when available.", + "You are running inside OpenClaw. Use OpenClaw dynamic tools for OpenClaw-specific integrations such as messaging, cron, sessions, media, gateway, and nodes when available.", "Preserve the user's existing channel/session context. If sending a channel reply, use the OpenClaw messaging tool instead of describing that you would reply.", promptOverlay, params.extraSystemPrompt,