@botpress/adk 1.7.19 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +754 -29
- package/dist/index.js.map +6 -3
- package/dist/knowledge/index.d.ts +6 -0
- package/dist/knowledge/index.d.ts.map +1 -0
- package/dist/knowledge/manager.d.ts +141 -0
- package/dist/knowledge/manager.d.ts.map +1 -0
- package/dist/knowledge/sync-formatter.d.ts +9 -0
- package/dist/knowledge/sync-formatter.d.ts.map +1 -0
- package/dist/knowledge/types.d.ts +136 -0
- package/dist/knowledge/types.d.ts.map +1 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -654,7 +654,7 @@ var PRETTIER_CONFIG, formatCode = async (code, filepath) => {
|
|
|
654
654
|
`));
|
|
655
655
|
return code;
|
|
656
656
|
}
|
|
657
|
-
}, ADK_VERSION = "1.
|
|
657
|
+
}, ADK_VERSION = "1.8.1", relative2 = (from, to) => {
|
|
658
658
|
const fromDir = path10.dirname(from);
|
|
659
659
|
const relative3 = path10.relative(fromDir, to);
|
|
660
660
|
return relative3.startsWith(".") ? relative3 : `./${relative3}`;
|
|
@@ -797,7 +797,7 @@ var init_integration_action_types = __esm(() => {
|
|
|
797
797
|
var require_package = __commonJS((exports, module) => {
|
|
798
798
|
module.exports = {
|
|
799
799
|
name: "@botpress/adk",
|
|
800
|
-
version: "1.
|
|
800
|
+
version: "1.8.1",
|
|
801
801
|
description: "Core ADK library for building AI agents on Botpress",
|
|
802
802
|
type: "module",
|
|
803
803
|
main: "dist/index.js",
|
|
@@ -844,7 +844,7 @@ var require_package = __commonJS((exports, module) => {
|
|
|
844
844
|
"@botpress/cli": "^4.23",
|
|
845
845
|
"@botpress/client": "^1.27.2",
|
|
846
846
|
"@botpress/cognitive": "^0.2.0",
|
|
847
|
-
"@botpress/runtime": "^1.
|
|
847
|
+
"@botpress/runtime": "^1.8.1",
|
|
848
848
|
"@botpress/sdk": "^4.18.1",
|
|
849
849
|
"@bpinternal/yargs-extra": "^0.0.21",
|
|
850
850
|
"@parcel/watcher": "^2.5.1",
|
|
@@ -4829,7 +4829,7 @@ class AgentProjectGenerator {
|
|
|
4829
4829
|
deploy: "adk deploy"
|
|
4830
4830
|
},
|
|
4831
4831
|
dependencies: {
|
|
4832
|
-
"@botpress/runtime": `^${"1.
|
|
4832
|
+
"@botpress/runtime": `^${"1.8.1"}`
|
|
4833
4833
|
},
|
|
4834
4834
|
devDependencies: {
|
|
4835
4835
|
typescript: "^5.9.3"
|
|
@@ -7814,10 +7814,732 @@ class TableManager {
|
|
|
7814
7814
|
};
|
|
7815
7815
|
}
|
|
7816
7816
|
}
|
|
7817
|
+
// src/knowledge/manager.ts
|
|
7818
|
+
import crypto4 from "crypto";
|
|
7819
|
+
import path31 from "path";
|
|
7820
|
+
import fs16 from "fs/promises";
|
|
7821
|
+
import { glob } from "glob";
|
|
7822
|
+
import { Client as Client12 } from "@botpress/client";
|
|
7823
|
+
import { DataSource } from "@botpress/runtime";
|
|
7824
|
+
|
|
7825
|
+
// src/knowledge/types.ts
|
|
7826
|
+
var KBSyncOperation;
|
|
7827
|
+
((KBSyncOperation2) => {
|
|
7828
|
+
KBSyncOperation2["Sync"] = "sync";
|
|
7829
|
+
KBSyncOperation2["Skip"] = "skip";
|
|
7830
|
+
})(KBSyncOperation ||= {});
|
|
7831
|
+
|
|
7832
|
+
// src/knowledge/manager.ts
|
|
7833
|
+
var WellKnownTags = {
|
|
7834
|
+
KNOWLEDGE: "knowledge",
|
|
7835
|
+
KNOWLEDGE_BASE_NAME: "kbName",
|
|
7836
|
+
KNOWLEDGE_SOURCE_ID: "sourceId",
|
|
7837
|
+
KNOWLEDGE_SOURCE_TYPE: "sourceType"
|
|
7838
|
+
};
|
|
7839
|
+
function sourceTag(sourceId, field) {
|
|
7840
|
+
const sanitizedId = sourceId.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
|
|
7841
|
+
return `source${sanitizedId}${field}`;
|
|
7842
|
+
}
|
|
7843
|
+
var WellKnownMetadata = {
|
|
7844
|
+
TITLE: "title"
|
|
7845
|
+
};
|
|
7846
|
+
function isFileMetadata(metadata) {
|
|
7847
|
+
return typeof metadata === "object" && metadata !== null && "hash" in metadata && typeof metadata.hash === "string" && "relPath" in metadata && typeof metadata.relPath === "string";
|
|
7848
|
+
}
|
|
7849
|
+
|
|
7850
|
+
class KnowledgeManager {
|
|
7851
|
+
client;
|
|
7852
|
+
botId;
|
|
7853
|
+
project;
|
|
7854
|
+
fileHashCache = new Map;
|
|
7855
|
+
constructor(options) {
|
|
7856
|
+
this.botId = options.botId;
|
|
7857
|
+
this.project = options.project;
|
|
7858
|
+
}
|
|
7859
|
+
clearHashCache() {
|
|
7860
|
+
this.fileHashCache.clear();
|
|
7861
|
+
}
|
|
7862
|
+
async getClient() {
|
|
7863
|
+
if (!this.client) {
|
|
7864
|
+
const credentials = await auth.getActiveCredentials();
|
|
7865
|
+
this.assertBotId("initialize client");
|
|
7866
|
+
this.client = new Client12({
|
|
7867
|
+
token: credentials.token,
|
|
7868
|
+
apiUrl: credentials.apiUrl,
|
|
7869
|
+
botId: this.botId,
|
|
7870
|
+
headers: {
|
|
7871
|
+
"x-multiple-integrations": "true"
|
|
7872
|
+
}
|
|
7873
|
+
});
|
|
7874
|
+
}
|
|
7875
|
+
return this.client;
|
|
7876
|
+
}
|
|
7877
|
+
assertBotId(operation) {
|
|
7878
|
+
if (!this.botId) {
|
|
7879
|
+
throw new Error(`Operation "${operation}" requires a bot ID. ` + "Please deploy your agent first or create agent.json with botId and workspaceId.");
|
|
7880
|
+
}
|
|
7881
|
+
}
|
|
7882
|
+
formatError(error) {
|
|
7883
|
+
if (!(error instanceof Error)) {
|
|
7884
|
+
return String(error);
|
|
7885
|
+
}
|
|
7886
|
+
let message = error.message;
|
|
7887
|
+
if ("response" in error && error.response !== null && typeof error.response === "object" && "data" in error.response) {
|
|
7888
|
+
message += ` - API: ${JSON.stringify(error.response.data)}`;
|
|
7889
|
+
}
|
|
7890
|
+
return message;
|
|
7891
|
+
}
|
|
7892
|
+
getLocalKnowledgeBases() {
|
|
7893
|
+
const kbs = [];
|
|
7894
|
+
for (const kbRef of this.project.knowledge) {
|
|
7895
|
+
const definition = kbRef.definition;
|
|
7896
|
+
kbs.push({
|
|
7897
|
+
name: definition.name,
|
|
7898
|
+
description: definition.description,
|
|
7899
|
+
sourceCount: definition.sources?.length || 0
|
|
7900
|
+
});
|
|
7901
|
+
}
|
|
7902
|
+
return kbs;
|
|
7903
|
+
}
|
|
7904
|
+
computeContentHash(fileHashes) {
|
|
7905
|
+
const sortedEntries = Object.entries(fileHashes).sort(([a], [b]) => a.localeCompare(b));
|
|
7906
|
+
const combined = sortedEntries.map(([filePath, hash]) => `${filePath}:${hash}`).join(`
|
|
7907
|
+
`);
|
|
7908
|
+
return crypto4.createHash("sha256").update(combined).digest("hex");
|
|
7909
|
+
}
|
|
7910
|
+
async listRemoteKnowledgeBases() {
|
|
7911
|
+
const client = await this.getClient();
|
|
7912
|
+
const kbs = [];
|
|
7913
|
+
let nextToken;
|
|
7914
|
+
do {
|
|
7915
|
+
const response = await client.listKnowledgeBases({ nextToken });
|
|
7916
|
+
kbs.push(...response.knowledgeBases);
|
|
7917
|
+
nextToken = response.meta.nextToken;
|
|
7918
|
+
} while (nextToken);
|
|
7919
|
+
return kbs;
|
|
7920
|
+
}
|
|
7921
|
+
async findRemoteKB(name) {
|
|
7922
|
+
const kbs = await this.listRemoteKnowledgeBases();
|
|
7923
|
+
return kbs.find((kb) => kb.name === name);
|
|
7924
|
+
}
|
|
7925
|
+
async createKnowledgeBase(name) {
|
|
7926
|
+
const client = await this.getClient();
|
|
7927
|
+
await client.createKnowledgeBase({ name });
|
|
7928
|
+
const created = await this.findRemoteKB(name);
|
|
7929
|
+
if (!created) {
|
|
7930
|
+
throw new Error(`Failed to find KB "${name}" after creation`);
|
|
7931
|
+
}
|
|
7932
|
+
return created;
|
|
7933
|
+
}
|
|
7934
|
+
async getOrphanedKBs() {
|
|
7935
|
+
const localKbNames = this.getLocalKnowledgeBases().map((kb) => kb.name);
|
|
7936
|
+
const remoteKbs = await this.listRemoteKnowledgeBases();
|
|
7937
|
+
return remoteKbs.filter((kb) => !localKbNames.includes(kb.name));
|
|
7938
|
+
}
|
|
7939
|
+
async getOrphanedSources(kbName, localSourceIds) {
|
|
7940
|
+
const client = await this.getClient();
|
|
7941
|
+
const tags = {
|
|
7942
|
+
[WellKnownTags.KNOWLEDGE]: "true",
|
|
7943
|
+
[WellKnownTags.KNOWLEDGE_BASE_NAME]: kbName
|
|
7944
|
+
};
|
|
7945
|
+
const files = [];
|
|
7946
|
+
let nextToken;
|
|
7947
|
+
do {
|
|
7948
|
+
const response = await client.listFiles({ tags, nextToken });
|
|
7949
|
+
files.push(...response.files);
|
|
7950
|
+
nextToken = response.meta.nextToken;
|
|
7951
|
+
} while (nextToken);
|
|
7952
|
+
const filesBySourceId = new Map;
|
|
7953
|
+
for (const file of files) {
|
|
7954
|
+
const sourceId = file.tags?.[WellKnownTags.KNOWLEDGE_SOURCE_ID] || file.metadata?.sourceId;
|
|
7955
|
+
if (sourceId) {
|
|
7956
|
+
filesBySourceId.set(sourceId, (filesBySourceId.get(sourceId) || 0) + 1);
|
|
7957
|
+
}
|
|
7958
|
+
}
|
|
7959
|
+
const orphaned = [];
|
|
7960
|
+
for (const [sourceId, fileCount] of filesBySourceId) {
|
|
7961
|
+
if (!localSourceIds.includes(sourceId)) {
|
|
7962
|
+
orphaned.push({ sourceId, fileCount });
|
|
7963
|
+
}
|
|
7964
|
+
}
|
|
7965
|
+
return orphaned;
|
|
7966
|
+
}
|
|
7967
|
+
async deleteOrphanedSource(kbName, sourceId) {
|
|
7968
|
+
const client = await this.getClient();
|
|
7969
|
+
const tags = {
|
|
7970
|
+
[WellKnownTags.KNOWLEDGE]: "true",
|
|
7971
|
+
[WellKnownTags.KNOWLEDGE_BASE_NAME]: kbName,
|
|
7972
|
+
[WellKnownTags.KNOWLEDGE_SOURCE_ID]: sourceId
|
|
7973
|
+
};
|
|
7974
|
+
const files = await this.listExistingFiles(client, tags);
|
|
7975
|
+
console.log(` Deleting ${files.length} files from orphaned source "${sourceId}"...`);
|
|
7976
|
+
const results = await Promise.allSettled(files.map((f) => client.deleteFile({ id: f.id })));
|
|
7977
|
+
const deletedFiles = results.filter((r) => r.status === "fulfilled").length;
|
|
7978
|
+
const errors = results.filter((r) => r.status === "rejected").map((r) => String(r.reason));
|
|
7979
|
+
return { deletedFiles, errors };
|
|
7980
|
+
}
|
|
7981
|
+
async cleanupSourceTags(kbId, kbName, sourceIds, existingTags) {
|
|
7982
|
+
const client = await this.getClient();
|
|
7983
|
+
const newTags = { ...existingTags };
|
|
7984
|
+
for (const sourceId of sourceIds) {
|
|
7985
|
+
const sanitizedId = sourceId.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
|
|
7986
|
+
newTags[`source${sanitizedId}hash`] = "";
|
|
7987
|
+
newTags[`source${sanitizedId}lastupdatedat`] = "";
|
|
7988
|
+
}
|
|
7989
|
+
await client.updateKnowledgeBase({ id: kbId, name: kbName, tags: newTags });
|
|
7990
|
+
}
|
|
7991
|
+
async deleteKnowledgeBase(kbId, kbName) {
|
|
7992
|
+
const client = await this.getClient();
|
|
7993
|
+
const tags = {
|
|
7994
|
+
[WellKnownTags.KNOWLEDGE]: "true",
|
|
7995
|
+
[WellKnownTags.KNOWLEDGE_BASE_NAME]: kbName
|
|
7996
|
+
};
|
|
7997
|
+
console.log(` Listing files for KB "${kbName}"...`);
|
|
7998
|
+
const files = await this.listExistingFiles(client, tags);
|
|
7999
|
+
console.log(` Found ${files.length} files to delete`);
|
|
8000
|
+
const results = await Promise.allSettled(files.map((file) => client.deleteFile({ id: file.id })));
|
|
8001
|
+
const deletedFiles = results.filter((r) => r.status === "fulfilled").length;
|
|
8002
|
+
console.log(` Deleting KB "${kbName}"...`);
|
|
8003
|
+
await client.deleteKnowledgeBase({ id: kbId });
|
|
8004
|
+
return { deletedFiles };
|
|
8005
|
+
}
|
|
8006
|
+
getRemoteSourceHash(kb, sourceId) {
|
|
8007
|
+
return kb.tags?.[sourceTag(sourceId, "hash")];
|
|
8008
|
+
}
|
|
8009
|
+
async updateSourceHash(kbId, kbName, sourceId, hash, existingTags) {
|
|
8010
|
+
const client = await this.getClient();
|
|
8011
|
+
await client.updateKnowledgeBase({
|
|
8012
|
+
id: kbId,
|
|
8013
|
+
name: kbName,
|
|
8014
|
+
tags: {
|
|
8015
|
+
...existingTags,
|
|
8016
|
+
[sourceTag(sourceId, "hash")]: hash,
|
|
8017
|
+
[sourceTag(sourceId, "lastupdatedat")]: new Date().toISOString()
|
|
8018
|
+
}
|
|
8019
|
+
});
|
|
8020
|
+
}
|
|
8021
|
+
computeConfigHash(config) {
|
|
8022
|
+
const sortedConfig = JSON.stringify(config, Object.keys(config).sort());
|
|
8023
|
+
return crypto4.createHash("sha256").update(sortedConfig).digest("hex");
|
|
8024
|
+
}
|
|
8025
|
+
async syncWebsiteSource(kbName, force) {
|
|
8026
|
+
const client = await this.getClient();
|
|
8027
|
+
const response = await client.createWorkflow({
|
|
8028
|
+
name: "builtin_knowledge_indexing",
|
|
8029
|
+
input: { kbName, force },
|
|
8030
|
+
status: "pending",
|
|
8031
|
+
timeoutAt: new Date(Date.now() + 180 * 60 * 1000).toISOString()
|
|
8032
|
+
});
|
|
8033
|
+
return { workflowId: response.workflow.id };
|
|
8034
|
+
}
|
|
8035
|
+
hasWebsiteSources(kbName) {
|
|
8036
|
+
const kbRef = this.project.knowledge.find((k) => k.definition.name === kbName);
|
|
8037
|
+
if (!kbRef)
|
|
8038
|
+
return false;
|
|
8039
|
+
return kbRef.definition.sources?.some((s) => DataSource.isWebsite(s)) || false;
|
|
8040
|
+
}
|
|
8041
|
+
getKBsWithWebsiteSources() {
|
|
8042
|
+
return this.project.knowledge.filter((k) => k.definition.sources?.some((s) => DataSource.isWebsite(s))).map((k) => k.definition.name);
|
|
8043
|
+
}
|
|
8044
|
+
async computeDirectorySourceHash(directoryPath, filterFn) {
|
|
8045
|
+
const fileHashes = await this.scanLocalFileHashes(directoryPath, filterFn);
|
|
8046
|
+
return this.computeContentHash(fileHashes);
|
|
8047
|
+
}
|
|
8048
|
+
async createSyncPlan() {
|
|
8049
|
+
const localKbs = this.getLocalKnowledgeBases();
|
|
8050
|
+
const remoteKbs = await this.listRemoteKnowledgeBases();
|
|
8051
|
+
const items = [];
|
|
8052
|
+
for (const kb of localKbs) {
|
|
8053
|
+
const kbRef = this.project.knowledge.find((k) => k.definition.name === kb.name);
|
|
8054
|
+
if (!kbRef)
|
|
8055
|
+
continue;
|
|
8056
|
+
const remoteKb = remoteKbs.find((r) => r.name === kb.name);
|
|
8057
|
+
if (!remoteKb) {
|
|
8058
|
+
const sources2 = (kbRef.definition.sources || []).map((source) => ({
|
|
8059
|
+
sourceId: source.id,
|
|
8060
|
+
sourceType: DataSource.isDirectory(source) ? "directory" : "website",
|
|
8061
|
+
needsSync: true,
|
|
8062
|
+
reason: "New KB"
|
|
8063
|
+
}));
|
|
8064
|
+
items.push({
|
|
8065
|
+
operation: "sync" /* Sync */,
|
|
8066
|
+
kb,
|
|
8067
|
+
reason: "Knowledge base not found remotely",
|
|
8068
|
+
needsCreation: true,
|
|
8069
|
+
sources: sources2
|
|
8070
|
+
});
|
|
8071
|
+
continue;
|
|
8072
|
+
}
|
|
8073
|
+
const sources = [];
|
|
8074
|
+
let hasChanges = false;
|
|
8075
|
+
for (const source of kbRef.definition.sources || []) {
|
|
8076
|
+
const remoteHash = this.getRemoteSourceHash(remoteKb, source.id);
|
|
8077
|
+
if (DataSource.isDirectory(source)) {
|
|
8078
|
+
const localHash = await this.computeDirectorySourceHash(source.directoryPath, source.filterFn);
|
|
8079
|
+
if (!remoteHash) {
|
|
8080
|
+
sources.push({
|
|
8081
|
+
sourceId: source.id,
|
|
8082
|
+
sourceType: "directory",
|
|
8083
|
+
needsSync: true,
|
|
8084
|
+
reason: "First-time sync"
|
|
8085
|
+
});
|
|
8086
|
+
hasChanges = true;
|
|
8087
|
+
} else if (localHash !== remoteHash) {
|
|
8088
|
+
const fileChanges = await this.detectDirectorySourceChanges(kb.name, source);
|
|
8089
|
+
sources.push({
|
|
8090
|
+
sourceId: source.id,
|
|
8091
|
+
sourceType: "directory",
|
|
8092
|
+
needsSync: true,
|
|
8093
|
+
reason: "Content changed",
|
|
8094
|
+
fileChanges
|
|
8095
|
+
});
|
|
8096
|
+
hasChanges = true;
|
|
8097
|
+
} else {
|
|
8098
|
+
sources.push({
|
|
8099
|
+
sourceId: source.id,
|
|
8100
|
+
sourceType: "directory",
|
|
8101
|
+
needsSync: false,
|
|
8102
|
+
reason: "No changes"
|
|
8103
|
+
});
|
|
8104
|
+
}
|
|
8105
|
+
} else if (DataSource.isWebsite(source)) {
|
|
8106
|
+
const config = source.getConfig();
|
|
8107
|
+
const localHash = this.computeConfigHash(config);
|
|
8108
|
+
if (!remoteHash) {
|
|
8109
|
+
sources.push({
|
|
8110
|
+
sourceId: source.id,
|
|
8111
|
+
sourceType: "website",
|
|
8112
|
+
needsSync: true,
|
|
8113
|
+
reason: "First-time crawl"
|
|
8114
|
+
});
|
|
8115
|
+
hasChanges = true;
|
|
8116
|
+
} else if (localHash !== remoteHash) {
|
|
8117
|
+
sources.push({
|
|
8118
|
+
sourceId: source.id,
|
|
8119
|
+
sourceType: "website",
|
|
8120
|
+
needsSync: true,
|
|
8121
|
+
reason: "Config changed - needs recrawl"
|
|
8122
|
+
});
|
|
8123
|
+
hasChanges = true;
|
|
8124
|
+
} else {
|
|
8125
|
+
sources.push({
|
|
8126
|
+
sourceId: source.id,
|
|
8127
|
+
sourceType: "website",
|
|
8128
|
+
needsSync: false,
|
|
8129
|
+
reason: "No config changes"
|
|
8130
|
+
});
|
|
8131
|
+
}
|
|
8132
|
+
}
|
|
8133
|
+
}
|
|
8134
|
+
const localSourceIds = (kbRef.definition.sources || []).map((s) => s.id);
|
|
8135
|
+
const orphaned = await this.getOrphanedSources(kb.name, localSourceIds);
|
|
8136
|
+
const orphanedSourceStatuses = orphaned.map((o) => ({
|
|
8137
|
+
sourceId: o.sourceId,
|
|
8138
|
+
fileCount: o.fileCount,
|
|
8139
|
+
willDelete: true
|
|
8140
|
+
}));
|
|
8141
|
+
const hasOrphanedSources = orphanedSourceStatuses.length > 0;
|
|
8142
|
+
items.push({
|
|
8143
|
+
operation: hasChanges || hasOrphanedSources ? "sync" /* Sync */ : "skip" /* Skip */,
|
|
8144
|
+
kb,
|
|
8145
|
+
reason: hasOrphanedSources ? hasChanges ? "Sources need sync and orphaned sources to remove" : "Orphaned sources to remove" : hasChanges ? "Sources need sync" : "No changes",
|
|
8146
|
+
sources,
|
|
8147
|
+
orphanedSources: hasOrphanedSources ? orphanedSourceStatuses : undefined
|
|
8148
|
+
});
|
|
8149
|
+
}
|
|
8150
|
+
const toSync = items.filter((i) => i.operation === "sync" /* Sync */).length;
|
|
8151
|
+
const toSkip = items.filter((i) => i.operation === "skip" /* Skip */).length;
|
|
8152
|
+
let sourcesToSync = 0;
|
|
8153
|
+
let sourcesToSkip = 0;
|
|
8154
|
+
let orphanedSourcesToDelete = 0;
|
|
8155
|
+
for (const item of items) {
|
|
8156
|
+
for (const source of item.sources || []) {
|
|
8157
|
+
if (source.needsSync) {
|
|
8158
|
+
sourcesToSync++;
|
|
8159
|
+
} else {
|
|
8160
|
+
sourcesToSkip++;
|
|
8161
|
+
}
|
|
8162
|
+
}
|
|
8163
|
+
orphanedSourcesToDelete += item.orphanedSources?.length || 0;
|
|
8164
|
+
}
|
|
8165
|
+
return {
|
|
8166
|
+
items,
|
|
8167
|
+
toSync,
|
|
8168
|
+
toSkip,
|
|
8169
|
+
hasChanges: toSync > 0,
|
|
8170
|
+
sourcesToSync,
|
|
8171
|
+
sourcesToSkip,
|
|
8172
|
+
orphanedSourcesToDelete
|
|
8173
|
+
};
|
|
8174
|
+
}
|
|
8175
|
+
async detectDirectorySourceChanges(kbName, source) {
|
|
8176
|
+
const client = await this.getClient();
|
|
8177
|
+
const added = [];
|
|
8178
|
+
const deleted = [];
|
|
8179
|
+
const modified = [];
|
|
8180
|
+
const tags = {
|
|
8181
|
+
[WellKnownTags.KNOWLEDGE]: "true",
|
|
8182
|
+
[WellKnownTags.KNOWLEDGE_SOURCE_ID]: source.id,
|
|
8183
|
+
[WellKnownTags.KNOWLEDGE_BASE_NAME]: kbName
|
|
8184
|
+
};
|
|
8185
|
+
const remoteFiles = await this.listExistingFiles(client, tags);
|
|
8186
|
+
const remoteHashes = {};
|
|
8187
|
+
for (const file of remoteFiles) {
|
|
8188
|
+
if (isFileMetadata(file.metadata)) {
|
|
8189
|
+
remoteHashes[file.metadata.relPath] = file.metadata.hash;
|
|
8190
|
+
}
|
|
8191
|
+
}
|
|
8192
|
+
const localHashes = await this.scanLocalFileHashes(source.directoryPath, source.filterFn);
|
|
8193
|
+
for (const [relPath, hash] of Object.entries(localHashes)) {
|
|
8194
|
+
if (!remoteHashes[relPath]) {
|
|
8195
|
+
added.push(relPath);
|
|
8196
|
+
} else if (remoteHashes[relPath] !== hash) {
|
|
8197
|
+
modified.push(relPath);
|
|
8198
|
+
}
|
|
8199
|
+
}
|
|
8200
|
+
for (const relPath of Object.keys(remoteHashes)) {
|
|
8201
|
+
if (!localHashes[relPath]) {
|
|
8202
|
+
deleted.push(relPath);
|
|
8203
|
+
}
|
|
8204
|
+
}
|
|
8205
|
+
return { added, deleted, modified };
|
|
8206
|
+
}
|
|
8207
|
+
async scanLocalFileHashes(directoryPath, filterFn) {
|
|
8208
|
+
const projectDir = this.project.path;
|
|
8209
|
+
const directory = path31.resolve(projectDir, directoryPath);
|
|
8210
|
+
if (this.fileHashCache.has(directory)) {
|
|
8211
|
+
return this.fileHashCache.get(directory);
|
|
8212
|
+
}
|
|
8213
|
+
const files = glob.sync(directory + "/**/*.*", { absolute: true, nodir: true }).filter((file) => !filterFn || filterFn(file));
|
|
8214
|
+
const hashes = {};
|
|
8215
|
+
for (const file of files) {
|
|
8216
|
+
const relPath = path31.relative(directory, file);
|
|
8217
|
+
const content = await fs16.readFile(file);
|
|
8218
|
+
hashes[relPath] = crypto4.createHash("sha256").update(content).digest("hex");
|
|
8219
|
+
}
|
|
8220
|
+
this.fileHashCache.set(directory, hashes);
|
|
8221
|
+
return hashes;
|
|
8222
|
+
}
|
|
8223
|
+
async executeSync(plan, options = {}) {
|
|
8224
|
+
this.assertBotId("sync knowledge bases");
|
|
8225
|
+
const client = await this.getClient();
|
|
8226
|
+
const result = {
|
|
8227
|
+
synced: [],
|
|
8228
|
+
skipped: [],
|
|
8229
|
+
failed: [],
|
|
8230
|
+
websiteSyncs: []
|
|
8231
|
+
};
|
|
8232
|
+
for (const item of plan.items) {
|
|
8233
|
+
if (item.operation === "skip" /* Skip */ && !options.force) {
|
|
8234
|
+
result.skipped.push({ name: item.kb.name, reason: item.reason });
|
|
8235
|
+
continue;
|
|
8236
|
+
}
|
|
8237
|
+
try {
|
|
8238
|
+
console.log(`Syncing KB "${item.kb.name}"...`);
|
|
8239
|
+
const kbRef = this.project.knowledge.find((k) => k.definition.name === item.kb.name);
|
|
8240
|
+
if (!kbRef) {
|
|
8241
|
+
throw new Error(`KB "${item.kb.name}" not found in project`);
|
|
8242
|
+
}
|
|
8243
|
+
let remoteKb = await this.findRemoteKB(item.kb.name);
|
|
8244
|
+
if (!remoteKb) {
|
|
8245
|
+
console.log(` Creating KB "${item.kb.name}"...`);
|
|
8246
|
+
remoteKb = await this.createKnowledgeBase(item.kb.name);
|
|
8247
|
+
}
|
|
8248
|
+
if (item.orphanedSources && item.orphanedSources.length > 0) {
|
|
8249
|
+
console.log(` Removing ${item.orphanedSources.length} orphaned source(s)...`);
|
|
8250
|
+
const deletedSourceIds = [];
|
|
8251
|
+
for (const orphaned of item.orphanedSources) {
|
|
8252
|
+
const { deletedFiles, errors } = await this.deleteOrphanedSource(item.kb.name, orphaned.sourceId);
|
|
8253
|
+
console.log(` ✕ ${orphaned.sourceId}: ${deletedFiles} files deleted`);
|
|
8254
|
+
if (errors.length === 0) {
|
|
8255
|
+
deletedSourceIds.push(orphaned.sourceId);
|
|
8256
|
+
} else {
|
|
8257
|
+
console.warn(` Warning: ${errors.length} errors during deletion`);
|
|
8258
|
+
}
|
|
8259
|
+
}
|
|
8260
|
+
if (deletedSourceIds.length > 0) {
|
|
8261
|
+
const freshKb = await this.findRemoteKB(item.kb.name);
|
|
8262
|
+
if (freshKb) {
|
|
8263
|
+
await this.cleanupSourceTags(freshKb.id, item.kb.name, deletedSourceIds, freshKb.tags || {});
|
|
8264
|
+
remoteKb = freshKb;
|
|
8265
|
+
}
|
|
8266
|
+
}
|
|
8267
|
+
}
|
|
8268
|
+
const syncOutput = {
|
|
8269
|
+
processed: 0,
|
|
8270
|
+
added: [],
|
|
8271
|
+
updated: [],
|
|
8272
|
+
deleted: [],
|
|
8273
|
+
errors: []
|
|
8274
|
+
};
|
|
8275
|
+
const sourcesToSync = options.force ? item.sources || [] : (item.sources || []).filter((s) => s.needsSync);
|
|
8276
|
+
const directorySourcesToSync = sourcesToSync.filter((s) => s.sourceType === "directory");
|
|
8277
|
+
const websiteSourcesToSync = sourcesToSync.filter((s) => s.sourceType === "website");
|
|
8278
|
+
for (const sourceStatus of directorySourcesToSync) {
|
|
8279
|
+
const source = kbRef.definition.sources?.find((s) => s.id === sourceStatus.sourceId);
|
|
8280
|
+
if (!source || !DataSource.isDirectory(source))
|
|
8281
|
+
continue;
|
|
8282
|
+
console.log(` Syncing directory source "${source.id}"...`);
|
|
8283
|
+
const sourceOutput = await this.syncDirectorySource(client, item.kb.name, source.id, source.directoryPath, source.filterFn, options.force || false);
|
|
8284
|
+
syncOutput.processed += sourceOutput.processed;
|
|
8285
|
+
syncOutput.added.push(...sourceOutput.added);
|
|
8286
|
+
syncOutput.updated.push(...sourceOutput.updated);
|
|
8287
|
+
syncOutput.deleted.push(...sourceOutput.deleted);
|
|
8288
|
+
syncOutput.errors.push(...sourceOutput.errors);
|
|
8289
|
+
const sourceHash = await this.computeDirectorySourceHash(source.directoryPath, source.filterFn);
|
|
8290
|
+
await this.updateSourceHash(remoteKb.id, item.kb.name, source.id, sourceHash, remoteKb.tags);
|
|
8291
|
+
}
|
|
8292
|
+
if (websiteSourcesToSync.length > 0) {
|
|
8293
|
+
try {
|
|
8294
|
+
console.log(` Triggering website sync workflow for ${websiteSourcesToSync.length} source(s)...`);
|
|
8295
|
+
const { workflowId } = await this.syncWebsiteSource(item.kb.name, options.force || false);
|
|
8296
|
+
result.websiteSyncs.push({ kbName: item.kb.name, workflowId });
|
|
8297
|
+
for (const sourceStatus of websiteSourcesToSync) {
|
|
8298
|
+
const source = kbRef.definition.sources?.find((s) => s.id === sourceStatus.sourceId);
|
|
8299
|
+
if (!source || !DataSource.isWebsite(source))
|
|
8300
|
+
continue;
|
|
8301
|
+
const config = source.getConfig();
|
|
8302
|
+
const configHash = this.computeConfigHash(config);
|
|
8303
|
+
await this.updateSourceHash(remoteKb.id, item.kb.name, source.id, configHash, remoteKb.tags);
|
|
8304
|
+
}
|
|
8305
|
+
} catch (error) {
|
|
8306
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
8307
|
+
console.warn(` Warning: Could not trigger website sync: ${errorMsg}`);
|
|
8308
|
+
}
|
|
8309
|
+
}
|
|
8310
|
+
result.synced.push({ name: item.kb.name, result: syncOutput });
|
|
8311
|
+
} catch (error) {
|
|
8312
|
+
const errorMessage = this.formatError(error);
|
|
8313
|
+
console.error(`Failed to sync KB "${item.kb.name}": ${errorMessage}`);
|
|
8314
|
+
result.failed.push({ name: item.kb.name, error: errorMessage });
|
|
8315
|
+
}
|
|
8316
|
+
}
|
|
8317
|
+
return result;
|
|
8318
|
+
}
|
|
8319
|
+
async syncDirectorySource(client, kbName, sourceId, directoryPath, filterFn, force) {
|
|
8320
|
+
const projectDir = this.project.path;
|
|
8321
|
+
const directory = path31.resolve(projectDir, directoryPath);
|
|
8322
|
+
if (!directory.startsWith(projectDir)) {
|
|
8323
|
+
throw new Error("Directory path must be within the agent's directory");
|
|
8324
|
+
}
|
|
8325
|
+
const tags = {
|
|
8326
|
+
[WellKnownTags.KNOWLEDGE]: "true",
|
|
8327
|
+
[WellKnownTags.KNOWLEDGE_SOURCE_ID]: sourceId,
|
|
8328
|
+
[WellKnownTags.KNOWLEDGE_SOURCE_TYPE]: "directory",
|
|
8329
|
+
[WellKnownTags.KNOWLEDGE_BASE_NAME]: kbName
|
|
8330
|
+
};
|
|
8331
|
+
let allFiles = glob.sync(directory + "/**/*.*", { absolute: true, nodir: true }).filter((file) => {
|
|
8332
|
+
if (filterFn) {
|
|
8333
|
+
try {
|
|
8334
|
+
return filterFn(file);
|
|
8335
|
+
} catch {
|
|
8336
|
+
return false;
|
|
8337
|
+
}
|
|
8338
|
+
}
|
|
8339
|
+
return true;
|
|
8340
|
+
}).map((f) => ({
|
|
8341
|
+
abs: f,
|
|
8342
|
+
rel: path31.relative(directory, f),
|
|
8343
|
+
name: path31.basename(f)
|
|
8344
|
+
}));
|
|
8345
|
+
console.log(` Found ${allFiles.length} files in ${directoryPath}`);
|
|
8346
|
+
const cachedHashes = await this.scanLocalFileHashes(directoryPath, filterFn);
|
|
8347
|
+
const existingFiles = await this.listExistingFiles(client, tags);
|
|
8348
|
+
console.log(` Found ${existingFiles.length} existing files in Botpress`);
|
|
8349
|
+
const toRemove = existingFiles.filter((f) => !allFiles.find((af) => af.rel === f.metadata?.relPath));
|
|
8350
|
+
const toAdd = allFiles.filter((af) => !existingFiles.find((f) => f.metadata?.relPath === af.rel));
|
|
8351
|
+
const toUpdate = allFiles.filter((af) => existingFiles.find((f) => f.metadata?.relPath === af.rel));
|
|
8352
|
+
const output = {
|
|
8353
|
+
processed: allFiles.length,
|
|
8354
|
+
added: [],
|
|
8355
|
+
updated: [],
|
|
8356
|
+
deleted: [],
|
|
8357
|
+
errors: []
|
|
8358
|
+
};
|
|
8359
|
+
for (const file of toRemove) {
|
|
8360
|
+
try {
|
|
8361
|
+
await client.deleteFile({ id: file.id });
|
|
8362
|
+
output.deleted.push({
|
|
8363
|
+
file: file.id,
|
|
8364
|
+
name: file.key,
|
|
8365
|
+
hash: file.metadata?.hash ?? "",
|
|
8366
|
+
size: file.size ?? -1
|
|
8367
|
+
});
|
|
8368
|
+
} catch (error) {
|
|
8369
|
+
output.errors.push({
|
|
8370
|
+
file: file.id,
|
|
8371
|
+
error: error instanceof Error ? error.message : String(error)
|
|
8372
|
+
});
|
|
8373
|
+
}
|
|
8374
|
+
}
|
|
8375
|
+
for (const local of toAdd) {
|
|
8376
|
+
const result = await this.upsertFile(client, local, sourceId, tags, force, cachedHashes[local.rel]);
|
|
8377
|
+
if (result) {
|
|
8378
|
+
output.added.push(result);
|
|
8379
|
+
}
|
|
8380
|
+
}
|
|
8381
|
+
for (const local of toUpdate) {
|
|
8382
|
+
const result = await this.upsertFile(client, local, sourceId, tags, force, cachedHashes[local.rel]);
|
|
8383
|
+
if (result) {
|
|
8384
|
+
output.updated.push(result);
|
|
8385
|
+
}
|
|
8386
|
+
}
|
|
8387
|
+
console.log(` Synced: ${output.added.length} added, ${output.updated.length} updated, ${output.deleted.length} deleted`);
|
|
8388
|
+
return output;
|
|
8389
|
+
}
|
|
8390
|
+
async listExistingFiles(client, tags) {
|
|
8391
|
+
const files = [];
|
|
8392
|
+
let nextToken;
|
|
8393
|
+
do {
|
|
8394
|
+
const response = await client.listFiles({ tags, nextToken });
|
|
8395
|
+
files.push(...response.files.map((f) => ({
|
|
8396
|
+
id: f.id,
|
|
8397
|
+
key: f.key,
|
|
8398
|
+
size: f.size,
|
|
8399
|
+
metadata: isFileMetadata(f.metadata) ? f.metadata : undefined
|
|
8400
|
+
})));
|
|
8401
|
+
nextToken = response.meta.nextToken;
|
|
8402
|
+
} while (nextToken);
|
|
8403
|
+
return files;
|
|
8404
|
+
}
|
|
8405
|
+
async upsertFile(client, local, sourceId, tags, force, cachedHash) {
|
|
8406
|
+
const key = `data_source://directory/${sourceId}/${local.rel}`;
|
|
8407
|
+
const content = await fs16.readFile(local.abs);
|
|
8408
|
+
const hash = cachedHash ?? crypto4.createHash("sha256").update(content).digest("hex");
|
|
8409
|
+
try {
|
|
8410
|
+
const { file } = await client.getFile({ id: key });
|
|
8411
|
+
if (!force && isFileMetadata(file.metadata) && file.metadata.hash === hash) {
|
|
8412
|
+
return null;
|
|
8413
|
+
}
|
|
8414
|
+
} catch {}
|
|
8415
|
+
const title = path31.basename(local.name, path31.extname(local.name));
|
|
8416
|
+
const metadata = {
|
|
8417
|
+
hash,
|
|
8418
|
+
sourceId,
|
|
8419
|
+
sourceType: "directory",
|
|
8420
|
+
relPath: local.rel,
|
|
8421
|
+
[WellKnownMetadata.TITLE]: title
|
|
8422
|
+
};
|
|
8423
|
+
const uploaded = await client.uploadFile({
|
|
8424
|
+
key,
|
|
8425
|
+
content,
|
|
8426
|
+
accessPolicies: [],
|
|
8427
|
+
tags,
|
|
8428
|
+
index: true,
|
|
8429
|
+
metadata
|
|
8430
|
+
});
|
|
8431
|
+
return {
|
|
8432
|
+
file: uploaded.file.id,
|
|
8433
|
+
hash,
|
|
8434
|
+
name: key,
|
|
8435
|
+
size: uploaded.file.size ?? -1
|
|
8436
|
+
};
|
|
8437
|
+
}
|
|
8438
|
+
}
|
|
8439
|
+
// src/knowledge/sync-formatter.ts
|
|
8440
|
+
import { readFileSync } from "fs";
|
|
8441
|
+
import { join as join7 } from "path";
|
|
8442
|
+
var getAdkVersion = () => {
|
|
8443
|
+
try {
|
|
8444
|
+
const packageJson = require_package();
|
|
8445
|
+
return packageJson.version;
|
|
8446
|
+
} catch {
|
|
8447
|
+
try {
|
|
8448
|
+
const adkPackagePath = join7(process.cwd(), "node_modules/@botpress/adk/package.json");
|
|
8449
|
+
const pkg = JSON.parse(readFileSync(adkPackagePath, "utf-8"));
|
|
8450
|
+
return pkg.version;
|
|
8451
|
+
} catch {
|
|
8452
|
+
return "unknown";
|
|
8453
|
+
}
|
|
8454
|
+
}
|
|
8455
|
+
};
|
|
8456
|
+
function pluralize(count, word) {
|
|
8457
|
+
return `${count} ${word}${count !== 1 ? "s" : ""}`;
|
|
8458
|
+
}
|
|
8459
|
+
|
|
8460
|
+
class KBSyncFormatter {
|
|
8461
|
+
static format(plan, kbsWithWebsites = []) {
|
|
8462
|
+
const sections = [];
|
|
8463
|
+
sections.push("");
|
|
8464
|
+
sections.push(" ▄▀█ █▀▄ █▄▀ Botpress ADK");
|
|
8465
|
+
sections.push(` █▀█ █▄▀ █░█ v${getAdkVersion()}`);
|
|
8466
|
+
sections.push("");
|
|
8467
|
+
sections.push("Knowledge Base Sync");
|
|
8468
|
+
sections.push("");
|
|
8469
|
+
if (!plan.hasChanges) {
|
|
8470
|
+
sections.push("✓ All knowledge bases are up to date.");
|
|
8471
|
+
sections.push("");
|
|
8472
|
+
return sections.join(`
|
|
8473
|
+
`);
|
|
8474
|
+
}
|
|
8475
|
+
const kbsToSync = plan.items.filter((i) => i.operation === "sync" /* Sync */);
|
|
8476
|
+
const kbsToSkip = plan.items.filter((i) => i.operation === "skip" /* Skip */);
|
|
8477
|
+
if (kbsToSync.length > 0) {
|
|
8478
|
+
sections.push(`Knowledge Bases to Sync:
|
|
8479
|
+
`);
|
|
8480
|
+
for (const item of kbsToSync) {
|
|
8481
|
+
const icon = item.needsCreation ? "+" : "~";
|
|
8482
|
+
const action = item.needsCreation ? "CREATE" : "UPDATE";
|
|
8483
|
+
sections.push(` ${icon} ${item.kb.name}`);
|
|
8484
|
+
sections.push(` Action: ${action}`);
|
|
8485
|
+
sections.push(` Reason: ${item.reason}`);
|
|
8486
|
+
if (item.sources && item.sources.length > 0) {
|
|
8487
|
+
sections.push(" Sources:");
|
|
8488
|
+
for (const source of item.sources) {
|
|
8489
|
+
if (source.needsSync) {
|
|
8490
|
+
const typeLabel = source.sourceType === "directory" ? "\uD83D\uDCC1" : "\uD83C\uDF10";
|
|
8491
|
+
sections.push(` ${typeLabel} ${source.sourceId} (${source.sourceType})`);
|
|
8492
|
+
sections.push(` ${source.reason}`);
|
|
8493
|
+
if (source.fileChanges) {
|
|
8494
|
+
const { added, modified, deleted } = source.fileChanges;
|
|
8495
|
+
if (added.length > 0) {
|
|
8496
|
+
sections.push(` + ${pluralize(added.length, "file")} to add`);
|
|
8497
|
+
}
|
|
8498
|
+
if (modified.length > 0) {
|
|
8499
|
+
sections.push(` ~ ${pluralize(modified.length, "file")} to update`);
|
|
8500
|
+
}
|
|
8501
|
+
if (deleted.length > 0) {
|
|
8502
|
+
sections.push(` - ${pluralize(deleted.length, "file")} to delete`);
|
|
8503
|
+
}
|
|
8504
|
+
}
|
|
8505
|
+
}
|
|
8506
|
+
}
|
|
8507
|
+
}
|
|
8508
|
+
sections.push("");
|
|
8509
|
+
}
|
|
8510
|
+
}
|
|
8511
|
+
if (kbsToSkip.length > 0) {
|
|
8512
|
+
sections.push(`Knowledge Bases Already Up to Date:
|
|
8513
|
+
`);
|
|
8514
|
+
for (const item of kbsToSkip) {
|
|
8515
|
+
sections.push(` ✓ ${item.kb.name}`);
|
|
8516
|
+
}
|
|
8517
|
+
sections.push("");
|
|
8518
|
+
}
|
|
8519
|
+
if (kbsWithWebsites.length > 0) {
|
|
8520
|
+
sections.push("⚠️ Website Sources");
|
|
8521
|
+
sections.push(" Website crawling will run asynchronously in the bot runtime.");
|
|
8522
|
+
sections.push(` KBs with websites: ${kbsWithWebsites.join(", ")}`);
|
|
8523
|
+
sections.push("");
|
|
8524
|
+
}
|
|
8525
|
+
sections.push(`Summary of Actions
|
|
8526
|
+
`);
|
|
8527
|
+
if (plan.toSync > 0) {
|
|
8528
|
+
sections.push(` • Sync: ${pluralize(plan.toSync, "knowledge base")}`);
|
|
8529
|
+
}
|
|
8530
|
+
if (plan.toSkip > 0) {
|
|
8531
|
+
sections.push(` • Skip: ${pluralize(plan.toSkip, "knowledge base")} (up to date)`);
|
|
8532
|
+
}
|
|
8533
|
+
sections.push(` • Sources: ${plan.sourcesToSync} to sync, ${plan.sourcesToSkip} up to date`);
|
|
8534
|
+
sections.push("");
|
|
8535
|
+
return sections.join(`
|
|
8536
|
+
`);
|
|
8537
|
+
}
|
|
8538
|
+
}
|
|
7817
8539
|
// src/file-watcher/watcher.ts
|
|
7818
8540
|
import { watch as watch2, readdirSync as readdirSync2 } from "fs";
|
|
7819
8541
|
import { EventEmitter as EventEmitter3 } from "events";
|
|
7820
|
-
import { join as
|
|
8542
|
+
import { join as join8, relative as relative3 } from "path";
|
|
7821
8543
|
import { existsSync as existsSync6 } from "fs";
|
|
7822
8544
|
|
|
7823
8545
|
class FileWatcher2 extends EventEmitter3 {
|
|
@@ -7835,12 +8557,12 @@ class FileWatcher2 extends EventEmitter3 {
|
|
|
7835
8557
|
start() {
|
|
7836
8558
|
const rootFiles = ["package.json", "agent.json", "agent.config.ts"];
|
|
7837
8559
|
for (const file of rootFiles) {
|
|
7838
|
-
const filePath =
|
|
8560
|
+
const filePath = join8(this.projectPath, file);
|
|
7839
8561
|
if (existsSync6(filePath)) {
|
|
7840
8562
|
this.watchFile(filePath);
|
|
7841
8563
|
}
|
|
7842
8564
|
}
|
|
7843
|
-
const srcPath =
|
|
8565
|
+
const srcPath = join8(this.projectPath, "src");
|
|
7844
8566
|
if (existsSync6(srcPath)) {
|
|
7845
8567
|
this.initializeDirectoryState(srcPath);
|
|
7846
8568
|
this.watchDirectory(srcPath);
|
|
@@ -7850,7 +8572,7 @@ class FileWatcher2 extends EventEmitter3 {
|
|
|
7850
8572
|
try {
|
|
7851
8573
|
const entries = readdirSync2(dirPath, { withFileTypes: true });
|
|
7852
8574
|
for (const entry of entries) {
|
|
7853
|
-
const fullPath =
|
|
8575
|
+
const fullPath = join8(dirPath, entry.name);
|
|
7854
8576
|
if (entry.isDirectory()) {
|
|
7855
8577
|
this.initializeDirectoryState(fullPath);
|
|
7856
8578
|
} else if (entry.isFile()) {
|
|
@@ -7880,7 +8602,7 @@ class FileWatcher2 extends EventEmitter3 {
|
|
|
7880
8602
|
try {
|
|
7881
8603
|
const watcher = watch2(dirPath, { recursive: true, persistent: true }, (_eventType, filename) => {
|
|
7882
8604
|
if (filename) {
|
|
7883
|
-
const fullPath =
|
|
8605
|
+
const fullPath = join8(dirPath, filename);
|
|
7884
8606
|
this.handleFileChange(fullPath);
|
|
7885
8607
|
}
|
|
7886
8608
|
});
|
|
@@ -7954,14 +8676,14 @@ class FileWatcher2 extends EventEmitter3 {
|
|
|
7954
8676
|
}
|
|
7955
8677
|
}
|
|
7956
8678
|
// src/preflight/checker.ts
|
|
7957
|
-
import { Client as
|
|
7958
|
-
import
|
|
8679
|
+
import { Client as Client13 } from "@botpress/client";
|
|
8680
|
+
import path32 from "path";
|
|
7959
8681
|
|
|
7960
8682
|
// src/preflight/types.ts
|
|
7961
8683
|
function hasIntegrationChanges(integrations) {
|
|
7962
8684
|
return integrations.toInstall.length > 0 || integrations.toRemove.length > 0 || integrations.toUpdate.length > 0;
|
|
7963
8685
|
}
|
|
7964
|
-
function
|
|
8686
|
+
function pluralize2(count, word) {
|
|
7965
8687
|
return `${count} ${word}${count > 1 ? "s" : ""}`;
|
|
7966
8688
|
}
|
|
7967
8689
|
|
|
@@ -8012,16 +8734,16 @@ class AgentConfigSyncManager {
|
|
|
8012
8734
|
}
|
|
8013
8735
|
|
|
8014
8736
|
// src/preflight/formatter.ts
|
|
8015
|
-
import { readFileSync } from "fs";
|
|
8016
|
-
import { join as
|
|
8017
|
-
var
|
|
8737
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
8738
|
+
import { join as join9 } from "path";
|
|
8739
|
+
var getAdkVersion2 = () => {
|
|
8018
8740
|
try {
|
|
8019
8741
|
const packageJson = require_package();
|
|
8020
8742
|
return packageJson.version;
|
|
8021
8743
|
} catch {
|
|
8022
8744
|
try {
|
|
8023
|
-
const adkPackagePath =
|
|
8024
|
-
const pkg = JSON.parse(
|
|
8745
|
+
const adkPackagePath = join9(process.cwd(), "node_modules/@botpress/adk/package.json");
|
|
8746
|
+
const pkg = JSON.parse(readFileSync2(adkPackagePath, "utf-8"));
|
|
8025
8747
|
return pkg.version;
|
|
8026
8748
|
} catch {
|
|
8027
8749
|
return "unknown";
|
|
@@ -8034,7 +8756,7 @@ class PreflightFormatter {
|
|
|
8034
8756
|
const sections = [];
|
|
8035
8757
|
sections.push("");
|
|
8036
8758
|
sections.push(" ▄▀█ █▀▄ █▄▀ Botpress ADK");
|
|
8037
|
-
sections.push(` █▀█ █▄▀ █░█ v${
|
|
8759
|
+
sections.push(` █▀█ █▄▀ █░█ v${getAdkVersion2()}`);
|
|
8038
8760
|
sections.push("");
|
|
8039
8761
|
sections.push("Running preflight checks...");
|
|
8040
8762
|
sections.push("");
|
|
@@ -8108,16 +8830,16 @@ class PreflightFormatter {
|
|
|
8108
8830
|
const update = result.integrations.toUpdate.length;
|
|
8109
8831
|
const agentConfig = result.agentConfig.length;
|
|
8110
8832
|
if (install > 0) {
|
|
8111
|
-
sections.push(` • Install: ${
|
|
8833
|
+
sections.push(` • Install: ${pluralize2(install, "integration")}`);
|
|
8112
8834
|
}
|
|
8113
8835
|
if (remove > 0) {
|
|
8114
|
-
sections.push(` • Remove: ${
|
|
8836
|
+
sections.push(` • Remove: ${pluralize2(remove, "integration")}`);
|
|
8115
8837
|
}
|
|
8116
8838
|
if (update > 0) {
|
|
8117
|
-
sections.push(` • Update: ${
|
|
8839
|
+
sections.push(` • Update: ${pluralize2(update, "integration")}`);
|
|
8118
8840
|
}
|
|
8119
8841
|
if (agentConfig > 0) {
|
|
8120
|
-
sections.push(` • Agent config: ${
|
|
8842
|
+
sections.push(` • Agent config: ${pluralize2(agentConfig, "change")}`);
|
|
8121
8843
|
}
|
|
8122
8844
|
sections.push("");
|
|
8123
8845
|
return sections.join(`
|
|
@@ -8169,7 +8891,7 @@ class PreflightChecker {
|
|
|
8169
8891
|
if (!workspaceId) {
|
|
8170
8892
|
throw new Error('No workspace ID found. Please login with "adk login"');
|
|
8171
8893
|
}
|
|
8172
|
-
this.client = new
|
|
8894
|
+
this.client = new Client13({
|
|
8173
8895
|
token: credentials.token,
|
|
8174
8896
|
apiUrl: credentials.apiUrl,
|
|
8175
8897
|
workspaceId,
|
|
@@ -8295,16 +9017,16 @@ class PreflightChecker {
|
|
|
8295
9017
|
const integrationSyncer = new IntegrationSyncManager(this.projectPath);
|
|
8296
9018
|
const syncResult = await integrationSyncer.applySyncPlan(integrationResults, botId);
|
|
8297
9019
|
if (syncResult.installed > 0) {
|
|
8298
|
-
options?.onSuccess?.(`Installed ${
|
|
9020
|
+
options?.onSuccess?.(`Installed ${pluralize2(syncResult.installed, "integration")}`);
|
|
8299
9021
|
}
|
|
8300
9022
|
if (syncResult.updated > 0) {
|
|
8301
|
-
options?.onSuccess?.(`Updated ${
|
|
9023
|
+
options?.onSuccess?.(`Updated ${pluralize2(syncResult.updated, "integration")}`);
|
|
8302
9024
|
}
|
|
8303
9025
|
if (syncResult.removed > 0) {
|
|
8304
|
-
options?.onSuccess?.(`Removed ${
|
|
9026
|
+
options?.onSuccess?.(`Removed ${pluralize2(syncResult.removed, "integration")}`);
|
|
8305
9027
|
}
|
|
8306
9028
|
if (syncResult.failed > 0) {
|
|
8307
|
-
options?.onError?.(`Failed to sync ${
|
|
9029
|
+
options?.onError?.(`Failed to sync ${pluralize2(syncResult.failed, "integration")}`);
|
|
8308
9030
|
for (const { alias, error } of syncResult.errors) {
|
|
8309
9031
|
options?.onError?.(` ${alias}: ${error}`);
|
|
8310
9032
|
}
|
|
@@ -8317,7 +9039,7 @@ class PreflightChecker {
|
|
|
8317
9039
|
options?.onProgress?.("Regenerating bot project...");
|
|
8318
9040
|
await generateBotProject({
|
|
8319
9041
|
projectPath: this.projectPath,
|
|
8320
|
-
outputPath:
|
|
9042
|
+
outputPath: path32.join(this.projectPath, ".adk", "bot")
|
|
8321
9043
|
});
|
|
8322
9044
|
options?.onSuccess?.("Bot project regenerated");
|
|
8323
9045
|
}
|
|
@@ -8344,6 +9066,9 @@ export {
|
|
|
8344
9066
|
ProjectState,
|
|
8345
9067
|
PreflightFormatter,
|
|
8346
9068
|
PreflightChecker,
|
|
9069
|
+
KnowledgeManager,
|
|
9070
|
+
KBSyncOperation,
|
|
9071
|
+
KBSyncFormatter,
|
|
8347
9072
|
InterfaceParser,
|
|
8348
9073
|
InterfaceOperations,
|
|
8349
9074
|
InterfaceManager,
|
|
@@ -8370,5 +9095,5 @@ export {
|
|
|
8370
9095
|
AgentProject
|
|
8371
9096
|
};
|
|
8372
9097
|
|
|
8373
|
-
//# debugId=
|
|
9098
|
+
//# debugId=D1FBF4E6E55AF89264756E2164756E21
|
|
8374
9099
|
//# sourceMappingURL=index.js.map
|