@aid-framework/runtime 0.0.0-stage → 0.1.39
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/LICENSE +201 -0
- package/README.md +52 -2
- package/dist/.tsbuildinfo +1 -0
- package/dist/agents/deep_agents.d.ts +78 -0
- package/dist/agents/deep_agents.d.ts.map +1 -0
- package/dist/agents/deep_agents.js +477 -0
- package/dist/agents/deep_agents.js.map +1 -0
- package/dist/agents/engine.d.ts +85 -0
- package/dist/agents/engine.d.ts.map +1 -0
- package/dist/agents/engine.js +129 -0
- package/dist/agents/engine.js.map +1 -0
- package/dist/agents/gateway_chat_model.d.ts +151 -0
- package/dist/agents/gateway_chat_model.d.ts.map +1 -0
- package/dist/agents/gateway_chat_model.js +350 -0
- package/dist/agents/gateway_chat_model.js.map +1 -0
- package/dist/agents/guardrail_middleware.d.ts +57 -0
- package/dist/agents/guardrail_middleware.d.ts.map +1 -0
- package/dist/agents/guardrail_middleware.js +85 -0
- package/dist/agents/guardrail_middleware.js.map +1 -0
- package/dist/agents/guardrails.d.ts +124 -0
- package/dist/agents/guardrails.d.ts.map +1 -0
- package/dist/agents/guardrails.js +336 -0
- package/dist/agents/guardrails.js.map +1 -0
- package/dist/agents/index.d.ts +15 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +15 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/ir.d.ts +144 -0
- package/dist/agents/ir.d.ts.map +1 -0
- package/dist/agents/ir.js +513 -0
- package/dist/agents/ir.js.map +1 -0
- package/dist/agents/loop.d.ts +145 -0
- package/dist/agents/loop.d.ts.map +1 -0
- package/dist/agents/loop.js +1025 -0
- package/dist/agents/loop.js.map +1 -0
- package/dist/agents/memory.d.ts +115 -0
- package/dist/agents/memory.d.ts.map +1 -0
- package/dist/agents/memory.js +258 -0
- package/dist/agents/memory.js.map +1 -0
- package/dist/agents/state.d.ts +137 -0
- package/dist/agents/state.d.ts.map +1 -0
- package/dist/agents/state.js +255 -0
- package/dist/agents/state.js.map +1 -0
- package/dist/concurrency.d.ts +36 -0
- package/dist/concurrency.d.ts.map +1 -0
- package/dist/concurrency.js +86 -0
- package/dist/concurrency.js.map +1 -0
- package/dist/control.d.ts +116 -0
- package/dist/control.d.ts.map +1 -0
- package/dist/control.js +281 -0
- package/dist/control.js.map +1 -0
- package/dist/cost.d.ts +95 -0
- package/dist/cost.d.ts.map +1 -0
- package/dist/cost.js +161 -0
- package/dist/cost.js.map +1 -0
- package/dist/errors.d.ts +213 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +316 -0
- package/dist/errors.js.map +1 -0
- package/dist/evals/dataset.d.ts +45 -0
- package/dist/evals/dataset.d.ts.map +1 -0
- package/dist/evals/dataset.js +147 -0
- package/dist/evals/dataset.js.map +1 -0
- package/dist/evals/gate.d.ts +236 -0
- package/dist/evals/gate.d.ts.map +1 -0
- package/dist/evals/gate.js +572 -0
- package/dist/evals/gate.js.map +1 -0
- package/dist/evals/metrics.d.ts +141 -0
- package/dist/evals/metrics.d.ts.map +1 -0
- package/dist/evals/metrics.js +364 -0
- package/dist/evals/metrics.js.map +1 -0
- package/dist/evals/predicate.d.ts +79 -0
- package/dist/evals/predicate.d.ts.map +1 -0
- package/dist/evals/predicate.js +178 -0
- package/dist/evals/predicate.js.map +1 -0
- package/dist/evals/runner.d.ts +94 -0
- package/dist/evals/runner.d.ts.map +1 -0
- package/dist/evals/runner.js +202 -0
- package/dist/evals/runner.js.map +1 -0
- package/dist/gateway.d.ts +118 -0
- package/dist/gateway.d.ts.map +1 -0
- package/dist/gateway.js +250 -0
- package/dist/gateway.js.map +1 -0
- package/dist/index.d.ts +83 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +59 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/json.d.ts +44 -0
- package/dist/internal/json.d.ts.map +1 -0
- package/dist/internal/json.js +90 -0
- package/dist/internal/json.js.map +1 -0
- package/dist/internal/text.d.ts +17 -0
- package/dist/internal/text.d.ts.map +1 -0
- package/dist/internal/text.js +22 -0
- package/dist/internal/text.js.map +1 -0
- package/dist/pipeline.d.ts +80 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +159 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/policy.d.ts +52 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +199 -0
- package/dist/policy.js.map +1 -0
- package/dist/prompts.d.ts +86 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +337 -0
- package/dist/prompts.js.map +1 -0
- package/dist/providers/base.d.ts +19 -0
- package/dist/providers/base.d.ts.map +1 -0
- package/dist/providers/base.js +13 -0
- package/dist/providers/base.js.map +1 -0
- package/dist/providers/fake.d.ts +98 -0
- package/dist/providers/fake.d.ts.map +1 -0
- package/dist/providers/fake.js +181 -0
- package/dist/providers/fake.js.map +1 -0
- package/dist/providers/http.d.ts +62 -0
- package/dist/providers/http.d.ts.map +1 -0
- package/dist/providers/http.js +245 -0
- package/dist/providers/http.js.map +1 -0
- package/dist/retrieval/chunking.d.ts +88 -0
- package/dist/retrieval/chunking.d.ts.map +1 -0
- package/dist/retrieval/chunking.js +188 -0
- package/dist/retrieval/chunking.js.map +1 -0
- package/dist/retrieval/citations.d.ts +98 -0
- package/dist/retrieval/citations.d.ts.map +1 -0
- package/dist/retrieval/citations.js +134 -0
- package/dist/retrieval/citations.js.map +1 -0
- package/dist/retrieval/connectors.d.ts +74 -0
- package/dist/retrieval/connectors.d.ts.map +1 -0
- package/dist/retrieval/connectors.js +218 -0
- package/dist/retrieval/connectors.js.map +1 -0
- package/dist/retrieval/embedding.d.ts +116 -0
- package/dist/retrieval/embedding.d.ts.map +1 -0
- package/dist/retrieval/embedding.js +282 -0
- package/dist/retrieval/embedding.js.map +1 -0
- package/dist/retrieval/gate.d.ts +52 -0
- package/dist/retrieval/gate.d.ts.map +1 -0
- package/dist/retrieval/gate.js +91 -0
- package/dist/retrieval/gate.js.map +1 -0
- package/dist/retrieval/hybrid.d.ts +76 -0
- package/dist/retrieval/hybrid.d.ts.map +1 -0
- package/dist/retrieval/hybrid.js +150 -0
- package/dist/retrieval/hybrid.js.map +1 -0
- package/dist/retrieval/metrics.d.ts +126 -0
- package/dist/retrieval/metrics.d.ts.map +1 -0
- package/dist/retrieval/metrics.js +200 -0
- package/dist/retrieval/metrics.js.map +1 -0
- package/dist/retrieval/pgvector.d.ts +62 -0
- package/dist/retrieval/pgvector.d.ts.map +1 -0
- package/dist/retrieval/pgvector.js +262 -0
- package/dist/retrieval/pgvector.js.map +1 -0
- package/dist/retrieval/rerank.d.ts +61 -0
- package/dist/retrieval/rerank.d.ts.map +1 -0
- package/dist/retrieval/rerank.js +105 -0
- package/dist/retrieval/rerank.js.map +1 -0
- package/dist/retrieval/retriever.d.ts +125 -0
- package/dist/retrieval/retriever.d.ts.map +1 -0
- package/dist/retrieval/retriever.js +281 -0
- package/dist/retrieval/retriever.js.map +1 -0
- package/dist/retrieval/stores.d.ts +106 -0
- package/dist/retrieval/stores.d.ts.map +1 -0
- package/dist/retrieval/stores.js +142 -0
- package/dist/retrieval/stores.js.map +1 -0
- package/dist/retrieval/types.d.ts +314 -0
- package/dist/retrieval/types.d.ts.map +1 -0
- package/dist/retrieval/types.js +388 -0
- package/dist/retrieval/types.js.map +1 -0
- package/dist/steps.d.ts +156 -0
- package/dist/steps.d.ts.map +1 -0
- package/dist/steps.js +199 -0
- package/dist/steps.js.map +1 -0
- package/dist/structured.d.ts +91 -0
- package/dist/structured.d.ts.map +1 -0
- package/dist/structured.js +155 -0
- package/dist/structured.js.map +1 -0
- package/dist/tools.d.ts +100 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +201 -0
- package/dist/tools.js.map +1 -0
- package/dist/tracing.d.ts +104 -0
- package/dist/tracing.d.ts.map +1 -0
- package/dist/tracing.js +155 -0
- package/dist/tracing.js.map +1 -0
- package/dist/types.d.ts +240 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +357 -0
- package/dist/types.js.map +1 -0
- package/package.json +77 -3
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading a `file` source.
|
|
3
|
+
*
|
|
4
|
+
* The IR names five source kinds and Phase 1 implements one. That is the spec
|
|
5
|
+
* validator's own position ("spec v0.1 indexes a local `file` source; the remote
|
|
6
|
+
* loaders belong to the phase that ships them"), so the other four raise
|
|
7
|
+
* {@link FeatureDeferredError} here rather than indexing an empty corpus and
|
|
8
|
+
* looking healthy.
|
|
9
|
+
*
|
|
10
|
+
* **Document identity is the POSIX path relative to the source root.** That is
|
|
11
|
+
* the vocabulary the IR's retrieval metric already uses -- its `expectDocs` hold
|
|
12
|
+
* `getting-started.md`, not `./docs/getting-started.md` -- and it is
|
|
13
|
+
* machine-independent, so the same corpus indexed on Windows and on Linux yields
|
|
14
|
+
* the same ids and the same eval outcome. Absolute paths would make a baseline
|
|
15
|
+
* non-portable.
|
|
16
|
+
*
|
|
17
|
+
* The protocol is `async` even though the only implementation reads local files
|
|
18
|
+
* synchronously, because the kinds that follow (`s3`, `http`, `db`, `mcp`) are
|
|
19
|
+
* genuinely concurrent. Making it sync now would be a breaking change to the seam
|
|
20
|
+
* exactly when the first real loader arrives.
|
|
21
|
+
*/
|
|
22
|
+
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
23
|
+
import { isAbsolute, relative, sep } from 'node:path';
|
|
24
|
+
import { ConfigurationError, FeatureDeferredError } from '../errors.js';
|
|
25
|
+
import { repr } from '../internal/json.js';
|
|
26
|
+
function tokenizeGlob(pattern) {
|
|
27
|
+
const tokens = [];
|
|
28
|
+
for (let index = 0; index < pattern.length; index += 1) {
|
|
29
|
+
const char = pattern[index];
|
|
30
|
+
if (char === '*') {
|
|
31
|
+
if (pattern[index + 1] === '*') {
|
|
32
|
+
index += 1;
|
|
33
|
+
if (pattern[index + 1] === '/') {
|
|
34
|
+
index += 1;
|
|
35
|
+
tokens.push({ kind: 'globstar-segment' });
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
tokens.push({ kind: 'globstar' });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
tokens.push({ kind: 'star' });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else if (char === '?') {
|
|
46
|
+
tokens.push({ kind: 'any-one' });
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
tokens.push({ kind: 'literal', char });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return tokens;
|
|
53
|
+
}
|
|
54
|
+
function compileGlob(pattern) {
|
|
55
|
+
const tokens = tokenizeGlob(pattern);
|
|
56
|
+
return (path) => {
|
|
57
|
+
let reachable = new Array(path.length + 1).fill(false);
|
|
58
|
+
reachable[0] = true;
|
|
59
|
+
for (const token of tokens) {
|
|
60
|
+
const next = new Array(path.length + 1).fill(false);
|
|
61
|
+
switch (token.kind) {
|
|
62
|
+
case 'literal':
|
|
63
|
+
for (let end = 1; end <= path.length; end += 1) {
|
|
64
|
+
next[end] = reachable[end - 1] === true && path[end - 1] === token.char;
|
|
65
|
+
}
|
|
66
|
+
break;
|
|
67
|
+
case 'any-one':
|
|
68
|
+
for (let end = 1; end <= path.length; end += 1) {
|
|
69
|
+
next[end] = reachable[end - 1] === true && path[end - 1] !== '/';
|
|
70
|
+
}
|
|
71
|
+
break;
|
|
72
|
+
case 'star':
|
|
73
|
+
// Zero or more non-slash characters: stay put, or extend a run that has
|
|
74
|
+
// already stayed inside one segment.
|
|
75
|
+
for (let end = 0; end <= path.length; end += 1) {
|
|
76
|
+
const extendsRun = end > 0 && next[end - 1] === true && path[end - 1] !== '/';
|
|
77
|
+
next[end] = reachable[end] === true || extendsRun;
|
|
78
|
+
}
|
|
79
|
+
break;
|
|
80
|
+
case 'globstar':
|
|
81
|
+
// Zero or more of any character, slashes included.
|
|
82
|
+
for (let end = 0; end <= path.length; end += 1) {
|
|
83
|
+
const extendsRun = end > 0 && next[end - 1] === true;
|
|
84
|
+
next[end] = reachable[end] === true || extendsRun;
|
|
85
|
+
}
|
|
86
|
+
break;
|
|
87
|
+
case 'globstar-segment':
|
|
88
|
+
// `(?:[^/]*/)*`: zero or more whole segments, so it lands on any boundary
|
|
89
|
+
// that follows a slash, including the one it started on.
|
|
90
|
+
{
|
|
91
|
+
let anyBefore = false;
|
|
92
|
+
for (let end = 0; end <= path.length; end += 1) {
|
|
93
|
+
const lands = anyBefore && end > 0 && path[end - 1] === '/';
|
|
94
|
+
next[end] = reachable[end] === true || lands;
|
|
95
|
+
if (reachable[end] === true)
|
|
96
|
+
anyBefore = true;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
reachable = next;
|
|
102
|
+
}
|
|
103
|
+
return reachable[path.length] === true;
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/** One document read from a source, before chunking. */
|
|
107
|
+
export class SourceDocument {
|
|
108
|
+
/** POSIX path relative to the source root; the document's identity everywhere. */
|
|
109
|
+
docId;
|
|
110
|
+
/** The absolute resolved location, for a human reading a citation. Never matched on. */
|
|
111
|
+
uri;
|
|
112
|
+
text;
|
|
113
|
+
metadata;
|
|
114
|
+
constructor(init) {
|
|
115
|
+
if (init.docId.length === 0) {
|
|
116
|
+
throw new ConfigurationError('docId must not be empty');
|
|
117
|
+
}
|
|
118
|
+
if (init.uri.length === 0) {
|
|
119
|
+
throw new ConfigurationError('uri must not be empty');
|
|
120
|
+
}
|
|
121
|
+
this.docId = init.docId;
|
|
122
|
+
this.uri = init.uri;
|
|
123
|
+
this.text = init.text;
|
|
124
|
+
this.metadata = { ...(init.metadata ?? {}) };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Reads `*.md`-style files under a local directory.
|
|
129
|
+
*
|
|
130
|
+
* Files are read and returned in sorted `docId` order, never in directory order:
|
|
131
|
+
* directory order is a filesystem accident, and a corpus whose chunk ids depend on
|
|
132
|
+
* it would reindex itself differently on a different machine.
|
|
133
|
+
*/
|
|
134
|
+
export class FileConnector {
|
|
135
|
+
_root;
|
|
136
|
+
_glob;
|
|
137
|
+
constructor(root, options = {}) {
|
|
138
|
+
this._root = root;
|
|
139
|
+
if (!existsSync(this._root)) {
|
|
140
|
+
throw new ConfigurationError(`source path ${repr(this._root)} does not exist`);
|
|
141
|
+
}
|
|
142
|
+
if (!statSync(this._root).isDirectory()) {
|
|
143
|
+
throw new ConfigurationError(`source path ${repr(this._root)} is not a directory`);
|
|
144
|
+
}
|
|
145
|
+
this._glob = options.glob ?? null;
|
|
146
|
+
}
|
|
147
|
+
get kind() {
|
|
148
|
+
return 'file';
|
|
149
|
+
}
|
|
150
|
+
async documents() {
|
|
151
|
+
return this.paths().map((path) => this.read(path));
|
|
152
|
+
}
|
|
153
|
+
async close() {
|
|
154
|
+
return Promise.resolve();
|
|
155
|
+
}
|
|
156
|
+
paths() {
|
|
157
|
+
const pattern = this._glob ?? '**/*';
|
|
158
|
+
const matcher = compileGlob(pattern);
|
|
159
|
+
const found = [];
|
|
160
|
+
const walk = (absolute) => {
|
|
161
|
+
for (const entry of readdirSync(absolute, { withFileTypes: true })) {
|
|
162
|
+
const child = `${absolute}${sep}${entry.name}`;
|
|
163
|
+
if (entry.isDirectory()) {
|
|
164
|
+
walk(child);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (!entry.isFile())
|
|
168
|
+
continue;
|
|
169
|
+
if (entry.name.startsWith('.'))
|
|
170
|
+
continue;
|
|
171
|
+
if (!matcher(this.docId(child)))
|
|
172
|
+
continue;
|
|
173
|
+
found.push(child);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
walk(this._root);
|
|
177
|
+
return found.sort((left, right) => {
|
|
178
|
+
const a = this.docId(left);
|
|
179
|
+
const b = this.docId(right);
|
|
180
|
+
if (a < b)
|
|
181
|
+
return -1;
|
|
182
|
+
return a > b ? 1 : 0;
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
docId(path) {
|
|
186
|
+
return relative(this._root, path).split(sep).join('/');
|
|
187
|
+
}
|
|
188
|
+
read(path) {
|
|
189
|
+
const docId = this.docId(path);
|
|
190
|
+
const suffix = docId.includes('.') ? `.${docId.split('.').pop()}` : '';
|
|
191
|
+
return new SourceDocument({
|
|
192
|
+
docId,
|
|
193
|
+
uri: path,
|
|
194
|
+
text: readFileSync(path, 'utf8'),
|
|
195
|
+
metadata: { path: docId, suffix },
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Open the connector for a source entry.
|
|
201
|
+
*
|
|
202
|
+
* `baseDir` resolves a relative source `uri`; it is explicit because the runtime
|
|
203
|
+
* has no opinion about a working directory, and a corpus must not depend on where a
|
|
204
|
+
* process happened to be started.
|
|
205
|
+
*/
|
|
206
|
+
export function openConnector(spec, options = {}) {
|
|
207
|
+
if (spec.kind !== 'file') {
|
|
208
|
+
throw new FeatureDeferredError(`source kind ${repr(spec.kind)} is declared but not implemented: spec v0.1 ` +
|
|
209
|
+
"indexes a local 'file' source, and the remote loaders (s3, http, db, mcp) " +
|
|
210
|
+
'belong to the phase that ships them');
|
|
211
|
+
}
|
|
212
|
+
let root = spec.uri;
|
|
213
|
+
if (!isAbsolute(root) && options.baseDir !== undefined && options.baseDir !== null) {
|
|
214
|
+
root = `${options.baseDir}${sep}${root}`;
|
|
215
|
+
}
|
|
216
|
+
return new FileConnector(root, { glob: spec.glob });
|
|
217
|
+
}
|
|
218
|
+
//# sourceMappingURL=connectors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connectors.js","sourceRoot":"","sources":["../../src/retrieval/connectors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning text into vectors.
|
|
3
|
+
*
|
|
4
|
+
* Two adapters, and that is the whole Phase 1 surface: one deterministic fake and
|
|
5
|
+
* one OpenAI-compatible HTTP client. The fake is not a testing afterthought -- it is
|
|
6
|
+
* the adapter the eval gate runs against, because a gate that needed an API key
|
|
7
|
+
* could not run offline in CI. That is the same reason the spec DSL already has
|
|
8
|
+
* `provider: fake` ("deterministic and keyless, which is what lets the eval gate run
|
|
9
|
+
* offline").
|
|
10
|
+
*
|
|
11
|
+
* The pinning rule lives in the seam, not in the adapters: `embed` takes a
|
|
12
|
+
* {@link PinnedEmbedding} and uses its `modelId` and `dimensions`. Nothing here
|
|
13
|
+
* resolves an alias, and the fake hashes the *pinned* model id into its vector, so a
|
|
14
|
+
* silently changed pin produces different vectors rather than a store full of
|
|
15
|
+
* incomparable ones.
|
|
16
|
+
*/
|
|
17
|
+
import { type FetchLike } from '../providers/http.js';
|
|
18
|
+
import { TokenUsage } from '../types.js';
|
|
19
|
+
import type { PinnedEmbedding } from './types.js';
|
|
20
|
+
/** Vectors plus the usage that prices them. */
|
|
21
|
+
export declare class EmbeddingBatch {
|
|
22
|
+
readonly vectors: readonly (readonly number[])[];
|
|
23
|
+
readonly usage: TokenUsage;
|
|
24
|
+
constructor(init: {
|
|
25
|
+
readonly vectors: readonly (readonly number[])[];
|
|
26
|
+
readonly usage: TokenUsage;
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Text to vectors, with the model pinned by the caller.
|
|
31
|
+
*
|
|
32
|
+
* `close` must be idempotent, matching `Provider`: a client's lifetime is owned by
|
|
33
|
+
* the caller, so closing twice is a caller's mistake that must stay harmless.
|
|
34
|
+
*/
|
|
35
|
+
export interface Embedder {
|
|
36
|
+
readonly name: string;
|
|
37
|
+
embed(texts: readonly string[], init: {
|
|
38
|
+
readonly model: PinnedEmbedding;
|
|
39
|
+
}): Promise<EmbeddingBatch>;
|
|
40
|
+
close(): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
/** The offline token estimate used for the fake's usage and for budgets. */
|
|
43
|
+
export declare function estimateTokens(text: string): number;
|
|
44
|
+
/**
|
|
45
|
+
* Keyless, offline, and byte-identical across runs and platforms.
|
|
46
|
+
*
|
|
47
|
+
* Vectors come from SHAKE-128, a hash-based extensible output function, rather than
|
|
48
|
+
* from a seeded PRNG. The reason is the same property the rest of this runtime
|
|
49
|
+
* depends on: re-ingesting a corpus has to reproduce the vectors exactly, and
|
|
50
|
+
* re-embedding a *query* has to reproduce what ingest stored. A PRNG seeded per call
|
|
51
|
+
* would be stable too, but a hash makes "same text, same vector" true by
|
|
52
|
+
* construction rather than by discipline, and it cannot drift if a vector is later
|
|
53
|
+
* requested one element at a time.
|
|
54
|
+
*
|
|
55
|
+
* Similarity is meaningless here, and that is the deliberate limitation rather than
|
|
56
|
+
* a bug. Lexical retrieval still works over these vectors because the store keeps
|
|
57
|
+
* the text and hybrid search reads it; what the fake proves is the *pipeline*, and
|
|
58
|
+
* what it deliberately does not prove is embedding quality.
|
|
59
|
+
*/
|
|
60
|
+
export declare class FakeDeterministicEmbedder implements Embedder {
|
|
61
|
+
private readonly _name;
|
|
62
|
+
constructor(init?: {
|
|
63
|
+
readonly name?: string;
|
|
64
|
+
});
|
|
65
|
+
get name(): string;
|
|
66
|
+
embed(texts: readonly string[], init: {
|
|
67
|
+
readonly model: PinnedEmbedding;
|
|
68
|
+
}): Promise<EmbeddingBatch>;
|
|
69
|
+
close(): Promise<void>;
|
|
70
|
+
private vector;
|
|
71
|
+
}
|
|
72
|
+
/** One POST to `/embeddings` on any OpenAI-compatible endpoint. */
|
|
73
|
+
export declare class OpenAICompatibleEmbedder implements Embedder {
|
|
74
|
+
private readonly _baseUrl;
|
|
75
|
+
private readonly _apiKey;
|
|
76
|
+
private readonly _name;
|
|
77
|
+
private readonly _maxAttempts;
|
|
78
|
+
private readonly _backoffSeconds;
|
|
79
|
+
private readonly _extraHeaders;
|
|
80
|
+
private readonly _fetch;
|
|
81
|
+
private readonly _ownsClient;
|
|
82
|
+
private _closed;
|
|
83
|
+
constructor(options?: {
|
|
84
|
+
readonly baseUrl?: string;
|
|
85
|
+
readonly apiKey?: string;
|
|
86
|
+
readonly name?: string;
|
|
87
|
+
readonly timeoutSeconds?: number;
|
|
88
|
+
readonly maxAttempts?: number;
|
|
89
|
+
readonly backoffSeconds?: number;
|
|
90
|
+
readonly fetchImpl?: FetchLike;
|
|
91
|
+
readonly extraHeaders?: Readonly<Record<string, string>>;
|
|
92
|
+
});
|
|
93
|
+
get name(): string;
|
|
94
|
+
embed(texts: readonly string[], init: {
|
|
95
|
+
readonly model: PinnedEmbedding;
|
|
96
|
+
}): Promise<EmbeddingBatch>;
|
|
97
|
+
close(): Promise<void>;
|
|
98
|
+
private headers;
|
|
99
|
+
private post;
|
|
100
|
+
private asObject;
|
|
101
|
+
private parse;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Pick the adapter for a pinned embedding model.
|
|
105
|
+
*
|
|
106
|
+
* This selects a *provider*, never a model: the model id and its width arrive
|
|
107
|
+
* already pinned, and are passed straight through to whichever adapter is chosen.
|
|
108
|
+
* `fake` is chosen for the same reason the spec can declare it -- so a gate runs
|
|
109
|
+
* keyless and offline.
|
|
110
|
+
*/
|
|
111
|
+
export declare function embedderFor(model: PinnedEmbedding, options?: {
|
|
112
|
+
readonly apiKey?: string;
|
|
113
|
+
readonly baseUrl?: string;
|
|
114
|
+
readonly fetchImpl?: FetchLike;
|
|
115
|
+
}): Embedder;
|
|
116
|
+
//# sourceMappingURL=embedding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedding.d.ts","sourceRoot":"","sources":["../../src/retrieval/embedding.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning text into vectors.
|
|
3
|
+
*
|
|
4
|
+
* Two adapters, and that is the whole Phase 1 surface: one deterministic fake and
|
|
5
|
+
* one OpenAI-compatible HTTP client. The fake is not a testing afterthought -- it is
|
|
6
|
+
* the adapter the eval gate runs against, because a gate that needed an API key
|
|
7
|
+
* could not run offline in CI. That is the same reason the spec DSL already has
|
|
8
|
+
* `provider: fake` ("deterministic and keyless, which is what lets the eval gate run
|
|
9
|
+
* offline").
|
|
10
|
+
*
|
|
11
|
+
* The pinning rule lives in the seam, not in the adapters: `embed` takes a
|
|
12
|
+
* {@link PinnedEmbedding} and uses its `modelId` and `dimensions`. Nothing here
|
|
13
|
+
* resolves an alias, and the fake hashes the *pinned* model id into its vector, so a
|
|
14
|
+
* silently changed pin produces different vectors rather than a store full of
|
|
15
|
+
* incomparable ones.
|
|
16
|
+
*/
|
|
17
|
+
import { createHash } from 'node:crypto';
|
|
18
|
+
import { ConfigurationError, ProviderError, ProviderResponseError } from '../errors.js';
|
|
19
|
+
import { repr } from '../internal/json.js';
|
|
20
|
+
import { stripTrailingSlashes } from '../internal/text.js';
|
|
21
|
+
import { DEFAULT_BASE_URL } from '../providers/http.js';
|
|
22
|
+
import { TokenUsage } from '../types.js';
|
|
23
|
+
/**
|
|
24
|
+
* Statuses worth a second attempt: the request was well-formed and the server was
|
|
25
|
+
* momentarily unwilling. Mirrors the chat provider's set so retry behaviour is one
|
|
26
|
+
* rule in this runtime rather than one rule per adapter.
|
|
27
|
+
*/
|
|
28
|
+
const RETRYABLE_STATUS = new Set([408, 409, 425, 429, 500, 502, 503, 504]);
|
|
29
|
+
/**
|
|
30
|
+
* Rough tokeniser. Deliberately the same arithmetic as `estimatePromptCostUsd`
|
|
31
|
+
* (4 characters per token, rounded up), so an offline estimate and an offline charge
|
|
32
|
+
* cannot disagree about what a text costs.
|
|
33
|
+
*/
|
|
34
|
+
const CHARS_PER_TOKEN = 4;
|
|
35
|
+
/** Vectors plus the usage that prices them. */
|
|
36
|
+
export class EmbeddingBatch {
|
|
37
|
+
vectors;
|
|
38
|
+
usage;
|
|
39
|
+
constructor(init) {
|
|
40
|
+
this.vectors = init.vectors.map((vector) => [...vector]);
|
|
41
|
+
this.usage = init.usage;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/** The offline token estimate used for the fake's usage and for budgets. */
|
|
45
|
+
export function estimateTokens(text) {
|
|
46
|
+
return (text.length + CHARS_PER_TOKEN - 1) >> 2;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Keyless, offline, and byte-identical across runs and platforms.
|
|
50
|
+
*
|
|
51
|
+
* Vectors come from SHAKE-128, a hash-based extensible output function, rather than
|
|
52
|
+
* from a seeded PRNG. The reason is the same property the rest of this runtime
|
|
53
|
+
* depends on: re-ingesting a corpus has to reproduce the vectors exactly, and
|
|
54
|
+
* re-embedding a *query* has to reproduce what ingest stored. A PRNG seeded per call
|
|
55
|
+
* would be stable too, but a hash makes "same text, same vector" true by
|
|
56
|
+
* construction rather than by discipline, and it cannot drift if a vector is later
|
|
57
|
+
* requested one element at a time.
|
|
58
|
+
*
|
|
59
|
+
* Similarity is meaningless here, and that is the deliberate limitation rather than
|
|
60
|
+
* a bug. Lexical retrieval still works over these vectors because the store keeps
|
|
61
|
+
* the text and hybrid search reads it; what the fake proves is the *pipeline*, and
|
|
62
|
+
* what it deliberately does not prove is embedding quality.
|
|
63
|
+
*/
|
|
64
|
+
export class FakeDeterministicEmbedder {
|
|
65
|
+
_name;
|
|
66
|
+
constructor(init = {}) {
|
|
67
|
+
this._name = init.name ?? 'fake-embedder';
|
|
68
|
+
}
|
|
69
|
+
get name() {
|
|
70
|
+
return this._name;
|
|
71
|
+
}
|
|
72
|
+
async embed(texts, init) {
|
|
73
|
+
return new EmbeddingBatch({
|
|
74
|
+
vectors: texts.map((text) => this.vector(text, init.model)),
|
|
75
|
+
usage: new TokenUsage({
|
|
76
|
+
inputTokens: texts.reduce((total, text) => total + estimateTokens(text), 0),
|
|
77
|
+
outputTokens: 0,
|
|
78
|
+
}),
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
async close() {
|
|
82
|
+
return Promise.resolve();
|
|
83
|
+
}
|
|
84
|
+
vector(text, model) {
|
|
85
|
+
// The pinned model id is part of the input so the same text under a different
|
|
86
|
+
// pin embeds differently: a changed pin must invalidate stored vectors rather
|
|
87
|
+
// than silently mix two vector spaces in one table.
|
|
88
|
+
const seed = `${model.modelId}:${model.dimensions}\u0000${text}`;
|
|
89
|
+
const raw = createHash('shake128', { outputLength: model.dimensions * 2 })
|
|
90
|
+
.update(seed, 'utf8')
|
|
91
|
+
.digest();
|
|
92
|
+
const values = [];
|
|
93
|
+
for (let index = 0; index < model.dimensions; index += 1) {
|
|
94
|
+
values.push(raw.readUInt16BE(index * 2) / 32767.5 - 1.0);
|
|
95
|
+
}
|
|
96
|
+
const norm = Math.sqrt(values.reduce((total, value) => total + value * value, 0)) || 1.0;
|
|
97
|
+
return values.map((value) => value / norm);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/** One POST to `/embeddings` on any OpenAI-compatible endpoint. */
|
|
101
|
+
export class OpenAICompatibleEmbedder {
|
|
102
|
+
_baseUrl;
|
|
103
|
+
_apiKey;
|
|
104
|
+
_name;
|
|
105
|
+
_maxAttempts;
|
|
106
|
+
_backoffSeconds;
|
|
107
|
+
_extraHeaders;
|
|
108
|
+
_fetch;
|
|
109
|
+
_ownsClient;
|
|
110
|
+
_closed = false;
|
|
111
|
+
constructor(options = {}) {
|
|
112
|
+
const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
|
|
113
|
+
if (!/^https?:\/\/./i.test(baseUrl)) {
|
|
114
|
+
throw new ConfigurationError(`base_url must be an absolute http(s) URL, got ${repr(baseUrl)}`);
|
|
115
|
+
}
|
|
116
|
+
const maxAttempts = options.maxAttempts ?? 3;
|
|
117
|
+
if (maxAttempts < 1) {
|
|
118
|
+
throw new ConfigurationError('max_attempts must be at least 1');
|
|
119
|
+
}
|
|
120
|
+
this._baseUrl = stripTrailingSlashes(baseUrl);
|
|
121
|
+
this._apiKey = options.apiKey;
|
|
122
|
+
this._name = options.name ?? 'openai-compatible-embedder';
|
|
123
|
+
this._maxAttempts = maxAttempts;
|
|
124
|
+
this._backoffSeconds = options.backoffSeconds ?? 0.5;
|
|
125
|
+
this._extraHeaders = { ...(options.extraHeaders ?? {}) };
|
|
126
|
+
// Eager, like the chat provider: the caller may inject a transport (a test's
|
|
127
|
+
// stub, or a shared pool). Whoever constructed it closes it, so ownership is
|
|
128
|
+
// tracked rather than assumed.
|
|
129
|
+
this._ownsClient = options.fetchImpl === undefined;
|
|
130
|
+
this._fetch = options.fetchImpl ?? globalThis.fetch;
|
|
131
|
+
}
|
|
132
|
+
get name() {
|
|
133
|
+
return this._name;
|
|
134
|
+
}
|
|
135
|
+
async embed(texts, init) {
|
|
136
|
+
const body = await this.post('/embeddings', { model: init.model.modelId, input: [...texts] });
|
|
137
|
+
return this.parse(body, init.model);
|
|
138
|
+
}
|
|
139
|
+
async close() {
|
|
140
|
+
if (this._closed)
|
|
141
|
+
return;
|
|
142
|
+
this._closed = true;
|
|
143
|
+
// An injected transport belongs to its injector; there is nothing owned to close.
|
|
144
|
+
if (!this._ownsClient)
|
|
145
|
+
return;
|
|
146
|
+
return Promise.resolve();
|
|
147
|
+
}
|
|
148
|
+
headers() {
|
|
149
|
+
const headers = {
|
|
150
|
+
'content-type': 'application/json',
|
|
151
|
+
...this._extraHeaders,
|
|
152
|
+
};
|
|
153
|
+
if (this._apiKey !== undefined && this._apiKey.length > 0) {
|
|
154
|
+
// A real bearer token, not the chat provider's redacted placeholder: a request
|
|
155
|
+
// that claims to be authenticated and is not fails with a 401 that reads like a
|
|
156
|
+
// credentials problem at the far end.
|
|
157
|
+
headers.authorization = `Bearer ${this._apiKey}`;
|
|
158
|
+
}
|
|
159
|
+
return headers;
|
|
160
|
+
}
|
|
161
|
+
async post(path, payload) {
|
|
162
|
+
const url = `${this._baseUrl}${path}`;
|
|
163
|
+
let lastError = 'unknown error';
|
|
164
|
+
for (let attempt = 1; attempt <= this._maxAttempts; attempt += 1) {
|
|
165
|
+
let response;
|
|
166
|
+
try {
|
|
167
|
+
response = await this._fetch(url, {
|
|
168
|
+
method: 'POST',
|
|
169
|
+
headers: this.headers(),
|
|
170
|
+
body: JSON.stringify(payload),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
lastError = error instanceof Error ? error.message : String(error);
|
|
175
|
+
}
|
|
176
|
+
if (response !== undefined) {
|
|
177
|
+
const text = await response.text();
|
|
178
|
+
if (response.status < 400) {
|
|
179
|
+
return this.asObject(text);
|
|
180
|
+
}
|
|
181
|
+
const failure = `${this._name} returned HTTP ${response.status}: ${text.slice(0, 200)}`;
|
|
182
|
+
// A status outside the retryable set is a decision, not a hiccup: retrying a
|
|
183
|
+
// 400 only wastes the caller's time.
|
|
184
|
+
if (!RETRYABLE_STATUS.has(response.status)) {
|
|
185
|
+
throw new ProviderError(failure);
|
|
186
|
+
}
|
|
187
|
+
lastError = failure;
|
|
188
|
+
}
|
|
189
|
+
if (attempt < this._maxAttempts) {
|
|
190
|
+
await delay(this._backoffSeconds * 2 ** (attempt - 1));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
throw new ProviderError(`${this._name} failed after ${this._maxAttempts} attempt(s): ${lastError}`);
|
|
194
|
+
}
|
|
195
|
+
asObject(text) {
|
|
196
|
+
let body;
|
|
197
|
+
try {
|
|
198
|
+
body = JSON.parse(text);
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
throw new ProviderResponseError(`${this._name} returned a body that is not JSON`);
|
|
202
|
+
}
|
|
203
|
+
if (typeof body !== 'object' || body === null || Array.isArray(body)) {
|
|
204
|
+
throw new ProviderResponseError(`${this._name} returned a JSON body that is not an object`);
|
|
205
|
+
}
|
|
206
|
+
return body;
|
|
207
|
+
}
|
|
208
|
+
parse(body, model) {
|
|
209
|
+
const entries = body.data;
|
|
210
|
+
if (!Array.isArray(entries) || entries.length === 0) {
|
|
211
|
+
throw new ProviderResponseError(`${this._name} returned no embeddings`);
|
|
212
|
+
}
|
|
213
|
+
const list = entries;
|
|
214
|
+
const ordered = [];
|
|
215
|
+
for (const [position, entry] of list.entries()) {
|
|
216
|
+
if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) {
|
|
217
|
+
throw new ProviderResponseError(`${this._name} returned a non-object embedding entry`);
|
|
218
|
+
}
|
|
219
|
+
const record = entry;
|
|
220
|
+
const index = record.index ?? position;
|
|
221
|
+
if (!Number.isInteger(index)) {
|
|
222
|
+
throw new ProviderResponseError(`${this._name} returned a non-integer embedding index`);
|
|
223
|
+
}
|
|
224
|
+
ordered.push({ index: index, vector: record.embedding });
|
|
225
|
+
}
|
|
226
|
+
ordered.sort((left, right) => left.index - right.index);
|
|
227
|
+
const vectors = [];
|
|
228
|
+
for (const entry of ordered) {
|
|
229
|
+
if (!Array.isArray(entry.vector)) {
|
|
230
|
+
throw new ProviderResponseError(`${this._name} returned a non-list embedding`);
|
|
231
|
+
}
|
|
232
|
+
const values = [];
|
|
233
|
+
for (const value of entry.vector) {
|
|
234
|
+
const numeric = typeof value === 'number' ? value : Number(value);
|
|
235
|
+
if (!Number.isFinite(numeric)) {
|
|
236
|
+
throw new ProviderResponseError(`${this._name} returned a non-numeric embedding`);
|
|
237
|
+
}
|
|
238
|
+
values.push(numeric);
|
|
239
|
+
}
|
|
240
|
+
if (values.length !== model.dimensions) {
|
|
241
|
+
throw new ProviderResponseError(`${this._name} returned ${values.length} dimensions for ${repr(model.modelId)} but ` +
|
|
242
|
+
`${model.dimensions} are pinned; the pin and the response must agree`);
|
|
243
|
+
}
|
|
244
|
+
vectors.push(values);
|
|
245
|
+
}
|
|
246
|
+
const usage = body.usage;
|
|
247
|
+
const found = typeof usage === 'object' && usage !== null
|
|
248
|
+
? usage.prompt_tokens
|
|
249
|
+
: undefined;
|
|
250
|
+
const promptTokens = typeof found === 'number' && Number.isInteger(found) ? found : 0;
|
|
251
|
+
return new EmbeddingBatch({
|
|
252
|
+
vectors,
|
|
253
|
+
usage: new TokenUsage({ inputTokens: promptTokens, outputTokens: 0 }),
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
function delay(seconds) {
|
|
258
|
+
if (seconds <= 0)
|
|
259
|
+
return Promise.resolve();
|
|
260
|
+
return new Promise((resolve) => {
|
|
261
|
+
setTimeout(resolve, seconds * 1000);
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Pick the adapter for a pinned embedding model.
|
|
266
|
+
*
|
|
267
|
+
* This selects a *provider*, never a model: the model id and its width arrive
|
|
268
|
+
* already pinned, and are passed straight through to whichever adapter is chosen.
|
|
269
|
+
* `fake` is chosen for the same reason the spec can declare it -- so a gate runs
|
|
270
|
+
* keyless and offline.
|
|
271
|
+
*/
|
|
272
|
+
export function embedderFor(model, options = {}) {
|
|
273
|
+
if (model.provider === 'fake') {
|
|
274
|
+
return new FakeDeterministicEmbedder();
|
|
275
|
+
}
|
|
276
|
+
return new OpenAICompatibleEmbedder({
|
|
277
|
+
baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,
|
|
278
|
+
apiKey: options.apiKey,
|
|
279
|
+
fetchImpl: options.fetchImpl,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
//# sourceMappingURL=embedding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedding.js","sourceRoot":"","sources":["../../src/retrieval/embedding.ts"],"names":[],"mappings":"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"}
|