mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-13 23:56:07 +00:00
feat(xai): add plugin-owned x_search onboarding
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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 {
|
||||
|
||||
85
src/flows/search-setup.test.ts
Normal file
85
src/flows/search-setup.test.ts
Normal 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",
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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>>;
|
||||
|
||||
Reference in New Issue
Block a user