feat(prefs): add search_provider to preferences.md (#1001)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
fe0f4f35e6
commit
01e28bc345
3 changed files with 36 additions and 3 deletions
|
|
@ -80,6 +80,7 @@ const KNOWN_PREFERENCE_KEYS = new Set<string>([
|
|||
"verification_commands",
|
||||
"verification_auto_fix",
|
||||
"verification_max_retries",
|
||||
"search_provider",
|
||||
]);
|
||||
|
||||
export interface GSDSkillRule {
|
||||
|
|
@ -182,6 +183,8 @@ export interface GSDPreferences {
|
|||
verification_commands?: string[];
|
||||
verification_auto_fix?: boolean;
|
||||
verification_max_retries?: number;
|
||||
/** Search provider preference. "brave"/"tavily"/"ollama" force that backend and disable native Anthropic search. "native" forces native only. "auto" = current default behavior. */
|
||||
search_provider?: "brave" | "tavily" | "ollama" | "native" | "auto";
|
||||
}
|
||||
|
||||
export interface LoadedGSDPreferences {
|
||||
|
|
@ -759,6 +762,15 @@ export function resolveInlineLevel(): InlineLevel {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the search provider preference from preferences.md.
|
||||
* Returns undefined if not configured (caller falls back to existing behavior).
|
||||
*/
|
||||
export function resolveSearchProviderFromPreferences(): GSDPreferences["search_provider"] | undefined {
|
||||
const prefs = loadEffectiveGSDPreferences();
|
||||
return prefs?.preferences.search_provider;
|
||||
}
|
||||
|
||||
function mergePreferences(base: GSDPreferences, override: GSDPreferences): GSDPreferences {
|
||||
return {
|
||||
version: override.version ?? base.version,
|
||||
|
|
@ -801,6 +813,7 @@ function mergePreferences(base: GSDPreferences, override: GSDPreferences): GSDPr
|
|||
verification_commands: mergeStringLists(base.verification_commands, override.verification_commands),
|
||||
verification_auto_fix: override.verification_auto_fix ?? base.verification_auto_fix,
|
||||
verification_max_retries: override.verification_max_retries ?? base.verification_max_retries,
|
||||
search_provider: override.search_provider ?? base.search_provider,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -935,6 +948,16 @@ export function validatePreferences(preferences: GSDPreferences): {
|
|||
}
|
||||
}
|
||||
|
||||
// ─── Search Provider ─────────────────────────────────────────────
|
||||
if (preferences.search_provider !== undefined) {
|
||||
const validSearchProviders = new Set(["brave", "tavily", "ollama", "native", "auto"]);
|
||||
if (typeof preferences.search_provider === "string" && validSearchProviders.has(preferences.search_provider)) {
|
||||
validated.search_provider = preferences.search_provider as GSDPreferences["search_provider"];
|
||||
} else {
|
||||
errors.push(`search_provider must be one of: brave, tavily, ollama, native, auto`);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Phase Skip Preferences ─────────────────────────────────────────
|
||||
if (preferences.phases !== undefined) {
|
||||
if (typeof preferences.phases === "object" && preferences.phases !== null) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
* the heavy tool-registration modules.
|
||||
*/
|
||||
|
||||
import { resolveSearchProviderFromPreferences } from "../gsd/preferences.js";
|
||||
|
||||
/** Tool names for the Brave-backed custom search tools */
|
||||
export const BRAVE_TOOL_NAMES = ["search-the-web", "search_and_read"];
|
||||
|
||||
|
|
@ -16,6 +18,11 @@ const THINKING_TYPES = new Set(["thinking", "redacted_thinking"]);
|
|||
|
||||
/** When true, skip native web search injection and keep Brave/custom tools active on Anthropic. */
|
||||
export function preferBraveSearch(): boolean {
|
||||
// preferences.md takes priority over env var
|
||||
const prefsPref = resolveSearchProviderFromPreferences();
|
||||
if (prefsPref === "brave" || prefsPref === "tavily" || prefsPref === "ollama") return true;
|
||||
if (prefsPref === "native") return false;
|
||||
// Fall back to env var
|
||||
return process.env.PREFER_BRAVE_SEARCH === "1" || process.env.PREFER_BRAVE_SEARCH === "true";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
import { AuthStorage } from '@gsd/pi-coding-agent'
|
||||
import { homedir } from 'os'
|
||||
import { join } from 'path'
|
||||
import { resolveSearchProviderFromPreferences } from '../gsd/preferences.js'
|
||||
|
||||
// Compute authFilePath locally instead of importing from app-paths.ts,
|
||||
// because extensions are copied to ~/.gsd/agent/extensions/ at runtime
|
||||
|
|
@ -94,9 +95,11 @@ export function resolveSearchProvider(overridePreference?: string): SearchProvid
|
|||
if (overridePreference && VALID_PREFERENCES.has(overridePreference)) {
|
||||
pref = overridePreference as SearchProviderPreference
|
||||
} else {
|
||||
// Invalid override or no override — read stored preference
|
||||
// If overridePreference is provided but invalid, treat as 'auto'
|
||||
if (overridePreference !== undefined && !VALID_PREFERENCES.has(overridePreference)) {
|
||||
// preferences.md takes priority over auth.json
|
||||
const mdPref = resolveSearchProviderFromPreferences()
|
||||
if (mdPref && mdPref !== 'auto' && mdPref !== 'native') {
|
||||
pref = mdPref as SearchProviderPreference
|
||||
} else if (overridePreference !== undefined && !VALID_PREFERENCES.has(overridePreference)) {
|
||||
pref = 'auto'
|
||||
} else {
|
||||
pref = getSearchProviderPreference()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue