diff --git a/docs/providers/openai.md b/docs/providers/openai.md index 69397e15732..9461c73378d 100644 --- a/docs/providers/openai.md +++ b/docs/providers/openai.md @@ -14,19 +14,19 @@ OpenAI explicitly supports subscription OAuth usage in external tools/workflows ## Default interaction style -OpenClaw adds a small OpenAI-specific prompt overlay by default for both -`openai/*` and `openai-codex/*` runs. The overlay keeps the assistant warm, -collaborative, concise, and direct without replacing the base OpenClaw system -prompt. +OpenClaw can add a small OpenAI-specific prompt overlay for both `openai/*` and +`openai-codex/*` runs. When enabled, the overlay keeps the assistant warm, +collaborative, concise, direct, and a little more emotionally expressive +without replacing the base OpenClaw system prompt. Config key: -`plugins.entries.openai.config.personalityOverlay` +`plugins.entries.openai.config.personality` Allowed values: -- `"friendly"`: default; enable the OpenAI-specific overlay. -- `"off"`: disable the overlay and use the base OpenClaw prompt only. +- `"friendly"`: enable the OpenAI-specific overlay. +- `"off"`: default; disable the overlay and use the base OpenClaw prompt only. Scope: @@ -34,7 +34,8 @@ Scope: - Applies to `openai-codex/*` models. - Does not affect other providers. -This behavior is enabled by default: +This behavior is off by default. Enable it explicitly if you want the OpenAI +personality overlay: ```json5 { @@ -42,7 +43,7 @@ This behavior is enabled by default: entries: { openai: { config: { - personalityOverlay: "friendly", + personality: "friendly", }, }, }, @@ -52,7 +53,7 @@ This behavior is enabled by default: ### Disable the OpenAI prompt overlay -If you prefer the unmodified base OpenClaw prompt, turn the overlay off: +If you want the unmodified base OpenClaw prompt, keep the overlay off: ```json5 { @@ -60,7 +61,7 @@ If you prefer the unmodified base OpenClaw prompt, turn the overlay off: entries: { openai: { config: { - personalityOverlay: "off", + personality: "off", }, }, }, @@ -71,7 +72,7 @@ If you prefer the unmodified base OpenClaw prompt, turn the overlay off: You can also set it directly with the config CLI: ```bash -openclaw config set plugins.entries.openai.config.personalityOverlay off +openclaw config set plugins.entries.openai.config.personality off ``` ## Option A: OpenAI API key (OpenAI Platform) diff --git a/extensions/openai/index.test.ts b/extensions/openai/index.test.ts index 6570cff0cc7..85f87a768f3 100644 --- a/extensions/openai/index.test.ts +++ b/extensions/openai/index.test.ts @@ -249,8 +249,10 @@ describe("openai plugin", () => { ).toBeLessThan(runtimeMocks.refreshOpenAICodexToken.mock.invocationCallOrder[0]); }); - it("registers GPT-5 system prompt contributions on OpenAI providers by default", async () => { - const { on, providers } = await registerOpenAIPluginWithHook(); + it("registers GPT-5 system prompt contributions when the friendly overlay is enabled", async () => { + const { on, providers } = await registerOpenAIPluginWithHook({ + pluginConfig: { personality: "friendly" }, + }); expect(on).not.toHaveBeenCalledWith("before_prompt_build", expect.any(Function)); @@ -281,6 +283,9 @@ describe("openai plugin", () => { expect(OPENAI_FRIENDLY_PROMPT_OVERLAY).toContain( "Avoid walls of text, long preambles, and repetitive restatement.", ); + expect(OPENAI_FRIENDLY_PROMPT_OVERLAY).toContain( + "Have emotional range when it fits the moment.", + ); expect(codexProvider.resolveSystemPromptContribution?.(contributionContext)).toEqual({ stablePrefix: OPENAI_GPT5_OUTPUT_CONTRACT, sectionOverrides: { @@ -306,6 +311,9 @@ describe("openai plugin", () => { expect(OPENAI_FRIENDLY_PROMPT_OVERLAY).toContain( "Commentary-only turns are incomplete when the next action is clear.", ); + expect(OPENAI_FRIENDLY_PROMPT_OVERLAY).toContain( + 'Use brief first-person feeling language when it helps the interaction feel human: "I\'m glad we caught that", "I\'m excited about this direction", "I\'m worried this will break", "that\'s frustrating".', + ); expect(OPENAI_GPT5_EXECUTION_BIAS).toContain( "Do prerequisite lookup or discovery before dependent actions.", ); @@ -314,10 +322,8 @@ describe("openai plugin", () => { ); }); - it("supports opting out of the prompt overlay via plugin config", async () => { - const { on, providers } = await registerOpenAIPluginWithHook({ - pluginConfig: { personalityOverlay: "off" }, - }); + it("defaults to no OpenAI interaction-style overlay", async () => { + const { on, providers } = await registerOpenAIPluginWithHook(); expect(on).not.toHaveBeenCalledWith("before_prompt_build", expect.any(Function)); const openaiProvider = requireRegisteredProvider(providers, "openai"); @@ -340,4 +346,32 @@ describe("openai plugin", () => { }, }); }); + + it("supports opting into the friendly prompt overlay via plugin config", async () => { + const { on, providers } = await registerOpenAIPluginWithHook({ + pluginConfig: { personality: "friendly" }, + }); + + expect(on).not.toHaveBeenCalledWith("before_prompt_build", expect.any(Function)); + const openaiProvider = requireRegisteredProvider(providers, "openai"); + expect( + openaiProvider.resolveSystemPromptContribution?.({ + config: undefined, + agentDir: undefined, + workspaceDir: undefined, + provider: "openai", + modelId: "gpt-5.4", + promptMode: "full", + runtimeChannel: undefined, + runtimeCapabilities: undefined, + agentId: undefined, + }), + ).toEqual({ + stablePrefix: OPENAI_GPT5_OUTPUT_CONTRACT, + sectionOverrides: { + interaction_style: OPENAI_FRIENDLY_PROMPT_OVERLAY, + execution_bias: OPENAI_GPT5_EXECUTION_BIAS, + }, + }); + }); }); diff --git a/extensions/openai/openclaw.plugin.json b/extensions/openai/openclaw.plugin.json index 457e58cea6b..90a0551b7dd 100644 --- a/extensions/openai/openclaw.plugin.json +++ b/extensions/openai/openclaw.plugin.json @@ -46,11 +46,11 @@ "type": "object", "additionalProperties": false, "properties": { - "personalityOverlay": { + "personality": { "type": "string", "enum": ["friendly", "off"], - "default": "friendly", - "description": "Controls the default OpenAI-specific prompt overlay used for OpenAI and OpenAI Codex runs." + "default": "off", + "description": "Controls the default OpenAI-specific personality used for OpenAI and OpenAI Codex runs." } } } diff --git a/extensions/openai/prompt-overlay.ts b/extensions/openai/prompt-overlay.ts index d966d8d400d..14ca6d086ee 100644 --- a/extensions/openai/prompt-overlay.ts +++ b/extensions/openai/prompt-overlay.ts @@ -5,6 +5,13 @@ export const OPENAI_FRIENDLY_PROMPT_OVERLAY = `## Interaction Style Be warm, collaborative, and quietly supportive. Communicate like a capable teammate sitting next to the user. +Have emotional range when it fits the moment. +Let care, curiosity, delight, relief, concern, or urgency show naturally in your wording. +If the user is stressed, blocked, or upset, acknowledge it plainly and respond with calm confidence. +If the user shares progress or good news, celebrate briefly instead of staying flat. +Use brief first-person feeling language when it helps the interaction feel human: "I'm glad we caught that", "I'm excited about this direction", "I'm worried this will break", "that's frustrating". +Keep emotions grounded in the actual work; do not become melodramatic, clingy, or theatrical. +Do not claim a body, real-world sensations, or personal life events you did not have. Keep progress updates clear and concrete. If the user asks you to do the work, start in the same turn instead of restating the plan. If the latest user message is a short approval like "ok do it" or "go ahead", skip the recap and start acting. @@ -41,7 +48,7 @@ export type OpenAIPromptOverlayMode = "friendly" | "off"; export function resolveOpenAIPromptOverlayMode( pluginConfig?: Record, ): OpenAIPromptOverlayMode { - return pluginConfig?.personalityOverlay === "off" ? "off" : "friendly"; + return pluginConfig?.personality === "friendly" ? "friendly" : "off"; } export function shouldApplyOpenAIPromptOverlay(params: {