n2-qln 3.4.2 → 4.1.1

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 (57) hide show
  1. package/README.ko.md +459 -470
  2. package/README.md +459 -490
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.js +87 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/lib/config.d.ts +9 -0
  7. package/{lib → dist/lib}/config.js +23 -27
  8. package/dist/lib/config.js.map +1 -0
  9. package/dist/lib/embedding.d.ts +28 -0
  10. package/{lib → dist/lib}/embedding.js +45 -47
  11. package/dist/lib/embedding.js.map +1 -0
  12. package/dist/lib/executor.d.ts +57 -0
  13. package/dist/lib/executor.js +175 -0
  14. package/dist/lib/executor.js.map +1 -0
  15. package/dist/lib/mcp-discovery.d.ts +83 -0
  16. package/dist/lib/mcp-discovery.js +206 -0
  17. package/dist/lib/mcp-discovery.js.map +1 -0
  18. package/dist/lib/provider-loader.d.ts +13 -0
  19. package/dist/lib/provider-loader.js +144 -0
  20. package/dist/lib/provider-loader.js.map +1 -0
  21. package/dist/lib/registry.d.ts +38 -0
  22. package/{lib → dist/lib}/registry.js +103 -101
  23. package/dist/lib/registry.js.map +1 -0
  24. package/dist/lib/router.d.ts +63 -0
  25. package/{lib → dist/lib}/router.js +75 -117
  26. package/dist/lib/router.js.map +1 -0
  27. package/dist/lib/schema.d.ts +20 -0
  28. package/{lib → dist/lib}/schema.js +38 -30
  29. package/dist/lib/schema.js.map +1 -0
  30. package/dist/lib/store.d.ts +48 -0
  31. package/dist/lib/store.js +234 -0
  32. package/dist/lib/store.js.map +1 -0
  33. package/dist/lib/validator.d.ts +37 -0
  34. package/dist/lib/validator.js +114 -0
  35. package/dist/lib/validator.js.map +1 -0
  36. package/dist/lib/vector-index.d.ts +37 -0
  37. package/{lib → dist/lib}/vector-index.js +19 -36
  38. package/dist/lib/vector-index.js.map +1 -0
  39. package/dist/tools/qln-call.d.ts +41 -0
  40. package/dist/tools/qln-call.js +353 -0
  41. package/dist/tools/qln-call.js.map +1 -0
  42. package/dist/tools/qln-helpers.d.ts +55 -0
  43. package/dist/tools/qln-helpers.js +88 -0
  44. package/dist/tools/qln-helpers.js.map +1 -0
  45. package/dist/types.d.ts +243 -0
  46. package/dist/types.js +4 -0
  47. package/dist/types.js.map +1 -0
  48. package/package.json +11 -4
  49. package/.github/FUNDING.yml +0 -3
  50. package/docs/README.md +0 -2
  51. package/docs/architecture.png +0 -0
  52. package/index.js +0 -80
  53. package/lib/executor.js +0 -104
  54. package/lib/provider-loader.js +0 -126
  55. package/lib/store.js +0 -217
  56. package/lib/validator.js +0 -171
  57. package/tools/qln-call.js +0 -257
@@ -0,0 +1,234 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Store = void 0;
7
+ exports.initSqlJs = initSqlJs;
8
+ // QLN — SQLite storage engine (pure JS via sql.js WASM). No native dependencies.
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const path_1 = __importDefault(require("path"));
11
+ /** sql.js module singleton */
12
+ let _SQL = null;
13
+ /** sql.js init promise */
14
+ let _initPromise = null;
15
+ /**
16
+ * Initialize sql.js WASM module (once per process).
17
+ */
18
+ async function initSqlJs() {
19
+ if (_SQL)
20
+ return _SQL;
21
+ if (_initPromise)
22
+ return _initPromise;
23
+ _initPromise = (async () => {
24
+ // sql.js uses CJS export — require is needed here
25
+ const initFn = require('sql.js');
26
+ _SQL = await initFn();
27
+ return _SQL;
28
+ })();
29
+ return _initPromise;
30
+ }
31
+ /**
32
+ * QLN SQLite store.
33
+ * Dedicated tool index DB — separated from Soul KV-Cache.
34
+ *
35
+ * File: {dataDir}/qln-tools.sqlite
36
+ */
37
+ class Store {
38
+ _dataDir;
39
+ _db;
40
+ _dbPath;
41
+ _batchMode;
42
+ _batchDirty;
43
+ constructor(dataDir) {
44
+ this._dataDir = dataDir;
45
+ this._db = null;
46
+ this._dbPath = path_1.default.join(dataDir, 'qln-tools.sqlite');
47
+ this._batchMode = false;
48
+ this._batchDirty = false;
49
+ }
50
+ /** Async init — load sql.js + open DB + create schema */
51
+ async init() {
52
+ const SQL = await initSqlJs();
53
+ if (!fs_1.default.existsSync(this._dataDir)) {
54
+ fs_1.default.mkdirSync(this._dataDir, { recursive: true });
55
+ }
56
+ if (fs_1.default.existsSync(this._dbPath)) {
57
+ const buffer = fs_1.default.readFileSync(this._dbPath);
58
+ this._db = new SQL.Database(buffer);
59
+ }
60
+ else {
61
+ this._db = new SQL.Database();
62
+ }
63
+ this._createSchema();
64
+ }
65
+ /** Create tools + providers table schema */
66
+ _createSchema() {
67
+ this._db.run(`
68
+ CREATE TABLE IF NOT EXISTS tools (
69
+ name TEXT PRIMARY KEY,
70
+ description TEXT DEFAULT '',
71
+ source TEXT DEFAULT 'unknown',
72
+ category TEXT DEFAULT 'misc',
73
+ provider TEXT DEFAULT '',
74
+ input_schema TEXT DEFAULT '{}',
75
+ triggers TEXT DEFAULT '[]',
76
+ tags TEXT DEFAULT '[]',
77
+ examples TEXT DEFAULT '[]',
78
+ endpoint TEXT DEFAULT '',
79
+ search_text TEXT DEFAULT '',
80
+ embedding TEXT DEFAULT '',
81
+ usage_count INTEGER DEFAULT 0,
82
+ success_rate REAL DEFAULT 1.0,
83
+ registered_at TEXT DEFAULT (datetime('now')),
84
+ updated_at TEXT DEFAULT (datetime('now'))
85
+ )
86
+ `);
87
+ this._db.run(`CREATE INDEX IF NOT EXISTS idx_tools_source ON tools(source)`);
88
+ this._db.run(`CREATE INDEX IF NOT EXISTS idx_tools_category ON tools(category)`);
89
+ this._db.run(`
90
+ CREATE TABLE IF NOT EXISTS providers (
91
+ name TEXT PRIMARY KEY,
92
+ version TEXT DEFAULT '1.0.0',
93
+ description TEXT DEFAULT '',
94
+ endpoint TEXT DEFAULT '',
95
+ tool_count INTEGER DEFAULT 0,
96
+ registered_at TEXT DEFAULT (datetime('now')),
97
+ updated_at TEXT DEFAULT (datetime('now'))
98
+ )
99
+ `);
100
+ this._migrateSchema();
101
+ }
102
+ /** Schema migration — safe ADD COLUMN (ignores if already exists) */
103
+ _migrateSchema() {
104
+ const addCol = (table, col, type, dflt) => {
105
+ try {
106
+ this._db.run(`ALTER TABLE ${table} ADD COLUMN ${col} ${type} DEFAULT ${dflt}`);
107
+ }
108
+ catch { /* column already exists */ }
109
+ };
110
+ addCol('tools', 'provider', 'TEXT', "''");
111
+ addCol('tools', 'examples', 'TEXT', "'[]'");
112
+ addCol('tools', 'endpoint', 'TEXT', "''");
113
+ addCol('tools', 'last_used_at', 'TEXT', 'NULL');
114
+ // v4.1.0: boostKeywords + Circuit Breaker
115
+ addCol('tools', 'boost_keywords', 'TEXT', "''");
116
+ addCol('tools', 'consecutive_failures', 'INTEGER', '0');
117
+ // Copy plugin_name → provider (if old schema has plugin_name)
118
+ try {
119
+ const cols = this._db.exec("PRAGMA table_info(tools)");
120
+ if (cols.length > 0) {
121
+ const colNames = cols[0].values.map(r => r[1]);
122
+ if (colNames.includes('plugin_name') && colNames.includes('provider')) {
123
+ this._db.run("UPDATE tools SET provider = plugin_name WHERE provider = '' AND plugin_name != ''");
124
+ }
125
+ }
126
+ }
127
+ catch { /* table doesn't exist yet */ }
128
+ try {
129
+ this._db.run(`CREATE INDEX IF NOT EXISTS idx_tools_provider ON tools(provider)`);
130
+ }
131
+ catch { /* already exists */ }
132
+ }
133
+ /**
134
+ * Enter batch mode — suppresses per-upsert disk writes.
135
+ * Call endBatch() when done to flush once.
136
+ */
137
+ beginBatch() {
138
+ this._batchMode = true;
139
+ this._batchDirty = false;
140
+ }
141
+ /**
142
+ * Exit batch mode — flush to disk if any writes occurred.
143
+ */
144
+ endBatch() {
145
+ this._batchMode = false;
146
+ if (this._batchDirty) {
147
+ this._persist();
148
+ this._batchDirty = false;
149
+ }
150
+ }
151
+ /** Upsert a tool entry. */
152
+ upsert(entry) {
153
+ this._db.run(`
154
+ INSERT INTO tools (name, description, source, category, provider,
155
+ input_schema, triggers, tags, examples, endpoint, search_text, boost_keywords,
156
+ embedding, usage_count, success_rate, consecutive_failures, last_used_at, updated_at)
157
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
158
+ ?, ?, COALESCE(?, (SELECT embedding FROM tools WHERE name = ?)),
159
+ ?, ?, ?, ?, datetime('now'))
160
+ ON CONFLICT(name) DO UPDATE SET
161
+ description = excluded.description,
162
+ source = excluded.source,
163
+ category = excluded.category,
164
+ provider = excluded.provider,
165
+ input_schema = excluded.input_schema,
166
+ triggers = excluded.triggers,
167
+ tags = excluded.tags,
168
+ examples = excluded.examples,
169
+ endpoint = excluded.endpoint,
170
+ search_text = excluded.search_text,
171
+ boost_keywords = excluded.boost_keywords,
172
+ embedding = COALESCE(excluded.embedding, tools.embedding),
173
+ usage_count = excluded.usage_count,
174
+ success_rate = excluded.success_rate,
175
+ consecutive_failures = excluded.consecutive_failures,
176
+ last_used_at = excluded.last_used_at,
177
+ updated_at = excluded.updated_at
178
+ `, [
179
+ entry.name, entry.description, entry.source, entry.category, entry.provider,
180
+ JSON.stringify(entry.inputSchema), JSON.stringify(entry.triggers),
181
+ JSON.stringify(entry.tags), JSON.stringify(entry.examples), entry.endpoint || '',
182
+ entry.searchText, entry.boostKeywords || '',
183
+ entry.embedding ? JSON.stringify(entry.embedding) : null, entry.name,
184
+ entry.usageCount, entry.successRate, entry.consecutiveFailures || 0,
185
+ entry.lastUsedAt || null,
186
+ ]);
187
+ if (this._batchMode) {
188
+ this._batchDirty = true;
189
+ }
190
+ else {
191
+ this._persist();
192
+ }
193
+ }
194
+ /** Remove a tool by name. */
195
+ remove(name) {
196
+ this._db.run('DELETE FROM tools WHERE name = ?', [name]);
197
+ this._persist();
198
+ return true;
199
+ }
200
+ /** Purge all tools by source (for re-sync). */
201
+ purgeBySource(source) {
202
+ this._db.run('DELETE FROM tools WHERE source = ?', [source]);
203
+ this._persist();
204
+ }
205
+ /** Load all tools from DB. */
206
+ loadAll() {
207
+ const results = this._db.exec('SELECT * FROM tools ORDER BY name');
208
+ if (results.length === 0)
209
+ return [];
210
+ const cols = results[0].columns;
211
+ return results[0].values.map(row => {
212
+ const obj = {};
213
+ cols.forEach((c, i) => { obj[c] = row[i]; });
214
+ return obj;
215
+ });
216
+ }
217
+ /** Persist DB to disk */
218
+ _persist() {
219
+ if (!this._db)
220
+ return;
221
+ const data = this._db.export();
222
+ fs_1.default.writeFileSync(this._dbPath, Buffer.from(data));
223
+ }
224
+ /** Close connection */
225
+ dispose() {
226
+ if (this._db) {
227
+ this._persist();
228
+ this._db.close();
229
+ this._db = null;
230
+ }
231
+ }
232
+ }
233
+ exports.Store = Store;
234
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/lib/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { ValidationError } from '../types';
2
+ /** Valid tool categories */
3
+ export declare const VALID_CATEGORIES: readonly ["web", "data", "file", "dev", "ai", "capture", "misc"];
4
+ /** Tool name pattern: verb_target (e.g. read_pdf, take_screenshot) */
5
+ export declare const NAME_PATTERN: RegExp;
6
+ /** Minimum description length */
7
+ export declare const MIN_DESCRIPTION_LENGTH = 10;
8
+ export interface ValidatableParams {
9
+ name?: string;
10
+ description?: string;
11
+ category?: string;
12
+ tags?: string[];
13
+ [key: string]: unknown;
14
+ }
15
+ interface RegistryLike {
16
+ get(name: string): unknown | null;
17
+ }
18
+ interface ValidationResult {
19
+ valid: boolean;
20
+ errors: ValidationError[];
21
+ }
22
+ /**
23
+ * Validate tool entry for registration.
24
+ * Pattern: accumulate errors → reject if any error exists.
25
+ */
26
+ export declare function validateToolEntry(params: ValidatableParams, registry: RegistryLike): ValidationResult;
27
+ /**
28
+ * Validate tool update params.
29
+ * Same rules as create, but no duplicate check (updating existing tool).
30
+ */
31
+ export declare function validateUpdateEntry(params: ValidatableParams, existing: ValidatableParams): ValidationResult;
32
+ /**
33
+ * Format validation errors as user-readable string.
34
+ */
35
+ export declare function formatValidationErrors(errors: ValidationError[]): string;
36
+ export {};
37
+ //# sourceMappingURL=validator.d.ts.map
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MIN_DESCRIPTION_LENGTH = exports.NAME_PATTERN = exports.VALID_CATEGORIES = void 0;
4
+ exports.validateToolEntry = validateToolEntry;
5
+ exports.validateUpdateEntry = validateUpdateEntry;
6
+ exports.formatValidationErrors = formatValidationErrors;
7
+ /** Valid tool categories */
8
+ exports.VALID_CATEGORIES = ['web', 'data', 'file', 'dev', 'ai', 'capture', 'misc'];
9
+ /** Tool name pattern: verb_target (e.g. read_pdf, take_screenshot) */
10
+ exports.NAME_PATTERN = /^[a-z]+_[a-z][a-z0-9_]*$/;
11
+ /** Minimum description length */
12
+ exports.MIN_DESCRIPTION_LENGTH = 10;
13
+ /** Validate name: required + verb_target format */
14
+ function _validateName(name, errors) {
15
+ if (!name || name.trim() === '') {
16
+ errors.push({ field: 'name', message: 'name is required', severity: 'error' });
17
+ }
18
+ else if (!exports.NAME_PATTERN.test(name)) {
19
+ errors.push({ field: 'name', message: `'${name}' must follow verb_target format (e.g. read_pdf, take_screenshot)`, severity: 'error' });
20
+ }
21
+ }
22
+ /** Validate description: required + min length */
23
+ function _validateDescription(desc, errors) {
24
+ if (!desc || desc.trim() === '') {
25
+ errors.push({ field: 'description', message: 'description is required (explain what the tool does)', severity: 'error' });
26
+ }
27
+ else if (desc.trim().length < exports.MIN_DESCRIPTION_LENGTH) {
28
+ errors.push({ field: 'description', message: `minimum ${exports.MIN_DESCRIPTION_LENGTH} characters required (current: ${desc.trim().length})`, severity: 'error' });
29
+ }
30
+ }
31
+ /** Validate category: must be in enum */
32
+ function _validateCategory(category, errors) {
33
+ if (category && !exports.VALID_CATEGORIES.includes(category)) {
34
+ errors.push({ field: 'category', message: `'${category}' is not valid — use one of: ${exports.VALID_CATEGORIES.join(' | ')}`, severity: 'error' });
35
+ }
36
+ }
37
+ /**
38
+ * Validate tool entry for registration.
39
+ * Pattern: accumulate errors → reject if any error exists.
40
+ */
41
+ function validateToolEntry(params, registry) {
42
+ const errors = [];
43
+ _validateName(params.name, errors);
44
+ _validateDescription(params.description, errors);
45
+ _validateCategory(params.category, errors);
46
+ // Rule 4: duplicate name check
47
+ if (params.name && registry && registry.get(params.name)) {
48
+ errors.push({ field: 'name', message: `'${params.name}' already exists. Use action: "update" instead`, severity: 'error' });
49
+ }
50
+ // Warning: no tags (search accuracy may be lower)
51
+ if (!params.tags || params.tags.length === 0) {
52
+ errors.push({ field: 'tags', message: 'no tags specified — search accuracy may be reduced', severity: 'warning' });
53
+ }
54
+ const errorCount = errors.filter(e => e.severity === 'error').length;
55
+ return { valid: errorCount === 0, errors };
56
+ }
57
+ /**
58
+ * Validate tool update params.
59
+ * Same rules as create, but no duplicate check (updating existing tool).
60
+ */
61
+ function validateUpdateEntry(params, existing) {
62
+ const errors = [];
63
+ // Rule 1: name format (if changed)
64
+ if (params.name && !exports.NAME_PATTERN.test(params.name)) {
65
+ errors.push({
66
+ field: 'name',
67
+ message: `'${params.name}' must follow verb_target format (e.g. read_pdf, take_screenshot)`,
68
+ severity: 'error',
69
+ });
70
+ }
71
+ // Rule 2: description min length (if changed)
72
+ if (params.description && params.description.trim().length < exports.MIN_DESCRIPTION_LENGTH) {
73
+ errors.push({
74
+ field: 'description',
75
+ message: `minimum ${exports.MIN_DESCRIPTION_LENGTH} characters required (current: ${params.description.trim().length})`,
76
+ severity: 'error',
77
+ });
78
+ }
79
+ // Rule 2b: warn if description is shorter than existing
80
+ if (params.description && existing.description
81
+ && params.description.trim().length < existing.description.trim().length * 0.5) {
82
+ errors.push({
83
+ field: 'description',
84
+ message: `description is >50% shorter than existing (${existing.description.trim().length} → ${params.description.trim().length} chars)`,
85
+ severity: 'warning',
86
+ });
87
+ }
88
+ // Rule 3: category enum (if changed)
89
+ if (params.category && !exports.VALID_CATEGORIES.includes(params.category)) {
90
+ errors.push({
91
+ field: 'category',
92
+ message: `'${params.category}' is not valid — use one of: ${exports.VALID_CATEGORIES.join(' | ')}`,
93
+ severity: 'error',
94
+ });
95
+ }
96
+ const errorCount = errors.filter(e => e.severity === 'error').length;
97
+ return { valid: errorCount === 0, errors };
98
+ }
99
+ /**
100
+ * Format validation errors as user-readable string.
101
+ */
102
+ function formatValidationErrors(errors) {
103
+ const errorCount = errors.filter(e => e.severity === 'error').length;
104
+ const warnCount = errors.filter(e => e.severity === 'warning').length;
105
+ const lines = errors.map(e => {
106
+ const icon = e.severity === 'error' ? '❌' : '⚠️';
107
+ return ` ${icon} [${e.field}] ${e.message}`;
108
+ });
109
+ const header = errorCount > 0
110
+ ? `Registration rejected (${errorCount} error${errorCount > 1 ? 's' : ''}${warnCount > 0 ? `, ${warnCount} warning` : ''}):`
111
+ : `Registration complete (${warnCount} warning${warnCount > 1 ? 's' : ''}):`;
112
+ return `${header}\n${lines.join('\n')}`;
113
+ }
114
+ //# sourceMappingURL=validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/lib/validator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { ToolEntry, VectorBuildResult, VectorStats } from '../types';
2
+ /**
3
+ * Vector index — Float32Array matrix + category centroid partitioned search.
4
+ *
5
+ * Scaling:
6
+ * 100 tools → ~1ms
7
+ * 1,000 tools → ~3ms
8
+ * 10,000 tools → ~5ms (centroid hierarchy)
9
+ */
10
+ export declare class VectorIndex {
11
+ private _matrix;
12
+ private _names;
13
+ private _dim;
14
+ private _count;
15
+ private _centroids;
16
+ private _partitions;
17
+ private _built;
18
+ constructor();
19
+ /**
20
+ * Build vector index from tool entries.
21
+ * Only indexes tools with embeddings, computes per-category centroids.
22
+ */
23
+ build(tools: ToolEntry[]): VectorBuildResult;
24
+ /**
25
+ * Centroid hierarchy search — top-K categories → scan within partition.
26
+ */
27
+ search(queryVec: number[], topK?: number, topCategories?: number): Array<{
28
+ name: string;
29
+ score: number;
30
+ }>;
31
+ stats(): VectorStats;
32
+ /** Reset index */
33
+ reset(): void;
34
+ /** Cosine similarity */
35
+ private _cosineSim;
36
+ }
37
+ //# sourceMappingURL=vector-index.d.ts.map
@@ -1,6 +1,6 @@
1
- // QLN — Float32Array vector index (centroid hierarchy)
2
- // Stage 3 semantic search only. ~3ms search at 1000 tools.
3
-
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VectorIndex = void 0;
4
4
  /**
5
5
  * Vector index — Float32Array matrix + category centroid partitioned search.
6
6
  *
@@ -10,27 +10,25 @@
10
10
  * 10,000 tools → ~5ms (centroid hierarchy)
11
11
  */
12
12
  class VectorIndex {
13
+ _matrix;
14
+ _names;
15
+ _dim;
16
+ _count;
17
+ _centroids;
18
+ _partitions;
19
+ _built;
13
20
  constructor() {
14
- /** @type {Float32Array|null} N tools × D dimensions */
15
21
  this._matrix = null;
16
- /** @type {string[]} Tool names (matrix row order) */
17
22
  this._names = [];
18
- /** @type {number} Embedding dimension */
19
23
  this._dim = 0;
20
- /** @type {number} Number of indexed tools */
21
24
  this._count = 0;
22
- /** @type {Map<string, Float32Array>} Category → centroid vector */
23
25
  this._centroids = new Map();
24
- /** @type {Map<string, number[]>} Category → matrix row indices */
25
26
  this._partitions = new Map();
26
27
  this._built = false;
27
28
  }
28
-
29
29
  /**
30
30
  * Build vector index from tool entries.
31
31
  * Only indexes tools with embeddings, computes per-category centroids.
32
- * @param {object[]} tools
33
- * @returns {{indexed: number, categories: number, dimension: number}}
34
32
  */
35
33
  build(tools) {
36
34
  const valid = tools.filter(t => t.embedding && Array.isArray(t.embedding) && t.embedding.length > 0);
@@ -38,11 +36,9 @@ class VectorIndex {
38
36
  this._built = false;
39
37
  return { indexed: 0, categories: 0, dimension: 0 };
40
38
  }
41
-
42
39
  this._dim = valid[0].embedding.length;
43
40
  this._count = valid.length;
44
41
  this._names = valid.map(t => t.name);
45
-
46
42
  // Pack into Float32Array matrix
47
43
  this._matrix = new Float32Array(this._count * this._dim);
48
44
  for (let i = 0; i < this._count; i++) {
@@ -51,16 +47,15 @@ class VectorIndex {
51
47
  this._matrix[i * this._dim + j] = vec[j] || 0;
52
48
  }
53
49
  }
54
-
55
50
  // Build category partitions
56
51
  this._partitions.clear();
57
52
  this._centroids.clear();
58
53
  for (let i = 0; i < valid.length; i++) {
59
54
  const cat = valid[i].category || 'misc';
60
- if (!this._partitions.has(cat)) this._partitions.set(cat, []);
55
+ if (!this._partitions.has(cat))
56
+ this._partitions.set(cat, []);
61
57
  this._partitions.get(cat).push(i);
62
58
  }
63
-
64
59
  // Compute centroids (category average vector)
65
60
  for (const [cat, indices] of this._partitions) {
66
61
  const centroid = new Float32Array(this._dim);
@@ -71,26 +66,20 @@ class VectorIndex {
71
66
  }
72
67
  }
73
68
  const n = indices.length;
74
- for (let j = 0; j < this._dim; j++) centroid[j] /= n;
69
+ for (let j = 0; j < this._dim; j++)
70
+ centroid[j] /= n;
75
71
  this._centroids.set(cat, centroid);
76
72
  }
77
-
78
73
  this._built = true;
79
74
  return { indexed: this._count, categories: this._partitions.size, dimension: this._dim };
80
75
  }
81
-
82
76
  /**
83
77
  * Centroid hierarchy search — top-K categories → scan within partition.
84
- * @param {number[]} queryVec
85
- * @param {number} topK
86
- * @param {number} topCategories
87
- * @returns {{name: string, score: number}[]}
88
78
  */
89
79
  search(queryVec, topK = 10, topCategories = 4) {
90
- if (!this._built || !this._matrix || !queryVec || queryVec.length !== this._dim) return [];
91
-
80
+ if (!this._built || !this._matrix || !queryVec || queryVec.length !== this._dim)
81
+ return [];
92
82
  const qVec = new Float32Array(queryVec);
93
-
94
83
  // Step 1: Rank categories by centroid similarity
95
84
  const catScores = [];
96
85
  for (const [cat, centroid] of this._centroids) {
@@ -98,7 +87,6 @@ class VectorIndex {
98
87
  }
99
88
  catScores.sort((a, b) => b.score - a.score);
100
89
  const selectedCats = catScores.slice(0, topCategories).map(c => c.cat);
101
-
102
90
  // Step 2: Search individual tools within selected partitions
103
91
  const candidates = [];
104
92
  for (const cat of selectedCats) {
@@ -107,12 +95,9 @@ class VectorIndex {
107
95
  candidates.push({ name: this._names[idx], score: this._cosineSim(qVec, toolVec) });
108
96
  }
109
97
  }
110
-
111
98
  candidates.sort((a, b) => b.score - a.score);
112
99
  return candidates.slice(0, topK);
113
100
  }
114
-
115
- /** @returns {object} */
116
101
  stats() {
117
102
  return {
118
103
  built: this._built,
@@ -123,7 +108,6 @@ class VectorIndex {
123
108
  memoryKB: this._matrix ? Math.round(this._matrix.byteLength / 1024) : 0,
124
109
  };
125
110
  }
126
-
127
111
  /** Reset index */
128
112
  reset() {
129
113
  this._matrix = null;
@@ -134,8 +118,7 @@ class VectorIndex {
134
118
  this._partitions.clear();
135
119
  this._built = false;
136
120
  }
137
-
138
- /** @private Cosine similarity */
121
+ /** Cosine similarity */
139
122
  _cosineSim(a, b) {
140
123
  let dot = 0, normA = 0, normB = 0;
141
124
  for (let i = 0; i < a.length; i++) {
@@ -147,5 +130,5 @@ class VectorIndex {
147
130
  return denom === 0 ? 0 : dot / denom;
148
131
  }
149
132
  }
150
-
151
- module.exports = { VectorIndex };
133
+ exports.VectorIndex = VectorIndex;
134
+ //# sourceMappingURL=vector-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vector-index.js","sourceRoot":"","sources":["../../src/lib/vector-index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import type { Router } from '../lib/router';
2
+ import type { Executor } from '../lib/executor';
3
+ import type { Registry } from '../lib/registry';
4
+ import type { McpDiscovery } from '../lib/mcp-discovery';
5
+ /** Zod-like validator interface (minimal) */
6
+ interface ZodLike {
7
+ enum(values: readonly string[]): {
8
+ describe(d: string): unknown;
9
+ };
10
+ string(): {
11
+ optional(): {
12
+ describe(d: string): unknown;
13
+ };
14
+ };
15
+ number(): {
16
+ optional(): {
17
+ describe(d: string): unknown;
18
+ };
19
+ };
20
+ record(v: unknown): {
21
+ optional(): {
22
+ describe(d: string): unknown;
23
+ };
24
+ };
25
+ array(v: unknown): {
26
+ optional(): {
27
+ describe(d: string): unknown;
28
+ };
29
+ };
30
+ unknown(): unknown;
31
+ }
32
+ /** MCP server interface (minimal — uses any to match SDK's complex overloads) */
33
+ interface McpServerLike {
34
+ tool(...args: unknown[]): unknown;
35
+ }
36
+ /**
37
+ * Register the unified n2_qln_call MCP tool.
38
+ */
39
+ export declare function registerQlnCall(server: McpServerLike, z: ZodLike, router: Router, executor: Executor, registry: Registry, discovery?: McpDiscovery | null): void;
40
+ export {};
41
+ //# sourceMappingURL=qln-call.d.ts.map