@superatomai/sdk-node 0.0.23 → 0.0.25
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/dist/index.d.mts +258 -1
- package/dist/index.d.ts +258 -1
- package/dist/index.js +879 -48
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +874 -47
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -164,6 +164,7 @@ var init_utils = __esm({
|
|
|
164
164
|
// src/index.ts
|
|
165
165
|
var index_exports = {};
|
|
166
166
|
__export(index_exports, {
|
|
167
|
+
BM25L: () => BM25L,
|
|
167
168
|
CONTEXT_CONFIG: () => CONTEXT_CONFIG,
|
|
168
169
|
CleanupService: () => CleanupService,
|
|
169
170
|
LLM: () => LLM,
|
|
@@ -175,7 +176,10 @@ __export(index_exports, {
|
|
|
175
176
|
UIBlock: () => UIBlock,
|
|
176
177
|
UILogCollector: () => UILogCollector,
|
|
177
178
|
UserManager: () => UserManager,
|
|
178
|
-
|
|
179
|
+
hybridRerank: () => hybridRerank,
|
|
180
|
+
logger: () => logger,
|
|
181
|
+
rerankChromaResults: () => rerankChromaResults,
|
|
182
|
+
rerankConversationResults: () => rerankConversationResults
|
|
179
183
|
});
|
|
180
184
|
module.exports = __toCommonJS(index_exports);
|
|
181
185
|
|
|
@@ -702,6 +706,36 @@ var BookmarksRequestMessageSchema = import_zod3.z.object({
|
|
|
702
706
|
type: import_zod3.z.literal("BOOKMARKS"),
|
|
703
707
|
payload: BookmarksRequestPayloadSchema
|
|
704
708
|
});
|
|
709
|
+
var KbNodesQueryFiltersSchema = import_zod3.z.object({
|
|
710
|
+
query: import_zod3.z.string().optional(),
|
|
711
|
+
category: import_zod3.z.string().optional(),
|
|
712
|
+
tags: import_zod3.z.array(import_zod3.z.string()).optional(),
|
|
713
|
+
createdBy: import_zod3.z.number().optional()
|
|
714
|
+
});
|
|
715
|
+
var KbNodesRequestPayloadSchema = import_zod3.z.object({
|
|
716
|
+
operation: import_zod3.z.enum(["create", "update", "delete", "getAll", "getOne", "search", "getByCategory", "getByUser", "getCategories", "getTags"]),
|
|
717
|
+
data: import_zod3.z.object({
|
|
718
|
+
id: import_zod3.z.number().optional(),
|
|
719
|
+
title: import_zod3.z.string().optional(),
|
|
720
|
+
content: import_zod3.z.string().optional(),
|
|
721
|
+
category: import_zod3.z.string().optional(),
|
|
722
|
+
tags: import_zod3.z.array(import_zod3.z.string()).optional(),
|
|
723
|
+
createdBy: import_zod3.z.number().optional(),
|
|
724
|
+
updatedBy: import_zod3.z.number().optional(),
|
|
725
|
+
userId: import_zod3.z.number().optional(),
|
|
726
|
+
// Query/search operation fields
|
|
727
|
+
query: import_zod3.z.string().optional(),
|
|
728
|
+
filters: KbNodesQueryFiltersSchema.optional(),
|
|
729
|
+
limit: import_zod3.z.number().optional(),
|
|
730
|
+
offset: import_zod3.z.number().optional()
|
|
731
|
+
}).optional()
|
|
732
|
+
});
|
|
733
|
+
var KbNodesRequestMessageSchema = import_zod3.z.object({
|
|
734
|
+
id: import_zod3.z.string(),
|
|
735
|
+
from: MessageParticipantSchema,
|
|
736
|
+
type: import_zod3.z.literal("KB_NODES"),
|
|
737
|
+
payload: KbNodesRequestPayloadSchema
|
|
738
|
+
});
|
|
705
739
|
|
|
706
740
|
// src/utils/logger.ts
|
|
707
741
|
var import_fs = __toESM(require("fs"));
|
|
@@ -3789,6 +3823,166 @@ var KB = {
|
|
|
3789
3823
|
};
|
|
3790
3824
|
var knowledge_base_default = KB;
|
|
3791
3825
|
|
|
3826
|
+
// src/utils/bm25l-reranker.ts
|
|
3827
|
+
var BM25L = class {
|
|
3828
|
+
/**
|
|
3829
|
+
* @param documents - Array of raw documents (strings)
|
|
3830
|
+
* @param opts - Optional BM25L parameters
|
|
3831
|
+
*/
|
|
3832
|
+
constructor(documents = [], opts = {}) {
|
|
3833
|
+
if (!Array.isArray(documents)) {
|
|
3834
|
+
throw new Error("BM25L: documents must be an array of strings.");
|
|
3835
|
+
}
|
|
3836
|
+
this.k1 = typeof opts.k1 === "number" ? opts.k1 : 1.5;
|
|
3837
|
+
this.b = typeof opts.b === "number" ? opts.b : 0.75;
|
|
3838
|
+
this.delta = typeof opts.delta === "number" ? opts.delta : 0.5;
|
|
3839
|
+
this.documents = documents.map((d) => typeof d === "string" ? this.tokenize(d) : []);
|
|
3840
|
+
this.docLengths = this.documents.map((doc) => doc.length);
|
|
3841
|
+
this.avgDocLength = this.docLengths.reduce((a, b) => a + b, 0) / (this.docLengths.length || 1);
|
|
3842
|
+
this.termDocFreq = {};
|
|
3843
|
+
this.documents.forEach((doc) => {
|
|
3844
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3845
|
+
doc.forEach((term) => {
|
|
3846
|
+
if (!seen.has(term)) {
|
|
3847
|
+
seen.add(term);
|
|
3848
|
+
this.termDocFreq[term] = (this.termDocFreq[term] || 0) + 1;
|
|
3849
|
+
}
|
|
3850
|
+
});
|
|
3851
|
+
});
|
|
3852
|
+
}
|
|
3853
|
+
/**
|
|
3854
|
+
* Tokenize text into lowercase alphanumeric tokens
|
|
3855
|
+
*/
|
|
3856
|
+
tokenize(text) {
|
|
3857
|
+
if (typeof text !== "string") return [];
|
|
3858
|
+
return text.toLowerCase().replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter(Boolean);
|
|
3859
|
+
}
|
|
3860
|
+
/**
|
|
3861
|
+
* Compute IDF (Inverse Document Frequency) with smoothing
|
|
3862
|
+
*/
|
|
3863
|
+
idf(term) {
|
|
3864
|
+
const df = this.termDocFreq[term] || 0;
|
|
3865
|
+
const N = this.documents.length || 1;
|
|
3866
|
+
return Math.log(1 + (N - df + 0.5) / (df + 0.5));
|
|
3867
|
+
}
|
|
3868
|
+
/**
|
|
3869
|
+
* Compute BM25L score for a single document
|
|
3870
|
+
*/
|
|
3871
|
+
score(query, docIndex) {
|
|
3872
|
+
if (typeof query !== "string") return 0;
|
|
3873
|
+
if (docIndex < 0 || docIndex >= this.documents.length) return 0;
|
|
3874
|
+
const tokens = this.tokenize(query);
|
|
3875
|
+
if (tokens.length === 0) return 0;
|
|
3876
|
+
const doc = this.documents[docIndex];
|
|
3877
|
+
const docLength = this.docLengths[docIndex] || 1;
|
|
3878
|
+
const freq = {};
|
|
3879
|
+
for (const t of doc) {
|
|
3880
|
+
freq[t] = (freq[t] || 0) + 1;
|
|
3881
|
+
}
|
|
3882
|
+
let sum = 0;
|
|
3883
|
+
for (const term of tokens) {
|
|
3884
|
+
const tf = freq[term] || 0;
|
|
3885
|
+
if (tf === 0) continue;
|
|
3886
|
+
const idfVal = this.idf(term);
|
|
3887
|
+
let tfL = tf - this.b * (docLength / this.avgDocLength) + this.delta;
|
|
3888
|
+
if (tfL < 0) tfL = 0;
|
|
3889
|
+
sum += idfVal * (tfL / (this.k1 + tfL));
|
|
3890
|
+
}
|
|
3891
|
+
return sum;
|
|
3892
|
+
}
|
|
3893
|
+
/**
|
|
3894
|
+
* Search and rank all documents
|
|
3895
|
+
*/
|
|
3896
|
+
search(query) {
|
|
3897
|
+
return this.documents.map((_, i) => ({
|
|
3898
|
+
index: i,
|
|
3899
|
+
score: this.score(query, i)
|
|
3900
|
+
})).sort((a, b) => b.score - a.score);
|
|
3901
|
+
}
|
|
3902
|
+
};
|
|
3903
|
+
function normalizeScores(scores) {
|
|
3904
|
+
if (scores.length === 0) return [];
|
|
3905
|
+
const min = Math.min(...scores);
|
|
3906
|
+
const max = Math.max(...scores);
|
|
3907
|
+
if (max === min) {
|
|
3908
|
+
return scores.map(() => max === 0 ? 0 : 1);
|
|
3909
|
+
}
|
|
3910
|
+
return scores.map((score) => (score - min) / (max - min));
|
|
3911
|
+
}
|
|
3912
|
+
function hybridRerank(query, items, getDocument, getSemanticScore, options = {}) {
|
|
3913
|
+
const {
|
|
3914
|
+
semanticWeight = 0.7,
|
|
3915
|
+
bm25Weight = 0.3,
|
|
3916
|
+
minScore = 0,
|
|
3917
|
+
k1 = 1.5,
|
|
3918
|
+
b = 0.75,
|
|
3919
|
+
delta = 0.5
|
|
3920
|
+
} = options;
|
|
3921
|
+
if (items.length === 0) return [];
|
|
3922
|
+
const documents = items.map(getDocument);
|
|
3923
|
+
const semanticScores = items.map(getSemanticScore);
|
|
3924
|
+
const bm25 = new BM25L(documents, { k1, b, delta });
|
|
3925
|
+
const bm25Scores = items.map((_, i) => bm25.score(query, i));
|
|
3926
|
+
const normalizedSemantic = normalizeScores(semanticScores);
|
|
3927
|
+
const normalizedBM25 = normalizeScores(bm25Scores);
|
|
3928
|
+
const results = items.map((item, i) => {
|
|
3929
|
+
const hybridScore = semanticWeight * normalizedSemantic[i] + bm25Weight * normalizedBM25[i];
|
|
3930
|
+
return {
|
|
3931
|
+
item,
|
|
3932
|
+
originalIndex: i,
|
|
3933
|
+
semanticScore: semanticScores[i],
|
|
3934
|
+
bm25Score: bm25Scores[i],
|
|
3935
|
+
hybridScore
|
|
3936
|
+
};
|
|
3937
|
+
});
|
|
3938
|
+
return results.filter((r) => r.hybridScore >= minScore).sort((a, b2) => b2.hybridScore - a.hybridScore);
|
|
3939
|
+
}
|
|
3940
|
+
function rerankChromaResults(query, chromaResults, options = {}) {
|
|
3941
|
+
const ids = chromaResults.ids[0] || [];
|
|
3942
|
+
const documents = chromaResults.documents[0] || [];
|
|
3943
|
+
const metadatas = chromaResults.metadatas[0] || [];
|
|
3944
|
+
const distances = chromaResults.distances[0] || [];
|
|
3945
|
+
if (ids.length === 0) return [];
|
|
3946
|
+
const items = ids.map((id, i) => ({
|
|
3947
|
+
id,
|
|
3948
|
+
document: documents[i],
|
|
3949
|
+
metadata: metadatas[i],
|
|
3950
|
+
distance: distances[i]
|
|
3951
|
+
}));
|
|
3952
|
+
const reranked = hybridRerank(
|
|
3953
|
+
query,
|
|
3954
|
+
items,
|
|
3955
|
+
(item) => item.document || "",
|
|
3956
|
+
// Convert L2 distance to similarity score
|
|
3957
|
+
(item) => 1 / (1 + item.distance),
|
|
3958
|
+
options
|
|
3959
|
+
);
|
|
3960
|
+
return reranked.map((r) => ({
|
|
3961
|
+
id: r.item.id,
|
|
3962
|
+
document: r.item.document,
|
|
3963
|
+
metadata: r.item.metadata,
|
|
3964
|
+
distance: r.item.distance,
|
|
3965
|
+
semanticScore: r.semanticScore,
|
|
3966
|
+
bm25Score: r.bm25Score,
|
|
3967
|
+
hybridScore: r.hybridScore
|
|
3968
|
+
}));
|
|
3969
|
+
}
|
|
3970
|
+
function rerankConversationResults(query, results, options = {}) {
|
|
3971
|
+
if (results.length === 0) return [];
|
|
3972
|
+
const reranked = hybridRerank(
|
|
3973
|
+
query,
|
|
3974
|
+
results,
|
|
3975
|
+
(item) => item.userPrompt || "",
|
|
3976
|
+
(item) => item.similarity || 0,
|
|
3977
|
+
options
|
|
3978
|
+
);
|
|
3979
|
+
return reranked.map((r) => ({
|
|
3980
|
+
...r.item,
|
|
3981
|
+
hybridScore: r.hybridScore,
|
|
3982
|
+
bm25Score: r.bm25Score
|
|
3983
|
+
}));
|
|
3984
|
+
}
|
|
3985
|
+
|
|
3792
3986
|
// src/userResponse/conversation-search.ts
|
|
3793
3987
|
var searchConversations = async ({
|
|
3794
3988
|
userPrompt,
|
|
@@ -3835,8 +4029,93 @@ var searchConversations = async ({
|
|
|
3835
4029
|
return null;
|
|
3836
4030
|
}
|
|
3837
4031
|
};
|
|
4032
|
+
var searchConversationsWithReranking = async (options) => {
|
|
4033
|
+
const {
|
|
4034
|
+
userPrompt,
|
|
4035
|
+
collections,
|
|
4036
|
+
userId,
|
|
4037
|
+
similarityThreshold = 0.6,
|
|
4038
|
+
rerankCandidates = 50,
|
|
4039
|
+
// Fetch more candidates for better reranking
|
|
4040
|
+
hybridOptions = {
|
|
4041
|
+
semanticWeight: 0.7,
|
|
4042
|
+
bm25Weight: 0.3
|
|
4043
|
+
}
|
|
4044
|
+
} = options;
|
|
4045
|
+
try {
|
|
4046
|
+
if (!collections || !collections["conversation-history"]) {
|
|
4047
|
+
logger.info("[ConversationSearch] conversation-history collection not registered, skipping");
|
|
4048
|
+
return null;
|
|
4049
|
+
}
|
|
4050
|
+
if (!collections["conversation-history"]["searchMultiple"]) {
|
|
4051
|
+
logger.info("[ConversationSearch] searchMultiple not available, falling back to standard search");
|
|
4052
|
+
return searchConversations({
|
|
4053
|
+
userPrompt,
|
|
4054
|
+
collections,
|
|
4055
|
+
userId,
|
|
4056
|
+
similarityThreshold
|
|
4057
|
+
});
|
|
4058
|
+
}
|
|
4059
|
+
logger.info(`[ConversationSearch] Hybrid search for: "${userPrompt.substring(0, 50)}..."`);
|
|
4060
|
+
logger.info(`[ConversationSearch] Fetching ${rerankCandidates} candidates for reranking`);
|
|
4061
|
+
logger.info(`[ConversationSearch] Weights - Semantic: ${hybridOptions.semanticWeight}, BM25: ${hybridOptions.bm25Weight}`);
|
|
4062
|
+
const results = await collections["conversation-history"]["searchMultiple"]({
|
|
4063
|
+
userPrompt,
|
|
4064
|
+
userId,
|
|
4065
|
+
limit: rerankCandidates,
|
|
4066
|
+
threshold: 0
|
|
4067
|
+
// No threshold - get all candidates for reranking
|
|
4068
|
+
});
|
|
4069
|
+
if (!results || results.length === 0) {
|
|
4070
|
+
logger.info("[ConversationSearch] No conversations found in database");
|
|
4071
|
+
return null;
|
|
4072
|
+
}
|
|
4073
|
+
logger.info(`[ConversationSearch] Retrieved ${results.length} candidates for reranking`);
|
|
4074
|
+
const candidatesForReranking = results.map((r) => ({
|
|
4075
|
+
...r,
|
|
4076
|
+
userPrompt: r.metadata?.userPrompt || ""
|
|
4077
|
+
}));
|
|
4078
|
+
const reranked = rerankConversationResults(userPrompt, candidatesForReranking, hybridOptions);
|
|
4079
|
+
if (reranked.length === 0) {
|
|
4080
|
+
logger.info("[ConversationSearch] No results after reranking");
|
|
4081
|
+
return null;
|
|
4082
|
+
}
|
|
4083
|
+
const best = reranked[0];
|
|
4084
|
+
const hybridScore = best.hybridScore;
|
|
4085
|
+
const semanticScore = best.similarity || 0;
|
|
4086
|
+
const matchedUserPrompt = best.userPrompt || best.metadata?.userPrompt || "";
|
|
4087
|
+
logger.info(`[ConversationSearch] Best match after reranking:`);
|
|
4088
|
+
logger.info(` - Hybrid score: ${(hybridScore * 100).toFixed(2)}%`);
|
|
4089
|
+
logger.info(` - Semantic score: ${(semanticScore * 100).toFixed(2)}%`);
|
|
4090
|
+
logger.info(` - BM25L score: ${best.bm25Score.toFixed(4)}`);
|
|
4091
|
+
logger.info(` - Matched prompt: "${matchedUserPrompt}"`);
|
|
4092
|
+
logger.info(` - Query prompt: "${userPrompt}"`);
|
|
4093
|
+
if (semanticScore < similarityThreshold) {
|
|
4094
|
+
logger.info(
|
|
4095
|
+
`[ConversationSearch] Semantic score ${(semanticScore * 100).toFixed(2)}% below threshold ${(similarityThreshold * 100).toFixed(2)}% - rejecting match`
|
|
4096
|
+
);
|
|
4097
|
+
return null;
|
|
4098
|
+
}
|
|
4099
|
+
logger.info(
|
|
4100
|
+
`[ConversationSearch] \u2713 Found match with semantic score ${(semanticScore * 100).toFixed(2)}%`
|
|
4101
|
+
);
|
|
4102
|
+
logger.info(` - Returning cached result for: "${matchedUserPrompt}"`);
|
|
4103
|
+
return {
|
|
4104
|
+
uiBlock: best.uiBlock,
|
|
4105
|
+
similarity: semanticScore,
|
|
4106
|
+
hybridScore,
|
|
4107
|
+
bm25Score: best.bm25Score,
|
|
4108
|
+
metadata: best.metadata
|
|
4109
|
+
};
|
|
4110
|
+
} catch (error) {
|
|
4111
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
4112
|
+
logger.warn(`[ConversationSearch] Error in hybrid search: ${errorMsg}`);
|
|
4113
|
+
return null;
|
|
4114
|
+
}
|
|
4115
|
+
};
|
|
3838
4116
|
var ConversationSearch = {
|
|
3839
|
-
searchConversations
|
|
4117
|
+
searchConversations,
|
|
4118
|
+
searchConversationsWithReranking
|
|
3840
4119
|
};
|
|
3841
4120
|
var conversation_search_default = ConversationSearch;
|
|
3842
4121
|
|
|
@@ -3885,7 +4164,7 @@ var BaseLLM = class {
|
|
|
3885
4164
|
* @param componentStreamCallback - Optional callback to stream primary KPI component as soon as it's identified
|
|
3886
4165
|
* @returns Object containing matched components, layout title/description, and follow-up actions
|
|
3887
4166
|
*/
|
|
3888
|
-
async matchComponentsFromAnalysis(analysisContent, components, apiKey, logCollector, componentStreamCallback) {
|
|
4167
|
+
async matchComponentsFromAnalysis(analysisContent, components, apiKey, logCollector, componentStreamCallback, deferredTools, executedTools) {
|
|
3889
4168
|
try {
|
|
3890
4169
|
logger.debug(`[${this.getProviderName()}] Starting component matching from text response`);
|
|
3891
4170
|
let availableComponentsText = "No components available";
|
|
@@ -3901,12 +4180,44 @@ var BaseLLM = class {
|
|
|
3901
4180
|
Props Structure: ${propsPreview}`;
|
|
3902
4181
|
}).join("\n\n");
|
|
3903
4182
|
}
|
|
4183
|
+
let deferredToolsText = "No deferred external tools for this request.";
|
|
4184
|
+
if (deferredTools && deferredTools.length > 0) {
|
|
4185
|
+
logger.info(`[${this.getProviderName()}] Passing ${deferredTools.length} deferred tools to component matching`);
|
|
4186
|
+
deferredToolsText = "The following external tools need user input via a Form component.\n**IMPORTANT: Use these EXACT values when generating Form externalTool prop.**\n\n" + deferredTools.map((tool, idx) => {
|
|
4187
|
+
return `${idx + 1}. **${tool.name}**
|
|
4188
|
+
toolId: "${tool.id}" (USE THIS EXACT VALUE - do not modify!)
|
|
4189
|
+
toolName: "${tool.name}"
|
|
4190
|
+
parameters: ${JSON.stringify(tool.params || {})}
|
|
4191
|
+
requiredFields:
|
|
4192
|
+
${JSON.stringify(tool.requiredFields || [], null, 2)}`;
|
|
4193
|
+
}).join("\n\n");
|
|
4194
|
+
}
|
|
4195
|
+
let executedToolsText = "No external tools were executed for data fetching.";
|
|
4196
|
+
if (executedTools && executedTools.length > 0) {
|
|
4197
|
+
logger.info(`[${this.getProviderName()}] Passing ${executedTools.length} executed tools to component matching`);
|
|
4198
|
+
executedToolsText = "The following external tools were executed to fetch data.\n**IMPORTANT: For components displaying this data, use externalTool prop instead of query.**\n**IMPORTANT: Use the result data to populate deferred tool parameters when applicable.**\n\n" + executedTools.map((tool, idx) => {
|
|
4199
|
+
let resultPreview = "No result data";
|
|
4200
|
+
if (tool.result) {
|
|
4201
|
+
const resultStr = typeof tool.result === "string" ? tool.result : JSON.stringify(tool.result, null, 2);
|
|
4202
|
+
resultPreview = resultStr.length > 2e3 ? resultStr.substring(0, 2e3) + "\n... (truncated)" : resultStr;
|
|
4203
|
+
}
|
|
4204
|
+
return `${idx + 1}. **${tool.name}**
|
|
4205
|
+
toolId: "${tool.id}" (USE THIS EXACT VALUE for externalTool.toolId)
|
|
4206
|
+
toolName: "${tool.name}" (USE THIS EXACT VALUE for externalTool.toolName)
|
|
4207
|
+
parameters: ${JSON.stringify(tool.params || {})} (USE THESE for externalTool.parameters)
|
|
4208
|
+
result: ${resultPreview}`;
|
|
4209
|
+
}).join("\n\n");
|
|
4210
|
+
}
|
|
3904
4211
|
const schemaDoc = schema.generateSchemaDocumentation();
|
|
3905
4212
|
logger.file("\n=============================\nText analysis response:", analysisContent);
|
|
4213
|
+
logger.file("\n=============================\nDeferred tools:", deferredToolsText);
|
|
4214
|
+
logger.file("\n=============================\nExecuted tools:", executedToolsText);
|
|
3906
4215
|
const prompts = await promptLoader.loadPrompts("match-text-components", {
|
|
3907
4216
|
ANALYSIS_CONTENT: analysisContent,
|
|
3908
4217
|
AVAILABLE_COMPONENTS: availableComponentsText,
|
|
3909
|
-
SCHEMA_DOC: schemaDoc
|
|
4218
|
+
SCHEMA_DOC: schemaDoc,
|
|
4219
|
+
DEFERRED_TOOLS: deferredToolsText,
|
|
4220
|
+
EXECUTED_TOOLS: executedToolsText
|
|
3910
4221
|
});
|
|
3911
4222
|
logger.debug(`[${this.getProviderName()}] Loaded match-text-components prompts`);
|
|
3912
4223
|
logger.file("\n=============================\nmatch text components system prompt:", prompts.system);
|
|
@@ -4026,9 +4337,6 @@ var BaseLLM = class {
|
|
|
4026
4337
|
matchedComponents.forEach((comp, idx) => {
|
|
4027
4338
|
logger.info(`[${this.getProviderName()}] ${idx + 1}. ${comp.componentType} (${comp.componentName}) - ${comp.originalSuggestion || "N/A"}`);
|
|
4028
4339
|
});
|
|
4029
|
-
if (suggestedComponents.length !== matchedComponents.length) {
|
|
4030
|
-
logger.warn(`[${this.getProviderName()}] \u26A0\uFE0F MISMATCH: Text suggested ${suggestedComponents.length} components, but LLM matched ${matchedComponents.length}`);
|
|
4031
|
-
}
|
|
4032
4340
|
logger.file("\n=============================\nFull LLM response:", JSON.stringify(result, null, 2));
|
|
4033
4341
|
const rawActions = result.actions || [];
|
|
4034
4342
|
const actions = convertQuestionsToActions(rawActions);
|
|
@@ -4250,21 +4558,44 @@ var BaseLLM = class {
|
|
|
4250
4558
|
let availableToolsDoc = "No external tools are available for this request.";
|
|
4251
4559
|
if (externalTools && externalTools.length > 0) {
|
|
4252
4560
|
logger.info(`[${this.getProviderName()}] External tools available: ${externalTools.map((t) => t.name).join(", ")}`);
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
}
|
|
4259
|
-
|
|
4561
|
+
const immediateTools = externalTools.filter((t) => t.executionType === "immediate" || t.executionType === "deferred" && t.userProvidedData);
|
|
4562
|
+
const deferredTools = externalTools.filter((t) => t.executionType === "deferred" && !t.userProvidedData);
|
|
4563
|
+
let toolsDocParts = [];
|
|
4564
|
+
if (immediateTools.length > 0) {
|
|
4565
|
+
const immediateDoc = "## IMMEDIATE EXECUTION TOOLS\nExecute these tools right away:\n\n" + immediateTools.map((tool, idx) => {
|
|
4566
|
+
const paramsText = Object.entries(tool.params || {}).map(([key, value]) => {
|
|
4567
|
+
const valueType = typeof value;
|
|
4568
|
+
if (valueType === "string" && ["string", "number", "integer", "boolean", "array", "object"].includes(String(value).toLowerCase())) {
|
|
4569
|
+
return `- ${key}: ${value}`;
|
|
4570
|
+
} else {
|
|
4571
|
+
return `- ${key}: ${JSON.stringify(value)} (default value - use this)`;
|
|
4572
|
+
}
|
|
4573
|
+
}).join("\n ");
|
|
4574
|
+
let userDataText = "";
|
|
4575
|
+
if (tool.userProvidedData) {
|
|
4576
|
+
userDataText = "\n **User Provided Data** (use these values):\n " + Object.entries(tool.userProvidedData).map(([key, value]) => `- ${key}: ${JSON.stringify(value)}`).join("\n ");
|
|
4260
4577
|
}
|
|
4261
|
-
|
|
4262
|
-
|
|
4578
|
+
return `${idx + 1}. **${tool.name}** (ID: ${tool.id})
|
|
4579
|
+
Execution Type: IMMEDIATE
|
|
4263
4580
|
Description: ${tool.description}
|
|
4264
|
-
**ACTION REQUIRED**: Call this tool with the parameters below
|
|
4265
4581
|
Parameters:
|
|
4266
|
-
${paramsText}`;
|
|
4267
|
-
|
|
4582
|
+
${paramsText}${userDataText}`;
|
|
4583
|
+
}).join("\n\n");
|
|
4584
|
+
toolsDocParts.push(immediateDoc);
|
|
4585
|
+
}
|
|
4586
|
+
if (deferredTools.length > 0) {
|
|
4587
|
+
const deferredDoc = "## DEFERRED TOOLS (DO NOT EXECUTE)\nThese tools need user input. A Form component will be generated to collect the data.\n**DO NOT call these tools.** Instead, acknowledge the request and inform user that a form will be shown.\n\n" + deferredTools.map((tool, idx) => {
|
|
4588
|
+
const requiredFieldsText = (tool.requiredFields || []).map((f) => `- ${f.label || f.name} (${f.type})${f.required ? " *required*" : ""}`).join("\n ");
|
|
4589
|
+
return `${idx + 1}. **${tool.name}** (ID: ${tool.id})
|
|
4590
|
+
Execution Type: DEFERRED (needs form input)
|
|
4591
|
+
Description: ${tool.description}
|
|
4592
|
+
Reason: ${tool.executionReason || "Write operation requires user confirmation"}
|
|
4593
|
+
Required Fields:
|
|
4594
|
+
${requiredFieldsText || "(fields will be determined by form)"}`;
|
|
4595
|
+
}).join("\n\n");
|
|
4596
|
+
toolsDocParts.push(deferredDoc);
|
|
4597
|
+
}
|
|
4598
|
+
availableToolsDoc = toolsDocParts.join("\n\n---\n\n");
|
|
4268
4599
|
}
|
|
4269
4600
|
const schemaDoc = schema.generateSchemaDocumentation();
|
|
4270
4601
|
const knowledgeBaseContext = await knowledge_base_default.getKnowledgeBase({
|
|
@@ -4305,8 +4636,12 @@ var BaseLLM = class {
|
|
|
4305
4636
|
}
|
|
4306
4637
|
}];
|
|
4307
4638
|
if (externalTools && externalTools.length > 0) {
|
|
4308
|
-
externalTools.
|
|
4309
|
-
|
|
4639
|
+
const executableTools = externalTools.filter(
|
|
4640
|
+
(t) => t.executionType === "immediate" || t.executionType === "deferred" && t.userProvidedData
|
|
4641
|
+
);
|
|
4642
|
+
logger.info(`[${this.getProviderName()}] Executable tools: ${executableTools.length} of ${externalTools.length} total`);
|
|
4643
|
+
executableTools.forEach((tool) => {
|
|
4644
|
+
logger.info(`[${this.getProviderName()}] Processing executable tool:`, JSON.stringify(tool, null, 2));
|
|
4310
4645
|
const properties = {};
|
|
4311
4646
|
const required = [];
|
|
4312
4647
|
Object.entries(tool.params || {}).forEach(([key, typeOrValue]) => {
|
|
@@ -4375,13 +4710,14 @@ var BaseLLM = class {
|
|
|
4375
4710
|
input_schema: inputSchema
|
|
4376
4711
|
});
|
|
4377
4712
|
});
|
|
4378
|
-
logger.info(`[${this.getProviderName()}] Added ${
|
|
4713
|
+
logger.info(`[${this.getProviderName()}] Added ${executableTools.length} executable tools to tool calling capability (${externalTools.length - executableTools.length} deferred tools await form input)`);
|
|
4379
4714
|
logger.info(`[${this.getProviderName()}] Complete tools array:`, JSON.stringify(tools, null, 2));
|
|
4380
4715
|
}
|
|
4381
4716
|
const queryAttempts = /* @__PURE__ */ new Map();
|
|
4382
4717
|
const MAX_QUERY_ATTEMPTS = 6;
|
|
4383
4718
|
const toolAttempts = /* @__PURE__ */ new Map();
|
|
4384
4719
|
const MAX_TOOL_ATTEMPTS = 3;
|
|
4720
|
+
const executedToolsList = [];
|
|
4385
4721
|
let maxAttemptsReached = false;
|
|
4386
4722
|
let fullStreamedText = "";
|
|
4387
4723
|
const wrappedStreamCallback = streamCallback ? (chunk) => {
|
|
@@ -4564,6 +4900,17 @@ Please try rephrasing your request or contact support.
|
|
|
4564
4900
|
const result2 = await externalTool.fn(toolInput);
|
|
4565
4901
|
logger.info(`[${this.getProviderName()}] External tool ${externalTool.name} executed successfully`);
|
|
4566
4902
|
logCollector?.info(`\u2713 ${externalTool.name} executed successfully`);
|
|
4903
|
+
if (!executedToolsList.find((t) => t.id === externalTool.id)) {
|
|
4904
|
+
executedToolsList.push({
|
|
4905
|
+
id: externalTool.id,
|
|
4906
|
+
name: externalTool.name,
|
|
4907
|
+
params: toolInput,
|
|
4908
|
+
// The actual parameters used in this execution
|
|
4909
|
+
result: result2
|
|
4910
|
+
// Store the actual result data for populating deferred tool params
|
|
4911
|
+
});
|
|
4912
|
+
logger.info(`[${this.getProviderName()}] Tracked executed tool: ${externalTool.name} with params: ${JSON.stringify(toolInput)}`);
|
|
4913
|
+
}
|
|
4567
4914
|
if (wrappedStreamCallback) {
|
|
4568
4915
|
wrappedStreamCallback(`\u2705 **${externalTool.name} completed successfully**
|
|
4569
4916
|
|
|
@@ -4653,12 +5000,31 @@ ${errorMsg}
|
|
|
4653
5000
|
wrappedStreamCallback(answerMarker);
|
|
4654
5001
|
logger.info(`[${this.getProviderName()}] Streamed answer component to frontend: ${component.name} (${component.type})`);
|
|
4655
5002
|
} : void 0;
|
|
5003
|
+
const deferredTools = externalTools?.filter((t) => {
|
|
5004
|
+
if (t.executionType === "deferred" && !t.userProvidedData) return true;
|
|
5005
|
+
if (category === "data_modification" && !t.userProvidedData) {
|
|
5006
|
+
const name = (t.name || t.id || "").toLowerCase();
|
|
5007
|
+
const isWriteOperation = /create|add|insert|new|update|edit|modify|delete|remove|send/.test(name);
|
|
5008
|
+
if (isWriteOperation) {
|
|
5009
|
+
logger.info(`[${this.getProviderName()}] Inferred deferred execution for tool: ${t.name}`);
|
|
5010
|
+
return true;
|
|
5011
|
+
}
|
|
5012
|
+
}
|
|
5013
|
+
return false;
|
|
5014
|
+
}) || [];
|
|
5015
|
+
if (deferredTools.length > 0) {
|
|
5016
|
+
logger.info(`[${this.getProviderName()}] Passing ${deferredTools.length} deferred tools for Form generation`);
|
|
5017
|
+
}
|
|
5018
|
+
logger.info(`[${this.getProviderName()}] passing deferred tools to the matching function: ${JSON.stringify(deferredTools, null, 2)}`);
|
|
5019
|
+
logger.info(`[${this.getProviderName()}] passing executed tools to the matching function: ${JSON.stringify(executedToolsList, null, 2)}`);
|
|
4656
5020
|
const matchResult = await this.matchComponentsFromAnalysis(
|
|
4657
5021
|
textResponse,
|
|
4658
5022
|
components,
|
|
4659
5023
|
apiKey,
|
|
4660
5024
|
logCollector,
|
|
4661
|
-
componentStreamCallback
|
|
5025
|
+
componentStreamCallback,
|
|
5026
|
+
deferredTools,
|
|
5027
|
+
executedToolsList
|
|
4662
5028
|
);
|
|
4663
5029
|
matchedComponents = matchResult.components;
|
|
4664
5030
|
layoutTitle = matchResult.layoutTitle;
|
|
@@ -4727,23 +5093,20 @@ ${errorMsg}
|
|
|
4727
5093
|
*/
|
|
4728
5094
|
async handleUserRequest(userPrompt, components, apiKey, logCollector, conversationHistory, responseMode = "text", streamCallback, collections, externalTools, userId) {
|
|
4729
5095
|
const startTime = Date.now();
|
|
4730
|
-
logger.info(`[${this.getProviderName()}] handleUserRequest called
|
|
5096
|
+
logger.info(`[${this.getProviderName()}] handleUserRequest called for user prompt: ${userPrompt}`);
|
|
4731
5097
|
logCollector?.info(`Starting request processing with mode: ${responseMode}`);
|
|
4732
5098
|
try {
|
|
4733
5099
|
logger.info(`[${this.getProviderName()}] Step 1: Searching previous conversations...`);
|
|
4734
5100
|
logCollector?.info("Step 1: Searching for similar previous conversations...");
|
|
4735
|
-
const conversationMatch = await conversation_search_default.
|
|
5101
|
+
const conversationMatch = await conversation_search_default.searchConversationsWithReranking({
|
|
4736
5102
|
userPrompt,
|
|
4737
5103
|
collections,
|
|
4738
5104
|
userId,
|
|
4739
5105
|
similarityThreshold: 0.6
|
|
4740
5106
|
// 60% threshold
|
|
4741
5107
|
});
|
|
4742
|
-
logger.info("conversationMatch:", conversationMatch);
|
|
4743
5108
|
if (conversationMatch) {
|
|
4744
|
-
logger.info(
|
|
4745
|
-
`[${this.getProviderName()}] \u2713 Found matching conversation with ${(conversationMatch.similarity * 100).toFixed(2)}% similarity`
|
|
4746
|
-
);
|
|
5109
|
+
logger.info(`[${this.getProviderName()}] \u2713 Found matching conversation with ${(conversationMatch.similarity * 100).toFixed(2)}% similarity`);
|
|
4747
5110
|
logCollector?.info(
|
|
4748
5111
|
`\u2713 Found similar conversation (${(conversationMatch.similarity * 100).toFixed(2)}% match)`
|
|
4749
5112
|
);
|
|
@@ -4751,7 +5114,6 @@ ${errorMsg}
|
|
|
4751
5114
|
const isValidComponent = rawComponent && typeof rawComponent === "object" && Object.keys(rawComponent).length > 0;
|
|
4752
5115
|
const component = isValidComponent ? rawComponent : null;
|
|
4753
5116
|
const cachedTextResponse = conversationMatch.uiBlock?.analysis || conversationMatch.uiBlock?.textResponse || conversationMatch.uiBlock?.text || "";
|
|
4754
|
-
logger.debug(`[${this.getProviderName()}] Cached component: ${component ? "present" : "null"}, cachedTextResponse: ${cachedTextResponse ? cachedTextResponse.substring(0, 50) + "..." : "empty"}`);
|
|
4755
5117
|
if (this.containsFormComponent(component)) {
|
|
4756
5118
|
logger.info(`[${this.getProviderName()}] Skipping cached result - Form components contain stale defaultValues, fetching fresh data`);
|
|
4757
5119
|
logCollector?.info("Skipping cache for form - fetching current values from database...");
|
|
@@ -4849,22 +5211,31 @@ ${errorMsg}
|
|
|
4849
5211
|
if (categoryClassification.externalTools && categoryClassification.externalTools.length > 0) {
|
|
4850
5212
|
logger.info(`[${this.getProviderName()}] Identified ${categoryClassification.externalTools.length} external tools needed`);
|
|
4851
5213
|
logCollector?.info(`Identified external tools: ${categoryClassification.externalTools.map((t) => t.name || t.type).join(", ")}`);
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
5214
|
+
logger.info(`[${this.getProviderName()}] Raw external tools from classification: ${JSON.stringify(categoryClassification.externalTools, null, 2)}`);
|
|
5215
|
+
toolsToUse = categoryClassification.externalTools?.map((t) => {
|
|
5216
|
+
const realTool = externalTools?.find((tool) => tool.id === t.type);
|
|
5217
|
+
logger.info(`[${this.getProviderName()}] Tool ${t.name}: executionType=${t.executionType}, userProvidedData=${t.userProvidedData ? "present" : "null"}`);
|
|
5218
|
+
return {
|
|
5219
|
+
id: t.type,
|
|
5220
|
+
name: t.name,
|
|
5221
|
+
description: t.description,
|
|
5222
|
+
params: t.parameters || {},
|
|
5223
|
+
// NEW: Include execution type info from category classification
|
|
5224
|
+
executionType: t.executionType || "immediate",
|
|
5225
|
+
executionReason: t.executionReason || "",
|
|
5226
|
+
requiredFields: t.requiredFields || [],
|
|
5227
|
+
userProvidedData: t.userProvidedData || null,
|
|
5228
|
+
fn: (() => {
|
|
5229
|
+
if (realTool) {
|
|
5230
|
+
logger.info(`[${this.getProviderName()}] Using real tool implementation for ${t.type}`);
|
|
5231
|
+
return realTool.fn;
|
|
5232
|
+
} else {
|
|
5233
|
+
logger.warn(`[${this.getProviderName()}] Tool ${t.type} not found in registered tools`);
|
|
5234
|
+
return async () => ({ success: false, message: `Tool ${t.name || t.type} not registered` });
|
|
5235
|
+
}
|
|
5236
|
+
})()
|
|
5237
|
+
};
|
|
5238
|
+
}) || [];
|
|
4868
5239
|
}
|
|
4869
5240
|
if (categoryClassification.category === "general") {
|
|
4870
5241
|
logger.info(`[${this.getProviderName()}] Routing to general conversation (no database operations)`);
|
|
@@ -5555,7 +5926,6 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
|
|
|
5555
5926
|
}
|
|
5556
5927
|
logCollector.info(`Starting user prompt request with ${components.length} components`);
|
|
5557
5928
|
const conversationHistory = thread.getConversationContext(CONTEXT_CONFIG.MAX_CONVERSATION_CONTEXT_BLOCKS, existingUiBlockId);
|
|
5558
|
-
logger.info("conversationHistory", conversationHistory);
|
|
5559
5929
|
const responseMode = payload.responseMode || "component";
|
|
5560
5930
|
logger.info("responseMode", responseMode);
|
|
5561
5931
|
let streamCallback;
|
|
@@ -7885,6 +8255,458 @@ function sendResponse7(id, res, sendMessage, clientId) {
|
|
|
7885
8255
|
sendMessage(response);
|
|
7886
8256
|
}
|
|
7887
8257
|
|
|
8258
|
+
// src/handlers/kb-nodes.ts
|
|
8259
|
+
async function handleKbNodesRequest(data, collections, sendMessage) {
|
|
8260
|
+
const executeCollection = async (collection, op, params) => {
|
|
8261
|
+
const handler = collections[collection]?.[op];
|
|
8262
|
+
if (!handler) {
|
|
8263
|
+
throw new Error(`Collection '${collection}' or operation '${op}' not found`);
|
|
8264
|
+
}
|
|
8265
|
+
return await handler(params);
|
|
8266
|
+
};
|
|
8267
|
+
try {
|
|
8268
|
+
const request = KbNodesRequestMessageSchema.parse(data);
|
|
8269
|
+
const { id, payload, from } = request;
|
|
8270
|
+
const { operation, data: requestData } = payload;
|
|
8271
|
+
const nodeId = requestData?.id;
|
|
8272
|
+
const title = requestData?.title;
|
|
8273
|
+
const content = requestData?.content;
|
|
8274
|
+
const category = requestData?.category;
|
|
8275
|
+
const tags = requestData?.tags;
|
|
8276
|
+
const createdBy = requestData?.createdBy;
|
|
8277
|
+
const updatedBy = requestData?.updatedBy;
|
|
8278
|
+
const userId = requestData?.userId;
|
|
8279
|
+
const query = requestData?.query;
|
|
8280
|
+
const filters = requestData?.filters;
|
|
8281
|
+
const limit = requestData?.limit;
|
|
8282
|
+
const offset = requestData?.offset;
|
|
8283
|
+
switch (operation) {
|
|
8284
|
+
case "create":
|
|
8285
|
+
await handleCreate6(id, { title, content, category, tags, createdBy }, executeCollection, sendMessage, from.id);
|
|
8286
|
+
break;
|
|
8287
|
+
case "update":
|
|
8288
|
+
await handleUpdate6(id, nodeId, { title, content, category, tags, updatedBy }, executeCollection, sendMessage, from.id);
|
|
8289
|
+
break;
|
|
8290
|
+
case "delete":
|
|
8291
|
+
await handleDelete6(id, nodeId, executeCollection, sendMessage, from.id);
|
|
8292
|
+
break;
|
|
8293
|
+
case "getAll":
|
|
8294
|
+
await handleGetAll6(id, limit, offset, executeCollection, sendMessage, from.id);
|
|
8295
|
+
break;
|
|
8296
|
+
case "getOne":
|
|
8297
|
+
await handleGetOne6(id, nodeId, executeCollection, sendMessage, from.id);
|
|
8298
|
+
break;
|
|
8299
|
+
case "search":
|
|
8300
|
+
await handleSearch(id, { query, category, tags, createdBy, limit, offset }, executeCollection, sendMessage, from.id);
|
|
8301
|
+
break;
|
|
8302
|
+
case "getByCategory":
|
|
8303
|
+
await handleGetByCategory(id, category, limit, offset, executeCollection, sendMessage, from.id);
|
|
8304
|
+
break;
|
|
8305
|
+
case "getByUser":
|
|
8306
|
+
await handleGetByUser(id, userId, limit, offset, executeCollection, sendMessage, from.id);
|
|
8307
|
+
break;
|
|
8308
|
+
case "getCategories":
|
|
8309
|
+
await handleGetCategories(id, executeCollection, sendMessage, from.id);
|
|
8310
|
+
break;
|
|
8311
|
+
case "getTags":
|
|
8312
|
+
await handleGetTags(id, executeCollection, sendMessage, from.id);
|
|
8313
|
+
break;
|
|
8314
|
+
default:
|
|
8315
|
+
sendResponse8(id, {
|
|
8316
|
+
success: false,
|
|
8317
|
+
error: `Unknown operation: ${operation}`
|
|
8318
|
+
}, sendMessage, from.id);
|
|
8319
|
+
}
|
|
8320
|
+
} catch (error) {
|
|
8321
|
+
logger.error("Failed to handle KB nodes request:", error);
|
|
8322
|
+
sendResponse8(null, {
|
|
8323
|
+
success: false,
|
|
8324
|
+
error: error instanceof Error ? error.message : "Unknown error occurred"
|
|
8325
|
+
}, sendMessage);
|
|
8326
|
+
}
|
|
8327
|
+
}
|
|
8328
|
+
async function handleCreate6(id, nodeData, executeCollection, sendMessage, clientId) {
|
|
8329
|
+
const { title, content, category, tags, createdBy } = nodeData;
|
|
8330
|
+
if (!title || title.trim().length === 0) {
|
|
8331
|
+
sendResponse8(id, {
|
|
8332
|
+
success: false,
|
|
8333
|
+
error: "Title is required and cannot be empty"
|
|
8334
|
+
}, sendMessage, clientId);
|
|
8335
|
+
return;
|
|
8336
|
+
}
|
|
8337
|
+
if (!content || content.trim().length === 0) {
|
|
8338
|
+
sendResponse8(id, {
|
|
8339
|
+
success: false,
|
|
8340
|
+
error: "Content is required and cannot be empty"
|
|
8341
|
+
}, sendMessage, clientId);
|
|
8342
|
+
return;
|
|
8343
|
+
}
|
|
8344
|
+
if (!createdBy) {
|
|
8345
|
+
sendResponse8(id, {
|
|
8346
|
+
success: false,
|
|
8347
|
+
error: "createdBy (user ID) is required"
|
|
8348
|
+
}, sendMessage, clientId);
|
|
8349
|
+
return;
|
|
8350
|
+
}
|
|
8351
|
+
try {
|
|
8352
|
+
const result = await executeCollection("kbNodes", "create", {
|
|
8353
|
+
title,
|
|
8354
|
+
content,
|
|
8355
|
+
category: category || void 0,
|
|
8356
|
+
tags: tags || void 0,
|
|
8357
|
+
createdBy
|
|
8358
|
+
});
|
|
8359
|
+
if (result && result.success) {
|
|
8360
|
+
logger.info(`[DB] KB node created successfully: ${title}`);
|
|
8361
|
+
sendResponse8(id, {
|
|
8362
|
+
success: true,
|
|
8363
|
+
data: {
|
|
8364
|
+
...result.data,
|
|
8365
|
+
message: `Knowledge node '${title}' created successfully`
|
|
8366
|
+
}
|
|
8367
|
+
}, sendMessage, clientId);
|
|
8368
|
+
return;
|
|
8369
|
+
}
|
|
8370
|
+
sendResponse8(id, {
|
|
8371
|
+
success: false,
|
|
8372
|
+
error: "Failed to create knowledge node"
|
|
8373
|
+
}, sendMessage, clientId);
|
|
8374
|
+
} catch (error) {
|
|
8375
|
+
logger.error("[DB] Failed to create KB node:", error);
|
|
8376
|
+
sendResponse8(id, {
|
|
8377
|
+
success: false,
|
|
8378
|
+
error: error instanceof Error ? error.message : "Failed to create knowledge node"
|
|
8379
|
+
}, sendMessage, clientId);
|
|
8380
|
+
}
|
|
8381
|
+
}
|
|
8382
|
+
async function handleUpdate6(id, nodeId, nodeData, executeCollection, sendMessage, clientId) {
|
|
8383
|
+
const { title, content, category, tags, updatedBy } = nodeData;
|
|
8384
|
+
if (!nodeId) {
|
|
8385
|
+
sendResponse8(id, {
|
|
8386
|
+
success: false,
|
|
8387
|
+
error: "Knowledge node ID is required"
|
|
8388
|
+
}, sendMessage, clientId);
|
|
8389
|
+
return;
|
|
8390
|
+
}
|
|
8391
|
+
if (!updatedBy) {
|
|
8392
|
+
sendResponse8(id, {
|
|
8393
|
+
success: false,
|
|
8394
|
+
error: "updatedBy (user ID) is required"
|
|
8395
|
+
}, sendMessage, clientId);
|
|
8396
|
+
return;
|
|
8397
|
+
}
|
|
8398
|
+
try {
|
|
8399
|
+
const result = await executeCollection("kbNodes", "update", {
|
|
8400
|
+
id: nodeId,
|
|
8401
|
+
title,
|
|
8402
|
+
content,
|
|
8403
|
+
category,
|
|
8404
|
+
tags,
|
|
8405
|
+
updatedBy
|
|
8406
|
+
});
|
|
8407
|
+
if (result && result.success) {
|
|
8408
|
+
logger.info(`[DB] KB node updated successfully, ID: ${nodeId}`);
|
|
8409
|
+
sendResponse8(id, {
|
|
8410
|
+
success: true,
|
|
8411
|
+
data: {
|
|
8412
|
+
...result.data,
|
|
8413
|
+
message: `Knowledge node updated successfully`
|
|
8414
|
+
}
|
|
8415
|
+
}, sendMessage, clientId);
|
|
8416
|
+
return;
|
|
8417
|
+
}
|
|
8418
|
+
sendResponse8(id, {
|
|
8419
|
+
success: false,
|
|
8420
|
+
error: "Failed to update knowledge node"
|
|
8421
|
+
}, sendMessage, clientId);
|
|
8422
|
+
} catch (error) {
|
|
8423
|
+
logger.error("[DB] Failed to update KB node:", error);
|
|
8424
|
+
sendResponse8(id, {
|
|
8425
|
+
success: false,
|
|
8426
|
+
error: error instanceof Error ? error.message : "Failed to update knowledge node"
|
|
8427
|
+
}, sendMessage, clientId);
|
|
8428
|
+
}
|
|
8429
|
+
}
|
|
8430
|
+
async function handleDelete6(id, nodeId, executeCollection, sendMessage, clientId) {
|
|
8431
|
+
if (!nodeId) {
|
|
8432
|
+
sendResponse8(id, {
|
|
8433
|
+
success: false,
|
|
8434
|
+
error: "Knowledge node ID is required"
|
|
8435
|
+
}, sendMessage, clientId);
|
|
8436
|
+
return;
|
|
8437
|
+
}
|
|
8438
|
+
try {
|
|
8439
|
+
const result = await executeCollection("kbNodes", "delete", { id: nodeId });
|
|
8440
|
+
if (result && result.success) {
|
|
8441
|
+
logger.info(`[DB] KB node deleted successfully, ID: ${nodeId}`);
|
|
8442
|
+
sendResponse8(id, {
|
|
8443
|
+
success: true,
|
|
8444
|
+
data: {
|
|
8445
|
+
id: nodeId,
|
|
8446
|
+
...result.data,
|
|
8447
|
+
message: `Knowledge node deleted successfully`
|
|
8448
|
+
}
|
|
8449
|
+
}, sendMessage, clientId);
|
|
8450
|
+
return;
|
|
8451
|
+
}
|
|
8452
|
+
sendResponse8(id, {
|
|
8453
|
+
success: false,
|
|
8454
|
+
error: "Failed to delete knowledge node"
|
|
8455
|
+
}, sendMessage, clientId);
|
|
8456
|
+
} catch (error) {
|
|
8457
|
+
logger.error("[DB] Failed to delete KB node:", error);
|
|
8458
|
+
sendResponse8(id, {
|
|
8459
|
+
success: false,
|
|
8460
|
+
error: error instanceof Error ? error.message : "Failed to delete knowledge node"
|
|
8461
|
+
}, sendMessage, clientId);
|
|
8462
|
+
}
|
|
8463
|
+
}
|
|
8464
|
+
async function handleGetAll6(id, limit, offset, executeCollection, sendMessage, clientId) {
|
|
8465
|
+
try {
|
|
8466
|
+
const result = await executeCollection("kbNodes", "getAll", {
|
|
8467
|
+
limit: limit || 100,
|
|
8468
|
+
offset: offset || 0
|
|
8469
|
+
});
|
|
8470
|
+
if (result && result.success) {
|
|
8471
|
+
logger.info(`[DB] Retrieved ${result.count} KB nodes`);
|
|
8472
|
+
sendResponse8(id, {
|
|
8473
|
+
success: true,
|
|
8474
|
+
data: {
|
|
8475
|
+
nodes: result.data,
|
|
8476
|
+
count: result.count,
|
|
8477
|
+
message: `Retrieved ${result.count} knowledge nodes`
|
|
8478
|
+
}
|
|
8479
|
+
}, sendMessage, clientId);
|
|
8480
|
+
return;
|
|
8481
|
+
}
|
|
8482
|
+
sendResponse8(id, {
|
|
8483
|
+
success: false,
|
|
8484
|
+
error: "Failed to retrieve knowledge nodes"
|
|
8485
|
+
}, sendMessage, clientId);
|
|
8486
|
+
} catch (error) {
|
|
8487
|
+
logger.error("[DB] Failed to get all KB nodes:", error);
|
|
8488
|
+
sendResponse8(id, {
|
|
8489
|
+
success: false,
|
|
8490
|
+
error: error instanceof Error ? error.message : "Failed to retrieve knowledge nodes"
|
|
8491
|
+
}, sendMessage, clientId);
|
|
8492
|
+
}
|
|
8493
|
+
}
|
|
8494
|
+
async function handleGetOne6(id, nodeId, executeCollection, sendMessage, clientId) {
|
|
8495
|
+
if (!nodeId) {
|
|
8496
|
+
sendResponse8(id, {
|
|
8497
|
+
success: false,
|
|
8498
|
+
error: "Knowledge node ID is required"
|
|
8499
|
+
}, sendMessage, clientId);
|
|
8500
|
+
return;
|
|
8501
|
+
}
|
|
8502
|
+
try {
|
|
8503
|
+
const result = await executeCollection("kbNodes", "getOne", { id: nodeId });
|
|
8504
|
+
if (result && result.success) {
|
|
8505
|
+
logger.info(`[DB] Retrieved KB node ID: ${nodeId}`);
|
|
8506
|
+
sendResponse8(id, {
|
|
8507
|
+
success: true,
|
|
8508
|
+
data: {
|
|
8509
|
+
node: result.data,
|
|
8510
|
+
message: `Retrieved knowledge node`
|
|
8511
|
+
}
|
|
8512
|
+
}, sendMessage, clientId);
|
|
8513
|
+
return;
|
|
8514
|
+
}
|
|
8515
|
+
sendResponse8(id, {
|
|
8516
|
+
success: false,
|
|
8517
|
+
error: "Failed to retrieve knowledge node"
|
|
8518
|
+
}, sendMessage, clientId);
|
|
8519
|
+
} catch (error) {
|
|
8520
|
+
logger.error("[DB] Failed to get KB node:", error);
|
|
8521
|
+
sendResponse8(id, {
|
|
8522
|
+
success: false,
|
|
8523
|
+
error: error instanceof Error ? error.message : "Failed to retrieve knowledge node"
|
|
8524
|
+
}, sendMessage, clientId);
|
|
8525
|
+
}
|
|
8526
|
+
}
|
|
8527
|
+
async function handleSearch(id, searchParams, executeCollection, sendMessage, clientId) {
|
|
8528
|
+
const { query, category, tags, createdBy, limit, offset } = searchParams;
|
|
8529
|
+
try {
|
|
8530
|
+
const result = await executeCollection("kbNodes", "search", {
|
|
8531
|
+
query,
|
|
8532
|
+
category,
|
|
8533
|
+
tags,
|
|
8534
|
+
createdBy,
|
|
8535
|
+
limit: limit || 50,
|
|
8536
|
+
offset: offset || 0
|
|
8537
|
+
});
|
|
8538
|
+
if (result && result.success) {
|
|
8539
|
+
logger.info(`[DB] Search returned ${result.count} KB nodes`);
|
|
8540
|
+
sendResponse8(id, {
|
|
8541
|
+
success: true,
|
|
8542
|
+
data: {
|
|
8543
|
+
nodes: result.data,
|
|
8544
|
+
count: result.count,
|
|
8545
|
+
message: `Search returned ${result.count} knowledge nodes`
|
|
8546
|
+
}
|
|
8547
|
+
}, sendMessage, clientId);
|
|
8548
|
+
return;
|
|
8549
|
+
}
|
|
8550
|
+
sendResponse8(id, {
|
|
8551
|
+
success: false,
|
|
8552
|
+
error: "Failed to search knowledge nodes"
|
|
8553
|
+
}, sendMessage, clientId);
|
|
8554
|
+
} catch (error) {
|
|
8555
|
+
logger.error("[DB] Failed to search KB nodes:", error);
|
|
8556
|
+
sendResponse8(id, {
|
|
8557
|
+
success: false,
|
|
8558
|
+
error: error instanceof Error ? error.message : "Failed to search knowledge nodes"
|
|
8559
|
+
}, sendMessage, clientId);
|
|
8560
|
+
}
|
|
8561
|
+
}
|
|
8562
|
+
async function handleGetByCategory(id, category, limit, offset, executeCollection, sendMessage, clientId) {
|
|
8563
|
+
if (!category) {
|
|
8564
|
+
sendResponse8(id, {
|
|
8565
|
+
success: false,
|
|
8566
|
+
error: "Category is required"
|
|
8567
|
+
}, sendMessage, clientId);
|
|
8568
|
+
return;
|
|
8569
|
+
}
|
|
8570
|
+
try {
|
|
8571
|
+
const result = await executeCollection("kbNodes", "getByCategory", {
|
|
8572
|
+
category,
|
|
8573
|
+
limit: limit || 50,
|
|
8574
|
+
offset: offset || 0
|
|
8575
|
+
});
|
|
8576
|
+
if (result && result.success) {
|
|
8577
|
+
logger.info(`[DB] Retrieved ${result.count} KB nodes for category: ${category}`);
|
|
8578
|
+
sendResponse8(id, {
|
|
8579
|
+
success: true,
|
|
8580
|
+
data: {
|
|
8581
|
+
nodes: result.data,
|
|
8582
|
+
count: result.count,
|
|
8583
|
+
category,
|
|
8584
|
+
message: `Retrieved ${result.count} knowledge nodes for category '${category}'`
|
|
8585
|
+
}
|
|
8586
|
+
}, sendMessage, clientId);
|
|
8587
|
+
return;
|
|
8588
|
+
}
|
|
8589
|
+
sendResponse8(id, {
|
|
8590
|
+
success: false,
|
|
8591
|
+
error: "Failed to retrieve knowledge nodes by category"
|
|
8592
|
+
}, sendMessage, clientId);
|
|
8593
|
+
} catch (error) {
|
|
8594
|
+
logger.error("[DB] Failed to get KB nodes by category:", error);
|
|
8595
|
+
sendResponse8(id, {
|
|
8596
|
+
success: false,
|
|
8597
|
+
error: error instanceof Error ? error.message : "Failed to retrieve knowledge nodes by category"
|
|
8598
|
+
}, sendMessage, clientId);
|
|
8599
|
+
}
|
|
8600
|
+
}
|
|
8601
|
+
async function handleGetByUser(id, userId, limit, offset, executeCollection, sendMessage, clientId) {
|
|
8602
|
+
if (!userId) {
|
|
8603
|
+
sendResponse8(id, {
|
|
8604
|
+
success: false,
|
|
8605
|
+
error: "User ID is required"
|
|
8606
|
+
}, sendMessage, clientId);
|
|
8607
|
+
return;
|
|
8608
|
+
}
|
|
8609
|
+
try {
|
|
8610
|
+
const result = await executeCollection("kbNodes", "getByUser", {
|
|
8611
|
+
userId,
|
|
8612
|
+
limit: limit || 50,
|
|
8613
|
+
offset: offset || 0
|
|
8614
|
+
});
|
|
8615
|
+
if (result && result.success) {
|
|
8616
|
+
logger.info(`[DB] Retrieved ${result.count} KB nodes for user: ${userId}`);
|
|
8617
|
+
sendResponse8(id, {
|
|
8618
|
+
success: true,
|
|
8619
|
+
data: {
|
|
8620
|
+
nodes: result.data,
|
|
8621
|
+
count: result.count,
|
|
8622
|
+
userId,
|
|
8623
|
+
message: `Retrieved ${result.count} knowledge nodes for user ${userId}`
|
|
8624
|
+
}
|
|
8625
|
+
}, sendMessage, clientId);
|
|
8626
|
+
return;
|
|
8627
|
+
}
|
|
8628
|
+
sendResponse8(id, {
|
|
8629
|
+
success: false,
|
|
8630
|
+
error: "Failed to retrieve knowledge nodes by user"
|
|
8631
|
+
}, sendMessage, clientId);
|
|
8632
|
+
} catch (error) {
|
|
8633
|
+
logger.error("[DB] Failed to get KB nodes by user:", error);
|
|
8634
|
+
sendResponse8(id, {
|
|
8635
|
+
success: false,
|
|
8636
|
+
error: error instanceof Error ? error.message : "Failed to retrieve knowledge nodes by user"
|
|
8637
|
+
}, sendMessage, clientId);
|
|
8638
|
+
}
|
|
8639
|
+
}
|
|
8640
|
+
async function handleGetCategories(id, executeCollection, sendMessage, clientId) {
|
|
8641
|
+
try {
|
|
8642
|
+
const result = await executeCollection("kbNodes", "getCategories", {});
|
|
8643
|
+
if (result && result.success) {
|
|
8644
|
+
logger.info(`[DB] Retrieved ${result.count} categories`);
|
|
8645
|
+
sendResponse8(id, {
|
|
8646
|
+
success: true,
|
|
8647
|
+
data: {
|
|
8648
|
+
categories: result.data,
|
|
8649
|
+
count: result.count,
|
|
8650
|
+
message: `Retrieved ${result.count} categories`
|
|
8651
|
+
}
|
|
8652
|
+
}, sendMessage, clientId);
|
|
8653
|
+
return;
|
|
8654
|
+
}
|
|
8655
|
+
sendResponse8(id, {
|
|
8656
|
+
success: false,
|
|
8657
|
+
error: "Failed to retrieve categories"
|
|
8658
|
+
}, sendMessage, clientId);
|
|
8659
|
+
} catch (error) {
|
|
8660
|
+
logger.error("[DB] Failed to get categories:", error);
|
|
8661
|
+
sendResponse8(id, {
|
|
8662
|
+
success: false,
|
|
8663
|
+
error: error instanceof Error ? error.message : "Failed to retrieve categories"
|
|
8664
|
+
}, sendMessage, clientId);
|
|
8665
|
+
}
|
|
8666
|
+
}
|
|
8667
|
+
async function handleGetTags(id, executeCollection, sendMessage, clientId) {
|
|
8668
|
+
try {
|
|
8669
|
+
const result = await executeCollection("kbNodes", "getTags", {});
|
|
8670
|
+
if (result && result.success) {
|
|
8671
|
+
logger.info(`[DB] Retrieved ${result.count} tags`);
|
|
8672
|
+
sendResponse8(id, {
|
|
8673
|
+
success: true,
|
|
8674
|
+
data: {
|
|
8675
|
+
tags: result.data,
|
|
8676
|
+
count: result.count,
|
|
8677
|
+
message: `Retrieved ${result.count} tags`
|
|
8678
|
+
}
|
|
8679
|
+
}, sendMessage, clientId);
|
|
8680
|
+
return;
|
|
8681
|
+
}
|
|
8682
|
+
sendResponse8(id, {
|
|
8683
|
+
success: false,
|
|
8684
|
+
error: "Failed to retrieve tags"
|
|
8685
|
+
}, sendMessage, clientId);
|
|
8686
|
+
} catch (error) {
|
|
8687
|
+
logger.error("[DB] Failed to get tags:", error);
|
|
8688
|
+
sendResponse8(id, {
|
|
8689
|
+
success: false,
|
|
8690
|
+
error: error instanceof Error ? error.message : "Failed to retrieve tags"
|
|
8691
|
+
}, sendMessage, clientId);
|
|
8692
|
+
}
|
|
8693
|
+
}
|
|
8694
|
+
function sendResponse8(id, res, sendMessage, clientId) {
|
|
8695
|
+
const response = {
|
|
8696
|
+
id: id || "unknown",
|
|
8697
|
+
type: "KB_NODES_RES",
|
|
8698
|
+
from: { type: "data-agent" },
|
|
8699
|
+
to: {
|
|
8700
|
+
type: "admin",
|
|
8701
|
+
id: clientId
|
|
8702
|
+
},
|
|
8703
|
+
payload: {
|
|
8704
|
+
...res
|
|
8705
|
+
}
|
|
8706
|
+
};
|
|
8707
|
+
sendMessage(response);
|
|
8708
|
+
}
|
|
8709
|
+
|
|
7888
8710
|
// src/auth/user-manager.ts
|
|
7889
8711
|
var import_fs4 = __toESM(require("fs"));
|
|
7890
8712
|
var import_path3 = __toESM(require("path"));
|
|
@@ -8914,6 +9736,11 @@ var SuperatomSDK = class {
|
|
|
8914
9736
|
logger.error("Failed to handle bookmarks request:", error);
|
|
8915
9737
|
});
|
|
8916
9738
|
break;
|
|
9739
|
+
case "KB_NODES":
|
|
9740
|
+
handleKbNodesRequest(parsed, this.collections, (msg) => this.send(msg)).catch((error) => {
|
|
9741
|
+
logger.error("Failed to handle KB nodes request:", error);
|
|
9742
|
+
});
|
|
9743
|
+
break;
|
|
8917
9744
|
default:
|
|
8918
9745
|
const handler = this.messageTypeHandlers.get(message.type);
|
|
8919
9746
|
if (handler) {
|
|
@@ -9036,6 +9863,7 @@ var SuperatomSDK = class {
|
|
|
9036
9863
|
};
|
|
9037
9864
|
// Annotate the CommonJS export names for ESM import in node:
|
|
9038
9865
|
0 && (module.exports = {
|
|
9866
|
+
BM25L,
|
|
9039
9867
|
CONTEXT_CONFIG,
|
|
9040
9868
|
CleanupService,
|
|
9041
9869
|
LLM,
|
|
@@ -9047,6 +9875,9 @@ var SuperatomSDK = class {
|
|
|
9047
9875
|
UIBlock,
|
|
9048
9876
|
UILogCollector,
|
|
9049
9877
|
UserManager,
|
|
9050
|
-
|
|
9878
|
+
hybridRerank,
|
|
9879
|
+
logger,
|
|
9880
|
+
rerankChromaResults,
|
|
9881
|
+
rerankConversationResults
|
|
9051
9882
|
});
|
|
9052
9883
|
//# sourceMappingURL=index.js.map
|