@mcp-abap-adt/llm-agent 6.0.2 → 8.0.0

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 (116) hide show
  1. package/dist/generated/version.d.ts +1 -1
  2. package/dist/generated/version.js +1 -1
  3. package/dist/index.d.ts +6 -2
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +2 -0
  6. package/dist/index.js.map +1 -1
  7. package/dist/llm-providers/anthropic.d.ts +1 -0
  8. package/dist/llm-providers/anthropic.d.ts.map +1 -1
  9. package/dist/llm-providers/anthropic.js +3 -0
  10. package/dist/llm-providers/anthropic.js.map +1 -1
  11. package/dist/llm-providers/base.d.ts +4 -0
  12. package/dist/llm-providers/base.d.ts.map +1 -1
  13. package/dist/llm-providers/base.js.map +1 -1
  14. package/dist/llm-providers/deepseek.d.ts +1 -0
  15. package/dist/llm-providers/deepseek.d.ts.map +1 -1
  16. package/dist/llm-providers/deepseek.js +3 -0
  17. package/dist/llm-providers/deepseek.js.map +1 -1
  18. package/dist/llm-providers/openai.d.ts +1 -0
  19. package/dist/llm-providers/openai.d.ts.map +1 -1
  20. package/dist/llm-providers/openai.js +6 -0
  21. package/dist/llm-providers/openai.js.map +1 -1
  22. package/dist/llm-providers/sap-core-ai.d.ts +6 -0
  23. package/dist/llm-providers/sap-core-ai.d.ts.map +1 -1
  24. package/dist/llm-providers/sap-core-ai.js +13 -2
  25. package/dist/llm-providers/sap-core-ai.js.map +1 -1
  26. package/dist/smart-agent/adapters/llm-adapter.d.ts +4 -2
  27. package/dist/smart-agent/adapters/llm-adapter.d.ts.map +1 -1
  28. package/dist/smart-agent/adapters/llm-adapter.js +26 -0
  29. package/dist/smart-agent/adapters/llm-adapter.js.map +1 -1
  30. package/dist/smart-agent/agent.d.ts +27 -1
  31. package/dist/smart-agent/agent.d.ts.map +1 -1
  32. package/dist/smart-agent/agent.js +79 -20
  33. package/dist/smart-agent/agent.js.map +1 -1
  34. package/dist/smart-agent/builder.d.ts.map +1 -1
  35. package/dist/smart-agent/builder.js +18 -5
  36. package/dist/smart-agent/builder.js.map +1 -1
  37. package/dist/smart-agent/config.d.ts +1 -1
  38. package/dist/smart-agent/config.d.ts.map +1 -1
  39. package/dist/smart-agent/config.js +1 -1
  40. package/dist/smart-agent/interfaces/model-provider.d.ts +7 -1
  41. package/dist/smart-agent/interfaces/model-provider.d.ts.map +1 -1
  42. package/dist/smart-agent/interfaces/pipeline.d.ts +7 -0
  43. package/dist/smart-agent/interfaces/pipeline.d.ts.map +1 -1
  44. package/dist/smart-agent/interfaces/query-embedding.d.ts +3 -0
  45. package/dist/smart-agent/interfaces/query-embedding.d.ts.map +1 -1
  46. package/dist/smart-agent/interfaces/rag.d.ts +9 -2
  47. package/dist/smart-agent/interfaces/rag.d.ts.map +1 -1
  48. package/dist/smart-agent/interfaces/rag.js.map +1 -1
  49. package/dist/smart-agent/pipeline/context.d.ts +2 -0
  50. package/dist/smart-agent/pipeline/context.d.ts.map +1 -1
  51. package/dist/smart-agent/pipeline/default-pipeline.d.ts +5 -2
  52. package/dist/smart-agent/pipeline/default-pipeline.d.ts.map +1 -1
  53. package/dist/smart-agent/pipeline/default-pipeline.js +24 -5
  54. package/dist/smart-agent/pipeline/default-pipeline.js.map +1 -1
  55. package/dist/smart-agent/pipeline/handlers/classify.d.ts.map +1 -1
  56. package/dist/smart-agent/pipeline/handlers/classify.js +10 -1
  57. package/dist/smart-agent/pipeline/handlers/classify.js.map +1 -1
  58. package/dist/smart-agent/pipeline/handlers/rag-query.d.ts.map +1 -1
  59. package/dist/smart-agent/pipeline/handlers/rag-query.js +16 -0
  60. package/dist/smart-agent/pipeline/handlers/rag-query.js.map +1 -1
  61. package/dist/smart-agent/pipeline/handlers/tool-loop.js +1 -1
  62. package/dist/smart-agent/pipeline/handlers/tool-loop.js.map +1 -1
  63. package/dist/smart-agent/pipeline/handlers/tool-select.js +1 -1
  64. package/dist/smart-agent/pipeline/handlers/tool-select.js.map +1 -1
  65. package/dist/smart-agent/providers.d.ts +8 -0
  66. package/dist/smart-agent/providers.d.ts.map +1 -1
  67. package/dist/smart-agent/providers.js +21 -1
  68. package/dist/smart-agent/providers.js.map +1 -1
  69. package/dist/smart-agent/rag/in-memory-rag.d.ts +7 -0
  70. package/dist/smart-agent/rag/in-memory-rag.d.ts.map +1 -1
  71. package/dist/smart-agent/rag/in-memory-rag.js +21 -5
  72. package/dist/smart-agent/rag/in-memory-rag.js.map +1 -1
  73. package/dist/smart-agent/rag/index.d.ts +4 -0
  74. package/dist/smart-agent/rag/index.d.ts.map +1 -1
  75. package/dist/smart-agent/rag/index.js +2 -0
  76. package/dist/smart-agent/rag/index.js.map +1 -1
  77. package/dist/smart-agent/rag/ollama-rag.d.ts +3 -3
  78. package/dist/smart-agent/rag/ollama-rag.d.ts.map +1 -1
  79. package/dist/smart-agent/rag/ollama-rag.js +2 -2
  80. package/dist/smart-agent/rag/ollama-rag.js.map +1 -1
  81. package/dist/smart-agent/rag/openai-embedder.d.ts +3 -3
  82. package/dist/smart-agent/rag/openai-embedder.d.ts.map +1 -1
  83. package/dist/smart-agent/rag/openai-embedder.js +19 -2
  84. package/dist/smart-agent/rag/openai-embedder.js.map +1 -1
  85. package/dist/smart-agent/rag/preprocessor.d.ts +82 -0
  86. package/dist/smart-agent/rag/preprocessor.d.ts.map +1 -0
  87. package/dist/smart-agent/rag/preprocessor.js +203 -0
  88. package/dist/smart-agent/rag/preprocessor.js.map +1 -0
  89. package/dist/smart-agent/rag/qdrant-rag.js +1 -1
  90. package/dist/smart-agent/rag/qdrant-rag.js.map +1 -1
  91. package/dist/smart-agent/rag/query-embedding.d.ts +4 -2
  92. package/dist/smart-agent/rag/query-embedding.d.ts.map +1 -1
  93. package/dist/smart-agent/rag/query-embedding.js +10 -4
  94. package/dist/smart-agent/rag/query-embedding.js.map +1 -1
  95. package/dist/smart-agent/rag/sap-ai-core-embedder.d.ts +3 -3
  96. package/dist/smart-agent/rag/sap-ai-core-embedder.d.ts.map +1 -1
  97. package/dist/smart-agent/rag/sap-ai-core-embedder.js +4 -4
  98. package/dist/smart-agent/rag/sap-ai-core-embedder.js.map +1 -1
  99. package/dist/smart-agent/rag/search-strategy.d.ts +89 -0
  100. package/dist/smart-agent/rag/search-strategy.d.ts.map +1 -0
  101. package/dist/smart-agent/rag/search-strategy.js +200 -0
  102. package/dist/smart-agent/rag/search-strategy.js.map +1 -0
  103. package/dist/smart-agent/rag/tool-indexing-strategy.d.ts +58 -0
  104. package/dist/smart-agent/rag/tool-indexing-strategy.d.ts.map +1 -0
  105. package/dist/smart-agent/rag/tool-indexing-strategy.js +130 -0
  106. package/dist/smart-agent/rag/tool-indexing-strategy.js.map +1 -0
  107. package/dist/smart-agent/rag/vector-rag.d.ts +11 -5
  108. package/dist/smart-agent/rag/vector-rag.d.ts.map +1 -1
  109. package/dist/smart-agent/rag/vector-rag.js +55 -46
  110. package/dist/smart-agent/rag/vector-rag.js.map +1 -1
  111. package/dist/smart-agent/resilience/circuit-breaker-embedder.d.ts +3 -3
  112. package/dist/smart-agent/resilience/circuit-breaker-embedder.d.ts.map +1 -1
  113. package/dist/smart-agent/smart-server.d.ts.map +1 -1
  114. package/dist/smart-agent/smart-server.js +29 -1
  115. package/dist/smart-agent/smart-server.js.map +1 -1
  116. package/package.json +2 -1
@@ -0,0 +1,200 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Module-private helpers (reused by all strategies in this file)
3
+ // ---------------------------------------------------------------------------
4
+ function cosine(a, b) {
5
+ let dot = 0;
6
+ let na = 0;
7
+ let nb = 0;
8
+ for (let i = 0; i < a.length; i++) {
9
+ dot += a[i] * b[i];
10
+ na += a[i] ** 2;
11
+ nb += b[i] ** 2;
12
+ }
13
+ return dot / (Math.sqrt(na) * Math.sqrt(nb) || 1);
14
+ }
15
+ function bm25(queryTokens, docText, context) {
16
+ const docTokens = context.tokenize(docText);
17
+ if (queryTokens.length === 0 || docTokens.length === 0)
18
+ return 0;
19
+ const avgDocLength = context.index.avgDocLength || 1;
20
+ const n = context.index.docCount || 1;
21
+ const k1 = 1.2;
22
+ const b = 0.75;
23
+ let score = 0;
24
+ for (const token of new Set(queryTokens)) {
25
+ const df = context.index.getDocFrequency(token);
26
+ const idf = Math.log((n - df + 0.5) / (df + 0.5) + 1);
27
+ const tf = docTokens.filter((t) => t === token).length;
28
+ const tfScored = (tf * (k1 + 1)) /
29
+ (tf + k1 * (1 - b + b * (docTokens.length / avgDocLength)));
30
+ score += idf * tfScored;
31
+ }
32
+ return Math.min(score / 5, 1.0);
33
+ }
34
+ // ---------------------------------------------------------------------------
35
+ // WeightedFusionStrategy
36
+ // ---------------------------------------------------------------------------
37
+ export class WeightedFusionStrategy {
38
+ name = 'weighted-fusion';
39
+ vectorWeight;
40
+ keywordWeight;
41
+ constructor(config) {
42
+ this.vectorWeight = config?.vectorWeight ?? 0.7;
43
+ this.keywordWeight = config?.keywordWeight ?? 0.3;
44
+ }
45
+ score(query, candidates, context) {
46
+ const queryTokens = context.tokenize(query.text);
47
+ return candidates
48
+ .map((c) => ({
49
+ text: c.text,
50
+ metadata: c.metadata,
51
+ score: cosine(query.vector, c.vector) * this.vectorWeight +
52
+ bm25(queryTokens, c.text, context) * this.keywordWeight,
53
+ }))
54
+ .sort((a, b) => b.score - a.score);
55
+ }
56
+ }
57
+ // ---------------------------------------------------------------------------
58
+ // RrfStrategy
59
+ // ---------------------------------------------------------------------------
60
+ /**
61
+ * Reciprocal Rank Fusion: combines vector and BM25 rankings using
62
+ * `score(doc) = 1/(k + rank_vector) + 1/(k + rank_bm25)`.
63
+ *
64
+ * RRF is rank-based — it doesn't depend on raw score magnitudes,
65
+ * which makes it more stable than weighted sum when vector and BM25
66
+ * score distributions differ.
67
+ */
68
+ export class RrfStrategy {
69
+ name = 'rrf';
70
+ k;
71
+ constructor(config) {
72
+ this.k = config?.k ?? 60;
73
+ }
74
+ score(query, candidates, context) {
75
+ const queryTokens = context.tokenize(query.text);
76
+ // Score by each method independently
77
+ const vectorScores = candidates.map((c, i) => ({
78
+ idx: i,
79
+ score: cosine(query.vector, c.vector),
80
+ }));
81
+ const bm25Scores = candidates.map((c, i) => ({
82
+ idx: i,
83
+ score: bm25(queryTokens, c.text, context),
84
+ }));
85
+ // Sort each list desc to get ranks
86
+ vectorScores.sort((a, b) => b.score - a.score);
87
+ bm25Scores.sort((a, b) => b.score - a.score);
88
+ // Build rank maps (0-indexed rank)
89
+ const vectorRank = new Map();
90
+ const bm25Rank = new Map();
91
+ for (let i = 0; i < vectorScores.length; i++)
92
+ vectorRank.set(vectorScores[i].idx, i);
93
+ for (let i = 0; i < bm25Scores.length; i++)
94
+ bm25Rank.set(bm25Scores[i].idx, i);
95
+ // Compute RRF score
96
+ return candidates
97
+ .map((c, i) => ({
98
+ text: c.text,
99
+ metadata: c.metadata,
100
+ score: 1 / (this.k + (vectorRank.get(i) ?? candidates.length)) +
101
+ 1 / (this.k + (bm25Rank.get(i) ?? candidates.length)),
102
+ }))
103
+ .sort((a, b) => b.score - a.score);
104
+ }
105
+ }
106
+ // ---------------------------------------------------------------------------
107
+ // VectorOnlyStrategy
108
+ // ---------------------------------------------------------------------------
109
+ /**
110
+ * Pure vector cosine similarity. No keyword component.
111
+ * Useful as a baseline or when BM25 tokenization doesn't match the domain.
112
+ */
113
+ export class VectorOnlyStrategy {
114
+ name = 'vector-only';
115
+ score(query, candidates, _context) {
116
+ return candidates
117
+ .map((c) => ({
118
+ text: c.text,
119
+ metadata: c.metadata,
120
+ score: cosine(query.vector, c.vector),
121
+ }))
122
+ .sort((a, b) => b.score - a.score);
123
+ }
124
+ }
125
+ // ---------------------------------------------------------------------------
126
+ // Bm25OnlyStrategy
127
+ // ---------------------------------------------------------------------------
128
+ /**
129
+ * Pure BM25 lexical scoring. No vector component.
130
+ * Useful when embedder is unavailable or for exact-match-heavy domains.
131
+ */
132
+ export class Bm25OnlyStrategy {
133
+ name = 'bm25-only';
134
+ score(query, candidates, context) {
135
+ const queryTokens = context.tokenize(query.text);
136
+ return candidates
137
+ .map((c) => ({
138
+ text: c.text,
139
+ metadata: c.metadata,
140
+ score: bm25(queryTokens, c.text, context),
141
+ }))
142
+ .sort((a, b) => b.score - a.score);
143
+ }
144
+ }
145
+ /**
146
+ * Combines multiple strategies via weighted Reciprocal Rank Fusion.
147
+ *
148
+ * Each child strategy scores all candidates independently.
149
+ * Results are merged using: `score(doc) = Σ weight_i / (k + rank_i)`
150
+ *
151
+ * All child strategies run synchronously on the same candidates —
152
+ * no I/O, pure CPU, single event-loop tick.
153
+ */
154
+ export class CompositeStrategy {
155
+ name;
156
+ entries;
157
+ k;
158
+ constructor(entries, config) {
159
+ this.entries = entries;
160
+ this.k = config?.k ?? 60;
161
+ this.name = `composite(${entries.map((e) => e.strategy.name).join('+')})`;
162
+ }
163
+ score(query, candidates, context) {
164
+ if (candidates.length === 0)
165
+ return [];
166
+ // Run all strategies on the same candidates
167
+ const rankedLists = this.entries.map((entry) => {
168
+ const scored = entry.strategy.score(query, candidates, context);
169
+ // Build rank map: metadata.id → rank (0-indexed)
170
+ const rankMap = new Map();
171
+ for (let i = 0; i < scored.length; i++) {
172
+ const id = scored[i].metadata.id;
173
+ // For dual-index: same tool may appear multiple times.
174
+ // Keep best rank (first occurrence = highest score).
175
+ if (!rankMap.has(id))
176
+ rankMap.set(id, i);
177
+ }
178
+ return { rankMap, weight: entry.weight };
179
+ });
180
+ // Compute weighted RRF per candidate
181
+ const scoreMap = new Map();
182
+ for (const c of candidates) {
183
+ const id = c.metadata.id;
184
+ if (scoreMap.has(id))
185
+ continue; // dedup by id — take first occurrence
186
+ let totalScore = 0;
187
+ for (const { rankMap, weight } of rankedLists) {
188
+ const rank = rankMap.get(id) ?? candidates.length;
189
+ totalScore += weight / (this.k + rank);
190
+ }
191
+ scoreMap.set(id, {
192
+ text: c.text,
193
+ metadata: c.metadata,
194
+ score: totalScore,
195
+ });
196
+ }
197
+ return [...scoreMap.values()].sort((a, b) => b.score - a.score);
198
+ }
199
+ }
200
+ //# sourceMappingURL=search-strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-strategy.js","sourceRoot":"","sources":["../../../src/smart-agent/rag/search-strategy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import type { ILlm } from '../interfaces/llm.js';
2
+ import type { IRequestLogger } from '../interfaces/request-logger.js';
3
+ import type { CallOptions } from '../interfaces/types.js';
4
+ /**
5
+ * A tool description to be indexed in RAG.
6
+ */
7
+ export interface IToolDescriptor {
8
+ name: string;
9
+ description: string;
10
+ }
11
+ /**
12
+ * A text variant to upsert into RAG. Each variant gets its own embedding.
13
+ * Multiple variants per tool = broader recall.
14
+ */
15
+ export interface IToolIndexEntry {
16
+ /** RAG record id. Format: tool:<name>[:<suffix>] */
17
+ id: string;
18
+ /** Text to embed and store. */
19
+ text: string;
20
+ }
21
+ /**
22
+ * Generates text variants for tool indexing in RAG.
23
+ * Each strategy produces one or more entries per tool.
24
+ * Strategies can be combined — builder upserts all entries from all strategies.
25
+ */
26
+ export interface IToolIndexingStrategy {
27
+ readonly name: string;
28
+ prepare(tool: IToolDescriptor, options?: CallOptions): Promise<IToolIndexEntry[]>;
29
+ }
30
+ /**
31
+ * Indexes the raw tool description as-is.
32
+ * This is the current default behavior.
33
+ */
34
+ export declare class OriginalToolIndexing implements IToolIndexingStrategy {
35
+ readonly name = "original";
36
+ prepare(tool: IToolDescriptor): Promise<IToolIndexEntry[]>;
37
+ }
38
+ /**
39
+ * LLM generates concise intent keywords for the tool.
40
+ * Indexed alongside the original for broader keyword coverage.
41
+ */
42
+ export declare class IntentToolIndexing implements IToolIndexingStrategy {
43
+ private readonly llm;
44
+ private readonly requestLogger?;
45
+ readonly name = "intent";
46
+ constructor(llm: ILlm, requestLogger?: IRequestLogger | undefined);
47
+ prepare(tool: IToolDescriptor, options?: CallOptions): Promise<IToolIndexEntry[]>;
48
+ }
49
+ /**
50
+ * Adds action verb synonyms to the tool description.
51
+ * E.g. "ReadClass" → also indexed with "show class, display class, view class".
52
+ * Purely deterministic — no LLM needed.
53
+ */
54
+ export declare class SynonymToolIndexing implements IToolIndexingStrategy {
55
+ readonly name = "synonym";
56
+ prepare(tool: IToolDescriptor): Promise<IToolIndexEntry[]>;
57
+ }
58
+ //# sourceMappingURL=tool-indexing-strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-indexing-strategy.d.ts","sourceRoot":"","sources":["../../../src/smart-agent/rag/tool-indexing-strategy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,oDAAoD;IACpD,EAAE,EAAE,MAAM,CAAC;IACX,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,OAAO,CACL,IAAI,EAAE,eAAe,EACrB,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;CAC/B;AAMD;;;GAGG;AACH,qBAAa,oBAAqB,YAAW,qBAAqB;IAChE,QAAQ,CAAC,IAAI,cAAc;IAErB,OAAO,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;CAQjE;AAmBD;;;GAGG;AACH,qBAAa,kBAAmB,YAAW,qBAAqB;IAI5D,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;IAJjC,QAAQ,CAAC,IAAI,YAAY;gBAGN,GAAG,EAAE,IAAI,EACT,aAAa,CAAC,EAAE,cAAc,YAAA;IAG3C,OAAO,CACX,IAAI,EAAE,eAAe,EACrB,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,eAAe,EAAE,CAAC;CAqC9B;AAmBD;;;;GAIG;AACH,qBAAa,mBAAoB,YAAW,qBAAqB;IAC/D,QAAQ,CAAC,IAAI,aAAa;IAEpB,OAAO,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;CA6BjE"}
@@ -0,0 +1,130 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Original — current behavior: "Tool: name — description"
3
+ // ---------------------------------------------------------------------------
4
+ /**
5
+ * Indexes the raw tool description as-is.
6
+ * This is the current default behavior.
7
+ */
8
+ export class OriginalToolIndexing {
9
+ name = 'original';
10
+ async prepare(tool) {
11
+ return [
12
+ {
13
+ id: `tool:${tool.name}`,
14
+ text: `${tool.name}: ${tool.description}`,
15
+ },
16
+ ];
17
+ }
18
+ }
19
+ // ---------------------------------------------------------------------------
20
+ // Intent — LLM generates concise keyword phrases
21
+ // ---------------------------------------------------------------------------
22
+ const INTENT_PROMPT = `You receive a tool description with its name and parameters.
23
+ Extract the core INTENT in 3-5 short keyword phrases that a user would type when needing this tool.
24
+ Focus on WHAT the tool does, not HOW. Use simple action words.
25
+
26
+ Format: return ONLY the keyword phrases separated by commas, no explanation.
27
+
28
+ Examples:
29
+ - Input: "GetTableContents: Retrieve contents (data preview) of an ABAP database table or CDS view."
30
+ Output: table data preview, read table contents, SE16 data, select from table, show table rows
31
+
32
+ - Input: "SearchObject: Find, search, locate, or check if an ABAP repository object exists by name or wildcard pattern."
33
+ Output: search object by name, find ABAP object, locate program class table, does object exist, wildcard search`;
34
+ /**
35
+ * LLM generates concise intent keywords for the tool.
36
+ * Indexed alongside the original for broader keyword coverage.
37
+ */
38
+ export class IntentToolIndexing {
39
+ llm;
40
+ requestLogger;
41
+ name = 'intent';
42
+ constructor(llm, requestLogger) {
43
+ this.llm = llm;
44
+ this.requestLogger = requestLogger;
45
+ }
46
+ async prepare(tool, options) {
47
+ const inputText = `${tool.name}: ${tool.description}`;
48
+ try {
49
+ const chatStart = Date.now();
50
+ const res = await this.llm.chat([
51
+ { role: 'system', content: INTENT_PROMPT },
52
+ { role: 'user', content: inputText },
53
+ ], [], options);
54
+ if (this.requestLogger) {
55
+ this.requestLogger.logLlmCall({
56
+ component: 'helper',
57
+ model: this.llm.model ?? 'unknown',
58
+ promptTokens: res.ok ? (res.value.usage?.promptTokens ?? 0) : 0,
59
+ completionTokens: res.ok
60
+ ? (res.value.usage?.completionTokens ?? 0)
61
+ : 0,
62
+ totalTokens: res.ok ? (res.value.usage?.totalTokens ?? 0) : 0,
63
+ durationMs: Date.now() - chatStart,
64
+ });
65
+ }
66
+ if (!res.ok || !res.value.content.trim())
67
+ return [];
68
+ return [
69
+ {
70
+ id: `tool:${tool.name}:intent`,
71
+ text: `${tool.name}: ${res.value.content.trim()}`,
72
+ },
73
+ ];
74
+ }
75
+ catch {
76
+ return [];
77
+ }
78
+ }
79
+ }
80
+ // ---------------------------------------------------------------------------
81
+ // Synonym — adds action verb synonyms
82
+ // ---------------------------------------------------------------------------
83
+ const ACTION_SYNONYMS = {
84
+ read: ['show', 'display', 'view', 'get', 'retrieve'],
85
+ create: ['add', 'new', 'make', 'generate'],
86
+ update: ['modify', 'change', 'edit', 'set'],
87
+ delete: ['remove', 'drop', 'destroy'],
88
+ search: ['find', 'locate', 'lookup', 'discover'],
89
+ list: ['show all', 'enumerate', 'browse'],
90
+ run: ['execute', 'start', 'launch', 'trigger'],
91
+ check: ['validate', 'verify', 'test', 'inspect'],
92
+ get: ['read', 'fetch', 'retrieve', 'show'],
93
+ activate: ['enable', 'publish', 'deploy'],
94
+ };
95
+ /**
96
+ * Adds action verb synonyms to the tool description.
97
+ * E.g. "ReadClass" → also indexed with "show class, display class, view class".
98
+ * Purely deterministic — no LLM needed.
99
+ */
100
+ export class SynonymToolIndexing {
101
+ name = 'synonym';
102
+ async prepare(tool) {
103
+ const nameLower = tool.name.toLowerCase();
104
+ const synonymPhrases = [];
105
+ for (const [verb, synonyms] of Object.entries(ACTION_SYNONYMS)) {
106
+ if (nameLower.startsWith(verb)) {
107
+ const objectPart = tool.name
108
+ .replace(/^[A-Z][a-z]+/, '') // Remove first word (the verb)
109
+ .replace(/([A-Z])/g, ' $1') // CamelCase to spaces
110
+ .trim()
111
+ .toLowerCase();
112
+ if (objectPart) {
113
+ for (const syn of synonyms) {
114
+ synonymPhrases.push(`${syn} ${objectPart}`);
115
+ }
116
+ }
117
+ break;
118
+ }
119
+ }
120
+ if (synonymPhrases.length === 0)
121
+ return [];
122
+ return [
123
+ {
124
+ id: `tool:${tool.name}:synonym`,
125
+ text: `${tool.name}: ${synonymPhrases.join(', ')}`,
126
+ },
127
+ ];
128
+ }
129
+ }
130
+ //# sourceMappingURL=tool-indexing-strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-indexing-strategy.js","sourceRoot":"","sources":["../../../src/smart-agent/rag/tool-indexing-strategy.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,8 @@
1
1
  import type { IQueryEmbedding } from '../interfaces/query-embedding.js';
2
2
  import type { IEmbedder, IPrecomputedVectorRag } from '../interfaces/rag.js';
3
3
  import { type CallOptions, RagError, type RagMetadata, type RagResult, type Result } from '../interfaces/types.js';
4
+ import type { IDocumentEnricher, IQueryPreprocessor } from './preprocessor.js';
5
+ import type { ISearchStrategy } from './search-strategy.js';
4
6
  export interface VectorRagConfig {
5
7
  /** Cosine similarity threshold for dedup. Default: 0.92 */
6
8
  dedupThreshold?: number;
@@ -10,6 +12,12 @@ export interface VectorRagConfig {
10
12
  vectorWeight?: number;
11
13
  /** Weight for keyword search (0..1). Default: 0.3 */
12
14
  keywordWeight?: number;
15
+ /** Search scoring strategy. Default: WeightedFusionStrategy with the configured weights. */
16
+ strategy?: ISearchStrategy;
17
+ /** Query preprocessors (translate, expand, etc.). Applied in order before embedding. */
18
+ queryPreprocessors?: IQueryPreprocessor[];
19
+ /** Document enrichers. Applied in order before embedding on upsert. */
20
+ documentEnrichers?: IDocumentEnricher[];
13
21
  }
14
22
  export declare class VectorRag implements IPrecomputedVectorRag {
15
23
  private readonly embedder;
@@ -19,6 +27,9 @@ export declare class VectorRag implements IPrecomputedVectorRag {
19
27
  private readonly namespace?;
20
28
  private vectorWeight;
21
29
  private keywordWeight;
30
+ private strategy;
31
+ private readonly queryPreprocessors;
32
+ private readonly documentEnrichers;
22
33
  constructor(embedder: IEmbedder, config?: VectorRagConfig);
23
34
  /** Update hybrid search weights at runtime (hot-reload). */
24
35
  updateWeights(config: {
@@ -27,11 +38,6 @@ export declare class VectorRag implements IPrecomputedVectorRag {
27
38
  }): void;
28
39
  private tokenize;
29
40
  private cosine;
30
- /**
31
- * BM25 Lexical Scorer.
32
- * Uses pre-built InvertedIndex for O(1) DF lookups.
33
- */
34
- private bm25Score;
35
41
  private upsertKnownVector;
36
42
  upsert(text: string, metadata: RagMetadata, options?: CallOptions): Promise<Result<void, RagError>>;
37
43
  upsertPrecomputed(text: string, vector: number[], metadata: RagMetadata, _options?: CallOptions): Promise<Result<void, RagError>>;
@@ -1 +1 @@
1
- {"version":3,"file":"vector-rag.d.ts","sourceRoot":"","sources":["../../../src/smart-agent/rag/vector-rag.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EACL,KAAK,WAAW,EAChB,QAAQ,EACR,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,MAAM,EACZ,MAAM,wBAAwB,CAAC;AAUhC,MAAM,WAAW,eAAe;IAC9B,2DAA2D;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gCAAgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,qBAAa,SAAU,YAAW,qBAAqB;IASnD,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAR3B,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuB;IAC7C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAS;IACpC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,aAAa,CAAS;gBAGX,QAAQ,EAAE,SAAS,EACpC,MAAM,GAAE,eAAoB;IAQ9B,4DAA4D;IAC5D,aAAa,CAAC,MAAM,EAAE;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,GAAG,IAAI;IAOR,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,MAAM;IAYd;;;OAGG;IACH,OAAO,CAAC,SAAS;IA4BjB,OAAO,CAAC,iBAAiB;IA0CnB,MAAM,CACV,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,WAAW,EACrB,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAsB5B,iBAAiB,CACrB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EAAE,EAChB,QAAQ,EAAE,WAAW,EACrB,QAAQ,CAAC,EAAE,WAAW,GACrB,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAS5B,KAAK,CACT,SAAS,EAAE,eAAe,EAC1B,CAAC,EAAE,MAAM,EACT,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,QAAQ,CAAC,CAAC;IAwDnC,WAAW,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAezE,KAAK,IAAI,IAAI;CAId"}
1
+ {"version":3,"file":"vector-rag.d.ts","sourceRoot":"","sources":["../../../src/smart-agent/rag/vector-rag.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EACL,KAAK,WAAW,EAChB,QAAQ,EACR,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,MAAM,EACZ,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE/E,OAAO,KAAK,EAIV,eAAe,EAChB,MAAM,sBAAsB,CAAC;AAS9B,MAAM,WAAW,eAAe;IAC9B,2DAA2D;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gCAAgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,wFAAwF;IACxF,kBAAkB,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC1C,uEAAuE;IACvE,iBAAiB,CAAC,EAAE,iBAAiB,EAAE,CAAC;CACzC;AAED,qBAAa,SAAU,YAAW,qBAAqB;IAYnD,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAX3B,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuB;IAC7C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAS;IACpC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAuB;IAC1D,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAsB;gBAGrC,QAAQ,EAAE,SAAS,EACpC,MAAM,GAAE,eAAoB;IAgB9B,4DAA4D;IAC5D,aAAa,CAAC,MAAM,EAAE;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,GAAG,IAAI;IAaR,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,MAAM;IAYd,OAAO,CAAC,iBAAiB;IA0CnB,MAAM,CACV,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,WAAW,EACrB,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IA2B5B,iBAAiB,CACrB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EAAE,EAChB,QAAQ,EAAE,WAAW,EACrB,QAAQ,CAAC,EAAE,WAAW,GACrB,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAS5B,KAAK,CACT,SAAS,EAAE,eAAe,EAC1B,CAAC,EAAE,MAAM,EACT,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,QAAQ,CAAC,CAAC;IAgEnC,WAAW,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAezE,KAAK,IAAI,IAAI;CAId"}
@@ -1,6 +1,7 @@
1
1
  import { RagError, } from '../interfaces/types.js';
2
2
  import { InvertedIndex } from './inverted-index.js';
3
- import { FallbackQueryEmbedding } from './query-embedding.js';
3
+ import { FallbackQueryEmbedding, QueryEmbedding } from './query-embedding.js';
4
+ import { WeightedFusionStrategy } from './search-strategy.js';
4
5
  export class VectorRag {
5
6
  embedder;
6
7
  records = [];
@@ -9,12 +10,23 @@ export class VectorRag {
9
10
  namespace;
10
11
  vectorWeight;
11
12
  keywordWeight;
13
+ strategy;
14
+ queryPreprocessors;
15
+ documentEnrichers;
12
16
  constructor(embedder, config = {}) {
13
17
  this.embedder = embedder;
14
18
  this.dedupThreshold = config.dedupThreshold ?? 0.92;
15
19
  this.namespace = config.namespace;
16
20
  this.vectorWeight = config.vectorWeight ?? 0.7;
17
21
  this.keywordWeight = config.keywordWeight ?? 0.3;
22
+ this.strategy =
23
+ config.strategy ??
24
+ new WeightedFusionStrategy({
25
+ vectorWeight: this.vectorWeight,
26
+ keywordWeight: this.keywordWeight,
27
+ });
28
+ this.queryPreprocessors = config.queryPreprocessors ?? [];
29
+ this.documentEnrichers = config.documentEnrichers ?? [];
18
30
  }
19
31
  /** Update hybrid search weights at runtime (hot-reload). */
20
32
  updateWeights(config) {
@@ -22,6 +34,12 @@ export class VectorRag {
22
34
  this.vectorWeight = config.vectorWeight;
23
35
  if (config.keywordWeight !== undefined)
24
36
  this.keywordWeight = config.keywordWeight;
37
+ if (this.strategy.name === 'weighted-fusion') {
38
+ this.strategy = new WeightedFusionStrategy({
39
+ vectorWeight: this.vectorWeight,
40
+ keywordWeight: this.keywordWeight,
41
+ });
42
+ }
25
43
  }
26
44
  tokenize(s) {
27
45
  return s
@@ -40,31 +58,6 @@ export class VectorRag {
40
58
  }
41
59
  return dot / (Math.sqrt(na) * Math.sqrt(nb) || 1);
42
60
  }
43
- /**
44
- * BM25 Lexical Scorer.
45
- * Uses pre-built InvertedIndex for O(1) DF lookups.
46
- */
47
- bm25Score(query, text) {
48
- const queryTokens = this.tokenize(query);
49
- const docTokens = this.tokenize(text);
50
- if (queryTokens.length === 0 || docTokens.length === 0)
51
- return 0;
52
- const avgDocLength = this.index.avgDocLength || 1;
53
- const n = this.index.docCount || 1;
54
- const k1 = 1.2;
55
- const b = 0.75;
56
- let score = 0;
57
- for (const token of new Set(queryTokens)) {
58
- const df = this.index.getDocFrequency(token);
59
- const idf = Math.log((n - df + 0.5) / (df + 0.5) + 1);
60
- const tf = docTokens.filter((t) => t === token).length;
61
- const tfScored = (tf * (k1 + 1)) /
62
- (tf + k1 * (1 - b + b * (docTokens.length / avgDocLength)));
63
- score += idf * tfScored;
64
- }
65
- // Normalize to [0, 1] range (rough approximation for fusion)
66
- return Math.min(score / 5, 1.0);
67
- }
68
61
  upsertKnownVector(text, vector, metadata) {
69
62
  const newTokens = this.tokenize(text);
70
63
  // Idempotent upsert: if metadata.id matches, replace in-place
@@ -109,8 +102,14 @@ export class VectorRag {
109
102
  return { ok: true, value: undefined };
110
103
  }
111
104
  try {
112
- const vector = await this.embedder.embed(text, options);
113
- return this.upsertKnownVector(text, vector, metadata);
105
+ let enrichedText = text;
106
+ for (const enricher of this.documentEnrichers) {
107
+ const eResult = await enricher.enrich(enrichedText, options);
108
+ if (eResult.ok)
109
+ enrichedText = eResult.value;
110
+ }
111
+ const { vector } = await this.embedder.embed(enrichedText, options);
112
+ return this.upsertKnownVector(enrichedText, vector, metadata);
114
113
  }
115
114
  catch (err) {
116
115
  if (err instanceof RagError)
@@ -134,15 +133,22 @@ export class VectorRag {
134
133
  }
135
134
  try {
136
135
  const text = embedding.text;
136
+ let searchText = text;
137
+ for (const pp of this.queryPreprocessors) {
138
+ const ppResult = await pp.process(searchText, options);
139
+ if (ppResult.ok)
140
+ searchText = ppResult.value;
141
+ }
137
142
  const nowSecs = Date.now() / 1000;
138
- const safe = new FallbackQueryEmbedding(embedding, this.embedder);
139
- const queryVector = await safe.toVector();
143
+ // If preprocessors transformed the text, embed the transformed version
144
+ const effectiveEmbedding = searchText !== text
145
+ ? new QueryEmbedding(searchText, this.embedder, options)
146
+ : new FallbackQueryEmbedding(embedding, this.embedder);
147
+ const queryVector = await effectiveEmbedding.toVector();
140
148
  const targetNamespace = options?.ragFilter?.namespace;
141
- const scored = this.records
142
- .filter((r) => {
149
+ const filtered = this.records.filter((r) => {
143
150
  if (r.metadata.ttl !== undefined && r.metadata.ttl < nowSecs)
144
151
  return false;
145
- // Apply dynamic filter from CallOptions
146
152
  if (targetNamespace !== undefined &&
147
153
  r.metadata.namespace !== targetNamespace)
148
154
  return false;
@@ -151,19 +157,22 @@ export class VectorRag {
151
157
  r.metadata.namespace !== this.namespace)
152
158
  return false;
153
159
  return true;
154
- })
155
- .map((r) => {
156
- const vScore = this.cosine(queryVector, r.vector);
157
- const lScore = this.bm25Score(text, r.text);
158
- // Hybrid Fusion: Weighted Sum
159
- const combinedScore = vScore * this.vectorWeight + lScore * this.keywordWeight;
160
- return {
161
- text: r.text,
162
- metadata: r.metadata,
163
- score: combinedScore,
164
- };
165
- })
166
- .sort((a, b) => b.score - a.score)
160
+ });
161
+ const candidates = filtered.map((r) => ({
162
+ text: r.text,
163
+ vector: r.vector,
164
+ metadata: r.metadata,
165
+ }));
166
+ const searchQuery = {
167
+ text: searchText,
168
+ vector: queryVector,
169
+ };
170
+ const context = {
171
+ index: this.index,
172
+ tokenize: this.tokenize.bind(this),
173
+ };
174
+ const scored = this.strategy
175
+ .score(searchQuery, candidates, context)
167
176
  .slice(0, k);
168
177
  return { ok: true, value: scored };
169
178
  }