diff --git a/src/commands/configure.wizard.ts b/src/commands/configure.wizard.ts index 80af67043ab..c4349e0f74b 100644 --- a/src/commands/configure.wizard.ts +++ b/src/commands/configure.wizard.ts @@ -188,10 +188,7 @@ async function promptWebToolsConfig( if (stored && SEARCH_PROVIDER_OPTIONS.some((e) => e.value === stored)) { return stored; } - return ( - SEARCH_PROVIDER_OPTIONS.find((e) => hasKeyForProvider(e.value))?.value ?? - SEARCH_PROVIDER_OPTIONS[0].value - ); + return SEARCH_PROVIDER_OPTIONS.find((e) => hasKeyForProvider(e.value))?.value ?? "brave"; })(); note( @@ -303,6 +300,122 @@ async function promptWebToolsConfig( }; } +async function promptCortexMemoryConfig( + nextConfig: OpenClawConfig, + runtime: RuntimeEnv, + workspaceDir: string, +): Promise { + const existing = nextConfig.agents?.defaults?.cortex; + const defaultGraphPath = nodePath.join(workspaceDir, ".cortex", "context.json"); + const graphExists = await fsPromises + .access(defaultGraphPath) + .then(() => true) + .catch(() => false); + + note( + [ + "Cortex can prepend a filtered local memory graph into agent system prompts.", + `Default workspace graph: ${defaultGraphPath}`, + graphExists + ? "A local Cortex graph was detected in this workspace." + : "No default Cortex graph was detected yet; you can still enable the bridge now.", + ].join("\n"), + "Cortex memory", + ); + + const enable = guardCancel( + await confirm({ + message: "Enable Cortex prompt bridge?", + initialValue: existing?.enabled ?? graphExists, + }), + runtime, + ); + + if (!enable) { + return { + ...nextConfig, + agents: { + ...nextConfig.agents, + defaults: { + ...nextConfig.agents?.defaults, + cortex: { + ...existing, + enabled: false, + }, + }, + }, + }; + } + + const mode = guardCancel( + await select({ + message: "Cortex prompt mode", + options: [ + { value: "technical", label: "Technical", hint: "Project and coding context" }, + { value: "professional", label: "Professional", hint: "Work-safe context slice" }, + { value: "minimal", label: "Minimal", hint: "Smallest safe context" }, + { value: "full", label: "Full", hint: "Largest context slice" }, + ], + initialValue: existing?.mode ?? "technical", + }), + runtime, + ) as NonNullable["defaults"]>["cortex"]["mode"]; + + const maxCharsInput = guardCancel( + await text({ + message: "Cortex max prompt chars", + initialValue: String(existing?.maxChars ?? 1500), + validate: (value) => { + const parsed = Number.parseInt(String(value), 10); + if (!Number.isFinite(parsed) || parsed <= 0) { + return "Enter a positive integer"; + } + return undefined; + }, + }), + runtime, + ); + const maxChars = Number.parseInt(String(maxCharsInput), 10); + + const useDefaultGraph = guardCancel( + await confirm({ + message: "Use the default workspace Cortex graph path?", + initialValue: !existing?.graphPath, + }), + runtime, + ); + + let graphPath: string | undefined; + if (!useDefaultGraph) { + const graphInput = guardCancel( + await text({ + message: "Cortex graph path", + initialValue: existing?.graphPath ?? defaultGraphPath, + }), + runtime, + ); + const trimmed = String(graphInput ?? "").trim(); + graphPath = trimmed || defaultGraphPath; + } + + return { + ...nextConfig, + agents: { + ...nextConfig.agents, + defaults: { + ...nextConfig.agents?.defaults, + cortex: { + ...existing, + enabled: true, + mode, + maxChars, + ...(graphPath ? { graphPath } : {}), + }, + }, + }, + }; +} + export async function runConfigureWizard( opts: ConfigureWizardParams, runtime: RuntimeEnv = defaultRuntime, @@ -530,6 +643,10 @@ export async function runConfigureWizard( nextConfig = await promptWebToolsConfig(nextConfig, runtime); } + if (selected.includes("memory")) { + nextConfig = await promptCortexMemoryConfig(nextConfig, runtime, workspaceDir); + } + if (selected.includes("gateway")) { const gateway = await promptGatewayConfig(nextConfig, runtime); nextConfig = gateway.config; @@ -584,6 +701,11 @@ export async function runConfigureWizard( await persistConfig(); } + if (choice === "memory") { + nextConfig = await promptCortexMemoryConfig(nextConfig, runtime, workspaceDir); + await persistConfig(); + } + if (choice === "gateway") { const gateway = await promptGatewayConfig(nextConfig, runtime); nextConfig = gateway.config;