Unverified 提交 9085b531 authored 作者: Will Chen's avatar Will Chen 提交者: GitHub

Propagate request id properly for OpenAI Response API model (e.g. GPT 5.2) (#2876)

## Summary - Improve compaction prompt/provider option handling in IPC handlers - Tighten local agent tool option passing and argument defaults - Align LLM engine provider option generation across related paths ## Test plan - npm run fmt - npm run lint:fix - npm run ts 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- devin-review-badge-begin --> --- <a href="https://app.devin.ai/review/dyad-sh/dyad/pull/2876" target="_blank"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open with Devin"> </picture> </a> <!-- devin-review-badge-end -->
上级 28bc0c04
...@@ -254,6 +254,7 @@ vi.mock("@/ipc/utils/token_utils", () => ({ ...@@ -254,6 +254,7 @@ vi.mock("@/ipc/utils/token_utils", () => ({
vi.mock("@/ipc/utils/provider_options", () => ({ vi.mock("@/ipc/utils/provider_options", () => ({
getProviderOptions: vi.fn(() => ({})), getProviderOptions: vi.fn(() => ({})),
getAiHeaders: vi.fn(() => ({})), getAiHeaders: vi.fn(() => ({})),
DYAD_INTERNAL_REQUEST_ID_HEADER: "x-dyad-internal-request-id",
})); }));
vi.mock("@/ipc/utils/mcp_manager", () => ({ vi.mock("@/ipc/utils/mcp_manager", () => ({
......
...@@ -24,7 +24,11 @@ import { ...@@ -24,7 +24,11 @@ import {
type CompactionMessage, type CompactionMessage,
} from "./compaction_storage"; } from "./compaction_storage";
import { getPostCompactionMessages } from "./compaction_utils"; import { getPostCompactionMessages } from "./compaction_utils";
import { getProviderOptions, getAiHeaders } from "@/ipc/utils/provider_options"; import {
getProviderOptions,
getAiHeaders,
DYAD_INTERNAL_REQUEST_ID_HEADER,
} from "@/ipc/utils/provider_options";
import { escapeXmlContent } from "../../../../shared/xmlEscape"; import { escapeXmlContent } from "../../../../shared/xmlEscape";
const logger = log.scope("compaction_handler"); const logger = log.scope("compaction_handler");
...@@ -174,9 +178,12 @@ export async function performCompaction( ...@@ -174,9 +178,12 @@ export async function performCompaction(
const summaryResult = streamText({ const summaryResult = streamText({
model: modelClient.model, model: modelClient.model,
headers: getAiHeaders({ headers: {
...getAiHeaders({
builtinProviderId: modelClient.builtinProviderId, builtinProviderId: modelClient.builtinProviderId,
}), }),
[DYAD_INTERNAL_REQUEST_ID_HEADER]: dyadRequestId,
},
providerOptions: getProviderOptions({ providerOptions: getProviderOptions({
dyadAppId: 0, dyadAppId: 0,
dyadRequestId, dyadRequestId,
......
...@@ -8,6 +8,7 @@ import { ...@@ -8,6 +8,7 @@ import {
import log from "electron-log"; import log from "electron-log";
import { getExtraProviderOptions } from "./thinking_utils"; import { getExtraProviderOptions } from "./thinking_utils";
import { DYAD_INTERNAL_REQUEST_ID_HEADER } from "./provider_options";
import type { UserSettings } from "../../lib/schemas"; import type { UserSettings } from "../../lib/schemas";
import type { LanguageModel } from "ai"; import type { LanguageModel } from "ai";
...@@ -118,6 +119,7 @@ export function createDyadEngine( ...@@ -118,6 +119,7 @@ export function createDyadEngine(
...JSON.parse(init.body), ...JSON.parse(init.body),
...getExtraProviderOptions(providerId, options.settings), ...getExtraProviderOptions(providerId, options.settings),
}; };
const dyadVersionedFiles = parsedBody.dyadVersionedFiles; const dyadVersionedFiles = parsedBody.dyadVersionedFiles;
if ("dyadVersionedFiles" in parsedBody) { if ("dyadVersionedFiles" in parsedBody) {
delete parsedBody.dyadVersionedFiles; delete parsedBody.dyadVersionedFiles;
...@@ -126,7 +128,14 @@ export function createDyadEngine( ...@@ -126,7 +128,14 @@ export function createDyadEngine(
if ("dyadFiles" in parsedBody) { if ("dyadFiles" in parsedBody) {
delete parsedBody.dyadFiles; delete parsedBody.dyadFiles;
} }
const requestId = parsedBody.dyadRequestId; // Read from body (OpenAICompatible models spread providerOptions into
// the body) with a fallback to an internal header (OpenAIResponses
// models don't forward providerOptions, so we pass it via header).
const requestId =
parsedBody.dyadRequestId ??
(init.headers as Record<string, string> | undefined)?.[
DYAD_INTERNAL_REQUEST_ID_HEADER
];
if ("dyadRequestId" in parsedBody) { if ("dyadRequestId" in parsedBody) {
delete parsedBody.dyadRequestId; delete parsedBody.dyadRequestId;
} }
...@@ -173,10 +182,12 @@ export function createDyadEngine( ...@@ -173,10 +182,12 @@ export function createDyadEngine(
} }
// Return modified request with files included and requestId in headers // Return modified request with files included and requestId in headers
const { [DYAD_INTERNAL_REQUEST_ID_HEADER]: _, ...outgoingHeaders } =
(init.headers as Record<string, string>) ?? {};
const modifiedInit = { const modifiedInit = {
...init, ...init,
headers: { headers: {
...init.headers, ...outgoingHeaders,
...(modifiedRequestId && { ...(modifiedRequestId && {
"X-Dyad-Request-Id": modifiedRequestId, "X-Dyad-Request-Id": modifiedRequestId,
}), }),
......
...@@ -86,6 +86,11 @@ export function getProviderOptions({ ...@@ -86,6 +86,11 @@ export function getProviderOptions({
return providerOptions; return providerOptions;
} }
// Header used to pass the request ID through AI SDK models that don't forward
// providerOptions into the request body (e.g. OpenAIResponsesLanguageModel).
export const DYAD_INTERNAL_REQUEST_ID_HEADER =
"x-dyad-internal-request-id" as const;
export interface GetAiHeadersParams { export interface GetAiHeadersParams {
builtinProviderId: string | undefined; builtinProviderId: string | undefined;
} }
......
...@@ -24,7 +24,11 @@ import { getDyadAppPath } from "@/paths/paths"; ...@@ -24,7 +24,11 @@ import { getDyadAppPath } from "@/paths/paths";
import { getModelClient } from "@/ipc/utils/get_model_client"; import { getModelClient } from "@/ipc/utils/get_model_client";
import { safeSend } from "@/ipc/utils/safe_sender"; import { safeSend } from "@/ipc/utils/safe_sender";
import { getMaxTokens, getTemperature } from "@/ipc/utils/token_utils"; import { getMaxTokens, getTemperature } from "@/ipc/utils/token_utils";
import { getProviderOptions, getAiHeaders } from "@/ipc/utils/provider_options"; import {
getProviderOptions,
getAiHeaders,
DYAD_INTERNAL_REQUEST_ID_HEADER,
} from "@/ipc/utils/provider_options";
import { import {
AgentToolName, AgentToolName,
...@@ -649,9 +653,12 @@ export async function handleLocalAgentStream( ...@@ -649,9 +653,12 @@ export async function handleLocalAgentStream(
try { try {
const streamResult = streamText({ const streamResult = streamText({
model: modelClient.model, model: modelClient.model,
headers: getAiHeaders({ headers: {
...getAiHeaders({
builtinProviderId: modelClient.builtinProviderId, builtinProviderId: modelClient.builtinProviderId,
}), }),
[DYAD_INTERNAL_REQUEST_ID_HEADER]: dyadRequestId,
},
providerOptions: getProviderOptions({ providerOptions: getProviderOptions({
dyadAppId: chat.app.id, dyadAppId: chat.app.id,
dyadRequestId, dyadRequestId,
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论