@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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/resolver.js +20 -65
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@o-lang/semantic-doc-search",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "O-Lang semantic document search resolver with vector embeddings",
5
5
  "main": "src/index.js",
6
6
  "exports": {
package/src/resolver.js CHANGED
@@ -36,125 +36,80 @@ function hashText(str) {
36
36
  }
37
37
 
38
38
  // ─────────────────────────────────────────────
39
- // 🔥 Parse O-Lang Action String
40
- // Format: Action <resolver> "<actionType>" "<arg1>" "<arg2>" ...
41
- // ─────────────────────────────────────────────
42
- function parseActionString(action) {
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
- // Parse the action string
67
- const parsed = parseActionString(action);
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. VECTOR INSERT (INGEST)
56
+ // ✅ INGEST: 1 arg = doc_root
84
57
  // =====================================================
85
- if (actionType.includes("vector.insert")) {
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. VECTOR SEARCH
93
+ // ✅ SEARCH: 2+ args = query + doc_root
133
94
  // =====================================================
134
- if (actionType.includes("vector.search")) {
135
- const query = sanitizeTextForEmbedding(args[0] || extractQuery(action) || "");
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 queryVector = Array.from(rawQueryVector);
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 doc-search action: "${actionType}"`);
107
+ console.warn(`⚠️ Unknown vector.search action format: "${action}"`);
154
108
  return;
155
109
  }
156
110
 
157
- resolver.resolverName = "doc-search";
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;