@tpsdev-ai/flair 0.3.15 → 0.3.17

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,24 +1,48 @@
1
1
  /**
2
2
  * embeddings-provider.ts
3
3
  *
4
- * Thin wrapper around harper-fabric-embeddings for Flair resources.
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.
4
+ * Wrapper around harper-fabric-embeddings for Flair resources.
5
+ *
6
+ * Harper loads resources in a VM sandbox with a separate module cache from
7
+ * the main thread. This means our import of harper-fabric-embeddings gets
8
+ * a different (uninitialized) instance from the one Harper initialized via
9
+ * handleApplication in config.yaml.
10
+ *
11
+ * Solution: we call hfe.init() ourselves on first use. The model is already
12
+ * on disk (downloaded by Harper's plugin loader), so init just loads the
13
+ * native binary and model file — no download needed.
9
14
  */
10
15
  import * as hfe from "harper-fabric-embeddings";
16
+ import { join } from "node:path";
17
+ let _ready = false;
18
+ async function ensureInit() {
19
+ if (_ready)
20
+ return;
21
+ try {
22
+ // Check if already initialized (e.g. shared context)
23
+ hfe.dimensions();
24
+ _ready = true;
25
+ return;
26
+ }
27
+ catch {
28
+ // Not initialized — init with modelsDir pointing to where Harper's
29
+ // plugin loader downloaded the model (process.cwd() is the app dir)
30
+ const modelsDir = join(process.cwd(), "models");
31
+ await hfe.init({ modelsDir });
32
+ _ready = true;
33
+ }
34
+ }
11
35
  /**
12
36
  * 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.
37
+ * Returns null if the embedding engine isn't available on this platform.
16
38
  */
17
39
  export async function getEmbedding(text) {
18
40
  try {
41
+ await ensureInit();
19
42
  return await hfe.embed(text);
20
43
  }
21
- catch {
44
+ catch (err) {
45
+ console.error(`[embeddings] embed failed: ${err.message}`);
22
46
  return null;
23
47
  }
24
48
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tpsdev-ai/flair",
3
- "version": "0.3.15",
3
+ "version": "0.3.17",
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",
@@ -51,7 +51,7 @@
51
51
  "dependencies": {
52
52
  "@harperfast/harper": "5.0.0-beta.4",
53
53
  "commander": "14.0.3",
54
- "harper-fabric-embeddings": "^0.2.0",
54
+ "harper-fabric-embeddings": "^0.2.2",
55
55
  "tweetnacl": "1.0.3"
56
56
  },
57
57
  "devDependencies": {
@@ -1,25 +1,49 @@
1
1
  /**
2
2
  * embeddings-provider.ts
3
3
  *
4
- * Thin wrapper around harper-fabric-embeddings for Flair resources.
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.
4
+ * Wrapper around harper-fabric-embeddings for Flair resources.
5
+ *
6
+ * Harper loads resources in a VM sandbox with a separate module cache from
7
+ * the main thread. This means our import of harper-fabric-embeddings gets
8
+ * a different (uninitialized) instance from the one Harper initialized via
9
+ * handleApplication in config.yaml.
10
+ *
11
+ * Solution: we call hfe.init() ourselves on first use. The model is already
12
+ * on disk (downloaded by Harper's plugin loader), so init just loads the
13
+ * native binary and model file — no download needed.
9
14
  */
10
15
 
11
16
  import * as hfe from "harper-fabric-embeddings";
17
+ import { join } from "node:path";
18
+
19
+ let _ready = false;
20
+
21
+ async function ensureInit(): Promise<void> {
22
+ if (_ready) return;
23
+ try {
24
+ // Check if already initialized (e.g. shared context)
25
+ hfe.dimensions();
26
+ _ready = true;
27
+ return;
28
+ } catch {
29
+ // Not initialized — init with modelsDir pointing to where Harper's
30
+ // plugin loader downloaded the model (process.cwd() is the app dir)
31
+ const modelsDir = join(process.cwd(), "models");
32
+ await hfe.init({ modelsDir });
33
+ _ready = true;
34
+ }
35
+ }
12
36
 
13
37
  /**
14
38
  * 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.
39
+ * Returns null if the embedding engine isn't available on this platform.
18
40
  */
19
41
  export async function getEmbedding(text: string): Promise<number[] | null> {
20
42
  try {
43
+ await ensureInit();
21
44
  return await hfe.embed(text);
22
- } catch {
45
+ } catch (err: any) {
46
+ console.error(`[embeddings] embed failed: ${err.message}`);
23
47
  return null;
24
48
  }
25
49
  }