Skip to content

Commit 5f965b3

Browse files
committed
refactor: streamline Gemini options and remove incompatible tools
- Remove Google Search and URL Context tools (incompatible with function calling in standard API) - Refactor Gemini thinking config to support both 2.5 (budget) and 3.0 (level) - Remove manual 'include thoughts' option in favor of global thinking mode - Clean up unused Google provider options Change-Id: I445daecd93ebc25536442943604f17c335e5c707 Signed-off-by: Thomas Kosiewski <tk@coder.com>
1 parent fb016a0 commit 5f965b3

File tree

12 files changed

+45
-120
lines changed

12 files changed

+45
-120
lines changed

bun.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"name": "@coder/cmux",
66
"dependencies": {
77
"@ai-sdk/anthropic": "^2.0.44",
8-
"@ai-sdk/google": "^2.0.36",
8+
"@ai-sdk/google": "^2.0.38",
99
"@ai-sdk/openai": "^2.0.66",
1010
"@openrouter/ai-sdk-provider": "^1.2.2",
1111
"@radix-ui/react-dialog": "^1.1.15",
@@ -135,7 +135,7 @@
135135

136136
"@ai-sdk/gateway": ["@ai-sdk/gateway@2.0.10", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.17", "@vercel/oidc": "3.0.3" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-c++qOKfjKokTPAJ+vP9UXXNuTQ819yEDCZVXBhpZbgRly1P4fHTJbIAwuh+Qxxe9Bmtu8PEta0JGYZxc+hm7/Q=="],
137137

138-
"@ai-sdk/google": ["@ai-sdk/google@2.0.36", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.17" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-1Z2tV6A4PobK+zTKDd9NqqlDPh0lwF8yf8+FcOLCjHzyDB498iyiBFwKQ6lhQT8YYhY60jVsmsSvSTm+TOyazw=="],
138+
"@ai-sdk/google": ["@ai-sdk/google@2.0.38", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.17" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-z+RFCxRA/dSd3eCkGBlnk79nz3jv8vwaW42gVc+qDuMofNfvjRz19rjnkFNuYQ6cEUcPKCo0P1rD/JLeTN2Z5A=="],
139139

140140
"@ai-sdk/openai": ["@ai-sdk/openai@2.0.68", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.17" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-qUSLFkqgUoFArzBwttu0KWVAZYjbsdZGOklSJXpfZ2nDC61yseHxtcnuG8u6tqKnGXDh4eakEgREDWU2sRht7A=="],
141141

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
},
4747
"dependencies": {
4848
"@ai-sdk/anthropic": "^2.0.44",
49-
"@ai-sdk/google": "^2.0.36",
49+
"@ai-sdk/google": "^2.0.38",
5050
"@ai-sdk/openai": "^2.0.66",
5151
"@openrouter/ai-sdk-provider": "^1.2.2",
5252
"@radix-ui/react-dialog": "^1.1.15",

src/browser/App.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ function AppInner() {
338338

339339
const recommended =
340340
typeof branchResult?.recommendedTrunk === "string" &&
341-
sanitizedBranches.includes(branchResult.recommendedTrunk)
341+
sanitizedBranches.includes(branchResult.recommendedTrunk)
342342
? branchResult.recommendedTrunk
343343
: (sanitizedBranches[0] ?? "");
344344

@@ -578,9 +578,9 @@ function AppInner() {
578578
onCancel={
579579
pendingNewWorkspaceProject
580580
? () => {
581-
// User cancelled workspace creation - clear pending state
582-
clearPendingWorkspaceCreation();
583-
}
581+
// User cancelled workspace creation - clear pending state
582+
clearPendingWorkspaceCreation();
583+
}
584584
: undefined
585585
}
586586
/>

src/browser/components/AIView.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ import {
1515
} from "@/browser/utils/messages/messageUtils";
1616
import { hasInterruptedStream } from "@/browser/utils/messages/retryEligibility";
1717
import { ThinkingProvider } from "@/browser/contexts/ThinkingContext";
18-
import { ModeProvider } from "@/browser/contexts/ModeContext";import { ProviderOptionsProvider } from "@/browser/contexts/ProviderOptionsContext";
18+
import { ModeProvider } from "@/browser/contexts/ModeContext";
19+
import { ProviderOptionsProvider } from "@/browser/contexts/ProviderOptionsContext";
1920

2021
import { formatKeybind, KEYBINDS } from "@/browser/utils/ui/keybinds";
2122
import { useAutoScroll } from "@/browser/hooks/useAutoScroll";

src/browser/components/ChatInput/index.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -177,15 +177,15 @@ export const ChatInput: React.FC<ChatInputProps> = (props) => {
177177
const creationState = useCreationWorkspace(
178178
variant === "creation"
179179
? {
180-
projectPath: props.projectPath,
181-
onWorkspaceCreated: props.onWorkspaceCreated,
182-
}
180+
projectPath: props.projectPath,
181+
onWorkspaceCreated: props.onWorkspaceCreated,
182+
}
183183
: {
184-
// Dummy values for workspace variant (never used)
185-
projectPath: "",
186-
// eslint-disable-next-line @typescript-eslint/no-empty-function
187-
onWorkspaceCreated: () => { },
188-
}
184+
// Dummy values for workspace variant (never used)
185+
projectPath: "",
186+
// eslint-disable-next-line @typescript-eslint/no-empty-function
187+
onWorkspaceCreated: () => {},
188+
}
189189
);
190190

191191
const focusMessageInput = useCallback(() => {
@@ -988,7 +988,7 @@ export const ChatInput: React.FC<ChatInputProps> = (props) => {
988988
<ThinkingSliderComponent modelString={preferredModel} />
989989
</div>
990990

991-
<div className="flex items-center ml-4" data-component="ModelSettingsGroup">
991+
<div className="ml-4 flex items-center" data-component="ModelSettingsGroup">
992992
<ModelSettings provider={(preferredModel || "").split(":")[0]} />
993993
</div>
994994

@@ -1009,7 +1009,7 @@ export const ChatInput: React.FC<ChatInputProps> = (props) => {
10091009
</div>
10101010
)}
10111011

1012-
<div className="flex items-center gap-2 ml-auto" data-component="ModelControls">
1012+
<div className="ml-auto flex items-center gap-2" data-component="ModelControls">
10131013
<ModeSelector mode={mode} onChange={setMode} />
10141014
</div>
10151015
</div>

src/browser/components/ModelSettings.tsx

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ interface ModelSettingsProps {
77
}
88

99
export const ModelSettings: React.FC<ModelSettingsProps> = ({ provider }) => {
10-
const { options, setAnthropicOptions, setOpenAIOptions, setGoogleOptions } = useProviderOptions();
10+
const { options, setAnthropicOptions, setOpenAIOptions } = useProviderOptions();
1111

1212
const renderOption = (
1313
id: string,
@@ -55,26 +55,5 @@ export const ModelSettings: React.FC<ModelSettingsProps> = ({ provider }) => {
5555
);
5656
}
5757

58-
if (provider === "google") {
59-
return (
60-
<div className="flex flex-row gap-4">
61-
{renderOption(
62-
"google-search",
63-
"Search",
64-
options.google?.useSearchGrounding ?? false,
65-
(checked) => setGoogleOptions({ ...options.google, useSearchGrounding: checked }),
66-
"Use Google Search Grounding"
67-
)}
68-
{renderOption(
69-
"google-url",
70-
"URL",
71-
options.google?.useUrlContext ?? false,
72-
(checked) => setGoogleOptions({ ...options.google, useUrlContext: checked }),
73-
"Use URL Context tool for reading web pages"
74-
)}
75-
</div>
76-
);
77-
}
78-
7958
return null;
8059
};

src/browser/contexts/ProviderOptionsContext.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,7 @@ export function ProviderOptionsProvider({ children }: { children: React.ReactNod
2727

2828
const [googleOptions, setGoogleOptions] = usePersistedState<MuxProviderOptions["google"]>(
2929
"provider_options_google",
30-
{
31-
useSearchGrounding: false,
32-
useUrlContext: false,
33-
includeThoughts: false,
34-
}
30+
{}
3531
);
3632

3733
const value = {

src/browser/utils/messages/sendOptions.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,7 @@ function getProviderOptions(): MuxProviderOptions {
1919
const openai = readPersistedState<MuxProviderOptions["openai"]>("provider_options_openai", {
2020
disableAutoTruncation: false,
2121
});
22-
const google = readPersistedState<MuxProviderOptions["google"]>("provider_options_google", {
23-
useSearchGrounding: false,
24-
useUrlContext: false,
25-
includeThoughts: false,
26-
});
22+
const google = readPersistedState<MuxProviderOptions["google"]>("provider_options_google", {});
2723

2824
return {
2925
anthropic,

src/common/types/providerOptions.ts

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,8 @@ export interface OpenAIProviderOptions {
3232
/**
3333
* Google-specific options
3434
*/
35-
36-
export interface GoogleProviderOptions {
37-
/** Enable Google Search grounding */
38-
useSearchGrounding?: boolean;
39-
/** Enable URL context tool for reading web pages */
40-
useUrlContext?: boolean;
41-
/** Include thoughts in the response (e.g. for gemini-3-pro-preview) */
42-
includeThoughts?: boolean;
43-
/** Thinking level for Gemini 3+ models */
44-
thinkingLevel?: "low" | "high";
45-
/** Thinking budget (token count) for Gemini 2.5 models */
46-
thinkingBudget?: number;
47-
}
35+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
36+
export interface GoogleProviderOptions {}
4837

4938
/**
5039
* Ollama-specific options

src/common/utils/ai/providerOptions.ts

Lines changed: 16 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,6 @@ type ExtendedOpenAIResponsesProviderOptions = OpenAIResponsesProviderOptions & {
3535
truncation?: "auto" | "disabled";
3636
};
3737

38-
/**
39-
* Extended Google provider options to include thinkingLevel
40-
*
41-
* NOTE: The SDK types don't yet include this parameter, but it's supported by the Gemini 3 API.
42-
*/
43-
type ExtendedGoogleProviderOptions = GoogleGenerativeAIProviderOptions & {
44-
thinkingConfig?: {
45-
thinkingLevel?: ThinkingLevel;
46-
};
47-
};
48-
4938
/**
5039
* OpenRouter reasoning options
5140
* @see https://openrouter.ai/docs/use-cases/reasoning-tokens
@@ -64,7 +53,7 @@ interface OpenRouterReasoningOptions {
6453
type ProviderOptions =
6554
| { anthropic: AnthropicProviderOptions }
6655
| { openai: ExtendedOpenAIResponsesProviderOptions }
67-
| { google: ExtendedGoogleProviderOptions }
56+
| { google: GoogleGenerativeAIProviderOptions }
6857
| { openrouter: OpenRouterReasoningOptions }
6958
| Record<string, never>; // Empty object for unsupported providers
7059

@@ -220,31 +209,29 @@ export function buildProviderOptions(
220209
// Build Google-specific options
221210
if (provider === "google") {
222211
const isGemini3 = modelString.includes("gemini-3");
223-
let thinkingConfig: ExtendedGoogleProviderOptions["thinkingConfig"];
212+
let thinkingConfig: GoogleGenerativeAIProviderOptions["thinkingConfig"];
224213

225-
if (isGemini3) {
226-
// Gemini 3 uses thinkingLevel (low/high)
214+
if (effectiveThinking !== "off") {
227215
thinkingConfig = {
228216
includeThoughts: true,
229-
thinkingLevel: effectiveThinking === "medium" ? "low" : effectiveThinking,
230217
};
231-
} else if (effectiveThinking !== "off") {
232-
// Gemini 2.5 uses thinkingBudget
233-
const budget = GEMINI_THINKING_BUDGETS[effectiveThinking];
234-
if (budget > 0) {
235-
thinkingConfig = {
236-
includeThoughts: true,
237-
thinkingBudget: budget,
238-
};
218+
219+
if (isGemini3) {
220+
// Gemini 3 uses thinkingLevel (low/high)
221+
thinkingConfig.thinkingLevel = effectiveThinking === "medium" ? "low" : effectiveThinking;
222+
} else {
223+
// Gemini 2.5 uses thinkingBudget
224+
const budget = GEMINI_THINKING_BUDGETS[effectiveThinking];
225+
if (budget > 0) {
226+
thinkingConfig.thinkingBudget = budget;
227+
}
239228
}
240229
}
241230

242-
const googleOptions: ExtendedGoogleProviderOptions = {
243-
...(thinkingConfig && { thinkingConfig }),
244-
};
245-
246231
const options: ProviderOptions = {
247-
google: googleOptions,
232+
google: {
233+
thinkingConfig,
234+
},
248235
};
249236
log.debug("buildProviderOptions: Google options", options);
250237
return options;

0 commit comments

Comments
 (0)