Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/Java/Openclaw/src/agents/   (KI Agentensystem Version 22©)  Datei vom 26.3.2026 mit Größe 15 kB image not shown  

Quelle  memory-search.test.ts

  Sprache: JAVA
 

import { afterEach, beforeEach, describe, expect, it } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
import {
  clearMemoryEmbeddingProviders,
  registerMemoryEmbeddingProvider,
} from "../plugins/memory-embedding-providers.js";
import { resolveMemorySearchConfig, resolveMemorySearchSyncConfig } from "./memory-search.js";

const asConfig = (cfg: OpenClawConfig): OpenClawConfig => cfg;

function registerBaseMemoryEmbeddingProviders(options?: { includeGemini?: boolean }): void {
  registerMemoryEmbeddingProvider({
    id: "openai",
    defaultModel: "text-embedding-3-small",
    transport: "remote",
    create: async () => ({ provider: null }),
  });
  registerMemoryEmbeddingProvider({
    id: "local",
    defaultModel: "local-default",
    transport: "local",
    create: async () => ({ provider: null }),
  });
  if (options?.includeGemini !== false) {
    registerMemoryEmbeddingProvider({
      id: "gemini",
      defaultModel: "gemini-embedding-001",
      transport: "remote",
      supportsMultimodalEmbeddings: ({ model }) =>
        model
          .trim()
          .replace(/^models\//, "")
          .replace(/^(gemini|google)\//, "") === "gemini-embedding-2-preview",
      create: async () => ({ provider: null }),
    });
  }
  registerMemoryEmbeddingProvider({
    id: "voyage",
    defaultModel: "voyage-4-large",
    transport: "remote",
    create: async () => ({ provider: null }),
  });
  registerMemoryEmbeddingProvider({
    id: "mistral",
    defaultModel: "mistral-embed",
    transport: "remote",
    create: async () => ({ provider: null }),
  });
  registerMemoryEmbeddingProvider({
    id: "lmstudio",
    defaultModel: "text-embedding-nomic-embed-text-v1.5",
    transport: "remote",
    create: async () => ({ provider: null }),
  });
  registerMemoryEmbeddingProvider({
    id: "ollama",
    defaultModel: "nomic-embed-text",
    transport: "remote",
    create: async () => ({ provider: null }),
  });
}

describe("memory search config", () => {
  beforeEach(() => {
    clearMemoryEmbeddingProviders();
    registerBaseMemoryEmbeddingProviders();
  });

  afterEach(() => {
    clearMemoryEmbeddingProviders();
  });

  function configWithDefaultProvider(provider: string): OpenClawConfig {
    return asConfig({
      agents: {
        defaults: {
          memorySearch: {
            provider,
          },
        },
      },
    });
  }

  function expectDefaultRemoteBatch(resolved: ReturnType<typeof resolveMemorySearchConfig>): void {
    expect(resolved?.remote?.batch).toEqual({
      enabled: false,
      wait: true,
      concurrency: 2,
      pollIntervalMs: 2000,
      timeoutMinutes: 60,
    });
  }

  function expectEmptyMultimodalConfig(resolved: ReturnType<typeof resolveMemorySearchConfig>) {
    expect(resolved?.multimodal).toEqual({
      enabled: true,
      modalities: [],
      maxFileBytes: 10 * 1024 * 1024,
    });
  }

  function configWithRemoteDefaults(remote: Record<string, unknown>) {
    return asConfig({
      agents: {
        defaults: {
          memorySearch: {
            provider: "openai",
            remote,
          },
        },
        list: [
          {
            id: "main",
            defaulttrue,
            memorySearch: {
              remote: {
                baseUrl: "https://agent.example/v1",
              },
            },
          },
        ],
      },
    });
  }

  function expectMergedRemoteConfig(
    resolved: ReturnType<typeof resolveMemorySearchConfig>,
    apiKey: unknown,
  ) {
    expect(resolved?.remote).toEqual({
      baseUrl: "https://agent.example/v1",
      apiKey,
      headers: { "X-Default""on" },
      batch: {
        enabled: false,
        wait: true,
        concurrency: 2,
        pollIntervalMs: 2000,
        timeoutMinutes: 60,
      },
    });
  }

  it("returns null when disabled", () => {
    const cfg = asConfig({
      agents: {
        defaults: {
          memorySearch: { enabled: true },
        },
        list: [
          {
            id: "main",
            defaulttrue,
            memorySearch: { enabled: false },
          },
        ],
      },
    });
    const resolved = resolveMemorySearchConfig(cfg, "main");
    expect(resolved).toBeNull();
  });

  it("returns null sync config when disabled", () => {
    const cfg = asConfig({
      agents: {
        defaults: {
          memorySearch: { enabled: true },
        },
        list: [
          {
            id: "main",
            defaulttrue,
            memorySearch: { enabled: false },
          },
        ],
      },
    });
    const resolved = resolveMemorySearchSyncConfig(cfg, "main");
    expect(resolved).toBeNull();
  });

  it("defaults provider to auto when unspecified", () => {
    const cfg = asConfig({
      agents: {
        defaults: {
          memorySearch: {
            enabled: true,
          },
        },
      },
    });
    const resolved = resolveMemorySearchConfig(cfg, "main");
    expect(resolved?.provider).toBe("auto");
    expect(resolved?.fallback).toBe("none");
  });

  it("resolves sync config without consulting embedding providers", () => {
    clearMemoryEmbeddingProviders();
    const cfg = asConfig({
      agents: {
        defaults: {
          memorySearch: {
            provider: "openai",
            sync: {
              onSessionStart: false,
              onSearch: true,
              watch: false,
              watchDebounceMs: 25,
              intervalMinutes: 3,
              sessions: {
                deltaBytes: 321,
                deltaMessages: 7,
                postCompactionForce: false,
              },
            },
          },
        },
      },
    });

    expect(resolveMemorySearchSyncConfig(cfg, "main")).toEqual({
      onSessionStart: false,
      onSearch: true,
      watch: false,
      watchDebounceMs: 25,
      intervalMinutes: 3,
      sessions: {
        deltaBytes: 321,
        deltaMessages: 7,
        postCompactionForce: false,
      },
    });
  });

  it("merges defaults and overrides", () => {
    const cfg = asConfig({
      agents: {
        defaults: {
          memorySearch: {
            provider: "openai",
            model: "text-embedding-3-small",
            store: {
              vector: {
                enabled: false,
                extensionPath: "/opt/sqlite-vec.dylib",
              },
            },
            chunking: { tokens: 500, overlap: 100 },
            query: { maxResults: 4, minScore: 0.2 },
          },
        },
        list: [
          {
            id: "main",
            defaulttrue,
            memorySearch: {
              chunking: { tokens: 320 },
              query: { maxResults: 8 },
              store: {
                vector: {
                  enabled: true,
                },
              },
            },
          },
        ],
      },
    });
    const resolved = resolveMemorySearchConfig(cfg, "main");
    expect(resolved?.provider).toBe("openai");
    expect(resolved?.model).toBe("text-embedding-3-small");
    expect(resolved?.chunking.tokens).toBe(320);
    expect(resolved?.chunking.overlap).toBe(100);
    expect(resolved?.query.maxResults).toBe(8);
    expect(resolved?.query.minScore).toBe(0.2);
    expect(resolved?.store.vector.enabled).toBe(true);
    expect(resolved?.store.vector.extensionPath).toBe("/opt/sqlite-vec.dylib");
  });

  it("merges extra memory paths from defaults and overrides", () => {
    const cfg = asConfig({
      agents: {
        defaults: {
          memorySearch: {
            extraPaths: ["/shared/notes"" docs "],
          },
        },
        list: [
          {
            id: "main",
            defaulttrue,
            memorySearch: {
              extraPaths: ["/shared/notes""../team-notes"],
            },
          },
        ],
      },
    });
    const resolved = resolveMemorySearchConfig(cfg, "main");
    expect(resolved?.extraPaths).toEqual(["/shared/notes""docs""../team-notes"]);
  });

  it("normalizes multimodal settings", () => {
    const cfg = asConfig({
      agents: {
        defaults: {
          memorySearch: {
            provider: "gemini",
            model: "gemini-embedding-2-preview",
            multimodal: {
              enabled: true,
              modalities: ["all"],
              maxFileBytes: 8192,
            },
          },
        },
      },
    });
    const resolved = resolveMemorySearchConfig(cfg, "main");
    expect(resolved?.multimodal).toEqual({
      enabled: true,
      modalities: ["image""audio"],
      maxFileBytes: 8192,
    });
  });

  it("keeps an explicit empty multimodal modalities list empty", () => {
    const cfg = asConfig({
      agents: {
        defaults: {
          memorySearch: {
            provider: "gemini",
            model: "gemini-embedding-2-preview",
            multimodal: {
              enabled: true,
              modalities: [],
            },
          },
        },
      },
    });
    const resolved = resolveMemorySearchConfig(cfg, "main");
    expectEmptyMultimodalConfig(resolved);
    expect(resolved?.provider).toBe("gemini");
  });

  it("does not enforce multimodal provider validation when no modalities are active", () => {
    const cfg = asConfig({
      agents: {
        defaults: {
          memorySearch: {
            provider: "openai",
            model: "text-embedding-3-small",
            fallback: "openai",
            multimodal: {
              enabled: true,
              modalities: [],
            },
          },
        },
      },
    });
    const resolved = resolveMemorySearchConfig(cfg, "main");
    expectEmptyMultimodalConfig(resolved);
  });

  it("rejects multimodal memory on unsupported providers", () => {
    const cfg = asConfig({
      agents: {
        defaults: {
          memorySearch: {
            provider: "openai",
            model: "text-embedding-3-small",
            multimodal: { enabled: true, modalities: ["image"] },
          },
        },
      },
    });
    expect(() => resolveMemorySearchConfig(cfg, "main")).toThrow(
      /memorySearch\.multimodal requires a provider adapter that supports multimodal embeddings/,
    );
  });

  it("accepts Gemini multimodal memory even when the runtime registry has not registered Gemini yet", () => {
    clearMemoryEmbeddingProviders();
    registerBaseMemoryEmbeddingProviders({ includeGemini: false });
    const cfg = asConfig({
      agents: {
        defaults: {
          memorySearch: {
            provider: "gemini",
            model: "gemini-embedding-2-preview",
            multimodal: { enabled: true, modalities: ["image"] },
          },
        },
      },
    });
    const resolved = resolveMemorySearchConfig(cfg, "main");
    expect(resolved?.provider).toBe("gemini");
    expect(resolved?.multimodal).toEqual({
      enabled: true,
      modalities: ["image"],
      maxFileBytes: 10 * 1024 * 1024,
    });
  });

  it("rejects multimodal memory when fallback is configured", () => {
    const cfg = asConfig({
      agents: {
        defaults: {
          memorySearch: {
            provider: "gemini",
            model: "gemini-embedding-2-preview",
            fallback: "openai",
            multimodal: { enabled: true, modalities: ["image"] },
          },
        },
      },
    });
    expect(() => resolveMemorySearchConfig(cfg, "main")).toThrow(
      /memorySearch\.multimodal does not support memorySearch\.fallback/,
    );
  });

  it("includes batch defaults for openai without remote overrides", () => {
    const cfg = configWithDefaultProvider("openai");
    const resolved = resolveMemorySearchConfig(cfg, "main");
    expectDefaultRemoteBatch(resolved);
  });

  it("keeps remote unset for local provider without overrides", () => {
    const cfg = configWithDefaultProvider("local");
    const resolved = resolveMemorySearchConfig(cfg, "main");
    expect(resolved?.remote).toBeUndefined();
  });

  it("includes remote defaults for gemini without overrides", () => {
    const cfg = configWithDefaultProvider("gemini");
    const resolved = resolveMemorySearchConfig(cfg, "main");
    expectDefaultRemoteBatch(resolved);
  });

  it("includes remote defaults and model default for mistral without overrides", () => {
    const cfg = configWithDefaultProvider("mistral");
    const resolved = resolveMemorySearchConfig(cfg, "main");
    expectDefaultRemoteBatch(resolved);
    expect(resolved?.model).toBe("mistral-embed");
  });

  it("includes remote defaults and model default for lmstudio without overrides", () => {
    const cfg = configWithDefaultProvider("lmstudio");
    const resolved = resolveMemorySearchConfig(cfg, "main");
    expectDefaultRemoteBatch(resolved);
    expect(resolved?.model).toBe("text-embedding-nomic-embed-text-v1.5");
  });

  it("includes remote defaults and model default for ollama without overrides", () => {
    const cfg = configWithDefaultProvider("ollama");
    const resolved = resolveMemorySearchConfig(cfg, "main");
    expectDefaultRemoteBatch(resolved);
    expect(resolved?.model).toBe("nomic-embed-text");
  });

  it("defaults session delta thresholds", () => {
    const cfg = asConfig({
      agents: {
        defaults: {
          memorySearch: {
            provider: "openai",
          },
        },
      },
    });
    const resolved = resolveMemorySearchConfig(cfg, "main");
    expect(resolved?.sync.sessions).toEqual({
      deltaBytes: 100000,
      deltaMessages: 50,
      postCompactionForce: true,
    });
  });

  it("merges remote defaults with agent overrides", () => {
    const cfg = configWithRemoteDefaults({
      baseUrl: "https://default.example/v1",
      apiKey: "default-key"// pragma: allowlist secret
      headers: { "X-Default""on" },
    });
    const resolved = resolveMemorySearchConfig(cfg, "main");
    expectMergedRemoteConfig(resolved, "default-key"); // pragma: allowlist secret
  });

  it("preserves SecretRef remote apiKey when merging defaults with agent overrides", () => {
    const cfg = configWithRemoteDefaults({
      apiKey: { source: "env", provider: "default", id: "OPENAI_API_KEY" }, // pragma: allowlist secret
      headers: { "X-Default""on" },
    });

    const resolved = resolveMemorySearchConfig(cfg, "main");

    expectMergedRemoteConfig(resolved, {
      source: "env",
      provider: "default",
      id: "OPENAI_API_KEY",
    });
  });

  it("gates session sources behind experimental flag", () => {
    const cfg = asConfig({
      agents: {
        defaults: {
          memorySearch: {
            provider: "openai",
            sources: ["memory""sessions"],
          },
        },
        list: [
          {
            id: "main",
            defaulttrue,
            memorySearch: {
              experimental: { sessionMemory: false },
            },
          },
        ],
      },
    });
    const resolved = resolveMemorySearchConfig(cfg, "main");
    expect(resolved?.sources).toEqual(["memory"]);
  });

  it("allows session sources when experimental flag is enabled", () => {
    const cfg = asConfig({
      agents: {
        defaults: {
          memorySearch: {
            provider: "openai",
            sources: ["memory""sessions"],
            experimental: { sessionMemory: true },
          },
        },
      },
    });
    const resolved = resolveMemorySearchConfig(cfg, "main");
    expect(resolved?.sources).toContain("sessions");
  });
});

Messung V0.5 in Prozent
C=99 H=100 G=99

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet am  2026-05-26) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.