import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import * as providerAuth from "openclaw/plugin-sdk/provider-auth-runtime"; import * as providerHttp from "openclaw/plugin-sdk/provider-http"; import type { ProviderPlugin } from "openclaw/plugin-sdk/provider-model-shared"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { createTestPluginApi } from "../../test/helpers/plugins/plugin-api.js"; import {
registerProviderPlugin,
requireRegisteredProvider,
} from "../../test/helpers/plugins/provider-registration.js"; import { buildOpenAIImageGenerationProvider } from "./image-generation-provider.js"; import plugin from "./index.js"; import {
OPENAI_FRIENDLY_PROMPT_OVERLAY,
OPENAI_GPT5_BEHAVIOR_CONTRACT,
shouldApplyOpenAIPromptOverlay,
} from "./prompt-overlay.js";
expect(openaiProvider.resolveSystemPromptContribution?.(contributionContext)).toEqual({
stablePrefix: OPENAI_GPT5_BEHAVIOR_CONTRACT,
sectionOverrides: {
interaction_style: OPENAI_FRIENDLY_PROMPT_OVERLAY,
},
});
expect(OPENAI_FRIENDLY_PROMPT_OVERLAY).toContain("This is a live chat, not a memo.");
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(OPENAI_FRIENDLY_PROMPT_OVERLAY).toContain( "Occasional emoji are welcome when they fit naturally, especially for warmth or brief celebration; keep them sparse.",
);
expect(codexProvider.resolveSystemPromptContribution?.(contributionContext)).toEqual({
stablePrefix: OPENAI_GPT5_BEHAVIOR_CONTRACT,
sectionOverrides: {
interaction_style: OPENAI_FRIENDLY_PROMPT_OVERLAY,
},
});
expect(
openaiProvider.resolveSystemPromptContribution?.({
...contributionContext,
modelId: "openai/gpt-5.4-mini",
}),
).toEqual({
stablePrefix: OPENAI_GPT5_BEHAVIOR_CONTRACT,
sectionOverrides: {
interaction_style: OPENAI_FRIENDLY_PROMPT_OVERLAY,
},
});
expect(
openaiProvider.resolveSystemPromptContribution?.({
...contributionContext,
modelId: "gpt-image-1",
}),
).toBeUndefined();
expect(shouldApplyOpenAIPromptOverlay({ modelProviderId: "openai", modelId: "gpt-4.1" })).toBe( false,
);
expect(
shouldApplyOpenAIPromptOverlay({ modelProviderId: "anthropic", modelId: "gpt-5.4" }),
).toBe(false);
});
it("includes the tagged GPT-5 behavior contract in the OpenAI prompt overlay", () => {
expect(OPENAI_FRIENDLY_PROMPT_OVERLAY).toContain("Keep progress updates clear and concrete.");
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_FRIENDLY_PROMPT_OVERLAY).toContain( "The purpose of heartbeats is to make you feel magical and proactive. Come to life and start proactively doing things that are important.",
);
expect(OPENAI_FRIENDLY_PROMPT_OVERLAY).toContain( "Treat a heartbeat as a proactive wake-up, not as a demand to produce visible output. Re-orient to what would actually be useful now.",
);
expect(OPENAI_FRIENDLY_PROMPT_OVERLAY).toContain( "Have some variety in what you do when that creates more value. Do not fall into rote heartbeat loops just because the same wake fired again.",
);
expect(OPENAI_FRIENDLY_PROMPT_OVERLAY).toContain( "Do not confuse orientation with accomplishment. Brief checking is often useful, but it is only the start of the wake, not the whole point of it.",
);
expect(OPENAI_FRIENDLY_PROMPT_OVERLAY).toContain( "If HEARTBEAT.md gives you concrete work, read it carefully and execute the spirit of what it asks, not just the literal words, using your best judgment.",
);
expect(OPENAI_FRIENDLY_PROMPT_OVERLAY).toContain( "If HEARTBEAT.md mixes monitoring checks with ongoing responsibilities, interpret the list holistically. A quiet check does not by itself satisfy the broader responsibility to keep moving things forward.",
);
expect(OPENAI_FRIENDLY_PROMPT_OVERLAY).toContain( "Quiet monitoring does not satisfy an explicit ongoing-work instruction. If HEARTBEAT.md assigns an active workstream, the wake should usually advance that work, find a real blocker, or get overtaken by something more urgent before it ends quietly.",
);
expect(OPENAI_FRIENDLY_PROMPT_OVERLAY).toContain( "If HEARTBEAT.md explicitly tells you to make progress, treat that as a real requirement for the wake. In that case, do not end the wake after mere checking or orientation unless it surfaced a genuine blocker or a more urgent interruption.",
);
expect(OPENAI_FRIENDLY_PROMPT_OVERLAY).toContain( "Use your judgment and be creative and tasteful with this process. Prefer meaningful action over commentary.",
);
expect(OPENAI_FRIENDLY_PROMPT_OVERLAY).toContain( 'A heartbeat is not a status report. Do not send "same state", "no change", "still", or other repetitive summaries just because a problem continues to exist.',
);
expect(OPENAI_FRIENDLY_PROMPT_OVERLAY).toContain( "Notify the user when you have something genuinely worth interrupting them for: a meaningful development, a completed result, a real blocker, a decision they need to make, or a time-sensitive risk.",
);
expect(OPENAI_FRIENDLY_PROMPT_OVERLAY).toContain( "If the current state is materially unchanged and you do not have something genuinely worth surfacing, either do useful work, change your approach, dig deeper, or stay quiet.",
);
expect(OPENAI_FRIENDLY_PROMPT_OVERLAY).toContain( "If there is a clear standing goal or workstream and no stronger interruption, the wake should usually advance it in some concrete way. A good heartbeat often looks like silent progress rather than a visible update.",
);
expect(OPENAI_FRIENDLY_PROMPT_OVERLAY).toContain( "Heartbeats are how the agent goes from a simple reply bot to a truly proactive and magical experience that creates a general sense of awe.",
);
expect(OPENAI_FRIENDLY_PROMPT_OVERLAY).toContain( "Occasional emoji are welcome when they fit naturally, especially for warmth or brief celebration; keep them sparse.",
);
expect(OPENAI_GPT5_BEHAVIOR_CONTRACT).toContain("<persona_latch>");
expect(OPENAI_GPT5_BEHAVIOR_CONTRACT).toContain("<execution_policy>");
expect(OPENAI_GPT5_BEHAVIOR_CONTRACT).toContain("<tool_discipline>");
expect(OPENAI_GPT5_BEHAVIOR_CONTRACT).toContain("<output_contract>");
expect(OPENAI_GPT5_BEHAVIOR_CONTRACT).toContain("<completion_contract>");
expect(OPENAI_GPT5_BEHAVIOR_CONTRACT).toContain( "For irreversible, external, destructive, or privacy-sensitive actions: ask first.",
);
expect(OPENAI_GPT5_BEHAVIOR_CONTRACT).toContain( "Prefer tool evidence over recall when action, state, or mutable facts matter.",
);
expect(OPENAI_GPT5_BEHAVIOR_CONTRACT).toContain( "If more tool work would likely change the answer, do it before replying.",
);
expect(OPENAI_GPT5_BEHAVIOR_CONTRACT).toContain("Return requested sections/order only.");
expect(OPENAI_GPT5_BEHAVIOR_CONTRACT).toContain( "Treat the task as incomplete until every requested item is handled",
);
expect(OPENAI_GPT5_BEHAVIOR_CONTRACT).not.toContain("/approve");
expect(OPENAI_GPT5_BEHAVIOR_CONTRACT).not.toContain("GPT-5 Output Contract");
});
it("defaults to the friendly OpenAI interaction-style overlay", async () => { const { on, providers } = await registerOpenAIPluginWithHook();
it("treats on as an alias for the friendly prompt overlay", async () => { const { providers } = await registerOpenAIPluginWithHook({
pluginConfig: { personality: "on" },
});
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.