@fevex/core 0.1.0-alpha.1 → 0.1.0-alpha.11

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.
Files changed (56) hide show
  1. package/README.md +786 -13
  2. package/dist/agents/index.d.mts +2 -2
  3. package/dist/agents/index.mjs +1 -1
  4. package/dist/artifacts/index.d.mts +2 -0
  5. package/dist/artifacts/index.mjs +2 -0
  6. package/dist/artifacts-gUzemET7.mjs +440 -0
  7. package/dist/channels/index.d.mts +2 -0
  8. package/dist/channels/index.mjs +192 -0
  9. package/dist/evals/index.d.mts +19 -11
  10. package/dist/evals/index.mjs +125 -122
  11. package/dist/fevex-_KOsOsB8.d.mts +129 -0
  12. package/dist/http/index.d.mts +150 -0
  13. package/dist/http/index.mjs +692 -0
  14. package/dist/index-26ilbzAs.d.mts +50 -0
  15. package/dist/index-B8EcvWeN.d.mts +103 -0
  16. package/dist/index-BEqYWean.d.mts +118 -0
  17. package/dist/index-Btth7rdL.d.mts +58 -0
  18. package/dist/{index-QTkd6a7C.d.mts → index-CFzrvDQ0.d.mts} +4 -3
  19. package/dist/index-CIHWc5V1.d.mts +116 -0
  20. package/dist/index-D7r0puBi.d.mts +64 -0
  21. package/dist/index-DHcfIfh-.d.mts +224 -0
  22. package/dist/index-DUhNa7IR.d.mts +73 -0
  23. package/dist/index-lCCFokc6.d.mts +617 -0
  24. package/dist/index.d.mts +22 -10
  25. package/dist/index.mjs +4178 -671
  26. package/dist/knowledge/index.d.mts +2 -0
  27. package/dist/knowledge/index.mjs +289 -0
  28. package/dist/model-stream-JQdHDDcj.mjs +131 -0
  29. package/dist/models/index.d.mts +2 -46
  30. package/dist/observability/index.d.mts +2 -2
  31. package/dist/policies/index.d.mts +1 -1
  32. package/dist/policies/index.mjs +1 -1
  33. package/dist/run-error-Cr17wPGH.mjs +23 -0
  34. package/dist/{model-stream-u2xMsEaf.mjs → run-support-CmZ6Xo6H.mjs} +41 -130
  35. package/dist/runtime/index.d.mts +2 -2
  36. package/dist/runtime/index.mjs +271 -9
  37. package/dist/sandbox/index.d.mts +2 -0
  38. package/dist/sandbox/index.mjs +147 -0
  39. package/dist/teams/index.d.mts +2 -0
  40. package/dist/teams/index.mjs +2 -0
  41. package/dist/teams-Ctz676G4.mjs +82 -0
  42. package/dist/testing/index.d.mts +39 -9
  43. package/dist/testing/index.mjs +512 -28
  44. package/dist/tools/index.d.mts +3 -3
  45. package/dist/tools/index.mjs +442 -2
  46. package/dist/types-CckDlhYo.d.mts +575 -0
  47. package/dist/workflows/index.d.mts +2 -0
  48. package/dist/workflows/index.mjs +6 -0
  49. package/package.json +31 -3
  50. package/dist/exact-definition-NHBBFlFR.d.mts +0 -4
  51. package/dist/fevex-Dz6GBz9o.d.mts +0 -32
  52. package/dist/index-BzxHfyYV.d.mts +0 -23
  53. package/dist/index-CZGyhNIQ.d.mts +0 -47
  54. package/dist/index-C_Zpr13f.d.mts +0 -124
  55. package/dist/index-DGWOGXzc.d.mts +0 -181
  56. package/dist/index-ojCY3lwm.d.mts +0 -79
@@ -1,4 +1,224 @@
1
- //#region src/tools/index.ts
1
+ //#region src/tools/connection.ts
2
+ /** Safe, provider-neutral error surfaced by connection adapters. */
3
+ var IntegrationError = class extends Error {
4
+ code;
5
+ category;
6
+ retryable;
7
+ safeMessage;
8
+ name = "IntegrationError";
9
+ constructor(code, category, retryable, safeMessage, options) {
10
+ super(safeMessage, options);
11
+ this.code = code;
12
+ this.category = category;
13
+ this.retryable = retryable;
14
+ this.safeMessage = safeMessage;
15
+ this.source = options?.source;
16
+ }
17
+ source;
18
+ };
19
+ function defineConnection(connection) {
20
+ return connection;
21
+ }
22
+ //#endregion
23
+ //#region src/tools/json-schema-profile.ts
24
+ const FEVEX_JSON_SCHEMA_PROFILE_VERSION = "1";
25
+ const DEFAULT_LIMITS = {
26
+ maxBytes: 64e3,
27
+ maxDepth: 32,
28
+ maxNodes: 1e3,
29
+ maxProperties: 200
30
+ };
31
+ const KEYWORDS = /* @__PURE__ */ new Set([
32
+ "$defs",
33
+ "$ref",
34
+ "additionalProperties",
35
+ "allOf",
36
+ "anyOf",
37
+ "const",
38
+ "default",
39
+ "description",
40
+ "enum",
41
+ "items",
42
+ "maxItems",
43
+ "maxLength",
44
+ "maximum",
45
+ "minItems",
46
+ "minLength",
47
+ "minimum",
48
+ "oneOf",
49
+ "properties",
50
+ "required",
51
+ "title",
52
+ "type"
53
+ ]);
54
+ const DEFERRED = /* @__PURE__ */ new Set([
55
+ "dependentSchemas",
56
+ "format",
57
+ "if",
58
+ "not",
59
+ "pattern",
60
+ "then",
61
+ "else",
62
+ "unevaluatedProperties"
63
+ ]);
64
+ function validateFevexJsonSchemaProfile(schema, options = {}) {
65
+ const limits = {
66
+ ...DEFAULT_LIMITS,
67
+ ...options.limits
68
+ };
69
+ if (JSON.stringify(schema).length > limits.maxBytes) throw new TypeError(`JSON Schema exceeds maxBytes limit of ${limits.maxBytes}`);
70
+ visitSchema(schema, options.rootDocument ?? schema, options.requireRootObject ?? false, limits, { nodes: 0 }, [], 0);
71
+ return schema;
72
+ }
73
+ function compileFevexJsonSchema(schema, options = {}) {
74
+ validateFevexJsonSchemaProfile(schema, options);
75
+ const rootDocument = options.rootDocument ?? schema;
76
+ return {
77
+ schema,
78
+ validate(value, path = "$") {
79
+ validateValue(schema, rootDocument, value, path, []);
80
+ return toJsonValue(value, `${path} must be JSON-serializable`);
81
+ }
82
+ };
83
+ }
84
+ function visitSchema(schema, rootDocument, requireRootObject, limits, stats, refs, depth) {
85
+ stats.nodes += 1;
86
+ if (stats.nodes > limits.maxNodes) throw new TypeError(`JSON Schema exceeds maxNodes limit of ${limits.maxNodes}`);
87
+ if (depth > limits.maxDepth) throw new TypeError(`JSON Schema exceeds maxDepth limit of ${limits.maxDepth}`);
88
+ for (const key of Object.keys(schema)) if (DEFERRED.has(key) || !KEYWORDS.has(key)) throw new TypeError(`JSON Schema keyword "${key}" is not supported`);
89
+ if (requireRootObject && schema.type !== "object" && !schema.$ref && !schema.allOf) throw new TypeError("Tool input JSON Schema root must be object");
90
+ if (typeof schema.$ref === "string") {
91
+ const ref = schema.$ref;
92
+ if (!ref.startsWith("#/")) throw new TypeError(`Remote JSON Schema ref "${ref}" is not supported`);
93
+ if (refs.includes(ref)) throw new TypeError(`JSON Schema ref cycle detected at "${ref}"`);
94
+ visitSchema(resolveRef(rootDocument, ref), rootDocument, false, limits, stats, [...refs, ref], depth + 1);
95
+ }
96
+ if (schema.properties !== void 0) {
97
+ if (!isRecord(schema.properties)) throw new TypeError("JSON Schema properties must be an object");
98
+ const entries = Object.entries(schema.properties);
99
+ if (entries.length > limits.maxProperties) throw new TypeError(`JSON Schema exceeds maxProperties limit of ${limits.maxProperties}`);
100
+ for (const [, child] of entries) {
101
+ if (!isRecord(child)) throw new TypeError("JSON Schema property schemas must be objects");
102
+ visitSchema(child, rootDocument, false, limits, stats, refs, depth + 1);
103
+ }
104
+ }
105
+ for (const key of ["$defs"]) {
106
+ if (schema[key] === void 0) continue;
107
+ if (!isRecord(schema[key])) throw new TypeError(`JSON Schema ${key} must be an object`);
108
+ for (const child of Object.values(schema[key])) {
109
+ if (!isRecord(child)) throw new TypeError(`JSON Schema ${key} entries must be objects`);
110
+ visitSchema(child, rootDocument, false, limits, stats, refs, depth + 1);
111
+ }
112
+ }
113
+ if (schema.items !== void 0) {
114
+ if (!isRecord(schema.items)) throw new TypeError("JSON Schema items must be an object");
115
+ visitSchema(schema.items, rootDocument, false, limits, stats, refs, depth + 1);
116
+ }
117
+ for (const key of [
118
+ "allOf",
119
+ "anyOf",
120
+ "oneOf"
121
+ ]) {
122
+ if (schema[key] === void 0) continue;
123
+ if (!Array.isArray(schema[key])) throw new TypeError(`JSON Schema ${key} must be an array`);
124
+ for (const child of schema[key]) {
125
+ if (!isRecord(child)) throw new TypeError(`JSON Schema ${key} entries must be objects`);
126
+ visitSchema(child, rootDocument, false, limits, stats, refs, depth + 1);
127
+ }
128
+ }
129
+ if (schema.additionalProperties !== void 0 && schema.additionalProperties !== false) {
130
+ if (schema.additionalProperties !== true && !isRecord(schema.additionalProperties)) throw new TypeError("JSON Schema additionalProperties must be boolean or object");
131
+ if (isRecord(schema.additionalProperties)) visitSchema(schema.additionalProperties, rootDocument, false, limits, stats, refs, depth + 1);
132
+ }
133
+ }
134
+ function validateValue(schema, rootDocument, value, path, refs) {
135
+ if (typeof schema.$ref === "string") {
136
+ if (refs.includes(schema.$ref)) throw new TypeError(`JSON Schema ref cycle detected at "${schema.$ref}"`);
137
+ return validateValue(resolveRef(rootDocument, schema.$ref), rootDocument, value, path, [...refs, schema.$ref]);
138
+ }
139
+ if (Array.isArray(schema.allOf)) for (const child of schema.allOf) validateValue(child, rootDocument, value, path, refs);
140
+ if (Array.isArray(schema.anyOf)) {
141
+ if (!schema.anyOf.some((child) => passes(child, rootDocument, value, path, refs))) throw new TypeError(`${path} must match anyOf`);
142
+ }
143
+ if (Array.isArray(schema.oneOf)) {
144
+ if (schema.oneOf.filter((child) => passes(child, rootDocument, value, path, refs)).length !== 1) throw new TypeError(`${path} must match exactly one oneOf schema`);
145
+ }
146
+ if ("const" in schema && JSON.stringify(value) !== JSON.stringify(schema.const)) throw new TypeError(`${path} must equal const`);
147
+ if (Array.isArray(schema.enum) && !schema.enum.some((item) => JSON.stringify(item) === JSON.stringify(value))) throw new TypeError(`${path} must be one of enum`);
148
+ validateType(schema.type, value, path);
149
+ if (schema.type === "object" || isRecord(value)) validateObject(schema, rootDocument, value, path, refs);
150
+ if (schema.type === "array" || Array.isArray(value)) validateArray(schema, rootDocument, value, path, refs);
151
+ if (typeof value === "string") {
152
+ if (typeof schema.minLength === "number" && value.length < schema.minLength) throw new TypeError(`${path} is shorter than minLength`);
153
+ if (typeof schema.maxLength === "number" && value.length > schema.maxLength) throw new TypeError(`${path} is longer than maxLength`);
154
+ }
155
+ if (typeof value === "number") {
156
+ if (typeof schema.minimum === "number" && value < schema.minimum) throw new TypeError(`${path} is below minimum`);
157
+ if (typeof schema.maximum === "number" && value > schema.maximum) throw new TypeError(`${path} is above maximum`);
158
+ }
159
+ }
160
+ function validateObject(schema, rootDocument, value, path, refs) {
161
+ if (!isRecord(value)) return;
162
+ const required = Array.isArray(schema.required) ? schema.required : [];
163
+ for (const key of required) if (typeof key === "string" && !(key in value)) throw new TypeError(`${path}.${key} is required`);
164
+ const properties = isRecord(schema.properties) ? schema.properties : {};
165
+ for (const [key, child] of Object.entries(properties)) if (key in value && isRecord(child)) validateValue(child, rootDocument, value[key], `${path}.${key}`, refs);
166
+ if (schema.additionalProperties === false) {
167
+ for (const key of Object.keys(value)) if (!(key in properties)) throw new TypeError(`${path}.${key} is not allowed`);
168
+ } else if (isRecord(schema.additionalProperties)) {
169
+ for (const [key, item] of Object.entries(value)) if (!(key in properties)) validateValue(schema.additionalProperties, rootDocument, item, `${path}.${key}`, refs);
170
+ }
171
+ }
172
+ function validateArray(schema, rootDocument, value, path, refs) {
173
+ if (!Array.isArray(value)) return;
174
+ if (typeof schema.minItems === "number" && value.length < schema.minItems) throw new TypeError(`${path} has fewer than minItems`);
175
+ if (typeof schema.maxItems === "number" && value.length > schema.maxItems) throw new TypeError(`${path} has more than maxItems`);
176
+ if (isRecord(schema.items)) value.forEach((item, index) => validateValue(schema.items, rootDocument, item, `${path}[${index}]`, refs));
177
+ }
178
+ function validateType(type, value, path) {
179
+ if (type === void 0) return;
180
+ const types = Array.isArray(type) ? type : [type];
181
+ if (!types.some((item) => {
182
+ if (item === "array") return Array.isArray(value);
183
+ if (item === "integer") return Number.isInteger(value);
184
+ if (item === "number") return typeof value === "number" && Number.isFinite(value);
185
+ if (item === "object") return isRecord(value);
186
+ if (item === "null") return value === null;
187
+ return typeof value === item;
188
+ })) throw new TypeError(`${path} must be ${types.join(" or ")}`);
189
+ }
190
+ function passes(schema, rootDocument, value, path, refs) {
191
+ try {
192
+ validateValue(schema, rootDocument, value, path, refs);
193
+ return true;
194
+ } catch {
195
+ return false;
196
+ }
197
+ }
198
+ function resolveRef(rootDocument, ref) {
199
+ const segments = ref.slice(2).split("/").map((part) => part.replace(/~1/g, "/").replace(/~0/g, "~"));
200
+ let current = rootDocument;
201
+ for (const segment of segments) {
202
+ if (!isRecord(current) || !(segment in current)) throw new TypeError(`JSON Schema ref "${ref}" cannot be resolved`);
203
+ current = current[segment];
204
+ }
205
+ if (!isRecord(current)) throw new TypeError(`JSON Schema ref "${ref}" must resolve to an object`);
206
+ return current;
207
+ }
208
+ function toJsonValue(value, message) {
209
+ try {
210
+ const cloned = JSON.parse(JSON.stringify(value));
211
+ if (cloned === void 0) throw new TypeError(message);
212
+ return cloned;
213
+ } catch {
214
+ throw new TypeError(message);
215
+ }
216
+ }
217
+ function isRecord(value) {
218
+ return typeof value === "object" && value !== null && !Array.isArray(value);
219
+ }
220
+ //#endregion
221
+ //#region src/tools/tool.ts
2
222
  function defineTool(tool) {
3
223
  return tool;
4
224
  }
@@ -10,4 +230,224 @@ function toToolSpec(tool, inputSchema) {
10
230
  };
11
231
  }
12
232
  //#endregion
13
- export { defineTool, toToolSpec };
233
+ //#region src/tools/tool-index.ts
234
+ /** Bounded LRU cache for tool embeddings. */
235
+ var InMemoryToolEmbeddingCache = class {
236
+ #entries = /* @__PURE__ */ new Map();
237
+ #maxEntries;
238
+ constructor(options = {}) {
239
+ const maxEntries = options.maxEntries ?? 1e3;
240
+ if (!Number.isSafeInteger(maxEntries) || maxEntries < 1) throw new TypeError("Tool embedding cache maxEntries must be a positive safe integer");
241
+ this.#maxEntries = maxEntries;
242
+ }
243
+ get size() {
244
+ return this.#entries.size;
245
+ }
246
+ get(key) {
247
+ assertKey(key);
248
+ const value = this.#entries.get(key);
249
+ if (value === void 0) return void 0;
250
+ this.#entries.delete(key);
251
+ this.#entries.set(key, value);
252
+ return [...value];
253
+ }
254
+ set(key, vector) {
255
+ assertKey(key);
256
+ assertVector(vector, "Tool embedding cache vector");
257
+ this.#entries.delete(key);
258
+ this.#entries.set(key, [...vector]);
259
+ while (this.#entries.size > this.#maxEntries) {
260
+ const oldest = this.#entries.keys().next().value;
261
+ if (oldest === void 0) break;
262
+ this.#entries.delete(oldest);
263
+ }
264
+ }
265
+ getMany(keys) {
266
+ return keys.map((key) => this.get(key));
267
+ }
268
+ setMany(entries) {
269
+ for (const entry of entries) this.set(entry.key, entry.vector);
270
+ }
271
+ };
272
+ /**
273
+ * Builds or refreshes a semantic index for a tool catalog. The content key is
274
+ * `sha256(embeddingModel.id + text)`, so changing the model or the tool text
275
+ * invalidates the cached vector.
276
+ */
277
+ async function buildToolEmbeddingIndex(options) {
278
+ assertEmbeddingModel(options.embeddings);
279
+ const batchSize = options.batchSize ?? 64;
280
+ if (!Number.isSafeInteger(batchSize) || batchSize < 1) throw new TypeError("Tool embedding batchSize must be a positive safe integer");
281
+ const tools = options.tools;
282
+ const texts = tools.map(toolEmbeddingText);
283
+ const keys = await Promise.all(texts.map((text) => toolEmbeddingKey(options.embeddings.id, text)));
284
+ const vectors = /* @__PURE__ */ new Map();
285
+ const missing = /* @__PURE__ */ new Map();
286
+ const batchCached = await readCacheMany(options.cache, keys, options.embeddings.dimensions);
287
+ for (let index = 0; index < tools.length; index += 1) {
288
+ const key = keys[index];
289
+ const cached = batchCached === void 0 ? await readCache(options.cache, key, options.embeddings.dimensions) : batchCached[index];
290
+ if (cached !== void 0) {
291
+ vectors.set(key, cached);
292
+ continue;
293
+ }
294
+ if (!missing.has(key)) missing.set(key, texts[index]);
295
+ }
296
+ const pending = [...missing.entries()];
297
+ for (let offset = 0; offset < pending.length; offset += batchSize) {
298
+ options.signal?.throwIfAborted();
299
+ const batch = pending.slice(offset, offset + batchSize);
300
+ const embedded = await options.embeddings.embed({
301
+ texts: batch.map(([, text]) => text),
302
+ ...options.signal === void 0 ? {} : { signal: options.signal }
303
+ });
304
+ if (!Array.isArray(embedded) || embedded.length !== batch.length) throw new Error(`Embedding model "${options.embeddings.id}" returned ${embedded.length} vectors for ${batch.length} texts`);
305
+ const writes = [];
306
+ for (let index = 0; index < batch.length; index += 1) {
307
+ const vector = embedded[index];
308
+ assertVector(vector, `Embedding for "${batch[index][1]}"`);
309
+ vectors.set(batch[index][0], vector);
310
+ writes.push({
311
+ key: batch[index][0],
312
+ vector
313
+ });
314
+ }
315
+ if (options.cache?.setMany !== void 0) try {
316
+ await options.cache.setMany(writes);
317
+ } catch {}
318
+ else for (const write of writes) await writeCache(options.cache, write.key, write.vector);
319
+ }
320
+ const dimensions = options.embeddings.dimensions ?? vectors.values().next().value?.length ?? 0;
321
+ for (const vector of vectors.values()) if (vector.length !== dimensions) throw new Error(`Embedding model "${options.embeddings.id}" returned mixed dimensions: ${dimensions} and ${vector.length}`);
322
+ return {
323
+ modelId: options.embeddings.id,
324
+ dimensions,
325
+ entries: tools.map((tool, index) => ({
326
+ tool,
327
+ vector: [...vectors.get(keys[index])]
328
+ }))
329
+ };
330
+ }
331
+ /** Returns cosine matches above `minScore`, ordered by score. */
332
+ function searchToolEmbeddingIndex(index, query, limit, minScore = 0) {
333
+ if (!Number.isSafeInteger(limit) || limit < 1) throw new TypeError("Tool embedding search limit must be a positive safe integer");
334
+ if (query.length !== index.dimensions) throw new TypeError(`Query embedding has ${query.length} dimensions; index expects ${index.dimensions}`);
335
+ assertVector([...query], "Query embedding");
336
+ if (typeof minScore !== "number" || !Number.isFinite(minScore)) throw new TypeError("Tool embedding minScore must be a finite number");
337
+ return index.entries.map((entry) => ({
338
+ tool: entry.tool,
339
+ score: cosineSimilarity(query, entry.vector)
340
+ })).filter(({ score }) => score >= minScore).sort((left, right) => right.score - left.score || left.tool.name.localeCompare(right.tool.name)).slice(0, limit);
341
+ }
342
+ /** Canonical text indexed for one tool: name, description and schema keywords. */
343
+ function toolEmbeddingText(tool) {
344
+ return [
345
+ tool.name,
346
+ tool.description ?? "",
347
+ schemaKeywords(tool.inputSchema)
348
+ ].filter(Boolean).join("\n");
349
+ }
350
+ /** Extracts property names, descriptions, titles, required fields and enum values. */
351
+ function schemaKeywords(schema) {
352
+ if (schema === void 0) return "";
353
+ const terms = /* @__PURE__ */ new Set();
354
+ const visit = (value, key) => {
355
+ if (typeof value === "string") {
356
+ if (key === "description" || key === "title" || key === "const") terms.add(value);
357
+ return;
358
+ }
359
+ if (Array.isArray(value)) {
360
+ for (const item of value) visit(item, key);
361
+ return;
362
+ }
363
+ if (value === null || typeof value !== "object") return;
364
+ for (const [childKey, child] of Object.entries(value)) {
365
+ if (childKey === "properties" && child !== null && typeof child === "object" && !Array.isArray(child)) {
366
+ for (const property of Object.keys(child)) terms.add(property);
367
+ visit(child, childKey);
368
+ continue;
369
+ }
370
+ if (childKey === "required" && Array.isArray(child)) {
371
+ for (const item of child) if (typeof item === "string") terms.add(item);
372
+ continue;
373
+ }
374
+ if (childKey === "enum" && Array.isArray(child)) {
375
+ for (const item of child) terms.add(String(item));
376
+ continue;
377
+ }
378
+ visit(child, childKey);
379
+ }
380
+ };
381
+ visit(schema);
382
+ return [...terms].join(" ");
383
+ }
384
+ /** Stable content key for one embedding model and tool text. */
385
+ async function toolEmbeddingKey(modelId, text) {
386
+ if (!modelId.trim()) throw new TypeError("Embedding model id cannot be empty");
387
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(`${modelId}\n${text}`));
388
+ return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
389
+ }
390
+ function cosineSimilarity(left, right) {
391
+ assertVector(left, "Left cosine vector");
392
+ assertVector(right, "Right cosine vector");
393
+ if (left.length !== right.length) throw new TypeError(`Cosine vectors must have the same dimensions: ${left.length} and ${right.length}`);
394
+ let dot = 0;
395
+ let leftNorm = 0;
396
+ let rightNorm = 0;
397
+ for (let index = 0; index < left.length; index += 1) {
398
+ const a = left[index];
399
+ const b = right[index];
400
+ dot += a * b;
401
+ leftNorm += a * a;
402
+ rightNorm += b * b;
403
+ }
404
+ if (leftNorm === 0 || rightNorm === 0) return 0;
405
+ return dot / Math.sqrt(leftNorm * rightNorm);
406
+ }
407
+ function assertEmbeddingModel(model) {
408
+ if (typeof model.id !== "string" || !model.id.trim()) throw new TypeError("Embedding model id must be a non-empty string");
409
+ if (typeof model.embed !== "function") throw new TypeError("Embedding model must implement embed");
410
+ if (model.dimensions !== void 0 && (!Number.isSafeInteger(model.dimensions) || model.dimensions < 1)) throw new TypeError("Embedding model dimensions must be a positive safe integer");
411
+ }
412
+ function assertKey(key) {
413
+ if (typeof key !== "string" || !key.trim()) throw new TypeError("Tool embedding cache key must be a non-empty string");
414
+ }
415
+ function assertVector(vector, label) {
416
+ if (!Array.isArray(vector) || vector.length === 0 || vector.some((value) => typeof value !== "number" || !Number.isFinite(value))) throw new TypeError(`${label} must be a non-empty array of finite numbers`);
417
+ }
418
+ async function readCache(cache, key, dimensions) {
419
+ if (cache === void 0) return void 0;
420
+ try {
421
+ return normalizeCached(await cache.get(key), dimensions);
422
+ } catch {
423
+ return;
424
+ }
425
+ }
426
+ async function readCacheMany(cache, keys, dimensions) {
427
+ if (cache?.getMany === void 0) return void 0;
428
+ try {
429
+ const values = await cache.getMany(keys);
430
+ if (!Array.isArray(values) || values.length !== keys.length) return void 0;
431
+ return values.map((value) => normalizeCached(value, dimensions));
432
+ } catch {
433
+ return;
434
+ }
435
+ }
436
+ function normalizeCached(value, dimensions) {
437
+ if (value === void 0) return void 0;
438
+ try {
439
+ assertVector(value, "Cached tool embedding");
440
+ if (dimensions !== void 0 && value.length !== dimensions) return void 0;
441
+ return [...value];
442
+ } catch {
443
+ return;
444
+ }
445
+ }
446
+ async function writeCache(cache, key, vector) {
447
+ if (cache === void 0) return;
448
+ try {
449
+ await cache.set(key, [...vector]);
450
+ } catch {}
451
+ }
452
+ //#endregion
453
+ export { FEVEX_JSON_SCHEMA_PROFILE_VERSION, InMemoryToolEmbeddingCache, IntegrationError, buildToolEmbeddingIndex, compileFevexJsonSchema, cosineSimilarity, defineConnection, defineTool, schemaKeywords, searchToolEmbeddingIndex, toToolSpec, toolEmbeddingKey, toolEmbeddingText, validateFevexJsonSchemaProfile };