feat(xai): add plugin-owned x_search onboarding

This commit is contained in:
Peter Steinberger
2026-03-29 00:12:15 +00:00
parent ebb4794952
commit 5872f860c9
11 changed files with 407 additions and 53 deletions

View File

@@ -18,6 +18,7 @@ Docs: https://docs.openclaw.ai
### Changes
- xAI/tools: move the bundled xAI provider to the Responses API, add first-class `x_search`, and auto-enable the xAI plugin from owned web-search and tool config so bundled Grok auth/configured search flows work without manual plugin toggles. (#56048) Thanks @huntharo.
- xAI/onboarding: let the bundled Grok web-search plugin offer optional `x_search` setup during `openclaw onboard` and `openclaw configure --section web`, including an x_search model picker with the shared xAI key.
- MiniMax: add image generation provider for `image-01` model, supporting generate and image-to-image editing with aspect ratio control. (#54487) Thanks @liyuan97.
- Plugins/hooks: add async `requireApproval` to `before_tool_call` hooks, letting plugins pause tool execution and prompt the user for approval via the exec approval overlay, Telegram buttons, Discord interactions, or the `/approve` command on any channel. The `/approve` command now handles both exec and plugin approvals with automatic fallback. (#55339) Thanks @vaclavbelak and @joshavant.
- ACP/channels: add current-conversation ACP binds for Discord, BlueBubbles, and iMessage so `/acp spawn codex --bind here` can turn the current chat into a Codex-backed workspace without creating a child thread, and document the distinction between chat surface, ACP session, and runtime workspace.

View File

@@ -253,7 +253,7 @@
"exportName": "CliBackendPlugin",
"kind": "type",
"source": {
"line": 1607,
"line": 1618,
"path": "src/plugins/types.ts"
}
},
@@ -397,7 +397,7 @@
"exportName": "MediaUnderstandingProviderPlugin",
"kind": "type",
"source": {
"line": 1258,
"line": 1269,
"path": "src/plugins/types.ts"
}
},
@@ -415,7 +415,7 @@
"exportName": "OpenClawPluginApi",
"kind": "type",
"source": {
"line": 1651,
"line": 1662,
"path": "src/plugins/types.ts"
}
},
@@ -523,7 +523,7 @@
"exportName": "SpeechProviderPlugin",
"kind": "type",
"source": {
"line": 1233,
"line": 1244,
"path": "src/plugins/types.ts"
}
},
@@ -3747,7 +3747,7 @@
"exportName": "MediaUnderstandingProviderPlugin",
"kind": "type",
"source": {
"line": 1258,
"line": 1269,
"path": "src/plugins/types.ts"
}
},
@@ -3765,7 +3765,7 @@
"exportName": "OpenClawPluginApi",
"kind": "type",
"source": {
"line": 1651,
"line": 1662,
"path": "src/plugins/types.ts"
}
},
@@ -3774,7 +3774,7 @@
"exportName": "OpenClawPluginCommandDefinition",
"kind": "type",
"source": {
"line": 1377,
"line": 1388,
"path": "src/plugins/types.ts"
}
},
@@ -3792,7 +3792,7 @@
"exportName": "OpenClawPluginDefinition",
"kind": "type",
"source": {
"line": 1633,
"line": 1644,
"path": "src/plugins/types.ts"
}
},
@@ -3801,7 +3801,7 @@
"exportName": "OpenClawPluginService",
"kind": "type",
"source": {
"line": 1600,
"line": 1611,
"path": "src/plugins/types.ts"
}
},
@@ -3810,7 +3810,7 @@
"exportName": "OpenClawPluginServiceContext",
"kind": "type",
"source": {
"line": 1592,
"line": 1603,
"path": "src/plugins/types.ts"
}
},
@@ -3837,7 +3837,7 @@
"exportName": "PluginCommandContext",
"kind": "type",
"source": {
"line": 1273,
"line": 1284,
"path": "src/plugins/types.ts"
}
},
@@ -3846,7 +3846,7 @@
"exportName": "PluginInteractiveTelegramHandlerContext",
"kind": "type",
"source": {
"line": 1406,
"line": 1417,
"path": "src/plugins/types.ts"
}
},
@@ -4170,7 +4170,7 @@
"exportName": "SpeechProviderPlugin",
"kind": "type",
"source": {
"line": 1233,
"line": 1244,
"path": "src/plugins/types.ts"
}
},
@@ -4262,7 +4262,7 @@
"exportName": "MediaUnderstandingProviderPlugin",
"kind": "type",
"source": {
"line": 1258,
"line": 1269,
"path": "src/plugins/types.ts"
}
},
@@ -4280,7 +4280,7 @@
"exportName": "OpenClawPluginApi",
"kind": "type",
"source": {
"line": 1651,
"line": 1662,
"path": "src/plugins/types.ts"
}
},
@@ -4289,7 +4289,7 @@
"exportName": "OpenClawPluginCommandDefinition",
"kind": "type",
"source": {
"line": 1377,
"line": 1388,
"path": "src/plugins/types.ts"
}
},
@@ -4307,7 +4307,7 @@
"exportName": "OpenClawPluginDefinition",
"kind": "type",
"source": {
"line": 1633,
"line": 1644,
"path": "src/plugins/types.ts"
}
},
@@ -4316,7 +4316,7 @@
"exportName": "OpenClawPluginService",
"kind": "type",
"source": {
"line": 1600,
"line": 1611,
"path": "src/plugins/types.ts"
}
},
@@ -4325,7 +4325,7 @@
"exportName": "OpenClawPluginServiceContext",
"kind": "type",
"source": {
"line": 1592,
"line": 1603,
"path": "src/plugins/types.ts"
}
},
@@ -4352,7 +4352,7 @@
"exportName": "PluginCommandContext",
"kind": "type",
"source": {
"line": 1273,
"line": 1284,
"path": "src/plugins/types.ts"
}
},
@@ -4361,7 +4361,7 @@
"exportName": "PluginInteractiveTelegramHandlerContext",
"kind": "type",
"source": {
"line": 1406,
"line": 1417,
"path": "src/plugins/types.ts"
}
},
@@ -4667,7 +4667,7 @@
"exportName": "SpeechProviderPlugin",
"kind": "type",
"source": {
"line": 1233,
"line": 1244,
"path": "src/plugins/types.ts"
}
}

View File

@@ -26,7 +26,7 @@
{"declaration":"export type ChannelStatusIssue = ChannelStatusIssue;","entrypoint":"index","exportName":"ChannelStatusIssue","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":100,"sourcePath":"src/channels/plugins/types.core.ts"}
{"declaration":"export type OpenClawConfig = OpenClawConfig;","entrypoint":"index","exportName":"ClawdbotConfig","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":32,"sourcePath":"src/config/types.openclaw.ts"}
{"declaration":"export type CliBackendConfig = CliBackendConfig;","entrypoint":"index","exportName":"CliBackendConfig","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":47,"sourcePath":"src/config/types.agent-defaults.ts"}
{"declaration":"export type CliBackendPlugin = CliBackendPlugin;","entrypoint":"index","exportName":"CliBackendPlugin","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":1607,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type CliBackendPlugin = CliBackendPlugin;","entrypoint":"index","exportName":"CliBackendPlugin","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":1618,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type CompiledConfiguredBinding = CompiledConfiguredBinding;","entrypoint":"index","exportName":"CompiledConfiguredBinding","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":38,"sourcePath":"src/channels/plugins/binding-types.ts"}
{"declaration":"export type ConfiguredBindingConversation = ConversationRef;","entrypoint":"index","exportName":"ConfiguredBindingConversation","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":13,"sourcePath":"src/channels/plugins/binding-types.ts"}
{"declaration":"export type ConfiguredBindingResolution = ConfiguredBindingResolution;","entrypoint":"index","exportName":"ConfiguredBindingResolution","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":49,"sourcePath":"src/channels/plugins/binding-types.ts"}
@@ -42,9 +42,9 @@
{"declaration":"export type ImageGenerationResolution = ImageGenerationResolution;","entrypoint":"index","exportName":"ImageGenerationResolution","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":12,"sourcePath":"src/image-generation/types.ts"}
{"declaration":"export type ImageGenerationResult = ImageGenerationResult;","entrypoint":"index","exportName":"ImageGenerationResult","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":36,"sourcePath":"src/image-generation/types.ts"}
{"declaration":"export type ImageGenerationSourceImage = ImageGenerationSourceImage;","entrypoint":"index","exportName":"ImageGenerationSourceImage","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":14,"sourcePath":"src/image-generation/types.ts"}
{"declaration":"export type MediaUnderstandingProviderPlugin = MediaUnderstandingProvider;","entrypoint":"index","exportName":"MediaUnderstandingProviderPlugin","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":1258,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type MediaUnderstandingProviderPlugin = MediaUnderstandingProvider;","entrypoint":"index","exportName":"MediaUnderstandingProviderPlugin","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":1269,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawConfig = OpenClawConfig;","entrypoint":"index","exportName":"OpenClawConfig","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":32,"sourcePath":"src/config/types.openclaw.ts"}
{"declaration":"export type OpenClawPluginApi = OpenClawPluginApi;","entrypoint":"index","exportName":"OpenClawPluginApi","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":1651,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginApi = OpenClawPluginApi;","entrypoint":"index","exportName":"OpenClawPluginApi","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":1662,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginConfigSchema = OpenClawPluginConfigSchema;","entrypoint":"index","exportName":"OpenClawPluginConfigSchema","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":100,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type PluginLogger = PluginLogger;","entrypoint":"index","exportName":"PluginLogger","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":71,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type PluginRuntime = PluginRuntime;","entrypoint":"index","exportName":"PluginRuntime","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":54,"sourcePath":"src/plugins/runtime/types.ts"}
@@ -56,7 +56,7 @@
{"declaration":"export type RuntimeLogger = RuntimeLogger;","entrypoint":"index","exportName":"RuntimeLogger","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":7,"sourcePath":"src/plugins/runtime/types-core.ts"}
{"declaration":"export type SecretInput = SecretInput;","entrypoint":"index","exportName":"SecretInput","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":16,"sourcePath":"src/config/types.secrets.ts"}
{"declaration":"export type SecretRef = SecretRef;","entrypoint":"index","exportName":"SecretRef","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":10,"sourcePath":"src/config/types.secrets.ts"}
{"declaration":"export type SpeechProviderPlugin = SpeechProviderPlugin;","entrypoint":"index","exportName":"SpeechProviderPlugin","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":1233,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type SpeechProviderPlugin = SpeechProviderPlugin;","entrypoint":"index","exportName":"SpeechProviderPlugin","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":1244,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type StatefulBindingTargetDescriptor = StatefulBindingTargetDescriptor;","entrypoint":"index","exportName":"StatefulBindingTargetDescriptor","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":17,"sourcePath":"src/channels/plugins/binding-types.ts"}
{"declaration":"export type StatefulBindingTargetDriver = StatefulBindingTargetDriver;","entrypoint":"index","exportName":"StatefulBindingTargetDriver","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":15,"sourcePath":"src/channels/plugins/stateful-target-drivers.ts"}
{"declaration":"export type StatefulBindingTargetReadyResult = StatefulBindingTargetReadyResult;","entrypoint":"index","exportName":"StatefulBindingTargetReadyResult","importSpecifier":"openclaw/plugin-sdk","kind":"type","recordType":"export","sourceLine":7,"sourcePath":"src/channels/plugins/stateful-target-drivers.ts"}
@@ -412,18 +412,18 @@
{"declaration":"export type ChannelPlugin = ChannelPlugin<ResolvedAccount, Probe, Audit>;","entrypoint":"core","exportName":"ChannelPlugin","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":77,"sourcePath":"src/channels/plugins/types.plugin.ts"}
{"declaration":"export type GatewayBindUrlResult = GatewayBindUrlResult;","entrypoint":"core","exportName":"GatewayBindUrlResult","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":1,"sourcePath":"src/shared/gateway-bind-url.ts"}
{"declaration":"export type GatewayRequestHandlerOptions = GatewayRequestHandlerOptions;","entrypoint":"core","exportName":"GatewayRequestHandlerOptions","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":115,"sourcePath":"src/gateway/server-methods/types.ts"}
{"declaration":"export type MediaUnderstandingProviderPlugin = MediaUnderstandingProvider;","entrypoint":"core","exportName":"MediaUnderstandingProviderPlugin","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":1258,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type MediaUnderstandingProviderPlugin = MediaUnderstandingProvider;","entrypoint":"core","exportName":"MediaUnderstandingProviderPlugin","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":1269,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawConfig = OpenClawConfig;","entrypoint":"core","exportName":"OpenClawConfig","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":32,"sourcePath":"src/config/types.openclaw.ts"}
{"declaration":"export type OpenClawPluginApi = OpenClawPluginApi;","entrypoint":"core","exportName":"OpenClawPluginApi","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":1651,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginCommandDefinition = OpenClawPluginCommandDefinition;","entrypoint":"core","exportName":"OpenClawPluginCommandDefinition","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":1377,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginApi = OpenClawPluginApi;","entrypoint":"core","exportName":"OpenClawPluginApi","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":1662,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginCommandDefinition = OpenClawPluginCommandDefinition;","entrypoint":"core","exportName":"OpenClawPluginCommandDefinition","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":1388,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginConfigSchema = OpenClawPluginConfigSchema;","entrypoint":"core","exportName":"OpenClawPluginConfigSchema","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":100,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginDefinition = OpenClawPluginDefinition;","entrypoint":"core","exportName":"OpenClawPluginDefinition","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":1633,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginService = OpenClawPluginService;","entrypoint":"core","exportName":"OpenClawPluginService","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":1600,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginServiceContext = OpenClawPluginServiceContext;","entrypoint":"core","exportName":"OpenClawPluginServiceContext","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":1592,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginDefinition = OpenClawPluginDefinition;","entrypoint":"core","exportName":"OpenClawPluginDefinition","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":1644,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginService = OpenClawPluginService;","entrypoint":"core","exportName":"OpenClawPluginService","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":1611,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginServiceContext = OpenClawPluginServiceContext;","entrypoint":"core","exportName":"OpenClawPluginServiceContext","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":1603,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginToolContext = OpenClawPluginToolContext;","entrypoint":"core","exportName":"OpenClawPluginToolContext","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":115,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginToolFactory = OpenClawPluginToolFactory;","entrypoint":"core","exportName":"OpenClawPluginToolFactory","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":140,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type PluginCommandContext = PluginCommandContext;","entrypoint":"core","exportName":"PluginCommandContext","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":1273,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type PluginInteractiveTelegramHandlerContext = PluginInteractiveTelegramHandlerContext;","entrypoint":"core","exportName":"PluginInteractiveTelegramHandlerContext","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":1406,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type PluginCommandContext = PluginCommandContext;","entrypoint":"core","exportName":"PluginCommandContext","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":1284,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type PluginInteractiveTelegramHandlerContext = PluginInteractiveTelegramHandlerContext;","entrypoint":"core","exportName":"PluginInteractiveTelegramHandlerContext","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":1417,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type PluginLogger = PluginLogger;","entrypoint":"core","exportName":"PluginLogger","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":71,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type PluginRuntime = PluginRuntime;","entrypoint":"core","exportName":"PluginRuntime","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":54,"sourcePath":"src/plugins/runtime/types.ts"}
{"declaration":"export type ProviderAugmentModelCatalogContext = ProviderAugmentModelCatalogContext;","entrypoint":"core","exportName":"ProviderAugmentModelCatalogContext","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":709,"sourcePath":"src/plugins/types.ts"}
@@ -459,7 +459,7 @@
{"declaration":"export type RoutePeerKind = ChatType;","entrypoint":"core","exportName":"RoutePeerKind","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":19,"sourcePath":"src/routing/resolve-route.ts"}
{"declaration":"export type SecretFileReadOptions = SecretFileReadOptions;","entrypoint":"core","exportName":"SecretFileReadOptions","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":7,"sourcePath":"src/infra/secret-file.ts"}
{"declaration":"export type SecretFileReadResult = SecretFileReadResult;","entrypoint":"core","exportName":"SecretFileReadResult","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":12,"sourcePath":"src/infra/secret-file.ts"}
{"declaration":"export type SpeechProviderPlugin = SpeechProviderPlugin;","entrypoint":"core","exportName":"SpeechProviderPlugin","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":1233,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type SpeechProviderPlugin = SpeechProviderPlugin;","entrypoint":"core","exportName":"SpeechProviderPlugin","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":1244,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type TailscaleStatusCommandResult = TailscaleStatusCommandResult;","entrypoint":"core","exportName":"TailscaleStatusCommandResult","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":4,"sourcePath":"src/shared/tailscale-status.ts"}
{"declaration":"export type TailscaleStatusCommandRunner = TailscaleStatusCommandRunner;","entrypoint":"core","exportName":"TailscaleStatusCommandRunner","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":9,"sourcePath":"src/shared/tailscale-status.ts"}
{"declaration":"export type UsageProviderId = UsageProviderId;","entrypoint":"core","exportName":"UsageProviderId","importSpecifier":"openclaw/plugin-sdk/core","kind":"type","recordType":"export","sourceLine":20,"sourcePath":"src/infra/provider-usage.types.ts"}
@@ -469,18 +469,18 @@
{"declaration":"export function definePluginEntry({ id, name, description, kind, configSchema, register, }: DefinePluginEntryOptions): DefinedPluginEntry;","entrypoint":"plugin-entry","exportName":"definePluginEntry","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"function","recordType":"export","sourceLine":137,"sourcePath":"src/plugin-sdk/plugin-entry.ts"}
{"declaration":"export function emptyPluginConfigSchema(): OpenClawPluginConfigSchema;","entrypoint":"plugin-entry","exportName":"emptyPluginConfigSchema","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"function","recordType":"export","sourceLine":108,"sourcePath":"src/plugins/config-schema.ts"}
{"declaration":"export type AnyAgentTool = AnyAgentTool;","entrypoint":"plugin-entry","exportName":"AnyAgentTool","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":9,"sourcePath":"src/agents/tools/common.ts"}
{"declaration":"export type MediaUnderstandingProviderPlugin = MediaUnderstandingProvider;","entrypoint":"plugin-entry","exportName":"MediaUnderstandingProviderPlugin","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":1258,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type MediaUnderstandingProviderPlugin = MediaUnderstandingProvider;","entrypoint":"plugin-entry","exportName":"MediaUnderstandingProviderPlugin","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":1269,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawConfig = OpenClawConfig;","entrypoint":"plugin-entry","exportName":"OpenClawConfig","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":32,"sourcePath":"src/config/types.openclaw.ts"}
{"declaration":"export type OpenClawPluginApi = OpenClawPluginApi;","entrypoint":"plugin-entry","exportName":"OpenClawPluginApi","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":1651,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginCommandDefinition = OpenClawPluginCommandDefinition;","entrypoint":"plugin-entry","exportName":"OpenClawPluginCommandDefinition","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":1377,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginApi = OpenClawPluginApi;","entrypoint":"plugin-entry","exportName":"OpenClawPluginApi","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":1662,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginCommandDefinition = OpenClawPluginCommandDefinition;","entrypoint":"plugin-entry","exportName":"OpenClawPluginCommandDefinition","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":1388,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginConfigSchema = OpenClawPluginConfigSchema;","entrypoint":"plugin-entry","exportName":"OpenClawPluginConfigSchema","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":100,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginDefinition = OpenClawPluginDefinition;","entrypoint":"plugin-entry","exportName":"OpenClawPluginDefinition","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":1633,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginService = OpenClawPluginService;","entrypoint":"plugin-entry","exportName":"OpenClawPluginService","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":1600,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginServiceContext = OpenClawPluginServiceContext;","entrypoint":"plugin-entry","exportName":"OpenClawPluginServiceContext","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":1592,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginDefinition = OpenClawPluginDefinition;","entrypoint":"plugin-entry","exportName":"OpenClawPluginDefinition","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":1644,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginService = OpenClawPluginService;","entrypoint":"plugin-entry","exportName":"OpenClawPluginService","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":1611,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginServiceContext = OpenClawPluginServiceContext;","entrypoint":"plugin-entry","exportName":"OpenClawPluginServiceContext","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":1603,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginToolContext = OpenClawPluginToolContext;","entrypoint":"plugin-entry","exportName":"OpenClawPluginToolContext","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":115,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type OpenClawPluginToolFactory = OpenClawPluginToolFactory;","entrypoint":"plugin-entry","exportName":"OpenClawPluginToolFactory","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":140,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type PluginCommandContext = PluginCommandContext;","entrypoint":"plugin-entry","exportName":"PluginCommandContext","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":1273,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type PluginInteractiveTelegramHandlerContext = PluginInteractiveTelegramHandlerContext;","entrypoint":"plugin-entry","exportName":"PluginInteractiveTelegramHandlerContext","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":1406,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type PluginCommandContext = PluginCommandContext;","entrypoint":"plugin-entry","exportName":"PluginCommandContext","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":1284,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type PluginInteractiveTelegramHandlerContext = PluginInteractiveTelegramHandlerContext;","entrypoint":"plugin-entry","exportName":"PluginInteractiveTelegramHandlerContext","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":1417,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type PluginLogger = PluginLogger;","entrypoint":"plugin-entry","exportName":"PluginLogger","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":71,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type ProviderAugmentModelCatalogContext = ProviderAugmentModelCatalogContext;","entrypoint":"plugin-entry","exportName":"ProviderAugmentModelCatalogContext","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":709,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type ProviderAuthContext = ProviderAuthContext;","entrypoint":"plugin-entry","exportName":"ProviderAuthContext","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":175,"sourcePath":"src/plugins/types.ts"}
@@ -514,7 +514,7 @@
{"declaration":"export type ProviderRuntimeModel = ProviderRuntimeModel;","entrypoint":"plugin-entry","exportName":"ProviderRuntimeModel","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":316,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type ProviderThinkingPolicyContext = ProviderThinkingPolicyContext;","entrypoint":"plugin-entry","exportName":"ProviderThinkingPolicyContext","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":674,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type ProviderWrapStreamFnContext = ProviderWrapStreamFnContext;","entrypoint":"plugin-entry","exportName":"ProviderWrapStreamFnContext","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":560,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type SpeechProviderPlugin = SpeechProviderPlugin;","entrypoint":"plugin-entry","exportName":"SpeechProviderPlugin","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":1233,"sourcePath":"src/plugins/types.ts"}
{"declaration":"export type SpeechProviderPlugin = SpeechProviderPlugin;","entrypoint":"plugin-entry","exportName":"SpeechProviderPlugin","importSpecifier":"openclaw/plugin-sdk/plugin-entry","kind":"type","recordType":"export","sourceLine":1244,"sourcePath":"src/plugins/types.ts"}
{"category":"provider","entrypoint":"provider-onboard","importSpecifier":"openclaw/plugin-sdk/provider-onboard","recordType":"module","sourceLine":1,"sourcePath":"src/plugin-sdk/provider-onboard.ts"}
{"declaration":"export function applyAgentDefaultModelPrimary(cfg: OpenClawConfig, primary: string): OpenClawConfig;","entrypoint":"provider-onboard","exportName":"applyAgentDefaultModelPrimary","importSpecifier":"openclaw/plugin-sdk/provider-onboard","kind":"function","recordType":"export","sourceLine":267,"sourcePath":"src/plugin-sdk/provider-onboard.ts"}
{"declaration":"export function applyOnboardAuthAgentModelsAndProviders(cfg: OpenClawConfig, params: { agentModels: Record<string, AgentModelEntryConfig>; providers: Record<string, ModelProviderConfig>; }): OpenClawConfig;","entrypoint":"provider-onboard","exportName":"applyOnboardAuthAgentModelsAndProviders","importSpecifier":"openclaw/plugin-sdk/provider-onboard","kind":"function","recordType":"export","sourceLine":244,"sourcePath":"src/plugin-sdk/provider-onboard.ts"}

View File

@@ -149,6 +149,8 @@ examples.
For `x_search`, configure `tools.web.x_search.*` directly. It uses the same
`XAI_API_KEY` fallback as Grok web search.
When you choose Grok during `openclaw onboard` or `openclaw configure --section web`,
OpenClaw can also offer optional `x_search` setup with the same key.
### Storing API keys

View File

@@ -1,7 +1,9 @@
import { describe, expect, it } from "vitest";
import { describe, expect, it, vi } from "vitest";
import { NON_ENV_SECRETREF_MARKER } from "../../src/agents/model-auth-markers.js";
import { capturePluginRegistration } from "../../src/plugins/captured-registration.js";
import { createNonExitingRuntime } from "../../src/runtime.js";
import { withEnv } from "../../test/helpers/extensions/env.js";
import { createWizardPrompter } from "../../test/helpers/wizard-prompter.js";
import xaiPlugin from "./index.js";
import { resolveXaiCatalogEntry } from "./model-definitions.js";
import { isModernXaiModel, resolveXaiForwardCompatModel } from "./provider-models.js";
@@ -110,6 +112,73 @@ describe("xai web search config resolution", () => {
});
});
it("offers plugin-owned x_search setup after Grok is selected", async () => {
const provider = createXaiWebSearchProvider();
const select = vi.fn().mockResolvedValueOnce("yes").mockResolvedValueOnce("grok-4-1-fast");
const prompter = createWizardPrompter({
select: select as never,
});
const next = await provider.runSetup?.({
config: {
plugins: {
entries: {
xai: {
enabled: true,
config: {
webSearch: {
apiKey: "xai-test-key",
},
},
},
},
},
tools: {
web: {
search: {
provider: "grok",
enabled: true,
},
},
},
},
runtime: createNonExitingRuntime(),
prompter,
});
expect(next?.tools?.web?.x_search).toMatchObject({
enabled: true,
model: "grok-4-1-fast",
});
});
it("keeps explicit x_search disablement untouched during provider-owned setup", async () => {
const provider = createXaiWebSearchProvider();
const config = {
tools: {
web: {
search: {
provider: "grok",
enabled: true,
},
x_search: {
enabled: false,
},
},
},
};
const prompter = createWizardPrompter({});
const next = await provider.runSetup?.({
config,
runtime: createNonExitingRuntime(),
prompter,
});
expect(next).toEqual(config);
expect(prompter.note).not.toHaveBeenCalled();
});
it("reuses the plugin web search api key for provider auth fallback", () => {
const captured = capturePluginRegistration(xaiPlugin);
const provider = captured.providers[0];

View File

@@ -2,6 +2,7 @@ import { Type } from "@sinclair/typebox";
import {
DEFAULT_CACHE_TTL_MINUTES,
DEFAULT_TIMEOUT_SECONDS,
formatCliCommand,
getScopedCredentialValue,
mergeScopedSearchConfig,
normalizeCacheKey,
@@ -15,6 +16,7 @@ import {
setProviderWebSearchPluginConfigValue,
setScopedCredentialValue,
type SearchConfigRecord,
type WebSearchProviderSetupContext,
type WebSearchProviderPlugin,
writeCache,
} from "openclaw/plugin-sdk/provider-web-search";
@@ -25,12 +27,121 @@ import {
resolveXaiInlineCitations,
resolveXaiWebSearchModel,
} from "./src/web-search-shared.js";
import { XAI_DEFAULT_X_SEARCH_MODEL } from "./src/x-search-shared.js";
const XAI_WEB_SEARCH_CACHE = new Map<
string,
{ value: Record<string, unknown>; insertedAt: number; expiresAt: number }
>();
const X_SEARCH_MODEL_OPTIONS = [
{
value: XAI_DEFAULT_X_SEARCH_MODEL,
label: XAI_DEFAULT_X_SEARCH_MODEL,
hint: "default · fast, no reasoning",
},
{
value: "grok-4-1-fast",
label: "grok-4-1-fast",
hint: "fast with reasoning",
},
] as const;
function resolveXSearchConfigRecord(
config?: WebSearchProviderSetupContext["config"],
): Record<string, unknown> | undefined {
const xSearch = config?.tools?.web?.x_search;
return xSearch && typeof xSearch === "object" ? (xSearch as Record<string, unknown>) : undefined;
}
function applyXSearchSetupConfig(
config: WebSearchProviderSetupContext["config"],
params: { enabled: boolean; model: string },
): WebSearchProviderSetupContext["config"] {
return {
...config,
tools: {
...config.tools,
web: {
...config.tools?.web,
x_search: {
...config.tools?.web?.x_search,
enabled: params.enabled,
model: params.model,
},
},
},
};
}
async function runXaiSearchProviderSetup(
ctx: WebSearchProviderSetupContext,
): Promise<WebSearchProviderSetupContext["config"]> {
const existingXSearch = resolveXSearchConfigRecord(ctx.config);
if (existingXSearch?.enabled === false) {
return ctx.config;
}
await ctx.prompter.note(
[
"x_search lets your agent search X (formerly Twitter) posts via xAI.",
"It reuses the same xAI API key you just configured for Grok web search.",
`You can change this later with ${formatCliCommand("openclaw configure --section web")}.`,
].join("\n"),
"X search",
);
const enableChoice = await ctx.prompter.select<"yes" | "skip">({
message: "Enable x_search too?",
options: [
{
value: "yes",
label: "Yes, enable x_search",
hint: "Search X posts with the same xAI key",
},
{
value: "skip",
label: "Skip for now",
hint: "Keep Grok web_search only",
},
],
initialValue: existingXSearch?.enabled === true || ctx.quickstartDefaults ? "yes" : "skip",
});
if (enableChoice === "skip") {
return ctx.config;
}
const existingModel =
typeof existingXSearch?.model === "string" && existingXSearch.model.trim()
? existingXSearch.model.trim()
: "";
const knownModel = X_SEARCH_MODEL_OPTIONS.find((entry) => entry.value === existingModel)?.value;
const modelPick = await ctx.prompter.select<string>({
message: "Grok model for x_search",
options: [
...X_SEARCH_MODEL_OPTIONS,
{ value: "__custom__", label: "Enter custom model name", hint: "" },
],
initialValue: knownModel ?? XAI_DEFAULT_X_SEARCH_MODEL,
});
let model = modelPick;
if (modelPick === "__custom__") {
const customModel = await ctx.prompter.text({
message: "Custom Grok model name",
initialValue: existingModel || XAI_DEFAULT_X_SEARCH_MODEL,
placeholder: XAI_DEFAULT_X_SEARCH_MODEL,
});
model = customModel.trim() || XAI_DEFAULT_X_SEARCH_MODEL;
}
return applyXSearchSetupConfig(ctx.config, {
enabled: true,
model: model || XAI_DEFAULT_X_SEARCH_MODEL,
});
}
function runXaiWebSearch(params: {
query: string;
model: string;
@@ -113,6 +224,7 @@ export function createXaiWebSearchProvider(): WebSearchProviderPlugin {
setConfiguredCredentialValue: (configTarget, value) => {
setProviderWebSearchPluginConfigValue(configTarget, "xai", "apiKey", value);
},
runSetup: runXaiSearchProviderSetup,
createTool: (ctx) => {
const searchConfig = resolveXaiToolSearchConfig(ctx);
return {

View File

@@ -0,0 +1,85 @@
import { describe, expect, it, vi } from "vitest";
import { createWizardPrompter } from "../../test/helpers/wizard-prompter.js";
import { createNonExitingRuntime } from "../runtime.js";
import { runSearchSetupFlow } from "./search-setup.js";
describe("runSearchSetupFlow", () => {
it("runs provider-owned setup after selecting Grok web search", async () => {
const select = vi
.fn()
.mockResolvedValueOnce("grok")
.mockResolvedValueOnce("yes")
.mockResolvedValueOnce("grok-4-1-fast");
const text = vi.fn().mockResolvedValue("xai-test-key");
const prompter = createWizardPrompter({
select: select as never,
text: text as never,
});
const next = await runSearchSetupFlow(
{ plugins: { allow: ["xai"] } },
createNonExitingRuntime(),
prompter,
);
expect(next.plugins?.entries?.xai?.config?.webSearch).toMatchObject({
apiKey: "xai-test-key",
});
expect(next.tools?.web?.search).toMatchObject({
provider: "grok",
enabled: true,
});
expect(next.tools?.web?.x_search).toMatchObject({
enabled: true,
model: "grok-4-1-fast",
});
});
it("preserves disabled web_search state while still allowing provider-owned x_search setup", async () => {
const select = vi
.fn()
.mockResolvedValueOnce("grok")
.mockResolvedValueOnce("yes")
.mockResolvedValueOnce("grok-4-1-fast");
const prompter = createWizardPrompter({
select: select as never,
});
const next = await runSearchSetupFlow(
{
plugins: {
allow: ["xai"],
entries: {
xai: {
enabled: true,
config: {
webSearch: {
apiKey: "xai-test-key",
},
},
},
},
},
tools: {
web: {
search: {
provider: "grok",
enabled: false,
},
},
},
},
createNonExitingRuntime(),
prompter,
);
expect(next.tools?.web?.search).toMatchObject({
provider: "grok",
enabled: false,
});
expect(next.tools?.web?.x_search).toMatchObject({
enabled: true,
model: "grok-4-1-fast",
});
});
});

View File

@@ -330,9 +330,31 @@ export type SetupSearchOptions = {
secretInputMode?: SecretInputMode;
};
async function finalizeSearchProviderSetup(params: {
originalConfig: OpenClawConfig;
nextConfig: OpenClawConfig;
entry: PluginWebSearchProviderEntry;
runtime: RuntimeEnv;
prompter: WizardPrompter;
opts?: SetupSearchOptions;
}): Promise<OpenClawConfig> {
let next = preserveDisabledState(params.originalConfig, params.nextConfig);
if (!params.entry.runSetup) {
return next;
}
next = await params.entry.runSetup({
config: next,
runtime: params.runtime,
prompter: params.prompter,
quickstartDefaults: params.opts?.quickstartDefaults,
secretInputMode: params.opts?.secretInputMode,
});
return preserveDisabledState(params.originalConfig, next);
}
export async function runSearchSetupFlow(
config: OpenClawConfig,
_runtime: RuntimeEnv,
runtime: RuntimeEnv,
prompter: WizardPrompter,
opts?: SetupSearchOptions,
): Promise<OpenClawConfig> {
@@ -413,7 +435,14 @@ export async function runSearchSetupFlow(
const result = existingKey
? applySearchKey(config, choice, existingKey)
: applySearchProviderSelection(config, choice);
return preserveDisabledState(config, result);
return await finalizeSearchProviderSetup({
originalConfig: config,
nextConfig: result,
entry,
runtime,
prompter,
opts,
});
}
if (!needsCredential) {
@@ -425,13 +454,27 @@ export async function runSearchSetupFlow(
].join("\n"),
"Web search",
);
return preserveDisabledState(config, applySearchProviderSelection(config, choice));
return await finalizeSearchProviderSetup({
originalConfig: config,
nextConfig: applySearchProviderSelection(config, choice),
entry,
runtime,
prompter,
opts,
});
}
const useSecretRefMode = opts?.secretInputMode === "ref"; // pragma: allowlist secret
if (useSecretRefMode) {
if (keyConfigured) {
return preserveDisabledState(config, applySearchProviderSelection(config, choice));
return await finalizeSearchProviderSetup({
originalConfig: config,
nextConfig: applySearchProviderSelection(config, choice),
entry,
runtime,
prompter,
opts,
});
}
const ref = buildSearchEnvRef(config, choice);
await prompter.note(
@@ -443,7 +486,14 @@ export async function runSearchSetupFlow(
].join("\n"),
"Web search",
);
return applySearchKey(config, choice, ref);
return await finalizeSearchProviderSetup({
originalConfig: config,
nextConfig: applySearchKey(config, choice, ref),
entry,
runtime,
prompter,
opts,
});
}
const keyInput = await prompter.text({
@@ -458,15 +508,36 @@ export async function runSearchSetupFlow(
const key = keyInput?.trim() ?? "";
if (key) {
const secretInput = resolveSearchSecretInput(config, choice, key, opts?.secretInputMode);
return applySearchKey(config, choice, secretInput);
return await finalizeSearchProviderSetup({
originalConfig: config,
nextConfig: applySearchKey(config, choice, secretInput),
entry,
runtime,
prompter,
opts,
});
}
if (existingKey) {
return preserveDisabledState(config, applySearchKey(config, choice, existingKey));
return await finalizeSearchProviderSetup({
originalConfig: config,
nextConfig: applySearchKey(config, choice, existingKey),
entry,
runtime,
prompter,
opts,
});
}
if (keyConfigured || envAvailable) {
return preserveDisabledState(config, applySearchProviderSelection(config, choice));
return await finalizeSearchProviderSetup({
originalConfig: config,
nextConfig: applySearchProviderSelection(config, choice),
entry,
runtime,
prompter,
opts,
});
}
await prompter.note(

View File

@@ -2,6 +2,7 @@
import type {
WebSearchCredentialResolutionSource,
WebSearchProviderSetupContext,
WebSearchProviderPlugin,
WebSearchProviderToolDefinition,
} from "../plugins/types.js";
@@ -62,6 +63,7 @@ export { formatCliCommand } from "../cli/command-format.js";
export { wrapWebContent } from "../security/external-content.js";
export type {
WebSearchCredentialResolutionSource,
WebSearchProviderSetupContext,
WebSearchProviderPlugin,
WebSearchProviderToolDefinition,
};

View File

@@ -127,5 +127,8 @@ export function installWebSearchProviderContractSuite(params: {
expect(tool?.description.trim()).not.toBe("");
expect(tool?.parameters).toEqual(expect.any(Object));
expect(typeof tool?.execute).toBe("function");
if (provider.runSetup) {
expect(typeof provider.runSetup).toBe("function");
}
});
}

View File

@@ -1192,6 +1192,14 @@ export type WebSearchRuntimeMetadataContext = {
};
};
export type WebSearchProviderSetupContext = {
config: OpenClawConfig;
runtime: RuntimeEnv;
prompter: WizardPrompter;
quickstartDefaults?: boolean;
secretInputMode?: SecretInputMode;
};
export type WebSearchProviderPlugin = {
id: WebSearchProviderId;
label: string;
@@ -1219,6 +1227,7 @@ export type WebSearchProviderPlugin = {
getConfiguredCredentialValue?: (config?: OpenClawConfig) => unknown;
setConfiguredCredentialValue?: (configTarget: OpenClawConfig, value: unknown) => void;
applySelectionConfig?: (config: OpenClawConfig) => OpenClawConfig;
runSetup?: (ctx: WebSearchProviderSetupContext) => OpenClawConfig | Promise<OpenClawConfig>;
resolveRuntimeMetadata?: (
ctx: WebSearchRuntimeMetadataContext,
) => Partial<RuntimeWebSearchMetadata> | Promise<Partial<RuntimeWebSearchMetadata>>;