mirror of https://github.com/openclaw/openclaw.git
feat(openai): add opt-in GPT personality
This commit is contained in:
parent
71fa5f481d
commit
dfd39a81d8
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<string, unknown>,
|
||||
): OpenAIPromptOverlayMode {
|
||||
return pluginConfig?.personalityOverlay === "off" ? "off" : "friendly";
|
||||
return pluginConfig?.personality === "friendly" ? "friendly" : "off";
|
||||
}
|
||||
|
||||
export function shouldApplyOpenAIPromptOverlay(params: {
|
||||
|
|
|
|||
Loading…
Reference in New Issue