feat: add remote config overrides to memorySearch

This commit is contained in:
Muhammed Mukhthar CM
2026-01-12 15:33:35 +00:00
committed by Peter Steinberger
parent 4086408b10
commit ba316a10cc
8 changed files with 75 additions and 9 deletions

View File

@@ -81,8 +81,28 @@ Defaults:
Remote embeddings **require** an OpenAI API key (`OPENAI_API_KEY` or Remote embeddings **require** an OpenAI API key (`OPENAI_API_KEY` or
`models.providers.openai.apiKey`). Codex OAuth only covers chat/completions and `models.providers.openai.apiKey`). Codex OAuth only covers chat/completions and
does **not** satisfy embeddings for memory search. If you don't want to set an does **not** satisfy embeddings for memory search.
API key, use `memorySearch.provider = "local"` or set
If you want to use a **custom OpenAI-compatible endpoint** (like Gemini, OpenRouter, or a proxy),
you can use the `remote` configuration:
```json5
agents: {
defaults: {
memorySearch: {
provider: "openai",
model: "text-embedding-3-small",
remote: {
baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai/",
apiKey: "YOUR_GEMINI_API_KEY",
headers: { "X-Custom-Header": "value" }
}
}
}
}
```
If you don't want to set an API key, use `memorySearch.provider = "local"` or set
`memorySearch.fallback = "none"`. `memorySearch.fallback = "none"`.
Config example: Config example:

View File

@@ -241,6 +241,14 @@ Save to `~/.clawdbot/clawdbot.json` and you can DM the bot from that number.
prompt: "HEARTBEAT", prompt: "HEARTBEAT",
ackMaxChars: 300 ackMaxChars: 300
}, },
memorySearch: {
provider: "openai",
model: "text-embedding-004",
remote: {
baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai/",
apiKey: "${GEMINI_API_KEY}"
}
},
sandbox: { sandbox: {
mode: "non-main", mode: "non-main",
perSession: true, perSession: true,

View File

@@ -9,6 +9,11 @@ import { resolveAgentConfig } from "./agent-scope.js";
export type ResolvedMemorySearchConfig = { export type ResolvedMemorySearchConfig = {
enabled: boolean; enabled: boolean;
provider: "openai" | "local"; provider: "openai" | "local";
remote?: {
baseUrl?: string;
apiKey?: string;
headers?: Record<string, string>;
};
fallback: "openai" | "none"; fallback: "openai" | "none";
model: string; model: string;
local: { local: {
@@ -60,6 +65,7 @@ function mergeConfig(
): ResolvedMemorySearchConfig { ): ResolvedMemorySearchConfig {
const enabled = overrides?.enabled ?? defaults?.enabled ?? true; const enabled = overrides?.enabled ?? defaults?.enabled ?? true;
const provider = overrides?.provider ?? defaults?.provider ?? "openai"; const provider = overrides?.provider ?? defaults?.provider ?? "openai";
const remote = overrides?.remote ?? defaults?.remote;
const fallback = overrides?.fallback ?? defaults?.fallback ?? "openai"; const fallback = overrides?.fallback ?? defaults?.fallback ?? "openai";
const model = overrides?.model ?? defaults?.model ?? DEFAULT_MODEL; const model = overrides?.model ?? defaults?.model ?? DEFAULT_MODEL;
const local = { const local = {
@@ -112,6 +118,7 @@ function mergeConfig(
return { return {
enabled, enabled,
provider, provider,
remote,
fallback, fallback,
model, model,
local, local,

View File

@@ -118,6 +118,8 @@ const FIELD_LABELS: Record<string, string> = {
"agents.defaults.memorySearch": "Memory Search", "agents.defaults.memorySearch": "Memory Search",
"agents.defaults.memorySearch.enabled": "Enable Memory Search", "agents.defaults.memorySearch.enabled": "Enable Memory Search",
"agents.defaults.memorySearch.provider": "Memory Search Provider", "agents.defaults.memorySearch.provider": "Memory Search Provider",
"agents.defaults.memorySearch.remote.baseUrl": "Remote Embedding Base URL",
"agents.defaults.memorySearch.remote.apiKey": "Remote Embedding API Key",
"agents.defaults.memorySearch.model": "Memory Search Model", "agents.defaults.memorySearch.model": "Memory Search Model",
"agents.defaults.memorySearch.fallback": "Memory Search Fallback", "agents.defaults.memorySearch.fallback": "Memory Search Fallback",
"agents.defaults.memorySearch.local.modelPath": "Local Embedding Model Path", "agents.defaults.memorySearch.local.modelPath": "Local Embedding Model Path",
@@ -236,6 +238,10 @@ const FIELD_HELP: Record<string, string> = {
"Vector search over MEMORY.md and memory/*.md (per-agent overrides supported).", "Vector search over MEMORY.md and memory/*.md (per-agent overrides supported).",
"agents.defaults.memorySearch.provider": "agents.defaults.memorySearch.provider":
'Embedding provider ("openai" or "local").', 'Embedding provider ("openai" or "local").',
"agents.defaults.memorySearch.remote.baseUrl":
"Custom OpenAI-compatible base URL (e.g. for Gemini/OpenRouter proxies).",
"agents.defaults.memorySearch.remote.apiKey":
"Custom API key for the remote embedding provider.",
"agents.defaults.memorySearch.local.modelPath": "agents.defaults.memorySearch.local.modelPath":
"Local GGUF model path or hf: URI (node-llama-cpp).", "Local GGUF model path or hf: URI (node-llama-cpp).",
"agents.defaults.memorySearch.fallback": "agents.defaults.memorySearch.fallback":

View File

@@ -1011,6 +1011,11 @@ export type MemorySearchConfig = {
enabled?: boolean; enabled?: boolean;
/** Embedding provider mode. */ /** Embedding provider mode. */
provider?: "openai" | "local"; provider?: "openai" | "local";
remote?: {
baseUrl?: string;
apiKey?: string;
headers?: Record<string, string>;
};
/** Fallback behavior when local embeddings fail. */ /** Fallback behavior when local embeddings fail. */
fallback?: "openai" | "none"; fallback?: "openai" | "none";
/** Embedding model id (remote) or alias (local). */ /** Embedding model id (remote) or alias (local). */

View File

@@ -886,6 +886,13 @@ const MemorySearchSchema = z
.object({ .object({
enabled: z.boolean().optional(), enabled: z.boolean().optional(),
provider: z.union([z.literal("openai"), z.literal("local")]).optional(), provider: z.union([z.literal("openai"), z.literal("local")]).optional(),
remote: z
.object({
baseUrl: z.string().optional(),
apiKey: z.string().optional(),
headers: z.record(z.string(), z.string()).optional(),
})
.optional(),
fallback: z.union([z.literal("openai"), z.literal("none")]).optional(), fallback: z.union([z.literal("openai"), z.literal("none")]).optional(),
model: z.string().optional(), model: z.string().optional(),
local: z local: z

View File

@@ -20,6 +20,11 @@ export type EmbeddingProviderOptions = {
config: ClawdbotConfig; config: ClawdbotConfig;
agentDir?: string; agentDir?: string;
provider: "openai" | "local"; provider: "openai" | "local";
remote?: {
baseUrl?: string;
apiKey?: string;
headers?: Record<string, string>;
};
model: string; model: string;
fallback: "openai" | "none"; fallback: "openai" | "none";
local?: { local?: {
@@ -42,16 +47,23 @@ function normalizeOpenAiModel(model: string): string {
async function createOpenAiEmbeddingProvider( async function createOpenAiEmbeddingProvider(
options: EmbeddingProviderOptions, options: EmbeddingProviderOptions,
): Promise<EmbeddingProvider> { ): Promise<EmbeddingProvider> {
const { apiKey } = await resolveApiKeyForProvider({ const remote = options.config.agents?.defaults?.memorySearch?.remote;
provider: "openai",
cfg: options.config, const { apiKey } = remote?.apiKey
agentDir: options.agentDir, ? { apiKey: remote.apiKey }
}); : await resolveApiKeyForProvider({
provider: "openai",
cfg: options.config,
agentDir: options.agentDir,
});
const providerConfig = options.config.models?.providers?.openai; const providerConfig = options.config.models?.providers?.openai;
const baseUrl = providerConfig?.baseUrl?.trim() || DEFAULT_OPENAI_BASE_URL; const baseUrl =
remote?.baseUrl?.trim() ||
providerConfig?.baseUrl?.trim() ||
DEFAULT_OPENAI_BASE_URL;
const url = `${baseUrl.replace(/\/$/, "")}/embeddings`; const url = `${baseUrl.replace(/\/$/, "")}/embeddings`;
const headerOverrides = providerConfig?.headers ?? {}; const headerOverrides = remote?.headers ?? providerConfig?.headers ?? {};
const headers: Record<string, string> = { const headers: Record<string, string> = {
"Content-Type": "application/json", "Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`, Authorization: `Bearer ${apiKey}`,

View File

@@ -88,6 +88,7 @@ export class MemoryIndexManager {
config: cfg, config: cfg,
agentDir: resolveAgentDir(cfg, agentId), agentDir: resolveAgentDir(cfg, agentId),
provider: settings.provider, provider: settings.provider,
remote: settings.remote,
model: settings.model, model: settings.model,
fallback: settings.fallback, fallback: settings.fallback,
local: settings.local, local: settings.local,