@tpsdev-ai/flair 0.3.14 → 0.3.15

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.
@@ -1,6 +1,6 @@
1
1
  import { patchRecord } from "./table-helpers.js";
2
2
  import { server, databases } from "@harperfast/harper";
3
- import { initEmbeddings, getEmbedding } from "./embeddings-provider.js";
3
+ import { getEmbedding } from "./embeddings-provider.js";
4
4
  // --- Admin credentials ---
5
5
  // Admin auth is sourced exclusively from Harper's own environment variables
6
6
  // (HDB_ADMIN_PASSWORD / FLAIR_ADMIN_PASSWORD). No filesystem token file.
@@ -93,7 +93,6 @@ async function importEd25519Key(publicKeyStr) {
93
93
  keyCache.set(publicKeyStr, key);
94
94
  return key;
95
95
  }
96
- initEmbeddings().catch((err) => console.error("[embeddings] init:", err.message));
97
96
  async function backfillEmbedding(memoryId) {
98
97
  try {
99
98
  const record = await databases.flair.Memory.get(memoryId);
@@ -2,59 +2,35 @@
2
2
  * embeddings-provider.ts
3
3
  *
4
4
  * Thin wrapper around harper-fabric-embeddings for Flair resources.
5
- * harper-fabric-embeddings handles loading and running the embedding model
6
- * at the Harper sub-component level we just delegate to its exported API.
7
- *
8
- * On platforms where the native binary isn't available, getEmbedding()
9
- * returns null and semantic search falls back to keyword matching.
5
+ * harper-fabric-embeddings is loaded by Harper as a sub-component
6
+ * (declared in config.yaml). It downloads the model and initializes
7
+ * in the background. We just call embed() — if it's not ready yet,
8
+ * we return null and the caller handles it gracefully.
10
9
  */
11
10
  import * as hfe from "harper-fabric-embeddings";
12
- const SINGLETON_KEY = "__flair_hfe_provider_v1__";
13
- function getState() {
14
- if (!globalThis[SINGLETON_KEY]) {
15
- globalThis[SINGLETON_KEY] = { initialized: false, available: false };
16
- }
17
- return globalThis[SINGLETON_KEY];
18
- }
19
- export async function initEmbeddings() {
20
- const state = getState();
21
- if (state.initialized)
22
- return;
23
- // harper-fabric-embeddings is initialized by Harper as a sub-component
24
- // (declared in config.yaml). It inits in the background so it may not
25
- // be ready when resources first load. Retry a few times before giving up.
26
- for (let attempt = 1; attempt <= 10; attempt++) {
27
- try {
28
- const dims = hfe.dimensions();
29
- state.available = true;
30
- state.initialized = true;
31
- console.log(`[embeddings] ready (${dims} dims, attempt ${attempt})`);
32
- return;
33
- }
34
- catch {
35
- if (attempt < 10)
36
- await new Promise(r => setTimeout(r, 500));
37
- }
38
- }
39
- console.log("[embeddings] not available after 10 attempts — search will be keyword-only");
40
- state.available = false;
41
- state.initialized = true;
42
- }
11
+ /**
12
+ * Generate an embedding vector for the given text.
13
+ * Returns null if the embedding engine isn't ready yet (model still loading)
14
+ * or not available on this platform. Never gives up permanently — each call
15
+ * checks independently.
16
+ */
43
17
  export async function getEmbedding(text) {
44
- const state = getState();
45
- if (!state.initialized)
46
- await initEmbeddings();
47
- if (!state.available)
48
- return null;
49
18
  try {
50
- return hfe.embed(text);
19
+ return await hfe.embed(text);
51
20
  }
52
- catch (err) {
53
- console.log(`[embeddings] embed failed: ${err.message}`);
21
+ catch {
54
22
  return null;
55
23
  }
56
24
  }
25
+ /**
26
+ * Check if the embedding engine is currently available.
27
+ */
57
28
  export function getMode() {
58
- const state = getState();
59
- return state.available ? "local" : "none";
29
+ try {
30
+ hfe.dimensions();
31
+ return "local";
32
+ }
33
+ catch {
34
+ return "none";
35
+ }
60
36
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tpsdev-ai/flair",
3
- "version": "0.3.14",
3
+ "version": "0.3.15",
4
4
  "description": "Identity, memory, and soul for AI agents. Cryptographic identity (Ed25519), semantic memory with local embeddings, and persistent personality — all in a single process.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -1,6 +1,6 @@
1
1
  import { patchRecord } from "./table-helpers.js";
2
2
  import { server, databases } from "@harperfast/harper";
3
- import { initEmbeddings, getEmbedding } from "./embeddings-provider.js";
3
+ import { getEmbedding } from "./embeddings-provider.js";
4
4
 
5
5
  // --- Admin credentials ---
6
6
  // Admin auth is sourced exclusively from Harper's own environment variables
@@ -102,7 +102,6 @@ async function importEd25519Key(publicKeyStr: string): Promise<CryptoKey> {
102
102
  return key;
103
103
  }
104
104
 
105
- initEmbeddings().catch((err: any) => console.error("[embeddings] init:", err.message));
106
105
 
107
106
  async function backfillEmbedding(memoryId: string): Promise<void> {
108
107
  try {
@@ -2,66 +2,36 @@
2
2
  * embeddings-provider.ts
3
3
  *
4
4
  * Thin wrapper around harper-fabric-embeddings for Flair resources.
5
- * harper-fabric-embeddings handles loading and running the embedding model
6
- * at the Harper sub-component level we just delegate to its exported API.
7
- *
8
- * On platforms where the native binary isn't available, getEmbedding()
9
- * returns null and semantic search falls back to keyword matching.
5
+ * harper-fabric-embeddings is loaded by Harper as a sub-component
6
+ * (declared in config.yaml). It downloads the model and initializes
7
+ * in the background. We just call embed() — if it's not ready yet,
8
+ * we return null and the caller handles it gracefully.
10
9
  */
11
10
 
12
11
  import * as hfe from "harper-fabric-embeddings";
13
12
 
14
- const SINGLETON_KEY = "__flair_hfe_provider_v1__";
15
-
16
- interface ProviderState {
17
- initialized: boolean;
18
- available: boolean;
19
- }
20
-
21
- function getState(): ProviderState {
22
- if (!(globalThis as any)[SINGLETON_KEY]) {
23
- (globalThis as any)[SINGLETON_KEY] = { initialized: false, available: false };
24
- }
25
- return (globalThis as any)[SINGLETON_KEY];
26
- }
27
-
28
- export async function initEmbeddings(): Promise<void> {
29
- const state = getState();
30
- if (state.initialized) return;
31
-
32
- // harper-fabric-embeddings is initialized by Harper as a sub-component
33
- // (declared in config.yaml). It inits in the background so it may not
34
- // be ready when resources first load. Retry a few times before giving up.
35
- for (let attempt = 1; attempt <= 10; attempt++) {
36
- try {
37
- const dims = hfe.dimensions();
38
- state.available = true;
39
- state.initialized = true;
40
- console.log(`[embeddings] ready (${dims} dims, attempt ${attempt})`);
41
- return;
42
- } catch {
43
- if (attempt < 10) await new Promise(r => setTimeout(r, 500));
44
- }
45
- }
46
-
47
- console.log("[embeddings] not available after 10 attempts — search will be keyword-only");
48
- state.available = false;
49
- state.initialized = true;
50
- }
51
-
13
+ /**
14
+ * Generate an embedding vector for the given text.
15
+ * Returns null if the embedding engine isn't ready yet (model still loading)
16
+ * or not available on this platform. Never gives up permanently — each call
17
+ * checks independently.
18
+ */
52
19
  export async function getEmbedding(text: string): Promise<number[] | null> {
53
- const state = getState();
54
- if (!state.initialized) await initEmbeddings();
55
- if (!state.available) return null;
56
20
  try {
57
- return hfe.embed(text);
58
- } catch (err: any) {
59
- console.log(`[embeddings] embed failed: ${err.message}`);
21
+ return await hfe.embed(text);
22
+ } catch {
60
23
  return null;
61
24
  }
62
25
  }
63
26
 
27
+ /**
28
+ * Check if the embedding engine is currently available.
29
+ */
64
30
  export function getMode(): "local" | "none" {
65
- const state = getState();
66
- return state.available ? "local" : "none";
31
+ try {
32
+ hfe.dimensions();
33
+ return "local";
34
+ } catch {
35
+ return "none";
36
+ }
67
37
  }