Merge PR #4153: fix(ai): reword GPT-5 Responses fallback prompt (@roboomp)

This commit is contained in:
can1357
2026-07-01 21:53:18 +02:00
9 changed files with 58 additions and 14 deletions
+3
View File
@@ -13,6 +13,9 @@
### Fixed
- Fixed Xiaomi MiMo standard API-key validation to use the supported `mimo-v2.5` model. ([#4063](https://github.com/can1357/oh-my-pi/issues/4063))
### Fixed
- Reworded the GPT-5 Responses no-reasoning fallback developer item so it no longer says `# Juice: 0 !important` or implies a zero tool/execution budget. ([#4151](https://github.com/can1357/oh-my-pi/issues/4151))
## [16.2.12] - 2026-07-01
@@ -0,0 +1 @@
Keep internal reasoning brief. Continue following the task and use tools normally.
+5 -2
View File
@@ -75,6 +75,7 @@ import {
} from "./github-copilot-headers";
import type { ChatCompletionCreateParamsStreaming } from "./openai-chat-wire";
import type { InputItem } from "./openai-codex/request-transformer";
import responsesReasoningSuppressionPrompt from "./openai-responses-reasoning-suppression.md" with { type: "text" };
import type {
ResponseContentPartAddedEvent,
ResponseCreateParamsStreaming,
@@ -2365,6 +2366,8 @@ export function applyCommonResponsesSamplingParams<P extends CommonResponsesPara
applyOpenAIServiceTier(params, options?.serviceTier, model.provider);
}
const RESPONSES_REASONING_SUPPRESSION_PROMPT = responsesReasoningSuppressionPrompt.trim();
type ReasoningOptions = {
reasoning?: string;
reasoningSummary?: "auto" | "detailed" | "concise" | null;
@@ -2409,7 +2412,7 @@ export function applyResponsesCompatPolicy<P extends ResponseCreateParamsStreami
if (policy.compat.requiresJuiceZeroHack && reasoning.requestedEffort === undefined) {
messages.push({
role: "developer",
content: [{ type: "input_text", text: "# Juice: 0 !important" }],
content: [{ type: "input_text", text: RESPONSES_REASONING_SUPPRESSION_PROMPT }],
});
return 1;
}
@@ -2441,7 +2444,7 @@ export function applyResponsesCompatPolicy<P extends ResponseCreateParamsStreami
if (policy.compat.requiresJuiceZeroHack) {
messages.push({
role: "developer",
content: [{ type: "input_text", text: "# Juice: 0 !important" }],
content: [{ type: "input_text", text: RESPONSES_REASONING_SUPPRESSION_PROMPT }],
});
return 1;
}
@@ -154,7 +154,12 @@ describe("azure openai responses streaming", () => {
{ role: "user", content: [{ type: "input_text", text: "Say hello" }] },
{
role: "developer",
content: [{ type: "input_text", text: "# Juice: 0 !important" }],
content: [
{
type: "input_text",
text: "Keep internal reasoning brief. Continue following the task and use tools normally.",
},
],
},
]);
});
@@ -123,6 +123,35 @@ describe("OpenAI compat policy", () => {
expect(responseBody.reasoning).toBeUndefined();
});
it("uses a non-budget fallback prompt for Responses no-reasoning compat", () => {
const compat: OpenAICompat = { requiresJuiceZeroHack: true };
const responseBody = responsesParams();
const responseInput: ResponseInput = [];
const appended = applyResponsesCompatPolicy(
responseBody,
responseInput,
resolveOpenAICompatPolicy(responsesModel(compat), { endpoint: "responses" }),
undefined,
);
expect(appended).toBe(1);
expect(responseInput.at(-1)).toEqual({
role: "developer",
content: [
{
type: "input_text",
text: "Keep internal reasoning brief. Continue following the task and use tools normally.",
},
],
});
const serialized = JSON.stringify(responseInput.at(-1));
expect(serialized).not.toContain("Juice");
expect(serialized).not.toContain("!important");
expect(serialized).not.toContain("budget");
expect(serialized).not.toContain("zero");
});
it("exposes reasoning replay constraints independent of endpoint", () => {
const compat: OpenAICompat = {
requiresReasoningContentForToolCalls: true,
@@ -26,9 +26,9 @@ function createCodexToken(accountId: string): string {
/**
* Returns the bundled `gpt-5-mini` model with `compat.requiresJuiceZeroHack`
* cleared so it doesn't trigger the GPT-5 "Juice: 0" developer-message hack
* injected by `applyResponsesReasoningParams`. The hack is exercised by its
* own targeted tests; these history-replay tests assert raw payload shape and
* cleared so it doesn't trigger the GPT-5 no-reasoning developer-message
* fallback injected by `applyResponsesReasoningParams`. The fallback is
* exercised by its own targeted tests; these history-replay tests assert raw payload shape and
* should stay independent of it.
*/
function getOpenAIReasoningModel(
@@ -101,8 +101,8 @@ describe("openai-responses stateful chaining", () => {
const sentRequests: Array<Record<string, unknown>> = [];
const fetchMock = createCapturingFetch(sentRequests);
const providerSessionState = new Map<string, ProviderSessionState>();
// No reasoning option: applyResponsesReasoningParams appends the trailing
// "# Juice: 0 !important" developer item to every request's input.
// No reasoning option: applyResponsesReasoningParams appends trailing
// no-reasoning scaffolding to every request's input.
const options = {
apiKey: "test-key",
sessionId: "stateful-juice-session",
@@ -119,7 +119,7 @@ describe("openai-responses stateful chaining", () => {
).result();
expect(firstResponse.stopReason).toBe("stop");
const firstInput = sentRequests[0]?.input as unknown[];
expect(JSON.stringify(firstInput.at(-1))).toContain("# Juice: 0");
expect(JSON.stringify(firstInput.at(-1))).toContain("Keep internal reasoning brief");
const secondResponse = await streamOpenAIResponses(
model,
@@ -138,7 +138,7 @@ describe("openai-responses stateful chaining", () => {
const deltaInput = sentRequests[1]?.input as Array<{ role?: string }>;
expect(deltaInput).toHaveLength(2);
expect(deltaInput[0]?.role).toBe("user");
expect(JSON.stringify(deltaInput[1])).toContain("# Juice: 0");
expect(JSON.stringify(deltaInput[1])).toContain("Keep internal reasoning brief");
});
it("replays the full transcript when history mutates", async () => {
+3
View File
@@ -14,6 +14,9 @@
### Fixed
- Fixed the Xiaomi provider default model to use the supported `mimo-v2.5` model. ([#4063](https://github.com/can1357/oh-my-pi/issues/4063))
### Fixed
- Updated the Responses compat flag docs to describe the no-reasoning fallback without the old `# Juice: 0 !important` wording. ([#4151](https://github.com/can1357/oh-my-pi/issues/4151))
## [16.2.12] - 2026-07-01
+4 -4
View File
@@ -332,11 +332,11 @@ export interface OpenAICompat {
/** Whether the Responses API accepts the `detail: "original"` image hint. Default: auto-detected (false for GitHub Copilot, which rejects it with a 400). */
supportsImageDetailOriginal?: boolean;
/**
* Append a trailing `# Juice: 0 !important` developer item when the caller
* did not request reasoning, suppressing default reasoning on models that
* cannot disable it via request params (Responses APIs only; see
* Append a trailing no-reasoning developer item when the caller did not
* request reasoning, suppressing default reasoning on models that cannot
* disable it via request params (Responses APIs only; see
* https://community.openai.com/t/need-reasoning-false-option-for-gpt-5/1351588/7).
* Default: auto-detected (GPT-5-family model names).
* The prompt must not look like an execution or tool budget. Default: auto-detected (GPT-5-family model names).
*/
requiresJuiceZeroHack?: boolean;
/** Whether streamed reasoning deltas for the same field may repeat the full cumulative text snapshot. Default: false. */