@o-lang/semantic-doc-search 1.0.24 → 1.0.26
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/package.json +1 -1
- package/src/adapters/vectorCapabilities.js +16 -5
- package/src/adapters/vectorRouter.js +16 -1
- package/src/index.js +3 -20
- package/src/resolver.js +40 -0
- package/src/utils/extractQuery.js +18 -0
- package/src/utils/formatResults.js +20 -0
package/package.json
CHANGED
|
@@ -1,29 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capability & metadata for vector backends.
|
|
3
|
+
* No hardcoded "default" assumptions.
|
|
4
|
+
* Resolvers and VectorRouter decide which backend to use at runtime.
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
module.exports = {
|
|
2
8
|
pgvector: {
|
|
3
9
|
persistent: true,
|
|
4
10
|
offline: false,
|
|
5
11
|
distance: "cosine",
|
|
6
|
-
maxDimension: 2000
|
|
12
|
+
maxDimension: 2000,
|
|
13
|
+
// capability declaration
|
|
14
|
+
capabilities: ["vector.insert", "vector.search"]
|
|
7
15
|
},
|
|
8
16
|
|
|
9
17
|
pinecone: {
|
|
10
18
|
persistent: true,
|
|
11
19
|
offline: false,
|
|
12
20
|
distance: "cosine",
|
|
13
|
-
maxDimension: 1536
|
|
21
|
+
maxDimension: 1536,
|
|
22
|
+
capabilities: ["vector.insert", "vector.search"]
|
|
14
23
|
},
|
|
15
24
|
|
|
16
25
|
redis: {
|
|
17
26
|
persistent: true,
|
|
18
27
|
offline: false,
|
|
19
28
|
distance: "cosine",
|
|
20
|
-
maxDimension: 2048
|
|
29
|
+
maxDimension: 2048,
|
|
30
|
+
capabilities: ["vector.insert", "vector.search"]
|
|
21
31
|
},
|
|
22
32
|
|
|
23
33
|
memory: {
|
|
24
34
|
persistent: false,
|
|
25
35
|
offline: true,
|
|
26
36
|
distance: "cosine",
|
|
27
|
-
maxDimension: 4096
|
|
37
|
+
maxDimension: 4096,
|
|
38
|
+
capabilities: ["vector.insert", "vector.search"]
|
|
28
39
|
}
|
|
29
|
-
};
|
|
40
|
+
};
|
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
class VectorRouter {
|
|
2
2
|
static create(config = {}) {
|
|
3
|
-
|
|
3
|
+
// 1. Explicit backend override (advanced users only)
|
|
4
|
+
if (config.backend) {
|
|
5
|
+
return VectorRouter._createExplicitBackend(config.backend, config);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// 2. Auto-detect pgvector (DEFAULT)
|
|
9
|
+
if (config.POSTGRES_URL) {
|
|
10
|
+
const PgVectorAdapter = require("./pgvectorAdapter");
|
|
11
|
+
return new PgVectorAdapter(config);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// 3. Fallback to in-memory (safe default)
|
|
15
|
+
const InMemoryAdapter = require("./inMemoryAdapter");
|
|
16
|
+
return new InMemoryAdapter(config);
|
|
17
|
+
}
|
|
4
18
|
|
|
19
|
+
static _createExplicitBackend(backend, config) {
|
|
5
20
|
switch (backend) {
|
|
6
21
|
case "pgvector": {
|
|
7
22
|
const PgVectorAdapter = require("./pgvectorAdapter");
|
package/src/index.js
CHANGED
|
@@ -246,27 +246,10 @@ async function performDocQA(query, context) {
|
|
|
246
246
|
|
|
247
247
|
/* ---------------- O-LANG RESOLVER ---------------- */
|
|
248
248
|
|
|
249
|
-
|
|
250
|
-
if (!action.startsWith("Ask doc-search")) return;
|
|
251
|
-
|
|
252
|
-
// Extract the query string
|
|
253
|
-
const match = action.match(/"(.*)"|'(.*)'/);
|
|
254
|
-
const query = match ? match[1] || match[2] : action.replace("Ask doc-search", "").trim();
|
|
255
|
-
|
|
256
|
-
// Optional: extract topK and minScore if provided in action, e.g. "Ask doc-search 'Vacation policy' topK=3 minScore=0.8"
|
|
257
|
-
let topK = 5;
|
|
258
|
-
let minScore = 0.75;
|
|
259
|
-
|
|
260
|
-
const topKMatch = action.match(/topK\s*=\s*(\d+)/i);
|
|
261
|
-
if (topKMatch) topK = parseInt(topKMatch[1], 10);
|
|
249
|
+
const semanticResolver = require("./resolver"); // ✅ IMPORT NEW FILE
|
|
262
250
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
// Pass these into context for hybrid search
|
|
267
|
-
const searchContext = { ...context, topK, minScore };
|
|
268
|
-
|
|
269
|
-
return performDocQA(query, searchContext);
|
|
251
|
+
async function docSearchResolver(action, context) {
|
|
252
|
+
return semanticResolver(action, context);
|
|
270
253
|
}
|
|
271
254
|
|
|
272
255
|
docSearchResolver.resolverName = "doc-search";
|
package/src/resolver.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const VectorRouter = require("./adapters/vectorRouter");
|
|
2
|
+
const { embed } = require("./embeddings/local");
|
|
3
|
+
const { extractQuery } = require("./utils/extractQuery");
|
|
4
|
+
const { formatResults } = require("./utils/formatResults");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Semantic Doc Search Resolver
|
|
8
|
+
* Invoked by O-Lang runtime when workflow uses:
|
|
9
|
+
* Ask doc-search: "..."
|
|
10
|
+
*/
|
|
11
|
+
async function resolver(action, context = {}) {
|
|
12
|
+
// Only handle doc-search actions
|
|
13
|
+
if (typeof action !== "string") return;
|
|
14
|
+
if (!action.toLowerCase().startsWith("ask doc-search")) return;
|
|
15
|
+
|
|
16
|
+
// 1️⃣ Extract natural language query
|
|
17
|
+
const query = extractQuery(action);
|
|
18
|
+
|
|
19
|
+
// 2️⃣ Select vector backend (pgvector if available, else fallback)
|
|
20
|
+
const vectorStore = VectorRouter.create(context);
|
|
21
|
+
|
|
22
|
+
if (!vectorStore.supports("vector.search")) {
|
|
23
|
+
throw new Error("Vector backend does not support vector.search");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// 3️⃣ Generate embedding
|
|
27
|
+
const vector = await embed(query);
|
|
28
|
+
|
|
29
|
+
// 4️⃣ Execute similarity search
|
|
30
|
+
const results = await vectorStore.query({
|
|
31
|
+
vector,
|
|
32
|
+
topK: context.topK || 5,
|
|
33
|
+
minScore: context.minScore || 0
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// 5️⃣ Normalize output for workflow consumption
|
|
37
|
+
return formatResults(results, query);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = resolver;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts the query from an O-Lang action.
|
|
3
|
+
* Example:
|
|
4
|
+
* "Ask doc-search: vacation policy"
|
|
5
|
+
*/
|
|
6
|
+
function extractQuery(action) {
|
|
7
|
+
const match = action.match(/ask doc-search\s*:?\s*(.+)$/i);
|
|
8
|
+
|
|
9
|
+
if (!match || !match[1]) {
|
|
10
|
+
throw new Error("Invalid doc-search action format");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return match[1].trim();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
module.exports = {
|
|
17
|
+
extractQuery
|
|
18
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes vector search results for O-Lang workflows.
|
|
3
|
+
*/
|
|
4
|
+
function formatResults(results = [], query) {
|
|
5
|
+
return {
|
|
6
|
+
query,
|
|
7
|
+
matches: results.map(r => ({
|
|
8
|
+
id: r.id,
|
|
9
|
+
content: r.content,
|
|
10
|
+
source: r.source,
|
|
11
|
+
score: typeof r.score === "number"
|
|
12
|
+
? Number(r.score.toFixed(4))
|
|
13
|
+
: undefined
|
|
14
|
+
}))
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = {
|
|
19
|
+
formatResults
|
|
20
|
+
};
|