fix: land codex native search follow-ups (#46579) (thanks @Evizero)

This commit is contained in:
Peter Steinberger
2026-04-01 03:28:58 +09:00
parent 13f1190149
commit 62a39381da
10 changed files with 497 additions and 112 deletions

View File

@@ -481,7 +481,6 @@ export async function compactEmbeddedPiSessionDirect(
modelId,
modelCompat: effectiveModel.compat,
modelApi: model.api,
modelCompat: effectiveModel.compat,
modelContextWindowTokens: ctxInfo.tokens,
modelAuthMode: resolveModelAuthMode(model.provider, params.config),
});

View File

@@ -32,7 +32,6 @@ import {
} from "./moonshot-stream-wrappers.js";
import {
createOpenAIAttributionHeadersWrapper,
createCodexDefaultTransportWrapper,
createCodexNativeWebSearchWrapper,
createOpenAIDefaultTransportWrapper,
createOpenAIFastModeWrapper,

View File

@@ -457,7 +457,6 @@ export async function runEmbeddedAttempt(
modelId: params.modelId,
modelCompat: params.model.compat,
modelApi: params.model.api,
modelCompat: params.model.compat,
modelContextWindowTokens: params.model.contextWindow,
modelAuthMode: resolveModelAuthMode(params.model.provider, params.config),
currentChannelId: params.currentChannelId,
@@ -921,9 +920,6 @@ export async function runEmbeddedAttempt(
effectiveWorkspace,
params.model,
agentDir,
effectiveWorkspace,
params.model,
agentDir,
);
const agentTransportOverride = resolveAgentTransportOverride({
settingsManager,

View File

@@ -160,12 +160,12 @@ async function promptWebToolsConfig(
runtime: RuntimeEnv,
prompter: ReturnType<typeof createClackPrompter>,
): Promise<OpenClawConfig> {
type WebSearchConfig = NonNullable<NonNullable<OpenClawConfig["tools"]>["web"]>["search"];
const existingSearch = nextConfig.tools?.web?.search;
const existingFetch = nextConfig.tools?.web?.fetch;
const { resolveSearchProviderOptions, setupSearch } = await import("./onboard-search.js");
const { describeCodexNativeWebSearch, isCodexNativeWebSearchRelevant } = await import(
"../agents/codex-native-web-search.js"
);
const { describeCodexNativeWebSearch, isCodexNativeWebSearchRelevant } =
await import("../agents/codex-native-web-search.js");
const searchProviderOptions = resolveSearchProviderOptions(nextConfig);
note(
@@ -185,7 +185,7 @@ async function promptWebToolsConfig(
runtime,
);
let nextSearch: Record<string, unknown> = {
let nextSearch: WebSearchConfig = {
...existingSearch,
enabled: enableSearch,
};

View File

@@ -536,54 +536,6 @@ function credentialMode(credential: AuthProfileCredential): "api_key" | "oauth"
return "oauth";
}
async function runBuiltInOpenAICodexLogin(params: {
opts: LoginOptions;
runtime: RuntimeEnv;
prompter: ReturnType<typeof createClackPrompter>;
agentDir: string;
}) {
const creds = await loginOpenAICodexOAuth({
prompter: params.prompter,
runtime: params.runtime,
isRemote: isRemoteEnvironment(),
openUrl: async (url) => {
await openUrl(url);
},
localBrowserMessage: "Complete sign-in in browser…",
});
if (!creds) {
throw new Error("OpenAI Codex OAuth did not return credentials.");
}
const profileId = await writeOAuthCredentials("openai-codex", creds, params.agentDir, {
syncSiblingAgents: true,
});
await updateConfig((cfg) => {
let next = applyAuthProfileConfig(cfg, {
profileId,
provider: "openai-codex",
mode: "oauth",
});
if (params.opts.setDefault) {
next = applyOpenAICodexModelDefault(next).next;
}
return next;
});
logConfigUpdated(params.runtime);
params.runtime.log(`Auth profile: ${profileId} (openai-codex/oauth)`);
if (params.opts.setDefault) {
params.runtime.log(`Default model set to ${OPENAI_CODEX_DEFAULT_MODEL}`);
} else {
params.runtime.log(
`Default model available: ${OPENAI_CODEX_DEFAULT_MODEL} (use --set-default to apply)`,
);
}
params.runtime.log(
"Tip: Codex-capable models can use native Codex web search. Enable it with openclaw configure --section web (recommended mode: cached). Docs: https://docs.openclaw.ai/tools/web",
);
}
function maybeLogOpenAICodexNativeSearchTip(runtime: RuntimeEnv, providerId: string) {
if (providerId !== "openai-codex") {
return;

View File

@@ -4,13 +4,7 @@ import { mergeMissing } from "./legacy.shared.js";
type JsonRecord = Record<string, unknown>;
const GENERIC_WEB_SEARCH_KEYS = new Set([
"enabled",
"provider",
"maxResults",
"timeoutSeconds",
"cacheTtlMinutes",
]);
const MODERN_SCOPED_WEB_SEARCH_KEYS = new Set(["openaiCodex"]);
// Tavily only ever used the plugin-owned config path, so there is no legacy
// `tools.web.search.tavily.*` shape to migrate.
@@ -213,9 +207,9 @@ function normalizeLegacyWebSearchConfigRecord<T extends JsonRecord>(
if (LEGACY_WEB_SEARCH_PROVIDER_ID_SET.has(key) && isRecord(value)) {
continue;
}
// Preserve modern non-legacy search config blocks so the active schema can
// validate them instead of silently dropping nested objects during migration.
nextSearch[key] = value;
if (MODERN_SCOPED_WEB_SEARCH_KEYS.has(key) || !isRecord(value)) {
nextSearch[key] = value;
}
}
web.search = nextSearch;

View File

@@ -5131,6 +5131,45 @@ export const GENERATED_BASE_CONFIG_SCHEMA = {
},
],
},
openaiCodex: {
type: "object",
properties: {
enabled: {
type: "boolean",
},
mode: {
anyOf: [
{
type: "string",
const: "cached",
},
{
type: "string",
const: "live",
},
],
},
allowedDomains: {},
contextSize: {
anyOf: [
{
type: "string",
const: "low",
},
{
type: "string",
const: "medium",
},
{
type: "string",
const: "high",
},
],
},
userLocation: {},
},
additionalProperties: false,
},
brave: {
type: "object",
properties: {
@@ -12934,7 +12973,7 @@ export const GENERATED_BASE_CONFIG_SCHEMA = {
},
"tools.web.search.enabled": {
label: "Enable Web Search Tool",
help: "Enable the web_search tool (requires a provider API key).",
help: "Enable managed web_search and optional Codex-native search for eligible models.",
tags: ["tools"],
},
"tools.web.search.provider": {
@@ -12957,6 +12996,105 @@ export const GENERATED_BASE_CONFIG_SCHEMA = {
help: "Cache TTL in minutes for web_search results.",
tags: ["performance", "storage", "tools"],
},
"tools.web.search.openaiCodex.enabled": {
label: "Enable Native Codex Web Search",
help: "Enable native Codex web search for Codex-capable models.",
tags: ["tools"],
},
"tools.web.search.openaiCodex.mode": {
label: "Codex Web Search Mode",
help: 'Native Codex web search mode: "cached" (default) or "live".',
tags: ["tools"],
},
"tools.web.search.openaiCodex.allowedDomains": {
label: "Codex Allowed Domains",
help: "Optional domain allowlist passed to the native Codex web_search tool.",
tags: ["access", "tools"],
},
"tools.web.search.openaiCodex.contextSize": {
label: "Codex Search Context Size",
help: 'Native Codex search context size hint: "low", "medium", or "high".',
tags: ["tools"],
},
"tools.web.search.openaiCodex.userLocation.country": {
label: "Codex User Country",
help: "Approximate country sent to native Codex web search.",
tags: ["tools"],
},
"tools.web.search.openaiCodex.userLocation.region": {
label: "Codex User Region",
help: "Approximate region/state sent to native Codex web search.",
tags: ["tools"],
},
"tools.web.search.openaiCodex.userLocation.city": {
label: "Codex User City",
help: "Approximate city sent to native Codex web search.",
tags: ["tools"],
},
"tools.web.search.openaiCodex.userLocation.timezone": {
label: "Codex User Timezone",
help: "Approximate timezone sent to native Codex web search.",
tags: ["tools"],
},
"tools.web.search.brave.mode": {
label: "Brave Search Mode",
help: 'Brave Search mode: "web" (URL results) or "llm-context" (pre-extracted page content for LLM grounding).',
tags: ["tools"],
},
"tools.web.search.gemini.apiKey": {
label: "Gemini Search API Key",
help: "Gemini API key for Google Search grounding (fallback: GEMINI_API_KEY env var).",
tags: ["security", "auth", "tools"],
sensitive: true,
},
"tools.web.search.gemini.model": {
label: "Gemini Search Model",
help: 'Gemini model override (default: "gemini-2.5-flash").',
tags: ["models", "tools"],
},
"tools.web.search.grok.apiKey": {
label: "Grok Search API Key",
help: "Grok (xAI) API key (fallback: XAI_API_KEY env var).",
tags: ["security", "auth", "tools"],
sensitive: true,
},
"tools.web.search.grok.model": {
label: "Grok Search Model",
help: 'Grok model override (default: "grok-4-1-fast").',
tags: ["models", "tools"],
},
"tools.web.search.kimi.apiKey": {
label: "Kimi Search API Key",
help: "Moonshot/Kimi API key (fallback: KIMI_API_KEY or MOONSHOT_API_KEY env var).",
tags: ["security", "auth", "tools"],
sensitive: true,
},
"tools.web.search.kimi.baseUrl": {
label: "Kimi Search Base URL",
help: 'Kimi base URL override (default: "https://api.moonshot.ai/v1").',
tags: ["tools", "url-secret"],
},
"tools.web.search.kimi.model": {
label: "Kimi Search Model",
help: 'Kimi model override (default: "moonshot-v1-128k").',
tags: ["models", "tools"],
},
"tools.web.search.perplexity.apiKey": {
label: "Perplexity API Key",
help: "Perplexity or OpenRouter API key (fallback: PERPLEXITY_API_KEY or OPENROUTER_API_KEY env var). Direct Perplexity keys default to the Search API; OpenRouter keys use Sonar chat completions.",
tags: ["security", "auth", "tools"],
sensitive: true,
},
"tools.web.search.perplexity.baseUrl": {
label: "Perplexity Base URL",
help: "Optional Perplexity/OpenRouter chat-completions base URL override. Setting this opts Perplexity into the legacy Sonar/OpenRouter compatibility path.",
tags: ["tools", "url-secret"],
},
"tools.web.search.perplexity.model": {
label: "Perplexity Model",
help: 'Optional Sonar/OpenRouter model override (default: "perplexity/sonar-pro"). Setting this opts Perplexity into the legacy chat-completions compatibility path.',
tags: ["models", "tools"],
},
"tools.web.fetch.enabled": {
label: "Enable Web Fetch Tool",
help: "Enable the web_fetch tool (lightweight HTTP fetch).",
@@ -15613,22 +15751,6 @@ export const GENERATED_BASE_CONFIG_SCHEMA = {
sensitive: true,
tags: ["security", "auth", "tools"],
},
"tools.web.search.gemini.apiKey": {
sensitive: true,
tags: ["security", "auth", "tools"],
},
"tools.web.search.grok.apiKey": {
sensitive: true,
tags: ["security", "auth", "tools"],
},
"tools.web.search.kimi.apiKey": {
sensitive: true,
tags: ["security", "auth", "tools"],
},
"tools.web.search.perplexity.apiKey": {
sensitive: true,
tags: ["security", "auth", "tools"],
},
"mcp.servers.*.headers.*": {
sensitive: true,
tags: ["security"],
@@ -15652,12 +15774,6 @@ export const GENERATED_BASE_CONFIG_SCHEMA = {
"tools.web.search.grok.baseUrl": {
tags: ["tools", "url-secret"],
},
"tools.web.search.kimi.baseUrl": {
tags: ["tools", "url-secret"],
},
"tools.web.search.perplexity.baseUrl": {
tags: ["tools", "url-secret"],
},
"tools.media.models[].baseUrl": {
tags: ["media", "tools", "url-secret"],
},