Replace thinking with native Gemini thinking summaries (#400)

This uses Gemini's native [thinking
summaries](https://cloud.google.com/vertex-ai/generative-ai/docs/thinking#thought-summaries)
which were recently added to the API.

Why? The grafted thinking would sometimes cause weird issues where the
model, especially Gemini 2.5 Flash, got confused and put dyad tags like
`<dyad-write>` inside the `<think>` tags.

This also improves the UX because you can see the native thoughts rather
than having the Gemini response load for a while without any feedback.

I tried adding Anthropic extended thinking, however it requires temp to
be set at 1, which isn't ideal for Dyad's use case where we need precise
syntax following.
This commit is contained in:
Will Chen
2025-06-16 17:29:32 -07:00
committed by GitHub
parent 3a6ab12bed
commit 30b5c0d0ef
39 changed files with 1020 additions and 628 deletions

View File

@@ -116,6 +116,7 @@ export async function getModelClient(
? createDyadEngine({
apiKey: dyadApiKey,
baseURL: dyadEngineUrl ?? "https://engine.dyad.sh/v1",
originalProviderId: model.provider,
dyadOptions: {
enableLazyEdits: settings.enableProLazyEditsMode,
enableSmartFilesContext: settings.enableProSmartFilesContextMode,
@@ -150,7 +151,7 @@ export async function getModelClient(
}
: undefined,
),
builtinProviderId: "auto",
builtinProviderId: model.provider,
};
return {

View File

@@ -11,6 +11,7 @@ import {
import { OpenAICompatibleChatSettings } from "@ai-sdk/openai-compatible";
import log from "electron-log";
import { getExtraProviderOptions } from "./thinking_utils";
const logger = log.scope("llm_engine_provider");
@@ -42,6 +43,7 @@ or to provide a custom fetch implementation for e.g. testing.
*/
fetch?: FetchFunction;
originalProviderId: string;
dyadOptions: {
enableLazyEdits?: boolean;
enableSmartFilesContext?: boolean;
@@ -113,42 +115,43 @@ export function createDyadEngine(
defaultObjectGenerationMode:
"tool" as LanguageModelV1ObjectGenerationMode,
// Custom fetch implementation that adds files to the request
fetch: files?.length
? (input: RequestInfo | URL, init?: RequestInit) => {
// Use default fetch if no init or body
if (!init || !init.body || typeof init.body !== "string") {
return (options.fetch || fetch)(input, init);
}
fetch: (input: RequestInfo | URL, init?: RequestInit) => {
// Use default fetch if no init or body
if (!init || !init.body || typeof init.body !== "string") {
return (options.fetch || fetch)(input, init);
}
try {
// Parse the request body to manipulate it
const parsedBody = JSON.parse(init.body);
try {
// Parse the request body to manipulate it
const parsedBody = {
...JSON.parse(init.body),
...getExtraProviderOptions(options.originalProviderId),
};
// Add files to the request if they exist
if (files?.length) {
parsedBody.dyad_options = {
files,
enable_lazy_edits: options.dyadOptions.enableLazyEdits,
enable_smart_files_context:
options.dyadOptions.enableSmartFilesContext,
};
}
// Return modified request with files included
const modifiedInit = {
...init,
body: JSON.stringify(parsedBody),
};
// Use the provided fetch or default fetch
return (options.fetch || fetch)(input, modifiedInit);
} catch (e) {
logger.error("Error parsing request body", e);
// If parsing fails, use original request
return (options.fetch || fetch)(input, init);
}
// Add files to the request if they exist
if (files?.length) {
parsedBody.dyad_options = {
files,
enable_lazy_edits: options.dyadOptions.enableLazyEdits,
enable_smart_files_context:
options.dyadOptions.enableSmartFilesContext,
};
}
: options.fetch,
// Return modified request with files included
const modifiedInit = {
...init,
body: JSON.stringify(parsedBody),
};
// Use the provided fetch or default fetch
return (options.fetch || fetch)(input, modifiedInit);
} catch (e) {
logger.error("Error parsing request body", e);
// If parsing fails, use original request
return (options.fetch || fetch)(input, init);
}
},
};
return new OpenAICompatibleChatLanguageModel(modelId, restSettings, config);

View File

@@ -0,0 +1,18 @@
import { PROVIDERS_THAT_SUPPORT_THINKING } from "../shared/language_model_helpers";
export function getExtraProviderOptions(
providerId: string | undefined,
): Record<string, any> {
if (!providerId) {
return {};
}
if (PROVIDERS_THAT_SUPPORT_THINKING.includes(providerId)) {
return {
thinking: {
type: "enabled",
include_thoughts: true,
},
};
}
return {};
}