agentfootprint 7.8.0 → 7.9.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/dist/embedders/index.js +74 -26
- package/dist/embedders/index.js.map +1 -1
- package/dist/esm/embedders/index.d.ts +96 -1
- package/dist/esm/embedders/index.js +74 -26
- package/dist/esm/embedders/index.js.map +1 -1
- package/dist/types/embedders/index.d.ts +96 -1
- package/dist/types/embedders/index.d.ts.map +1 -1
- package/package.json +4 -1
package/dist/embedders/index.js
CHANGED
|
@@ -24,6 +24,35 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.staticEmbedder = exports.localEmbedder = exports.openaiEmbedder = void 0;
|
|
27
|
+
/**
|
|
28
|
+
* Native output size of every OpenAI embedding model, so `.dimensions` reports
|
|
29
|
+
* the truth instead of one hard-coded guess.
|
|
30
|
+
*
|
|
31
|
+
* Sources: OpenAI embeddings guide — text-embedding-3-small "By default, the
|
|
32
|
+
* length of the embedding vector is 1536", text-embedding-3-large "3072"
|
|
33
|
+
* (https://developers.openai.com/api/docs/guides/embeddings); Microsoft Learn's
|
|
34
|
+
* Azure OpenAI model table, "Output Dimensions" column, for ada-002 = 1,536
|
|
35
|
+
* (https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/models).
|
|
36
|
+
*/
|
|
37
|
+
const NATIVE_DIMENSIONS = {
|
|
38
|
+
'text-embedding-3-small': 1536,
|
|
39
|
+
'text-embedding-3-large': 3072,
|
|
40
|
+
'text-embedding-ada-002': 1536,
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* OpenAI's hosted embeddings endpoint.
|
|
44
|
+
*
|
|
45
|
+
* `.dimensions` is the length callers WILL get back, never an assumption:
|
|
46
|
+
* an explicit `{ dimensions }` is sent to the API and reported; otherwise the
|
|
47
|
+
* model's documented native size is reported. A model outside
|
|
48
|
+
* {@link NATIVE_DIMENSIONS} (a gateway, a self-hosted model behind `baseURL`,
|
|
49
|
+
* an Azure deployment name, a future OpenAI model) has no size this library can
|
|
50
|
+
* know, so it is a construction-time error rather than a guess that a vector
|
|
51
|
+
* store would silently trust.
|
|
52
|
+
*
|
|
53
|
+
* @throws if there is no API key, or if `model` is unknown and `dimensions`
|
|
54
|
+
* was not supplied.
|
|
55
|
+
*/
|
|
27
56
|
function openaiEmbedder(options = {}) {
|
|
28
57
|
const apiKey = options.apiKey ??
|
|
29
58
|
(typeof process !== 'undefined' ? process.env?.['OPENAI_API_KEY'] : undefined);
|
|
@@ -31,13 +60,22 @@ function openaiEmbedder(options = {}) {
|
|
|
31
60
|
throw new Error('openaiEmbedder: no API key — set OPENAI_API_KEY or pass { apiKey }.');
|
|
32
61
|
}
|
|
33
62
|
const model = options.model ?? 'text-embedding-3-small';
|
|
34
|
-
|
|
63
|
+
// Only an EXPLICIT request is sent. Defaulting it and sending that would
|
|
64
|
+
// break ada-002 (which rejects the parameter) for callers who asked for
|
|
65
|
+
// nothing — the request body stays byte-identical unless you opt in.
|
|
66
|
+
const requested = options.dimensions;
|
|
67
|
+
const dimensions = requested ?? NATIVE_DIMENSIONS[model];
|
|
68
|
+
if (dimensions === undefined) {
|
|
69
|
+
throw new Error(`openaiEmbedder: unknown model '${model}' — its vector length is not something this ` +
|
|
70
|
+
`library can know, and reporting a wrong .dimensions silently corrupts a vector store. ` +
|
|
71
|
+
`Pass { dimensions } with the length that model returns.`);
|
|
72
|
+
}
|
|
35
73
|
const url = `${options.baseURL ?? 'https://api.openai.com/v1'}/embeddings`;
|
|
36
74
|
async function call(input, signal) {
|
|
37
75
|
const res = await fetch(url, {
|
|
38
76
|
method: 'POST',
|
|
39
77
|
headers: { 'content-type': 'application/json', authorization: `Bearer ${apiKey}` },
|
|
40
|
-
body: JSON.stringify({ model, input }),
|
|
78
|
+
body: JSON.stringify(requested === undefined ? { model, input } : { model, input, dimensions: requested }),
|
|
41
79
|
...(signal ? { signal } : {}),
|
|
42
80
|
});
|
|
43
81
|
if (!res.ok)
|
|
@@ -61,17 +99,22 @@ function localEmbedder(options = {}) {
|
|
|
61
99
|
const dimensions = options.dimensions ?? 384;
|
|
62
100
|
const dtype = options.dtype ?? 'q8';
|
|
63
101
|
let pipe;
|
|
102
|
+
const build = (m) => {
|
|
103
|
+
if (options.cacheDir && m.env && typeof m.env === 'object') {
|
|
104
|
+
m.env['cacheDir'] = options.cacheDir;
|
|
105
|
+
}
|
|
106
|
+
return m.pipeline('feature-extraction', model, { dtype });
|
|
107
|
+
};
|
|
64
108
|
const getPipe = () => {
|
|
109
|
+
const injected = options.backend;
|
|
110
|
+
if (injected)
|
|
111
|
+
return (pipe ??= build(injected));
|
|
65
112
|
// Variable specifier so the compiler/bundler does NOT resolve the module at
|
|
66
113
|
// build time — @huggingface/transformers stays an optional peer dep, loaded
|
|
67
|
-
// only when localEmbedder is actually used.
|
|
114
|
+
// only when localEmbedder is actually used. A bundler cannot see through
|
|
115
|
+
// this; bundled apps pass { backend } instead.
|
|
68
116
|
const spec = '@huggingface/transformers';
|
|
69
|
-
return (pipe ??= Promise.resolve(`${spec}`).then(s => __importStar(require(s))).then((mod) =>
|
|
70
|
-
const m = mod;
|
|
71
|
-
if (options.cacheDir)
|
|
72
|
-
m.env['cacheDir'] = options.cacheDir;
|
|
73
|
-
return m.pipeline('feature-extraction', model, { dtype });
|
|
74
|
-
}));
|
|
117
|
+
return (pipe ??= Promise.resolve(`${spec}`).then(s => __importStar(require(s))).then((mod) => build(mod)));
|
|
75
118
|
};
|
|
76
119
|
return {
|
|
77
120
|
dimensions,
|
|
@@ -92,24 +135,29 @@ function staticEmbedder(options = {}) {
|
|
|
92
135
|
const dimensions = options.dimensions ?? 256;
|
|
93
136
|
const spec = options.module ?? '@yarflam/potion-base-8m';
|
|
94
137
|
let embedFn;
|
|
138
|
+
// potion-base-8m exports `embed(texts) => Promise<Float32Array[]>` (a batch
|
|
139
|
+
// async fn, also on its default export). Accept a small set of shapes so
|
|
140
|
+
// other Model2Vec builds slot in: a named `embed`/`encode` on the module or
|
|
141
|
+
// its default, or a default export that IS the fn.
|
|
142
|
+
const pick = (mod, source) => {
|
|
143
|
+
const m = mod;
|
|
144
|
+
const d = (m.default ?? {});
|
|
145
|
+
const fn = m['embed'] ??
|
|
146
|
+
d['embed'] ??
|
|
147
|
+
m['encode'] ??
|
|
148
|
+
d['encode'] ??
|
|
149
|
+
(typeof m.default === 'function' ? m.default : undefined);
|
|
150
|
+
if (!fn) {
|
|
151
|
+
throw new Error(`staticEmbedder: no embed()/encode() export on ${source}. Pass { module } or wrap it in your own Embedder.`);
|
|
152
|
+
}
|
|
153
|
+
return fn;
|
|
154
|
+
};
|
|
95
155
|
const getEmbed = () => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const m = mod;
|
|
102
|
-
const d = (m.default ?? {});
|
|
103
|
-
const fn = m['embed'] ??
|
|
104
|
-
d['embed'] ??
|
|
105
|
-
m['encode'] ??
|
|
106
|
-
d['encode'] ??
|
|
107
|
-
(typeof m.default === 'function' ? m.default : undefined);
|
|
108
|
-
if (!fn) {
|
|
109
|
-
throw new Error(`staticEmbedder: no embed()/encode() export on '${spec}'. Pass { module } or wrap it in your own Embedder.`);
|
|
110
|
-
}
|
|
111
|
-
return fn;
|
|
112
|
-
}));
|
|
156
|
+
const injected = options.backend;
|
|
157
|
+
if (injected) {
|
|
158
|
+
return (embedFn ??= Promise.resolve(pick(injected, 'the module passed as { backend }')));
|
|
159
|
+
}
|
|
160
|
+
return (embedFn ??= Promise.resolve(`${spec}`).then(s => __importStar(require(s))).then((mod) => pick(mod, `'${spec}'`)));
|
|
113
161
|
};
|
|
114
162
|
// Normalize a batch result into number[][] (one row per input). Handles
|
|
115
163
|
// Float32Array[] (potion), number[][], and a single flat vector for the call.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/embedders/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/embedders/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,19 +16,74 @@
|
|
|
16
16
|
* All three satisfy the same `Embedder` shape, so they drop into
|
|
17
17
|
* `toolChoiceRecorder({ embedder })` / `semanticPipeline({ embedder })` etc.
|
|
18
18
|
* unchanged. Dimensions differ per model — never mix two in one store.
|
|
19
|
+
*
|
|
20
|
+
* ─── Bundlers / browsers: pass `backend` ────────────────────────────────
|
|
21
|
+
*
|
|
22
|
+
* The lazy `import(spec)` above keeps the peer deps optional, but a BUNDLER
|
|
23
|
+
* cannot see through a variable specifier: the bare name survives into the
|
|
24
|
+
* output and the browser throws
|
|
25
|
+
* `TypeError: Failed to resolve module specifier '@huggingface/transformers'`
|
|
26
|
+
* at first embed. So both on-device factories also accept an ALREADY-IMPORTED
|
|
27
|
+
* module — a static import your own bundler resolves:
|
|
28
|
+
*
|
|
29
|
+
* import * as transformers from '@huggingface/transformers';
|
|
30
|
+
* const embedder = localEmbedder({ backend: transformers });
|
|
31
|
+
*
|
|
32
|
+
* Same mechanism as the `client` option on the store adapters (RedisStore,
|
|
33
|
+
* AgentCoreStore): the library states the surface it needs, the host owns the
|
|
34
|
+
* construction. Nothing changes for Node callers who pass nothing.
|
|
19
35
|
*/
|
|
36
|
+
export type { Embedder } from '../memory/embedding/types.js';
|
|
20
37
|
import type { Embedder } from '../memory/embedding/types.js';
|
|
21
38
|
export interface OpenAIEmbedderOptions {
|
|
22
39
|
/** Default: process.env.OPENAI_API_KEY. */
|
|
23
40
|
readonly apiKey?: string;
|
|
24
41
|
/** Default: 'text-embedding-3-small'. */
|
|
25
42
|
readonly model?: string;
|
|
26
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* Shorten the vectors the model returns (OpenAI's Matryoshka truncation).
|
|
45
|
+
*
|
|
46
|
+
* When set, the value is SENT as the `dimensions` request parameter AND
|
|
47
|
+
* reported as `.dimensions` — the two can never disagree. Only supported on
|
|
48
|
+
* `text-embedding-3` and later models; ada-002 rejects it, which is exactly
|
|
49
|
+
* why nothing is sent unless you ask.
|
|
50
|
+
*
|
|
51
|
+
* Leave it unset to get the model's native size (looked up from
|
|
52
|
+
* {@link NATIVE_DIMENSIONS}). Required for a model this library doesn't know
|
|
53
|
+
* — see {@link openaiEmbedder}.
|
|
54
|
+
*/
|
|
27
55
|
readonly dimensions?: number;
|
|
28
56
|
/** Override the API base (Azure/OpenAI-compatible gateways). */
|
|
29
57
|
readonly baseURL?: string;
|
|
30
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* OpenAI's hosted embeddings endpoint.
|
|
61
|
+
*
|
|
62
|
+
* `.dimensions` is the length callers WILL get back, never an assumption:
|
|
63
|
+
* an explicit `{ dimensions }` is sent to the API and reported; otherwise the
|
|
64
|
+
* model's documented native size is reported. A model outside
|
|
65
|
+
* {@link NATIVE_DIMENSIONS} (a gateway, a self-hosted model behind `baseURL`,
|
|
66
|
+
* an Azure deployment name, a future OpenAI model) has no size this library can
|
|
67
|
+
* know, so it is a construction-time error rather than a guess that a vector
|
|
68
|
+
* store would silently trust.
|
|
69
|
+
*
|
|
70
|
+
* @throws if there is no API key, or if `model` is unknown and `dimensions`
|
|
71
|
+
* was not supplied.
|
|
72
|
+
*/
|
|
31
73
|
export declare function openaiEmbedder(options?: OpenAIEmbedderOptions): Embedder;
|
|
74
|
+
/**
|
|
75
|
+
* The slice of `@huggingface/transformers` {@link localEmbedder} uses.
|
|
76
|
+
*
|
|
77
|
+
* Structural, so `await import('@huggingface/transformers')` (or a stub, or a
|
|
78
|
+
* pinned fork) satisfies it without this package taking a hard type dependency
|
|
79
|
+
* on the optional peer.
|
|
80
|
+
*/
|
|
81
|
+
export interface TransformersBackend {
|
|
82
|
+
/** transformers.js `pipeline(task, model, options)`. */
|
|
83
|
+
pipeline(task: string, model?: string, options?: Record<string, unknown>): Promise<unknown>;
|
|
84
|
+
/** transformers.js `env` — mutated only when `cacheDir` is set. */
|
|
85
|
+
env?: unknown;
|
|
86
|
+
}
|
|
32
87
|
export interface LocalEmbedderOptions {
|
|
33
88
|
/** ONNX model id. Default 'Xenova/all-MiniLM-L6-v2' (384-dim). */
|
|
34
89
|
readonly model?: string;
|
|
@@ -38,12 +93,52 @@ export interface LocalEmbedderOptions {
|
|
|
38
93
|
readonly dtype?: string;
|
|
39
94
|
/** On-disk model cache directory. */
|
|
40
95
|
readonly cacheDir?: string;
|
|
96
|
+
/**
|
|
97
|
+
* An ALREADY-IMPORTED `@huggingface/transformers`. Supply this and the lazy
|
|
98
|
+
* `import('@huggingface/transformers')` never happens — which is what makes
|
|
99
|
+
* the embedder work in a BUNDLED app, where a bare specifier reaches the
|
|
100
|
+
* browser unresolved:
|
|
101
|
+
*
|
|
102
|
+
* import * as transformers from '@huggingface/transformers';
|
|
103
|
+
* localEmbedder({ backend: transformers });
|
|
104
|
+
*
|
|
105
|
+
* Your bundler resolves that static import; the peer dep stays optional for
|
|
106
|
+
* everyone who doesn't.
|
|
107
|
+
*/
|
|
108
|
+
readonly backend?: TransformersBackend;
|
|
41
109
|
}
|
|
42
110
|
export declare function localEmbedder(options?: LocalEmbedderOptions): Embedder;
|
|
111
|
+
/**
|
|
112
|
+
* The slice of a Model2Vec package {@link staticEmbedder} uses: a batch
|
|
113
|
+
* `embed`/`encode`, on the module or on its default export.
|
|
114
|
+
*
|
|
115
|
+
* Structural, so `await import('@yarflam/potion-base-8m')` — or any other
|
|
116
|
+
* Model2Vec build with one of those shapes — satisfies it.
|
|
117
|
+
*/
|
|
118
|
+
export interface Model2VecBackend {
|
|
119
|
+
/** Batch embed: `embed(texts) => vectors` (may be async). */
|
|
120
|
+
embed?(texts: readonly string[]): unknown;
|
|
121
|
+
/** Alternative name some builds use. */
|
|
122
|
+
encode?(texts: readonly string[]): unknown;
|
|
123
|
+
/** A default export that is the fn, or carries `embed`/`encode`. */
|
|
124
|
+
readonly default?: unknown;
|
|
125
|
+
}
|
|
43
126
|
export interface StaticEmbedderOptions {
|
|
44
127
|
/** Vector length of the bundled model. Default 256 (potion-base-8m). */
|
|
45
128
|
readonly dimensions?: number;
|
|
46
129
|
/** Override the package specifier for a different Model2Vec build. */
|
|
47
130
|
readonly module?: string;
|
|
131
|
+
/**
|
|
132
|
+
* An ALREADY-IMPORTED Model2Vec module. Supply this and no dynamic import
|
|
133
|
+
* happens — the only way this embedder can run in a BUNDLED app, since a
|
|
134
|
+
* bundler cannot resolve the specifier `module` names:
|
|
135
|
+
*
|
|
136
|
+
* import * as potion from '@yarflam/potion-base-8m';
|
|
137
|
+
* staticEmbedder({ backend: potion });
|
|
138
|
+
*
|
|
139
|
+
* Takes precedence over `module`. (The potion backend itself is Node-only
|
|
140
|
+
* today — see the embedders guide.)
|
|
141
|
+
*/
|
|
142
|
+
readonly backend?: Model2VecBackend;
|
|
48
143
|
}
|
|
49
144
|
export declare function staticEmbedder(options?: StaticEmbedderOptions): Embedder;
|
|
@@ -1,3 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native output size of every OpenAI embedding model, so `.dimensions` reports
|
|
3
|
+
* the truth instead of one hard-coded guess.
|
|
4
|
+
*
|
|
5
|
+
* Sources: OpenAI embeddings guide — text-embedding-3-small "By default, the
|
|
6
|
+
* length of the embedding vector is 1536", text-embedding-3-large "3072"
|
|
7
|
+
* (https://developers.openai.com/api/docs/guides/embeddings); Microsoft Learn's
|
|
8
|
+
* Azure OpenAI model table, "Output Dimensions" column, for ada-002 = 1,536
|
|
9
|
+
* (https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/models).
|
|
10
|
+
*/
|
|
11
|
+
const NATIVE_DIMENSIONS = {
|
|
12
|
+
'text-embedding-3-small': 1536,
|
|
13
|
+
'text-embedding-3-large': 3072,
|
|
14
|
+
'text-embedding-ada-002': 1536,
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* OpenAI's hosted embeddings endpoint.
|
|
18
|
+
*
|
|
19
|
+
* `.dimensions` is the length callers WILL get back, never an assumption:
|
|
20
|
+
* an explicit `{ dimensions }` is sent to the API and reported; otherwise the
|
|
21
|
+
* model's documented native size is reported. A model outside
|
|
22
|
+
* {@link NATIVE_DIMENSIONS} (a gateway, a self-hosted model behind `baseURL`,
|
|
23
|
+
* an Azure deployment name, a future OpenAI model) has no size this library can
|
|
24
|
+
* know, so it is a construction-time error rather than a guess that a vector
|
|
25
|
+
* store would silently trust.
|
|
26
|
+
*
|
|
27
|
+
* @throws if there is no API key, or if `model` is unknown and `dimensions`
|
|
28
|
+
* was not supplied.
|
|
29
|
+
*/
|
|
1
30
|
export function openaiEmbedder(options = {}) {
|
|
2
31
|
const apiKey = options.apiKey ??
|
|
3
32
|
(typeof process !== 'undefined' ? process.env?.['OPENAI_API_KEY'] : undefined);
|
|
@@ -5,13 +34,22 @@ export function openaiEmbedder(options = {}) {
|
|
|
5
34
|
throw new Error('openaiEmbedder: no API key — set OPENAI_API_KEY or pass { apiKey }.');
|
|
6
35
|
}
|
|
7
36
|
const model = options.model ?? 'text-embedding-3-small';
|
|
8
|
-
|
|
37
|
+
// Only an EXPLICIT request is sent. Defaulting it and sending that would
|
|
38
|
+
// break ada-002 (which rejects the parameter) for callers who asked for
|
|
39
|
+
// nothing — the request body stays byte-identical unless you opt in.
|
|
40
|
+
const requested = options.dimensions;
|
|
41
|
+
const dimensions = requested ?? NATIVE_DIMENSIONS[model];
|
|
42
|
+
if (dimensions === undefined) {
|
|
43
|
+
throw new Error(`openaiEmbedder: unknown model '${model}' — its vector length is not something this ` +
|
|
44
|
+
`library can know, and reporting a wrong .dimensions silently corrupts a vector store. ` +
|
|
45
|
+
`Pass { dimensions } with the length that model returns.`);
|
|
46
|
+
}
|
|
9
47
|
const url = `${options.baseURL ?? 'https://api.openai.com/v1'}/embeddings`;
|
|
10
48
|
async function call(input, signal) {
|
|
11
49
|
const res = await fetch(url, {
|
|
12
50
|
method: 'POST',
|
|
13
51
|
headers: { 'content-type': 'application/json', authorization: `Bearer ${apiKey}` },
|
|
14
|
-
body: JSON.stringify({ model, input }),
|
|
52
|
+
body: JSON.stringify(requested === undefined ? { model, input } : { model, input, dimensions: requested }),
|
|
15
53
|
...(signal ? { signal } : {}),
|
|
16
54
|
});
|
|
17
55
|
if (!res.ok)
|
|
@@ -34,17 +72,22 @@ export function localEmbedder(options = {}) {
|
|
|
34
72
|
const dimensions = options.dimensions ?? 384;
|
|
35
73
|
const dtype = options.dtype ?? 'q8';
|
|
36
74
|
let pipe;
|
|
75
|
+
const build = (m) => {
|
|
76
|
+
if (options.cacheDir && m.env && typeof m.env === 'object') {
|
|
77
|
+
m.env['cacheDir'] = options.cacheDir;
|
|
78
|
+
}
|
|
79
|
+
return m.pipeline('feature-extraction', model, { dtype });
|
|
80
|
+
};
|
|
37
81
|
const getPipe = () => {
|
|
82
|
+
const injected = options.backend;
|
|
83
|
+
if (injected)
|
|
84
|
+
return (pipe ??= build(injected));
|
|
38
85
|
// Variable specifier so the compiler/bundler does NOT resolve the module at
|
|
39
86
|
// build time — @huggingface/transformers stays an optional peer dep, loaded
|
|
40
|
-
// only when localEmbedder is actually used.
|
|
87
|
+
// only when localEmbedder is actually used. A bundler cannot see through
|
|
88
|
+
// this; bundled apps pass { backend } instead.
|
|
41
89
|
const spec = '@huggingface/transformers';
|
|
42
|
-
return (pipe ??= import(spec).then((mod) =>
|
|
43
|
-
const m = mod;
|
|
44
|
-
if (options.cacheDir)
|
|
45
|
-
m.env['cacheDir'] = options.cacheDir;
|
|
46
|
-
return m.pipeline('feature-extraction', model, { dtype });
|
|
47
|
-
}));
|
|
90
|
+
return (pipe ??= import(spec).then((mod) => build(mod)));
|
|
48
91
|
};
|
|
49
92
|
return {
|
|
50
93
|
dimensions,
|
|
@@ -64,24 +107,29 @@ export function staticEmbedder(options = {}) {
|
|
|
64
107
|
const dimensions = options.dimensions ?? 256;
|
|
65
108
|
const spec = options.module ?? '@yarflam/potion-base-8m';
|
|
66
109
|
let embedFn;
|
|
110
|
+
// potion-base-8m exports `embed(texts) => Promise<Float32Array[]>` (a batch
|
|
111
|
+
// async fn, also on its default export). Accept a small set of shapes so
|
|
112
|
+
// other Model2Vec builds slot in: a named `embed`/`encode` on the module or
|
|
113
|
+
// its default, or a default export that IS the fn.
|
|
114
|
+
const pick = (mod, source) => {
|
|
115
|
+
const m = mod;
|
|
116
|
+
const d = (m.default ?? {});
|
|
117
|
+
const fn = m['embed'] ??
|
|
118
|
+
d['embed'] ??
|
|
119
|
+
m['encode'] ??
|
|
120
|
+
d['encode'] ??
|
|
121
|
+
(typeof m.default === 'function' ? m.default : undefined);
|
|
122
|
+
if (!fn) {
|
|
123
|
+
throw new Error(`staticEmbedder: no embed()/encode() export on ${source}. Pass { module } or wrap it in your own Embedder.`);
|
|
124
|
+
}
|
|
125
|
+
return fn;
|
|
126
|
+
};
|
|
67
127
|
const getEmbed = () => {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const m = mod;
|
|
74
|
-
const d = (m.default ?? {});
|
|
75
|
-
const fn = m['embed'] ??
|
|
76
|
-
d['embed'] ??
|
|
77
|
-
m['encode'] ??
|
|
78
|
-
d['encode'] ??
|
|
79
|
-
(typeof m.default === 'function' ? m.default : undefined);
|
|
80
|
-
if (!fn) {
|
|
81
|
-
throw new Error(`staticEmbedder: no embed()/encode() export on '${spec}'. Pass { module } or wrap it in your own Embedder.`);
|
|
82
|
-
}
|
|
83
|
-
return fn;
|
|
84
|
-
}));
|
|
128
|
+
const injected = options.backend;
|
|
129
|
+
if (injected) {
|
|
130
|
+
return (embedFn ??= Promise.resolve(pick(injected, 'the module passed as { backend }')));
|
|
131
|
+
}
|
|
132
|
+
return (embedFn ??= import(spec).then((mod) => pick(mod, `'${spec}'`)));
|
|
85
133
|
};
|
|
86
134
|
// Normalize a batch result into number[][] (one row per input). Handles
|
|
87
135
|
// Float32Array[] (potion), number[][], and a single flat vector for the call.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/embedders/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/embedders/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,19 +16,74 @@
|
|
|
16
16
|
* All three satisfy the same `Embedder` shape, so they drop into
|
|
17
17
|
* `toolChoiceRecorder({ embedder })` / `semanticPipeline({ embedder })` etc.
|
|
18
18
|
* unchanged. Dimensions differ per model — never mix two in one store.
|
|
19
|
+
*
|
|
20
|
+
* ─── Bundlers / browsers: pass `backend` ────────────────────────────────
|
|
21
|
+
*
|
|
22
|
+
* The lazy `import(spec)` above keeps the peer deps optional, but a BUNDLER
|
|
23
|
+
* cannot see through a variable specifier: the bare name survives into the
|
|
24
|
+
* output and the browser throws
|
|
25
|
+
* `TypeError: Failed to resolve module specifier '@huggingface/transformers'`
|
|
26
|
+
* at first embed. So both on-device factories also accept an ALREADY-IMPORTED
|
|
27
|
+
* module — a static import your own bundler resolves:
|
|
28
|
+
*
|
|
29
|
+
* import * as transformers from '@huggingface/transformers';
|
|
30
|
+
* const embedder = localEmbedder({ backend: transformers });
|
|
31
|
+
*
|
|
32
|
+
* Same mechanism as the `client` option on the store adapters (RedisStore,
|
|
33
|
+
* AgentCoreStore): the library states the surface it needs, the host owns the
|
|
34
|
+
* construction. Nothing changes for Node callers who pass nothing.
|
|
19
35
|
*/
|
|
36
|
+
export type { Embedder } from '../memory/embedding/types.js';
|
|
20
37
|
import type { Embedder } from '../memory/embedding/types.js';
|
|
21
38
|
export interface OpenAIEmbedderOptions {
|
|
22
39
|
/** Default: process.env.OPENAI_API_KEY. */
|
|
23
40
|
readonly apiKey?: string;
|
|
24
41
|
/** Default: 'text-embedding-3-small'. */
|
|
25
42
|
readonly model?: string;
|
|
26
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* Shorten the vectors the model returns (OpenAI's Matryoshka truncation).
|
|
45
|
+
*
|
|
46
|
+
* When set, the value is SENT as the `dimensions` request parameter AND
|
|
47
|
+
* reported as `.dimensions` — the two can never disagree. Only supported on
|
|
48
|
+
* `text-embedding-3` and later models; ada-002 rejects it, which is exactly
|
|
49
|
+
* why nothing is sent unless you ask.
|
|
50
|
+
*
|
|
51
|
+
* Leave it unset to get the model's native size (looked up from
|
|
52
|
+
* {@link NATIVE_DIMENSIONS}). Required for a model this library doesn't know
|
|
53
|
+
* — see {@link openaiEmbedder}.
|
|
54
|
+
*/
|
|
27
55
|
readonly dimensions?: number;
|
|
28
56
|
/** Override the API base (Azure/OpenAI-compatible gateways). */
|
|
29
57
|
readonly baseURL?: string;
|
|
30
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* OpenAI's hosted embeddings endpoint.
|
|
61
|
+
*
|
|
62
|
+
* `.dimensions` is the length callers WILL get back, never an assumption:
|
|
63
|
+
* an explicit `{ dimensions }` is sent to the API and reported; otherwise the
|
|
64
|
+
* model's documented native size is reported. A model outside
|
|
65
|
+
* {@link NATIVE_DIMENSIONS} (a gateway, a self-hosted model behind `baseURL`,
|
|
66
|
+
* an Azure deployment name, a future OpenAI model) has no size this library can
|
|
67
|
+
* know, so it is a construction-time error rather than a guess that a vector
|
|
68
|
+
* store would silently trust.
|
|
69
|
+
*
|
|
70
|
+
* @throws if there is no API key, or if `model` is unknown and `dimensions`
|
|
71
|
+
* was not supplied.
|
|
72
|
+
*/
|
|
31
73
|
export declare function openaiEmbedder(options?: OpenAIEmbedderOptions): Embedder;
|
|
74
|
+
/**
|
|
75
|
+
* The slice of `@huggingface/transformers` {@link localEmbedder} uses.
|
|
76
|
+
*
|
|
77
|
+
* Structural, so `await import('@huggingface/transformers')` (or a stub, or a
|
|
78
|
+
* pinned fork) satisfies it without this package taking a hard type dependency
|
|
79
|
+
* on the optional peer.
|
|
80
|
+
*/
|
|
81
|
+
export interface TransformersBackend {
|
|
82
|
+
/** transformers.js `pipeline(task, model, options)`. */
|
|
83
|
+
pipeline(task: string, model?: string, options?: Record<string, unknown>): Promise<unknown>;
|
|
84
|
+
/** transformers.js `env` — mutated only when `cacheDir` is set. */
|
|
85
|
+
env?: unknown;
|
|
86
|
+
}
|
|
32
87
|
export interface LocalEmbedderOptions {
|
|
33
88
|
/** ONNX model id. Default 'Xenova/all-MiniLM-L6-v2' (384-dim). */
|
|
34
89
|
readonly model?: string;
|
|
@@ -38,13 +93,53 @@ export interface LocalEmbedderOptions {
|
|
|
38
93
|
readonly dtype?: string;
|
|
39
94
|
/** On-disk model cache directory. */
|
|
40
95
|
readonly cacheDir?: string;
|
|
96
|
+
/**
|
|
97
|
+
* An ALREADY-IMPORTED `@huggingface/transformers`. Supply this and the lazy
|
|
98
|
+
* `import('@huggingface/transformers')` never happens — which is what makes
|
|
99
|
+
* the embedder work in a BUNDLED app, where a bare specifier reaches the
|
|
100
|
+
* browser unresolved:
|
|
101
|
+
*
|
|
102
|
+
* import * as transformers from '@huggingface/transformers';
|
|
103
|
+
* localEmbedder({ backend: transformers });
|
|
104
|
+
*
|
|
105
|
+
* Your bundler resolves that static import; the peer dep stays optional for
|
|
106
|
+
* everyone who doesn't.
|
|
107
|
+
*/
|
|
108
|
+
readonly backend?: TransformersBackend;
|
|
41
109
|
}
|
|
42
110
|
export declare function localEmbedder(options?: LocalEmbedderOptions): Embedder;
|
|
111
|
+
/**
|
|
112
|
+
* The slice of a Model2Vec package {@link staticEmbedder} uses: a batch
|
|
113
|
+
* `embed`/`encode`, on the module or on its default export.
|
|
114
|
+
*
|
|
115
|
+
* Structural, so `await import('@yarflam/potion-base-8m')` — or any other
|
|
116
|
+
* Model2Vec build with one of those shapes — satisfies it.
|
|
117
|
+
*/
|
|
118
|
+
export interface Model2VecBackend {
|
|
119
|
+
/** Batch embed: `embed(texts) => vectors` (may be async). */
|
|
120
|
+
embed?(texts: readonly string[]): unknown;
|
|
121
|
+
/** Alternative name some builds use. */
|
|
122
|
+
encode?(texts: readonly string[]): unknown;
|
|
123
|
+
/** A default export that is the fn, or carries `embed`/`encode`. */
|
|
124
|
+
readonly default?: unknown;
|
|
125
|
+
}
|
|
43
126
|
export interface StaticEmbedderOptions {
|
|
44
127
|
/** Vector length of the bundled model. Default 256 (potion-base-8m). */
|
|
45
128
|
readonly dimensions?: number;
|
|
46
129
|
/** Override the package specifier for a different Model2Vec build. */
|
|
47
130
|
readonly module?: string;
|
|
131
|
+
/**
|
|
132
|
+
* An ALREADY-IMPORTED Model2Vec module. Supply this and no dynamic import
|
|
133
|
+
* happens — the only way this embedder can run in a BUNDLED app, since a
|
|
134
|
+
* bundler cannot resolve the specifier `module` names:
|
|
135
|
+
*
|
|
136
|
+
* import * as potion from '@yarflam/potion-base-8m';
|
|
137
|
+
* staticEmbedder({ backend: potion });
|
|
138
|
+
*
|
|
139
|
+
* Takes precedence over `module`. (The potion backend itself is Node-only
|
|
140
|
+
* today — see the embedders guide.)
|
|
141
|
+
*/
|
|
142
|
+
readonly backend?: Model2VecBackend;
|
|
48
143
|
}
|
|
49
144
|
export declare function staticEmbedder(options?: StaticEmbedderOptions): Embedder;
|
|
50
145
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/embedders/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/embedders/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,YAAY,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAM7D,MAAM,WAAW,qBAAqB;IACpC,2CAA2C;IAC3C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,yCAAyC;IACzC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,gEAAgE;IAChE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAkBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,qBAA0B,GAAG,QAAQ,CA6C5E;AAMD;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,wDAAwD;IACxD,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5F,mEAAmE;IACnE,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB;IACnC,kEAAkE;IAClE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,+CAA+C;IAC/C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,qCAAqC;IACrC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,mBAAmB,CAAC;CACxC;AAMD,wBAAgB,aAAa,CAAC,OAAO,GAAE,oBAAyB,GAAG,QAAQ,CAqC1E;AAMD;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6DAA6D;IAC7D,KAAK,CAAC,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC;IAC1C,wCAAwC;IACxC,MAAM,CAAC,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC;IAC3C,oEAAoE;IACpE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC,wEAAwE;IACxE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,sEAAsE;IACtE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,gBAAgB,CAAC;CACrC;AAKD,wBAAgB,cAAc,CAAC,OAAO,GAAE,qBAA0B,GAAG,QAAQ,CA2D5E"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentfootprint",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.9.0",
|
|
4
4
|
"description": "The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Sanjay Krishna Anbalagan",
|
|
@@ -66,6 +66,9 @@
|
|
|
66
66
|
"example": "TSX_TSCONFIG_PATH=examples/runtime.tsconfig.json npx --yes tsx",
|
|
67
67
|
"test:watch": "vitest --watch",
|
|
68
68
|
"docs:api": "typedoc",
|
|
69
|
+
"docs:truth": "node scripts/docs-truth-check.mjs",
|
|
70
|
+
"docs:truth:baseline": "node scripts/docs-truth-check.mjs --update-baseline",
|
|
71
|
+
"docs:truth:exercise": "node scripts/docs-truth-exercise.mjs",
|
|
69
72
|
"lint": "eslint 'src/**/*.ts' 'test/**/*.ts' --ext .ts",
|
|
70
73
|
"lint:fix": "eslint 'src/**/*.ts' 'test/**/*.ts' --ext .ts --fix",
|
|
71
74
|
"format": "prettier --config .prettierrc.js --list-different 'src/**/*.ts' 'test/**/*.ts'",
|