@o-lang/semantic-doc-search 1.1.0 → 1.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.
- package/package.json +1 -1
- package/src/resolver.js +20 -65
package/package.json
CHANGED
package/src/resolver.js
CHANGED
|
@@ -36,125 +36,80 @@ function hashText(str) {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
// ─────────────────────────────────────────────
|
|
39
|
-
// 🔥
|
|
40
|
-
// Format: Action
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
if (!action || typeof action !== "string") return null;
|
|
44
|
-
|
|
45
|
-
// Remove "Action doc-search " prefix if present
|
|
46
|
-
const cleaned = action.replace(/^Action\s+doc-search\s+/, "").trim();
|
|
47
|
-
|
|
48
|
-
// Extract quoted strings: "vector.search" "query" "./docs"
|
|
49
|
-
const matches = [...cleaned.matchAll(/"([^"]*)"/g)].map(m => m[1]);
|
|
50
|
-
|
|
51
|
-
if (matches.length < 1) return null;
|
|
52
|
-
|
|
53
|
-
return {
|
|
54
|
-
actionType: matches[0], // "vector.search" or "vector.insert"
|
|
55
|
-
args: matches.slice(1), // remaining args
|
|
56
|
-
raw: action
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// ─────────────────────────────────────────────
|
|
61
|
-
// 🔥 MAIN RESOLVER
|
|
39
|
+
// 🔥 MAIN RESOLVER - Simplified: action type = resolver name
|
|
40
|
+
// Format: Action vector.search "arg1" "arg2" ...
|
|
41
|
+
// - 1 arg = ingest: "{doc_root}"
|
|
42
|
+
// - 2+ args = search: "{query}" "{doc_root}"
|
|
62
43
|
// ─────────────────────────────────────────────
|
|
63
44
|
async function resolver(action, context = {}) {
|
|
64
45
|
if (typeof action !== "string") return;
|
|
65
46
|
|
|
66
|
-
//
|
|
67
|
-
const
|
|
68
|
-
if (!parsed) {
|
|
69
|
-
console.error("❌ Invalid doc-search action format:", action);
|
|
70
|
-
throw new Error("Invalid doc-search action format");
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const { actionType, args } = parsed;
|
|
47
|
+
// Extract ALL quoted args from action string
|
|
48
|
+
const args = [...action.matchAll(/"([^"]*)"/g)].map(m => m[1]);
|
|
74
49
|
|
|
75
50
|
const vectorStore = VectorRouter.create(context);
|
|
76
51
|
const getEmbedFn = await embedder({ dimension: 384 });
|
|
77
|
-
|
|
78
|
-
const doc_root = context.doc_root || args[1] || "./docs";
|
|
79
52
|
const useCache = !!context.POSTGRES_URL || !!context.REDIS_URL;
|
|
80
53
|
const cache = useCache ? loadCache() : {};
|
|
81
54
|
|
|
82
55
|
// =====================================================
|
|
83
|
-
// ✅ 1
|
|
56
|
+
// ✅ INGEST: 1 arg = doc_root
|
|
84
57
|
// =====================================================
|
|
85
|
-
if (
|
|
58
|
+
if (args.length === 1) {
|
|
86
59
|
let inserted = 0;
|
|
87
|
-
const ingestRoot = args[0] || doc_root;
|
|
60
|
+
const ingestRoot = args[0] || context.doc_root || "./docs";
|
|
88
61
|
|
|
89
62
|
if (fs.existsSync(ingestRoot)) {
|
|
90
63
|
const files = fs.readdirSync(ingestRoot);
|
|
91
|
-
|
|
92
64
|
for (const file of files) {
|
|
93
65
|
const fullPath = path.join(ingestRoot, file);
|
|
94
66
|
if (!fs.statSync(fullPath).isFile()) continue;
|
|
95
|
-
|
|
96
67
|
const content = fs.readFileSync(fullPath, "utf8");
|
|
97
68
|
if (!content) continue;
|
|
98
|
-
|
|
99
|
-
const chunkText = require("./utils/chunker").chunkText;
|
|
100
|
-
const chunks = chunkText(content, 500, 50);
|
|
101
|
-
|
|
69
|
+
const chunks = require("./utils/chunker").chunkText(content, 500, 50);
|
|
102
70
|
for (let i = 0; i < chunks.length; i++) {
|
|
103
71
|
const text = sanitizeTextForEmbedding(chunks[i]);
|
|
104
72
|
if (!text) continue;
|
|
105
|
-
|
|
106
73
|
const hash = hashText(text);
|
|
107
74
|
if (useCache && cache[hash]) continue;
|
|
108
|
-
|
|
109
75
|
const rawVector = await getEmbedFn(text);
|
|
110
|
-
const vector = Array.from(rawVector);
|
|
111
|
-
|
|
112
76
|
await vectorStore.upsert({
|
|
113
77
|
id: `${file}:${i}`,
|
|
114
|
-
vector,
|
|
78
|
+
vector: Array.from(rawVector),
|
|
115
79
|
content: text,
|
|
116
80
|
source: `file:${file}`,
|
|
117
81
|
});
|
|
118
|
-
|
|
119
82
|
if (useCache) cache[hash] = true;
|
|
120
83
|
inserted++;
|
|
121
84
|
}
|
|
122
85
|
}
|
|
123
86
|
}
|
|
124
|
-
|
|
125
87
|
if (useCache) saveCache(cache);
|
|
126
88
|
if (vectorStore.close) await vectorStore.close();
|
|
127
|
-
|
|
128
89
|
return { inserted, doc_root: ingestRoot };
|
|
129
90
|
}
|
|
130
91
|
|
|
131
92
|
// =====================================================
|
|
132
|
-
// ✅ 2
|
|
93
|
+
// ✅ SEARCH: 2+ args = query + doc_root
|
|
133
94
|
// =====================================================
|
|
134
|
-
if (
|
|
135
|
-
const query = sanitizeTextForEmbedding(args[0]
|
|
95
|
+
if (args.length >= 2) {
|
|
96
|
+
const query = sanitizeTextForEmbedding(args[0]);
|
|
136
97
|
if (!query) return { text: "", matches: [] };
|
|
137
|
-
|
|
138
98
|
const rawQueryVector = await getEmbedFn(query);
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
const results = await vectorStore.query(queryVector, {
|
|
142
|
-
topK: context.topK || 5,
|
|
143
|
-
});
|
|
144
|
-
|
|
99
|
+
const results = await vectorStore.query(Array.from(rawQueryVector), { topK: context.topK || 5 });
|
|
145
100
|
if (vectorStore.close) await vectorStore.close();
|
|
146
|
-
|
|
147
101
|
return formatResults(results, query);
|
|
148
102
|
}
|
|
149
103
|
|
|
150
104
|
// =====================================================
|
|
151
|
-
// ❌ Unknown action
|
|
105
|
+
// ❌ Unknown action format
|
|
152
106
|
// =====================================================
|
|
153
|
-
console.warn(`⚠️ Unknown
|
|
107
|
+
console.warn(`⚠️ Unknown vector.search action format: "${action}"`);
|
|
154
108
|
return;
|
|
155
109
|
}
|
|
156
110
|
|
|
157
|
-
|
|
111
|
+
// ✅ Must match workflow's "Allow resolvers: - vector.search"
|
|
112
|
+
resolver.resolverName = "vector.search";
|
|
158
113
|
resolver.version = "1.0.42";
|
|
159
114
|
|
|
160
|
-
module.exports = resolver;
|
|
115
|
+
module.exports = resolver;
|