@smyslenny/agent-memory 4.2.0 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -22,7 +22,7 @@ AgentMemory is a SQLite-first memory layer for AI agents. It lets an agent:
22
22
  - **maintain** them over time with `reflect`, `reindex`, and feedback signals
23
23
  - **integrate** through **CLI**, **MCP stdio**, or **HTTP/SSE**
24
24
 
25
- Current release: **`4.0.0-alpha.1`**.
25
+ Current release: **`4.3.0`**.
26
26
 
27
27
  Without an embedding provider, AgentMemory still works in **BM25-only mode**.
28
28
  With one configured, it adds **hybrid recall** and **semantic dedup**.
@@ -691,6 +691,44 @@ function createLocalHttpEmbeddingProvider(opts) {
691
691
  }
692
692
  };
693
693
  }
694
+ function createGeminiEmbeddingProvider(opts) {
695
+ const id = stableProviderId(`gemini:${opts.model}`, `${opts.model}|${opts.dimension}`);
696
+ return {
697
+ id,
698
+ model: opts.model,
699
+ dimension: opts.dimension,
700
+ async embed(texts) {
701
+ if (texts.length === 0) return [];
702
+ const fetchFn = getFetch(opts.fetchImpl);
703
+ const url = `https://generativelanguage.googleapis.com/v1beta/models/${opts.model}:batchEmbedContents?key=${opts.apiKey}`;
704
+ const requests = texts.map((text) => ({
705
+ model: `models/${opts.model}`,
706
+ content: { parts: [{ text }] },
707
+ outputDimensionality: opts.dimension
708
+ }));
709
+ const response = await fetchFn(url, {
710
+ method: "POST",
711
+ headers: { "content-type": "application/json" },
712
+ body: JSON.stringify({ requests })
713
+ });
714
+ if (!response.ok) {
715
+ const detail = await response.text().catch(() => "");
716
+ throw new Error(`Gemini embedding request failed: ${response.status} ${response.statusText}${detail ? ` \u2014 ${detail}` : ""}`);
717
+ }
718
+ const json2 = await response.json();
719
+ const embeddings = json2?.embeddings;
720
+ if (!Array.isArray(embeddings)) {
721
+ throw new Error("Gemini embedding response missing embeddings array");
722
+ }
723
+ return embeddings.map(
724
+ (entry, index) => assertEmbeddingVector(entry?.values, opts.dimension, `Gemini embedding item ${index}`)
725
+ );
726
+ },
727
+ async healthcheck() {
728
+ await this.embed(["healthcheck"]);
729
+ }
730
+ };
731
+ }
694
732
  function normalizeEmbeddingBaseUrl(baseUrl) {
695
733
  return trimTrailingSlashes(baseUrl);
696
734
  }
@@ -708,7 +746,7 @@ function parseDimension(raw) {
708
746
  }
709
747
  function parseProvider(raw) {
710
748
  if (!raw) return null;
711
- if (raw === "openai-compatible" || raw === "local-http") {
749
+ if (raw === "openai-compatible" || raw === "local-http" || raw === "gemini") {
712
750
  return raw;
713
751
  }
714
752
  throw new Error(`Unsupported embedding provider: ${raw}`);
@@ -719,8 +757,8 @@ function getEmbeddingProviderConfigFromEnv(env = process.env) {
719
757
  const baseUrl = env.AGENT_MEMORY_EMBEDDING_BASE_URL;
720
758
  const model = env.AGENT_MEMORY_EMBEDDING_MODEL;
721
759
  const dimension = parseDimension(env.AGENT_MEMORY_EMBEDDING_DIMENSION);
722
- if (!baseUrl) {
723
- throw new Error("AGENT_MEMORY_EMBEDDING_BASE_URL is required when embeddings are enabled");
760
+ if (!baseUrl && provider !== "gemini") {
761
+ throw new Error("AGENT_MEMORY_EMBEDDING_BASE_URL is required when embeddings are enabled (not needed for gemini provider)");
724
762
  }
725
763
  if (!model) {
726
764
  throw new Error("AGENT_MEMORY_EMBEDDING_MODEL is required when embeddings are enabled");
@@ -731,9 +769,12 @@ function getEmbeddingProviderConfigFromEnv(env = process.env) {
731
769
  if (provider === "openai-compatible" && !env.AGENT_MEMORY_EMBEDDING_API_KEY) {
732
770
  throw new Error("AGENT_MEMORY_EMBEDDING_API_KEY is required for openai-compatible providers");
733
771
  }
772
+ if (provider === "gemini" && !env.AGENT_MEMORY_EMBEDDING_API_KEY) {
773
+ throw new Error("AGENT_MEMORY_EMBEDDING_API_KEY is required for gemini provider (Google AI API key)");
774
+ }
734
775
  return {
735
776
  provider,
736
- baseUrl,
777
+ baseUrl: baseUrl ?? "",
737
778
  model,
738
779
  dimension,
739
780
  apiKey: env.AGENT_MEMORY_EMBEDDING_API_KEY
@@ -742,8 +783,16 @@ function getEmbeddingProviderConfigFromEnv(env = process.env) {
742
783
  function createEmbeddingProvider(input, opts) {
743
784
  const normalized = {
744
785
  ...input,
745
- baseUrl: normalizeEmbeddingBaseUrl(input.baseUrl)
786
+ baseUrl: input.baseUrl ? normalizeEmbeddingBaseUrl(input.baseUrl) : ""
746
787
  };
788
+ if (normalized.provider === "gemini") {
789
+ return createGeminiEmbeddingProvider({
790
+ model: normalized.model,
791
+ dimension: normalized.dimension,
792
+ apiKey: normalized.apiKey,
793
+ fetchImpl: opts?.fetchImpl
794
+ });
795
+ }
747
796
  if (normalized.provider === "openai-compatible") {
748
797
  return createOpenAICompatibleEmbeddingProvider({
749
798
  baseUrl: normalized.baseUrl,
@@ -770,13 +819,16 @@ function resolveEmbeddingProviderConfig(opts) {
770
819
  const model = opts?.config?.model ?? envConfig?.model;
771
820
  const dimension = opts?.config?.dimension ?? envConfig?.dimension;
772
821
  const apiKey = opts?.config?.apiKey ?? envConfig?.apiKey;
773
- if (!provider || !baseUrl || !model || !dimension) {
822
+ if (!provider || !model || !dimension) {
774
823
  throw new Error("Incomplete embedding provider configuration");
775
824
  }
776
- if (provider === "openai-compatible" && !apiKey) {
777
- throw new Error("OpenAI-compatible embedding providers require an API key");
825
+ if (provider !== "gemini" && !baseUrl) {
826
+ throw new Error("baseUrl is required for non-gemini embedding providers");
827
+ }
828
+ if ((provider === "openai-compatible" || provider === "gemini") && !apiKey) {
829
+ throw new Error(`${provider} embedding provider requires an API key`);
778
830
  }
779
- return { provider, baseUrl, model, dimension, apiKey };
831
+ return { provider, baseUrl: baseUrl ?? "", model, dimension, apiKey };
780
832
  }
781
833
  function getEmbeddingProvider(opts) {
782
834
  const config = resolveEmbeddingProviderConfig({ config: opts?.config, env: opts?.env });