@botpress/adk 1.16.6 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-init/agent-project-generator.d.ts.map +1 -1
- package/dist/agent-project/agent-project.d.ts +9 -1
- package/dist/agent-project/agent-project.d.ts.map +1 -1
- package/dist/agent-project/agent-resolver.d.ts.map +1 -1
- package/dist/agent-project/dependencies-parser.d.ts.map +1 -1
- package/dist/agent-project/types.d.ts +27 -19
- package/dist/agent-project/types.d.ts.map +1 -1
- package/dist/agent-project/validation-errors.d.ts.map +1 -1
- package/dist/auth/credentials.d.ts +15 -1
- package/dist/auth/credentials.d.ts.map +1 -1
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/bot-generator/generator.d.ts.map +1 -1
- package/dist/commands/base-command.d.ts.map +1 -1
- package/dist/commands/bp-add-command.d.ts.map +1 -1
- package/dist/commands/bp-build-command.d.ts.map +1 -1
- package/dist/commands/bp-chat-command.d.ts.map +1 -1
- package/dist/commands/bp-deploy-command.d.ts.map +1 -1
- package/dist/commands/bp-dev-command.d.ts +6 -0
- package/dist/commands/bp-dev-command.d.ts.map +1 -1
- package/dist/commands/index.d.ts +4 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/opencode-command.d.ts +45 -0
- package/dist/commands/opencode-command.d.ts.map +1 -0
- package/dist/commands/opencode-config.d.ts +29 -0
- package/dist/commands/opencode-config.d.ts.map +1 -0
- package/dist/config/coerce-config-value.d.ts.map +1 -1
- package/dist/config/manager.d.ts +5 -5
- package/dist/config/manager.d.ts.map +1 -1
- package/dist/eval/client.d.ts +8 -0
- package/dist/eval/client.d.ts.map +1 -1
- package/dist/eval/graders/index.d.ts +1 -0
- package/dist/eval/graders/index.d.ts.map +1 -1
- package/dist/eval/graders/llm.d.ts +6 -2
- package/dist/eval/graders/llm.d.ts.map +1 -1
- package/dist/eval/graders/outcome.d.ts +3 -2
- package/dist/eval/graders/outcome.d.ts.map +1 -1
- package/dist/eval/graders/response.d.ts +1 -0
- package/dist/eval/graders/response.d.ts.map +1 -1
- package/dist/eval/graders/state.d.ts +1 -1
- package/dist/eval/graders/state.d.ts.map +1 -1
- package/dist/eval/graders/tables.d.ts.map +1 -1
- package/dist/eval/graders/timing.d.ts +7 -0
- package/dist/eval/graders/timing.d.ts.map +1 -0
- package/dist/eval/graders/workflow.d.ts +3 -2
- package/dist/eval/graders/workflow.d.ts.map +1 -1
- package/dist/eval/index.d.ts +2 -2
- package/dist/eval/index.d.ts.map +1 -1
- package/dist/eval/runner.d.ts +2 -3
- package/dist/eval/runner.d.ts.map +1 -1
- package/dist/eval/traces.d.ts.map +1 -1
- package/dist/eval/types.d.ts +56 -14
- package/dist/eval/types.d.ts.map +1 -1
- package/dist/file-watcher/watcher.d.ts +9 -0
- package/dist/file-watcher/watcher.d.ts.map +1 -1
- package/dist/generators/client-wrapper.d.ts.map +1 -1
- package/dist/generators/conversation-types.d.ts.map +1 -1
- package/dist/generators/integration-types.d.ts.map +1 -1
- package/dist/generators/interface-types.d.ts.map +1 -1
- package/dist/generators/plugin-types.d.ts.map +1 -1
- package/dist/generators/table-types.d.ts.map +1 -1
- package/dist/generators/tests.d.ts.map +1 -1
- package/dist/generators/utils.d.ts +0 -11
- package/dist/generators/utils.d.ts.map +1 -1
- package/dist/generators/workflow-types.d.ts.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +792 -194
- package/dist/index.js.map +60 -57
- package/dist/integrations/checker.d.ts +2 -2
- package/dist/integrations/checker.d.ts.map +1 -1
- package/dist/integrations/config-utils.d.ts +3 -3
- package/dist/integrations/config-utils.d.ts.map +1 -1
- package/dist/integrations/types.d.ts +1 -1
- package/dist/integrations/types.d.ts.map +1 -1
- package/dist/interfaces/manager.d.ts.map +1 -1
- package/dist/interfaces/types.d.ts +1 -1
- package/dist/interfaces/types.d.ts.map +1 -1
- package/dist/knowledge/manager.d.ts.map +1 -1
- package/dist/plugins/types.d.ts +1 -1
- package/dist/plugins/types.d.ts.map +1 -1
- package/dist/preflight/agent-config-sync.d.ts +2 -1
- package/dist/preflight/agent-config-sync.d.ts.map +1 -1
- package/dist/preflight/types.d.ts +8 -8
- package/dist/preflight/types.d.ts.map +1 -1
- package/dist/runner/index.d.ts +1 -1
- package/dist/runner/script-runner.d.ts +1 -1
- package/dist/runner/script-runner.d.ts.map +1 -1
- package/dist/tables/table-manager.d.ts.map +1 -1
- package/dist/tables/types.d.ts +2 -1
- package/dist/tables/types.d.ts.map +1 -1
- package/dist/utils/json-ordering.d.ts +5 -4
- package/dist/utils/json-ordering.d.ts.map +1 -1
- package/package.json +33 -32
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
15
15
|
|
|
16
16
|
// src/agent-project/types.ts
|
|
17
17
|
import { z } from "@botpress/sdk";
|
|
18
|
-
var pluginDependencyMappingSchema, dependenciesSchema, agentInfoSchema, ValidationErrorCode, ValidationSeverity, ProjectState;
|
|
18
|
+
var pluginDependencyMappingSchema, dependenciesSchema, agentInfoSchema, agentLocalInfoSchema, ValidationErrorCode, ValidationSeverity, ProjectState;
|
|
19
19
|
var init_types = __esm(() => {
|
|
20
20
|
pluginDependencyMappingSchema = z.object({
|
|
21
21
|
integrationAlias: z.string(),
|
|
@@ -40,6 +40,9 @@ var init_types = __esm(() => {
|
|
|
40
40
|
apiUrl: z.string().optional().describe("The Botpress API URL (e.g., https://api.botpress.cloud)"),
|
|
41
41
|
devId: z.string().optional().describe("The development ID used during local development")
|
|
42
42
|
});
|
|
43
|
+
agentLocalInfoSchema = z.object({
|
|
44
|
+
devId: z.string().optional().describe("The development bot ID used during local development")
|
|
45
|
+
});
|
|
43
46
|
((ValidationErrorCode2) => {
|
|
44
47
|
ValidationErrorCode2["DIRECTORY_NOT_FOUND"] = "DIRECTORY_NOT_FOUND";
|
|
45
48
|
ValidationErrorCode2["DIRECTORY_ACCESS_ERROR"] = "DIRECTORY_ACCESS_ERROR";
|
|
@@ -487,6 +490,15 @@ async function resolveAgent(agentPath, options = {}) {
|
|
|
487
490
|
if (!agentInfo.apiUrl) {
|
|
488
491
|
agentInfo.apiUrl = DEFAULT_API_URL;
|
|
489
492
|
}
|
|
493
|
+
const localPath = path.join(agentPath, "agent.local.json");
|
|
494
|
+
try {
|
|
495
|
+
const localContent = await fs.readFile(localPath, "utf-8");
|
|
496
|
+
const localData = JSON.parse(localContent);
|
|
497
|
+
const localResult = agentLocalInfoSchema.safeParse(localData);
|
|
498
|
+
if (localResult.success && localResult.data.devId) {
|
|
499
|
+
agentInfo.devId = localResult.data.devId;
|
|
500
|
+
}
|
|
501
|
+
} catch {}
|
|
490
502
|
if (requireWorkspace && !agentInfo.workspaceId) {
|
|
491
503
|
throw ValidationErrors.workspaceIdMissing();
|
|
492
504
|
}
|
|
@@ -525,10 +537,14 @@ import os from "os";
|
|
|
525
537
|
class CredentialsManager {
|
|
526
538
|
credentialsPath;
|
|
527
539
|
configDir;
|
|
540
|
+
profileOverride;
|
|
528
541
|
constructor() {
|
|
529
542
|
this.configDir = path2.join(os.homedir(), ".adk");
|
|
530
543
|
this.credentialsPath = path2.join(this.configDir, "credentials");
|
|
531
544
|
}
|
|
545
|
+
setProfileOverride(profile) {
|
|
546
|
+
this.profileOverride = profile;
|
|
547
|
+
}
|
|
532
548
|
async ensureConfigDir() {
|
|
533
549
|
try {
|
|
534
550
|
await fs2.mkdir(this.configDir, { recursive: true });
|
|
@@ -644,23 +660,54 @@ class CredentialsManager {
|
|
|
644
660
|
await this.writeCredentials(store);
|
|
645
661
|
}
|
|
646
662
|
async getActiveCredentials() {
|
|
647
|
-
const
|
|
648
|
-
const credentials = await this.getCredentials(
|
|
663
|
+
const profileName = this.profileOverride || process.env.ADK_PROFILE;
|
|
664
|
+
const credentials = await this.getCredentials(profileName);
|
|
649
665
|
if (!credentials) {
|
|
650
|
-
const
|
|
651
|
-
throw new Error(`No credentials found for profile '${
|
|
666
|
+
const displayName = profileName || "default";
|
|
667
|
+
throw new Error(`No credentials found for profile '${displayName}'. ` + `Please run 'adk login' to authenticate.`);
|
|
652
668
|
}
|
|
653
669
|
return credentials;
|
|
654
670
|
}
|
|
671
|
+
findProfileByApiUrl(store, apiUrl) {
|
|
672
|
+
const normalizedUrl = apiUrl.replace(/\/+$/, "");
|
|
673
|
+
for (const [, credentials] of Object.entries(store.profiles)) {
|
|
674
|
+
if (!credentials.apiUrl)
|
|
675
|
+
continue;
|
|
676
|
+
const profileUrl = credentials.apiUrl.replace(/\/+$/, "");
|
|
677
|
+
if (profileUrl === normalizedUrl) {
|
|
678
|
+
return credentials;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
return null;
|
|
682
|
+
}
|
|
655
683
|
async getAgentCredentials(agentPath) {
|
|
656
|
-
const baseCredentials = await this.getActiveCredentials();
|
|
657
684
|
const agentInfo = await resolveAgent(agentPath, {
|
|
658
685
|
required: true,
|
|
659
686
|
requireWorkspace: true
|
|
660
687
|
});
|
|
688
|
+
const agentApiUrl = agentInfo.apiUrl;
|
|
689
|
+
let baseCredentials;
|
|
690
|
+
const hasExplicitProfile = !!(this.profileOverride || process.env.ADK_PROFILE);
|
|
691
|
+
if (hasExplicitProfile) {
|
|
692
|
+
baseCredentials = await this.getActiveCredentials();
|
|
693
|
+
} else {
|
|
694
|
+
const store = await this.readCredentials();
|
|
695
|
+
const matchingCredentials = this.findProfileByApiUrl(store, agentApiUrl);
|
|
696
|
+
if (matchingCredentials) {
|
|
697
|
+
console.info(`Using profile matching agent.json API URL (${agentApiUrl})`);
|
|
698
|
+
baseCredentials = matchingCredentials;
|
|
699
|
+
} else {
|
|
700
|
+
const profileName = store.currentProfile || "default";
|
|
701
|
+
const activeCredentials = store.profiles[profileName];
|
|
702
|
+
if (!activeCredentials) {
|
|
703
|
+
throw new Error(`No credentials found for profile '${profileName}'. ` + `Please run 'adk login' to authenticate.`);
|
|
704
|
+
}
|
|
705
|
+
baseCredentials = activeCredentials;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
661
708
|
return {
|
|
662
709
|
...baseCredentials,
|
|
663
|
-
apiUrl:
|
|
710
|
+
apiUrl: agentApiUrl,
|
|
664
711
|
workspaceId: agentInfo.workspaceId,
|
|
665
712
|
botId: agentInfo.botId
|
|
666
713
|
};
|
|
@@ -682,7 +729,16 @@ var init_fs = () => {};
|
|
|
682
729
|
|
|
683
730
|
// src/generators/utils.ts
|
|
684
731
|
import path10 from "path";
|
|
685
|
-
|
|
732
|
+
async function getFormat() {
|
|
733
|
+
if (!_formatLoaded) {
|
|
734
|
+
_formatLoaded = true;
|
|
735
|
+
try {
|
|
736
|
+
const oxfmt = await import("oxfmt");
|
|
737
|
+
_format = oxfmt.format;
|
|
738
|
+
} catch {}
|
|
739
|
+
}
|
|
740
|
+
return _format;
|
|
741
|
+
}
|
|
686
742
|
function toMultilineComment(comment) {
|
|
687
743
|
if (!comment || comment.trim() === "") {
|
|
688
744
|
return "";
|
|
@@ -702,40 +758,30 @@ function toMultilineComment(comment) {
|
|
|
702
758
|
result += " */";
|
|
703
759
|
return result;
|
|
704
760
|
}
|
|
705
|
-
var
|
|
761
|
+
var _format = null, _formatLoaded = false, formatCode = async (code, filepath) => {
|
|
706
762
|
try {
|
|
707
763
|
if (!code || code.length > 1e6) {
|
|
708
764
|
return code;
|
|
709
765
|
}
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
766
|
+
const format = await getFormat();
|
|
767
|
+
if (!format)
|
|
768
|
+
return code;
|
|
769
|
+
const fileName = filepath || "file.ts";
|
|
770
|
+
const result = await format(fileName, code);
|
|
771
|
+
return result.code;
|
|
714
772
|
} catch (err) {
|
|
715
|
-
console.warn("Failed to format code with
|
|
773
|
+
console.warn("Failed to format code with oxfmt:", err);
|
|
716
774
|
console.warn(code.slice(0, 1000).split(`
|
|
717
775
|
`).map((l, i) => ` ${i.toString().padStart(2, "0")} | ${l}`).join(`
|
|
718
776
|
`));
|
|
719
777
|
return code;
|
|
720
778
|
}
|
|
721
|
-
}, ADK_VERSION = "1.
|
|
779
|
+
}, ADK_VERSION = "1.17.0", relative2 = (from, to) => {
|
|
722
780
|
const fromDir = path10.dirname(from);
|
|
723
781
|
const relative3 = path10.relative(fromDir, to);
|
|
724
782
|
return relative3.startsWith(".") ? relative3 : `./${relative3}`;
|
|
725
783
|
};
|
|
726
|
-
var init_utils =
|
|
727
|
-
PRETTIER_CONFIG = {
|
|
728
|
-
semi: true,
|
|
729
|
-
singleQuote: false,
|
|
730
|
-
tabWidth: 2,
|
|
731
|
-
trailingComma: "es5",
|
|
732
|
-
printWidth: 80,
|
|
733
|
-
arrowParens: "always",
|
|
734
|
-
requirePragma: false,
|
|
735
|
-
insertPragma: false,
|
|
736
|
-
proseWrap: "preserve"
|
|
737
|
-
};
|
|
738
|
-
});
|
|
784
|
+
var init_utils = () => {};
|
|
739
785
|
|
|
740
786
|
// src/generators/action-types.ts
|
|
741
787
|
var exports_action_types = {};
|
|
@@ -861,16 +907,31 @@ var init_integration_action_types = __esm(() => {
|
|
|
861
907
|
var require_package = __commonJS((exports, module) => {
|
|
862
908
|
module.exports = {
|
|
863
909
|
name: "@botpress/adk",
|
|
864
|
-
version: "1.
|
|
910
|
+
version: "1.17.0",
|
|
865
911
|
description: "Core ADK library for building AI agents on Botpress",
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
912
|
+
keywords: [
|
|
913
|
+
"adk",
|
|
914
|
+
"agent",
|
|
915
|
+
"ai",
|
|
916
|
+
"botpress",
|
|
917
|
+
"chatbot",
|
|
918
|
+
"conversational-ai",
|
|
919
|
+
"development-kit"
|
|
920
|
+
],
|
|
921
|
+
license: "MIT",
|
|
922
|
+
author: "Botpress",
|
|
923
|
+
repository: {
|
|
924
|
+
type: "git",
|
|
925
|
+
url: "https://github.com/botpress/adk"
|
|
926
|
+
},
|
|
869
927
|
files: [
|
|
870
928
|
"dist/**/*",
|
|
871
929
|
"package.json",
|
|
872
930
|
"README.md"
|
|
873
931
|
],
|
|
932
|
+
type: "module",
|
|
933
|
+
main: "dist/index.js",
|
|
934
|
+
types: "dist/index.d.ts",
|
|
874
935
|
exports: {
|
|
875
936
|
".": {
|
|
876
937
|
types: "./dist/index.d.ts",
|
|
@@ -885,33 +946,18 @@ var require_package = __commonJS((exports, module) => {
|
|
|
885
946
|
watch: "bun run build:types && bun build ./src/index.ts --outdir ./dist --target node --format esm --sourcemap --watch",
|
|
886
947
|
clean: "rm -rf dist",
|
|
887
948
|
prepublishOnly: "bun run clean && bun run build",
|
|
888
|
-
test: "
|
|
889
|
-
"test:watch": "
|
|
890
|
-
"test:
|
|
891
|
-
"
|
|
892
|
-
},
|
|
893
|
-
keywords: [
|
|
894
|
-
"botpress",
|
|
895
|
-
"adk",
|
|
896
|
-
"agent",
|
|
897
|
-
"ai",
|
|
898
|
-
"chatbot",
|
|
899
|
-
"conversational-ai",
|
|
900
|
-
"development-kit"
|
|
901
|
-
],
|
|
902
|
-
author: "Botpress",
|
|
903
|
-
license: "MIT",
|
|
904
|
-
repository: {
|
|
905
|
-
type: "git",
|
|
906
|
-
url: "https://github.com/botpress/adk"
|
|
949
|
+
test: "bun test",
|
|
950
|
+
"test:watch": "bun test --watch",
|
|
951
|
+
"test:coverage": "bun test",
|
|
952
|
+
"check:type": "tsc --noEmit"
|
|
907
953
|
},
|
|
908
954
|
dependencies: {
|
|
909
|
-
"@botpress/chat": "
|
|
910
|
-
"@botpress/cli": "
|
|
911
|
-
"@botpress/client": "
|
|
912
|
-
"@botpress/cognitive": "
|
|
913
|
-
"@botpress/runtime": "^1.
|
|
914
|
-
"@botpress/sdk": "
|
|
955
|
+
"@botpress/chat": "0.5.5",
|
|
956
|
+
"@botpress/cli": "6.2.2",
|
|
957
|
+
"@botpress/client": "1.38.1",
|
|
958
|
+
"@botpress/cognitive": "0.4.2",
|
|
959
|
+
"@botpress/runtime": "^1.17.0",
|
|
960
|
+
"@botpress/sdk": "6.3.1",
|
|
915
961
|
"@bpinternal/jex": "^1.2.4",
|
|
916
962
|
"@bpinternal/yargs-extra": "^0.0.21",
|
|
917
963
|
"@parcel/watcher": "^2.5.1",
|
|
@@ -920,11 +966,12 @@ var require_package = __commonJS((exports, module) => {
|
|
|
920
966
|
execa: "9.6.1",
|
|
921
967
|
glob: "^11.1.0",
|
|
922
968
|
luxon: "^3.7.2",
|
|
923
|
-
|
|
969
|
+
oxfmt: "^0.41.0",
|
|
924
970
|
semver: "^7.7.2",
|
|
925
971
|
"ts-morph": "^27.0.2"
|
|
926
972
|
},
|
|
927
973
|
devDependencies: {
|
|
974
|
+
"@bpinternal/zui": "2.1.0",
|
|
928
975
|
"@types/debug": "^4.1.12",
|
|
929
976
|
"@types/glob": "^9.0.0",
|
|
930
977
|
"@types/luxon": "^3.7.1",
|
|
@@ -935,8 +982,8 @@ var require_package = __commonJS((exports, module) => {
|
|
|
935
982
|
typescript: ">=4.5.0"
|
|
936
983
|
},
|
|
937
984
|
engines: {
|
|
938
|
-
|
|
939
|
-
|
|
985
|
+
bun: ">=1.3.9",
|
|
986
|
+
node: ">=22.0.0"
|
|
940
987
|
},
|
|
941
988
|
packageManager: "bun@1.3.9"
|
|
942
989
|
};
|
|
@@ -1105,6 +1152,9 @@ class Auth {
|
|
|
1105
1152
|
async setCurrentProfile(profileName) {
|
|
1106
1153
|
return this.credentialsManager.setCurrentProfile(profileName);
|
|
1107
1154
|
}
|
|
1155
|
+
setProfileOverride(profile) {
|
|
1156
|
+
this.credentialsManager.setProfileOverride(profile);
|
|
1157
|
+
}
|
|
1108
1158
|
async getActiveCredentials() {
|
|
1109
1159
|
return this.credentialsManager.getActiveCredentials();
|
|
1110
1160
|
}
|
|
@@ -1154,7 +1204,7 @@ import os3 from "os";
|
|
|
1154
1204
|
import path4 from "path";
|
|
1155
1205
|
import createDebug from "debug";
|
|
1156
1206
|
var debug = createDebug("adk:bp-cli");
|
|
1157
|
-
var BP_CLI_VERSION = "
|
|
1207
|
+
var BP_CLI_VERSION = "6.2.2";
|
|
1158
1208
|
var BP_CLI_INSTALL_ALL = path4.join(os3.homedir(), ".adk", `bp-cli`);
|
|
1159
1209
|
var BP_CLI_INSTALL_DIR = path4.join(BP_CLI_INSTALL_ALL, BP_CLI_VERSION);
|
|
1160
1210
|
var BP_CLI_BIN_PATH = path4.join(BP_CLI_INSTALL_DIR, "node_modules", "@botpress", "cli", "bin.js");
|
|
@@ -1649,6 +1699,15 @@ class BpDevCommand extends BaseCommand {
|
|
|
1649
1699
|
if (sourceMap) {
|
|
1650
1700
|
bpArgs.push("--sourceMap");
|
|
1651
1701
|
}
|
|
1702
|
+
const spanIngestUrl = `http://localhost:${this.options.spanIngestPort}`;
|
|
1703
|
+
const otlpEndpoint = this.options.otlpPort ? `http://localhost:${this.options.otlpPort}` : undefined;
|
|
1704
|
+
const traceLines = [`[bp-dev] Trace endpoints:`, ` ADK_SPAN_INGEST_URL=${spanIngestUrl}`];
|
|
1705
|
+
if (otlpEndpoint) {
|
|
1706
|
+
traceLines.push(` OTEL_EXPORTER_OTLP_ENDPOINT=${otlpEndpoint}`);
|
|
1707
|
+
}
|
|
1708
|
+
this.emit("stdout", traceLines.join(`
|
|
1709
|
+
`) + `
|
|
1710
|
+
`);
|
|
1652
1711
|
this.childProcess = execa4(bpCommand, bpArgs, {
|
|
1653
1712
|
cwd: botPath,
|
|
1654
1713
|
env: {
|
|
@@ -1665,6 +1724,9 @@ class BpDevCommand extends BaseCommand {
|
|
|
1665
1724
|
},
|
|
1666
1725
|
WORKER_MODE: "true",
|
|
1667
1726
|
WORKER_LIFETIME_MS: process.env.WORKER_LIFETIME_MS || "120000",
|
|
1727
|
+
ADK_SPAN_INGEST_URL: spanIngestUrl,
|
|
1728
|
+
...otlpEndpoint && { OTEL_EXPORTER_OTLP_ENDPOINT: otlpEndpoint },
|
|
1729
|
+
...this.options.botName && { ADK_BOT_NAME: this.options.botName },
|
|
1668
1730
|
ADK_DIRECTORY: join2(botPath, ".."),
|
|
1669
1731
|
AGENT_DIRECTORY: this.options.agentPath,
|
|
1670
1732
|
NODE_OPTIONS: `${process.env.NODE_OPTIONS || ""} --enable-source-maps`.trim()
|
|
@@ -1891,10 +1953,11 @@ class BpChatCommand extends BaseCommand {
|
|
|
1891
1953
|
try {
|
|
1892
1954
|
await this.childProcess;
|
|
1893
1955
|
} catch (error) {
|
|
1956
|
+
const errObj = error != null && typeof error === "object" ? error : {};
|
|
1894
1957
|
this.emit("error", {
|
|
1895
|
-
exitCode:
|
|
1896
|
-
stderr:
|
|
1897
|
-
message: error.message || "Chat command failed"
|
|
1958
|
+
exitCode: "exitCode" in errObj ? errObj.exitCode || 1 : 1,
|
|
1959
|
+
stderr: "stderr" in errObj ? errObj.stderr || "" : "",
|
|
1960
|
+
message: error instanceof Error ? error.message || "Chat command failed" : "Chat command failed"
|
|
1898
1961
|
});
|
|
1899
1962
|
throw error;
|
|
1900
1963
|
}
|
|
@@ -1905,6 +1968,227 @@ class BpChatCommand extends BaseCommand {
|
|
|
1905
1968
|
}
|
|
1906
1969
|
}
|
|
1907
1970
|
}
|
|
1971
|
+
// src/commands/opencode-command.ts
|
|
1972
|
+
import { execa as execa6 } from "execa";
|
|
1973
|
+
|
|
1974
|
+
// src/commands/opencode-config.ts
|
|
1975
|
+
var COPILOT_PROMPT = `You are the ADK Copilot — an expert assistant embedded in the Botpress Agent Development Kit control panel.
|
|
1976
|
+
|
|
1977
|
+
## Who you help
|
|
1978
|
+
A developer building an AI agent with the ADK. They're running \`adk dev\` and have the control panel open alongside you. They can see traces, logs, integrations, workflows, and tables in the UI.
|
|
1979
|
+
|
|
1980
|
+
## What you know
|
|
1981
|
+
The ADK is a high-level framework built on Botpress. An agent project has:
|
|
1982
|
+
- /actions — strongly-typed callable functions (Action from @botpress/runtime)
|
|
1983
|
+
- /tools — LLM-callable interfaces with natural language descriptions (Tool from @botpress/runtime)
|
|
1984
|
+
- /workflows — step-based, resumable long-running processes (Workflow from @botpress/runtime)
|
|
1985
|
+
- /conversations — channel-specific interaction handlers (Conversation from @botpress/runtime)
|
|
1986
|
+
- /tables — schema-validated data storage with semantic search (Table from @botpress/runtime)
|
|
1987
|
+
- /triggers — event subscription system (Trigger from @botpress/runtime)
|
|
1988
|
+
- /knowledge — RAG knowledge base documents
|
|
1989
|
+
- agent.config.ts — agent metadata, integrations, model configuration, variables
|
|
1990
|
+
|
|
1991
|
+
The ADK compiles these high-level primitives down to Botpress SDK primitives. Default to ADK terms. Only drop to Botpress SDK concepts when the problem requires it (SDK-level errors, compilation issues, or when the developer explicitly asks).
|
|
1992
|
+
|
|
1993
|
+
Schemas use \`z\` from @botpress/sdk (a Zod fork) — never import Zod directly.
|
|
1994
|
+
|
|
1995
|
+
You also have access to Botpress documentation search for platform-level questions (SDK, API, integrations).
|
|
1996
|
+
|
|
1997
|
+
## How you work
|
|
1998
|
+
|
|
1999
|
+
**Orient on first interaction.** If you haven't yet, use \`adk_get_agent_info\` to learn the project's structure, primitives, and integrations before answering.
|
|
2000
|
+
|
|
2001
|
+
**Conceptual vs. project questions.** Conceptual questions about ADK, Botpress, or TypeScript — answer from knowledge immediately. Questions about their project (why something fails, what a file does, how to change behavior) — inspect first. If in doubt, answer what you can immediately and inspect in parallel.
|
|
2002
|
+
|
|
2003
|
+
**Read freely, write carefully.** Inspecting files, querying traces, and searching the hub are always safe — do them without asking. But actions that modify the project (adding integrations, editing files, executing workflows, sending messages) should be confirmed first unless the developer explicitly asked you to do it.
|
|
2004
|
+
|
|
2005
|
+
**Debug by matching the approach to the problem:**
|
|
2006
|
+
- Developer gives you an error message → start from the error, don't begin at "step 1"
|
|
2007
|
+
- Build or type error → check the file and generated types. Traces won't help.
|
|
2008
|
+
- Runtime behavior is wrong ("it responds wrong") → query traces (\`adk_query_traces\`) for the conversation to find the failing span
|
|
2009
|
+
- Nothing happens → check dev logs (\`adk_get_dev_logs\`) for silent failures, then check if the handler is registered
|
|
2010
|
+
- When in doubt → start with \`adk_get_dev_logs\` with error filtering, then query traces
|
|
2011
|
+
|
|
2012
|
+
**Integrations.** First check if the integration already exists in the project. If it does, inspect its current configuration. Only search the hub (\`adk_search_integrations\`) when adding a new integration. Get details (\`adk_get_integration\`) to understand actions, events, channels, and config requirements. Add it (\`adk_add_integration\`) after the developer confirms.
|
|
2013
|
+
|
|
2014
|
+
**Test iteratively.** Send messages to the running bot (\`adk_send_message\`) to verify behavior. To continue a conversation, pass back both the \`conversationId\` and \`userKey\` from the previous response. Only test against the local dev bot.
|
|
2015
|
+
|
|
2016
|
+
**Workflows.** Get the input schema first by calling \`adk_start_workflow\` without a payload, then execute by calling it again with \`payload\` set to the correct input. For workflows with no required input, pass \`payload: {}\` — omitting payload returns the schema, it does not execute.
|
|
2017
|
+
|
|
2018
|
+
**Handle failures.** If a tool returns an error, tell the developer what happened and suggest a concrete next step (e.g., "Dev server isn't running — start it with \`adk dev\`"). Don't silently retry or ignore errors.
|
|
2019
|
+
|
|
2020
|
+
**Edit with precision.** When modifying code, change only what's needed to solve the problem. Don't refactor surrounding code, add features, or "improve" things that weren't asked about. When writing ADK primitives, match ADK conventions. For utility code, match the patterns already in the project.
|
|
2021
|
+
|
|
2022
|
+
## How you communicate
|
|
2023
|
+
|
|
2024
|
+
**Lead with the answer.** First sentence is the diagnosis, the solution, or the action you took. Context and explanation come after, if needed.
|
|
2025
|
+
|
|
2026
|
+
**Show, don't describe.** Instead of "you should add error handling," show the code change. Instead of "the trace shows a failure," show the relevant span data and what it means.
|
|
2027
|
+
|
|
2028
|
+
**Match the developer's energy.** Short question → short answer. Detailed question → detailed response. "Why is this broken?" → diagnosis + fix. "How do workflows work?" → teach.
|
|
2029
|
+
|
|
2030
|
+
**Hypothesize while verifying.** If you have a likely diagnosis, say so while you check. "This usually means X — checking your trace now" is better than silence followed by an answer.
|
|
2031
|
+
|
|
2032
|
+
**When you fix something, explain what you changed and why.** Don't apply changes silently — the developer needs to understand the fix to trust it and learn from it.
|
|
2033
|
+
|
|
2034
|
+
**When you don't know, say so plainly.** "I don't have enough context — can you share the error message?" is fine.
|
|
2035
|
+
|
|
2036
|
+
**Skip the filler.** No "Great question!", no "Let me help you with that." Just do it.
|
|
2037
|
+
|
|
2038
|
+
**Never read or display the contents of .env files or credentials.** If you need to verify a configuration value, ask the developer to confirm it.`;
|
|
2039
|
+
function buildOpenCodeConfig(options) {
|
|
2040
|
+
const command = [options.adkBinPath, "mcp", "--cwd", options.agentPath];
|
|
2041
|
+
if (options.uiServerPort)
|
|
2042
|
+
command.push("--port", String(options.uiServerPort));
|
|
2043
|
+
return {
|
|
2044
|
+
...options.openCodePort && {
|
|
2045
|
+
server: {
|
|
2046
|
+
port: options.openCodePort,
|
|
2047
|
+
...options.corsOrigins?.length && { cors: options.corsOrigins }
|
|
2048
|
+
}
|
|
2049
|
+
},
|
|
2050
|
+
mcp: {
|
|
2051
|
+
adk: {
|
|
2052
|
+
type: "local",
|
|
2053
|
+
command
|
|
2054
|
+
}
|
|
2055
|
+
},
|
|
2056
|
+
agent: {
|
|
2057
|
+
default: {
|
|
2058
|
+
description: "ADK Copilot — helps build and debug Botpress ADK agents",
|
|
2059
|
+
prompt: COPILOT_PROMPT
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
};
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
// src/commands/opencode-command.ts
|
|
2066
|
+
class OpenCodeCommand extends BaseCommand {
|
|
2067
|
+
options;
|
|
2068
|
+
childProcess = null;
|
|
2069
|
+
killed = false;
|
|
2070
|
+
readyEmitted = false;
|
|
2071
|
+
constructor(options) {
|
|
2072
|
+
super();
|
|
2073
|
+
this.options = options;
|
|
2074
|
+
}
|
|
2075
|
+
static async isInstalled() {
|
|
2076
|
+
try {
|
|
2077
|
+
const cmd = process.platform === "win32" ? "where" : "which";
|
|
2078
|
+
await execa6(cmd, ["opencode"]);
|
|
2079
|
+
return true;
|
|
2080
|
+
} catch {
|
|
2081
|
+
return false;
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
emitReady() {
|
|
2085
|
+
if (this.readyEmitted || this.killed)
|
|
2086
|
+
return;
|
|
2087
|
+
this.readyEmitted = true;
|
|
2088
|
+
this.emit("progress", {
|
|
2089
|
+
type: "ready",
|
|
2090
|
+
startTime: Date.now(),
|
|
2091
|
+
data: { port: this.options.port }
|
|
2092
|
+
});
|
|
2093
|
+
}
|
|
2094
|
+
async run() {
|
|
2095
|
+
const { port, cwd, corsOrigins = [] } = this.options;
|
|
2096
|
+
this.emit("progress", { type: "checking", startTime: Date.now() });
|
|
2097
|
+
const installed = await OpenCodeCommand.isInstalled();
|
|
2098
|
+
if (!installed) {
|
|
2099
|
+
this.emit("progress", {
|
|
2100
|
+
type: "error",
|
|
2101
|
+
startTime: Date.now(),
|
|
2102
|
+
data: { reason: "opencode not installed" }
|
|
2103
|
+
});
|
|
2104
|
+
return;
|
|
2105
|
+
}
|
|
2106
|
+
this.emit("progress", { type: "starting", startTime: Date.now() });
|
|
2107
|
+
const args = ["serve", "--port", String(port)];
|
|
2108
|
+
for (const origin of corsOrigins) {
|
|
2109
|
+
args.push("--cors", origin);
|
|
2110
|
+
}
|
|
2111
|
+
const adkBin = this.options.adkBinPath || "adk";
|
|
2112
|
+
const opencodeConfig = JSON.stringify(buildOpenCodeConfig({
|
|
2113
|
+
adkBinPath: adkBin,
|
|
2114
|
+
agentPath: cwd,
|
|
2115
|
+
uiServerPort: this.options.uiServerPort,
|
|
2116
|
+
openCodePort: port,
|
|
2117
|
+
corsOrigins
|
|
2118
|
+
}));
|
|
2119
|
+
this.childProcess = execa6("opencode", args, {
|
|
2120
|
+
cwd,
|
|
2121
|
+
env: { ...process.env, OPENCODE_CONFIG_CONTENT: opencodeConfig },
|
|
2122
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
2123
|
+
});
|
|
2124
|
+
if (this.childProcess.stdout) {
|
|
2125
|
+
this.childProcess.stdout.on("data", (data) => {
|
|
2126
|
+
this.emit("stdout", data.toString());
|
|
2127
|
+
});
|
|
2128
|
+
}
|
|
2129
|
+
if (this.childProcess.stderr) {
|
|
2130
|
+
this.childProcess.stderr.on("data", (data) => {
|
|
2131
|
+
const text = data.toString();
|
|
2132
|
+
this.emit("stderr", text);
|
|
2133
|
+
const lower = text.toLowerCase();
|
|
2134
|
+
if (lower.includes("eaddrinuse") || lower.includes("address already in use")) {
|
|
2135
|
+
this.emit("progress", {
|
|
2136
|
+
type: "error",
|
|
2137
|
+
startTime: Date.now(),
|
|
2138
|
+
data: { reason: `Port ${port} already in use` }
|
|
2139
|
+
});
|
|
2140
|
+
this.kill();
|
|
2141
|
+
}
|
|
2142
|
+
});
|
|
2143
|
+
}
|
|
2144
|
+
this.childProcess.then(() => {
|
|
2145
|
+
if (!this.killed && !this.readyEmitted) {
|
|
2146
|
+
this.readyEmitted = true;
|
|
2147
|
+
this.emit("progress", {
|
|
2148
|
+
type: "error",
|
|
2149
|
+
startTime: Date.now(),
|
|
2150
|
+
data: { reason: "OpenCode process exited unexpectedly" }
|
|
2151
|
+
});
|
|
2152
|
+
}
|
|
2153
|
+
}, (error) => {
|
|
2154
|
+
if (this.killed)
|
|
2155
|
+
return;
|
|
2156
|
+
this.readyEmitted = true;
|
|
2157
|
+
this.emit("progress", {
|
|
2158
|
+
type: "error",
|
|
2159
|
+
startTime: Date.now(),
|
|
2160
|
+
data: { reason: error.message || "OpenCode process exited unexpectedly" }
|
|
2161
|
+
});
|
|
2162
|
+
});
|
|
2163
|
+
this.pollUntilReady(port);
|
|
2164
|
+
}
|
|
2165
|
+
async pollUntilReady(port) {
|
|
2166
|
+
const deadline = Date.now() + 15000;
|
|
2167
|
+
while (!this.killed && !this.readyEmitted && Date.now() < deadline) {
|
|
2168
|
+
try {
|
|
2169
|
+
const res = await fetch(`http://localhost:${port}/`);
|
|
2170
|
+
if (res.ok || res.status < 500) {
|
|
2171
|
+
this.emitReady();
|
|
2172
|
+
return;
|
|
2173
|
+
}
|
|
2174
|
+
} catch {}
|
|
2175
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
2176
|
+
}
|
|
2177
|
+
if (!this.readyEmitted && !this.killed) {
|
|
2178
|
+
this.emit("progress", {
|
|
2179
|
+
type: "error",
|
|
2180
|
+
startTime: Date.now(),
|
|
2181
|
+
data: { reason: "OpenCode server did not respond in time" }
|
|
2182
|
+
});
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
kill(signal = "SIGTERM") {
|
|
2186
|
+
this.killed = true;
|
|
2187
|
+
if (this.childProcess) {
|
|
2188
|
+
this.childProcess.kill(signal);
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
1908
2192
|
// src/workspace/workspace-cache.ts
|
|
1909
2193
|
import { Client as Client3 } from "@botpress/client";
|
|
1910
2194
|
class WorkspaceCache {
|
|
@@ -1981,7 +2265,8 @@ function getChatClient(cwd = process.cwd()) {
|
|
|
1981
2265
|
return Client4;
|
|
1982
2266
|
}
|
|
1983
2267
|
// src/utils/json-ordering.ts
|
|
1984
|
-
var agentInfoKeyOrder = ["botId", "workspaceId", "apiUrl"
|
|
2268
|
+
var agentInfoKeyOrder = ["botId", "workspaceId", "apiUrl"];
|
|
2269
|
+
var agentLocalInfoKeyOrder = ["devId"];
|
|
1985
2270
|
var dependenciesKeyOrder = ["integrations"];
|
|
1986
2271
|
var integrationKeyOrder = ["version", "enabled", "configurationType", "config"];
|
|
1987
2272
|
function orderKeys(obj, keyOrder) {
|
|
@@ -2066,7 +2351,7 @@ class AssetsCacheManager {
|
|
|
2066
2351
|
const content = await fs4.readFile(this.cachePath, "utf-8");
|
|
2067
2352
|
this.cache = JSON.parse(content);
|
|
2068
2353
|
return this.cache;
|
|
2069
|
-
} catch
|
|
2354
|
+
} catch {
|
|
2070
2355
|
this.cache = {
|
|
2071
2356
|
version: "1.0",
|
|
2072
2357
|
entries: {}
|
|
@@ -2599,7 +2884,7 @@ class EnhancedIntegrationCache {
|
|
|
2599
2884
|
|
|
2600
2885
|
// src/agent-project/dependencies-parser.ts
|
|
2601
2886
|
init_validation_errors();
|
|
2602
|
-
import { z as z2
|
|
2887
|
+
import { z as z2 } from "@botpress/sdk";
|
|
2603
2888
|
var INTEGRATION_ALIAS_MIN_LENGTH = 2;
|
|
2604
2889
|
var INTEGRATION_ALIAS_MAX_LENGTH = 100;
|
|
2605
2890
|
var INTEGRATION_ALIAS_REGEX = /^(?:[a-z][a-z0-9_-]*\/)?[a-z][a-z0-9_-]*$/;
|
|
@@ -2610,10 +2895,10 @@ var integrationRefSchema = z2.string().transform((val, ctx) => {
|
|
|
2610
2895
|
const match = val.match(/^(?:([^/]+)\/)?([^@]+)@(.+)$/);
|
|
2611
2896
|
if (!match) {
|
|
2612
2897
|
ctx.addIssue({
|
|
2613
|
-
code:
|
|
2898
|
+
code: "custom",
|
|
2614
2899
|
message: `Invalid integration version format: ${val}. Expected format: 'name@version' or 'workspace/name@version'`
|
|
2615
2900
|
});
|
|
2616
|
-
return
|
|
2901
|
+
return;
|
|
2617
2902
|
}
|
|
2618
2903
|
const [, workspace, name, version] = match;
|
|
2619
2904
|
return {
|
|
@@ -2712,10 +2997,10 @@ var pluginRefSchema = z2.string().transform((val, ctx) => {
|
|
|
2712
2997
|
const match = val.match(/^([^/@]+)@(.+)$/);
|
|
2713
2998
|
if (!match) {
|
|
2714
2999
|
ctx.addIssue({
|
|
2715
|
-
code:
|
|
3000
|
+
code: "custom",
|
|
2716
3001
|
message: `Invalid plugin version format: ${val}. Expected format: 'name@version' (no workspace prefix)`
|
|
2717
3002
|
});
|
|
2718
|
-
return
|
|
3003
|
+
return;
|
|
2719
3004
|
}
|
|
2720
3005
|
const [, name, version] = match;
|
|
2721
3006
|
return {
|
|
@@ -2772,7 +3057,7 @@ class PluginParser {
|
|
|
2772
3057
|
if (!pluginConfig.dependencies) {
|
|
2773
3058
|
continue;
|
|
2774
3059
|
}
|
|
2775
|
-
for (const [
|
|
3060
|
+
for (const [_depAlias, depMapping] of Object.entries(pluginConfig.dependencies)) {
|
|
2776
3061
|
if (!integrationAliases.includes(depMapping.integrationAlias)) {
|
|
2777
3062
|
errors.push(ValidationErrors.invalidPluginDependency(alias, depMapping.integrationAlias, integrationAliases));
|
|
2778
3063
|
}
|
|
@@ -3043,7 +3328,7 @@ class IntegrationCache {
|
|
|
3043
3328
|
}
|
|
3044
3329
|
}
|
|
3045
3330
|
return cached.definition;
|
|
3046
|
-
} catch
|
|
3331
|
+
} catch {
|
|
3047
3332
|
return null;
|
|
3048
3333
|
}
|
|
3049
3334
|
}
|
|
@@ -4432,7 +4717,7 @@ async function expandExports(options) {
|
|
|
4432
4717
|
});
|
|
4433
4718
|
return {};
|
|
4434
4719
|
}
|
|
4435
|
-
currentError = currentError.cause;
|
|
4720
|
+
currentError = currentError instanceof Error ? currentError.cause : undefined;
|
|
4436
4721
|
}
|
|
4437
4722
|
throw importError;
|
|
4438
4723
|
}
|
|
@@ -4698,20 +4983,62 @@ class AgentProject {
|
|
|
4698
4983
|
return this._assetsManager;
|
|
4699
4984
|
}
|
|
4700
4985
|
async createAgentInfo(info) {
|
|
4986
|
+
const { devId, ...agentJsonInfo } = info;
|
|
4701
4987
|
const agentPath = path13.join(this._path, "agent.json");
|
|
4702
|
-
const agentContent = stringifyWithOrder(
|
|
4988
|
+
const agentContent = stringifyWithOrder(agentJsonInfo, agentInfoKeyOrder);
|
|
4703
4989
|
await fs10.writeFile(agentPath, agentContent);
|
|
4704
4990
|
this._agentInfo = info;
|
|
4991
|
+
if (devId) {
|
|
4992
|
+
await this.createAgentLocalInfo({ devId });
|
|
4993
|
+
}
|
|
4705
4994
|
}
|
|
4706
4995
|
async updateAgentInfo(updates) {
|
|
4707
4996
|
if (!this._agentInfo) {
|
|
4708
4997
|
throw new Error("No agent.json found. Use createAgentInfo() first.");
|
|
4709
4998
|
}
|
|
4710
|
-
const
|
|
4999
|
+
const { devId, ...agentJsonUpdates } = updates;
|
|
5000
|
+
const updatedInfo = { ...this._agentInfo, ...agentJsonUpdates };
|
|
5001
|
+
const { devId: _devId, ...agentJsonData } = updatedInfo;
|
|
4711
5002
|
const agentPath = path13.join(this._path, "agent.json");
|
|
4712
|
-
const agentContent = stringifyWithOrder(
|
|
5003
|
+
const agentContent = stringifyWithOrder(agentJsonData, agentInfoKeyOrder);
|
|
4713
5004
|
await fs10.writeFile(agentPath, agentContent);
|
|
4714
5005
|
this._agentInfo = updatedInfo;
|
|
5006
|
+
if (devId !== undefined) {
|
|
5007
|
+
await this.updateAgentLocalInfo({ devId });
|
|
5008
|
+
}
|
|
5009
|
+
}
|
|
5010
|
+
async createAgentLocalInfo(info) {
|
|
5011
|
+
const localPath = path13.join(this._path, "agent.local.json");
|
|
5012
|
+
let existing = {};
|
|
5013
|
+
try {
|
|
5014
|
+
const content2 = await fs10.readFile(localPath, "utf-8");
|
|
5015
|
+
existing = JSON.parse(content2);
|
|
5016
|
+
} catch {}
|
|
5017
|
+
const merged = { ...existing, ...info };
|
|
5018
|
+
const content = stringifyWithOrder(merged, agentLocalInfoKeyOrder);
|
|
5019
|
+
await fs10.writeFile(localPath, content);
|
|
5020
|
+
if (this._agentInfo) {
|
|
5021
|
+
this._agentInfo.devId = merged.devId;
|
|
5022
|
+
}
|
|
5023
|
+
}
|
|
5024
|
+
async updateAgentLocalInfo(updates) {
|
|
5025
|
+
const localPath = path13.join(this._path, "agent.local.json");
|
|
5026
|
+
let existing = {};
|
|
5027
|
+
try {
|
|
5028
|
+
const content2 = await fs10.readFile(localPath, "utf-8");
|
|
5029
|
+
existing = JSON.parse(content2);
|
|
5030
|
+
} catch {}
|
|
5031
|
+
const updated = { ...existing, ...updates };
|
|
5032
|
+
for (const key of Object.keys(updated)) {
|
|
5033
|
+
if (updated[key] === undefined) {
|
|
5034
|
+
delete updated[key];
|
|
5035
|
+
}
|
|
5036
|
+
}
|
|
5037
|
+
const content = stringifyWithOrder(updated, agentLocalInfoKeyOrder);
|
|
5038
|
+
await fs10.writeFile(localPath, content);
|
|
5039
|
+
if (this._agentInfo) {
|
|
5040
|
+
this._agentInfo.devId = updated.devId;
|
|
5041
|
+
}
|
|
4715
5042
|
}
|
|
4716
5043
|
requiresAgentInfo(operation) {
|
|
4717
5044
|
if (!this._agentInfo?.botId) {
|
|
@@ -4902,6 +5229,19 @@ ${err.stack?.split(`
|
|
|
4902
5229
|
console.warn(`Failed to register data source workflows for ${kbPath}:`, error);
|
|
4903
5230
|
}
|
|
4904
5231
|
}
|
|
5232
|
+
isBarrelReexport(existing, newPath, newExport, newDefinition) {
|
|
5233
|
+
const isNewBarrel = /^index\.[tj]s$/i.test(path13.basename(newPath));
|
|
5234
|
+
const isExistingBarrel = /^index\.[tj]s$/i.test(path13.basename(existing.path));
|
|
5235
|
+
if (!isNewBarrel && !isExistingBarrel) {
|
|
5236
|
+
return false;
|
|
5237
|
+
}
|
|
5238
|
+
if (isExistingBarrel && !isNewBarrel) {
|
|
5239
|
+
existing.path = newPath;
|
|
5240
|
+
existing.export = newExport;
|
|
5241
|
+
existing.definition = newDefinition;
|
|
5242
|
+
}
|
|
5243
|
+
return true;
|
|
5244
|
+
}
|
|
4905
5245
|
getChannelsList(channelSpec) {
|
|
4906
5246
|
if (channelSpec === "*") {
|
|
4907
5247
|
return ["*"];
|
|
@@ -4984,6 +5324,9 @@ ${err.stack?.split(`
|
|
|
4984
5324
|
return existingChannels.some((ch) => newChannels.includes(ch));
|
|
4985
5325
|
});
|
|
4986
5326
|
if (overlapping) {
|
|
5327
|
+
if (this.isBarrelReexport(overlapping, relPath, key, definition)) {
|
|
5328
|
+
continue;
|
|
5329
|
+
}
|
|
4987
5330
|
this._warnings.push({
|
|
4988
5331
|
$type: "ValidationError",
|
|
4989
5332
|
code: "DUPLICATE_PRIMITIVE" /* DUPLICATE_PRIMITIVE */,
|
|
@@ -5001,6 +5344,9 @@ ${err.stack?.split(`
|
|
|
5001
5344
|
} else if (Primitives2.Definitions.isKnowledgeDefinition(definition)) {
|
|
5002
5345
|
const existing = this._knowledge.find((p) => p.definition.name === definition.name);
|
|
5003
5346
|
if (existing) {
|
|
5347
|
+
if (this.isBarrelReexport(existing, relPath, key, definition)) {
|
|
5348
|
+
continue;
|
|
5349
|
+
}
|
|
5004
5350
|
this._warnings.push({
|
|
5005
5351
|
$type: "ValidationError",
|
|
5006
5352
|
code: "DUPLICATE_PRIMITIVE" /* DUPLICATE_PRIMITIVE */,
|
|
@@ -5019,6 +5365,9 @@ ${err.stack?.split(`
|
|
|
5019
5365
|
} else if (Primitives2.Definitions.isTriggerDefinition(definition)) {
|
|
5020
5366
|
const existing = this._triggers.find((p) => p.definition.name === definition.name);
|
|
5021
5367
|
if (existing) {
|
|
5368
|
+
if (this.isBarrelReexport(existing, relPath, key, definition)) {
|
|
5369
|
+
continue;
|
|
5370
|
+
}
|
|
5022
5371
|
this._warnings.push({
|
|
5023
5372
|
$type: "ValidationError",
|
|
5024
5373
|
code: "DUPLICATE_PRIMITIVE" /* DUPLICATE_PRIMITIVE */,
|
|
@@ -5036,6 +5385,9 @@ ${err.stack?.split(`
|
|
|
5036
5385
|
} else if (Primitives2.Definitions.isWorkflowDefinition(definition)) {
|
|
5037
5386
|
const existing = this._workflows.find((p) => p.definition.name === definition.name);
|
|
5038
5387
|
if (existing) {
|
|
5388
|
+
if (this.isBarrelReexport(existing, relPath, key, definition)) {
|
|
5389
|
+
continue;
|
|
5390
|
+
}
|
|
5039
5391
|
this._warnings.push({
|
|
5040
5392
|
$type: "ValidationError",
|
|
5041
5393
|
code: "DUPLICATE_PRIMITIVE" /* DUPLICATE_PRIMITIVE */,
|
|
@@ -5053,6 +5405,9 @@ ${err.stack?.split(`
|
|
|
5053
5405
|
} else if (Primitives2.Definitions.isActionDefinition(definition)) {
|
|
5054
5406
|
const existing = this._actions.find((p) => p.definition.name === definition.name);
|
|
5055
5407
|
if (existing) {
|
|
5408
|
+
if (this.isBarrelReexport(existing, relPath, key, definition)) {
|
|
5409
|
+
continue;
|
|
5410
|
+
}
|
|
5056
5411
|
this._warnings.push({
|
|
5057
5412
|
$type: "ValidationError",
|
|
5058
5413
|
code: "DUPLICATE_PRIMITIVE" /* DUPLICATE_PRIMITIVE */,
|
|
@@ -5070,6 +5425,9 @@ ${err.stack?.split(`
|
|
|
5070
5425
|
} else if (Primitives2.Definitions.isTableDefinition(definition)) {
|
|
5071
5426
|
const existing = this._tables.find((p) => p.definition.name === definition.name);
|
|
5072
5427
|
if (existing) {
|
|
5428
|
+
if (this.isBarrelReexport(existing, relPath, key, definition)) {
|
|
5429
|
+
continue;
|
|
5430
|
+
}
|
|
5073
5431
|
this._warnings.push({
|
|
5074
5432
|
$type: "ValidationError",
|
|
5075
5433
|
code: "DUPLICATE_PRIMITIVE" /* DUPLICATE_PRIMITIVE */,
|
|
@@ -5393,22 +5751,36 @@ adk deploy # Deploy to Botpress Cloud
|
|
|
5393
5751
|
adk chat # Chat with your agent in the terminal
|
|
5394
5752
|
\`\`\`
|
|
5395
5753
|
|
|
5396
|
-
##
|
|
5754
|
+
## MCP Tools (ADK Dev Server)
|
|
5397
5755
|
|
|
5398
|
-
This project
|
|
5756
|
+
This project includes an MCP server that provides AI coding assistants with deep ADK integration.
|
|
5757
|
+
Run \`adk mcp:init --all\` to generate configuration for your editor, or use the tools below directly.
|
|
5399
5758
|
|
|
5400
|
-
|
|
5401
|
-
| ------------------ | ------------------------------------------------ |
|
|
5402
|
-
| \`/adk\` | ADK concepts, patterns, and API reference |
|
|
5403
|
-
| \`/adk-integration\` | Finding and using Botpress integrations |
|
|
5404
|
-
| \`/adk-debugger\` | Debugging with traces and test conversations |
|
|
5405
|
-
| \`/adk-frontend\` | Building frontends that connect to ADK bots |
|
|
5759
|
+
### Debugging & Testing
|
|
5406
5760
|
|
|
5407
|
-
|
|
5761
|
+
| Tool | Use for |
|
|
5762
|
+
| ------------------ | ------------------------------------------------------------ |
|
|
5763
|
+
| \`adk_send_message\` | Send a test message to the running bot and receive responses |
|
|
5764
|
+
| \`adk_query_traces\` | Query trace spans for debugging conversations and workflows |
|
|
5765
|
+
| \`adk_get_dev_logs\` | Get dev server logs, build output, errors, and warnings |
|
|
5408
5766
|
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5767
|
+
### Project & Integration Management
|
|
5768
|
+
|
|
5769
|
+
| Tool | Use for |
|
|
5770
|
+
| ------------------------- | ----------------------------------------------------------- |
|
|
5771
|
+
| \`adk_get_agent_info\` | Get project info: name, version, and all primitives |
|
|
5772
|
+
| \`adk_search_integrations\` | Search available integrations on the Botpress Hub |
|
|
5773
|
+
| \`adk_get_integration\` | Get detailed info about an integration before adding it |
|
|
5774
|
+
| \`adk_add_integration\` | Add an integration to the project (updates agent.config.ts) |
|
|
5775
|
+
|
|
5776
|
+
### Workflows
|
|
5777
|
+
|
|
5778
|
+
| Tool | Use for |
|
|
5779
|
+
| -------------------- | ------------------------------------------ |
|
|
5780
|
+
| \`adk_list_workflows\` | List available workflows with descriptions |
|
|
5781
|
+
| \`adk_start_workflow\` | Start a workflow or get its input schema |
|
|
5782
|
+
|
|
5783
|
+
> **Tip:** The dev server must be running (\`adk dev\`) for debugging and testing tools to work.
|
|
5412
5784
|
|
|
5413
5785
|
## Project Overview
|
|
5414
5786
|
|
|
@@ -5468,7 +5840,7 @@ class AgentProjectGenerator {
|
|
|
5468
5840
|
deploy: "adk deploy"
|
|
5469
5841
|
},
|
|
5470
5842
|
dependencies: {
|
|
5471
|
-
"@botpress/runtime": `^${"1.
|
|
5843
|
+
"@botpress/runtime": `^${"1.17.0"}`
|
|
5472
5844
|
},
|
|
5473
5845
|
devDependencies: {
|
|
5474
5846
|
typescript: "^5.9.3"
|
|
@@ -5571,6 +5943,12 @@ dist/
|
|
|
5571
5943
|
.env.local
|
|
5572
5944
|
.env.production
|
|
5573
5945
|
|
|
5946
|
+
# Local development
|
|
5947
|
+
agent.local.json
|
|
5948
|
+
|
|
5949
|
+
# MCP configuration (auto-generated by adk mcp:init)
|
|
5950
|
+
.mcp.json
|
|
5951
|
+
|
|
5574
5952
|
# IDE files
|
|
5575
5953
|
.vscode/
|
|
5576
5954
|
.idea/
|
|
@@ -6001,7 +6379,7 @@ if (typeof globalThis !== 'undefined') {
|
|
|
6001
6379
|
}
|
|
6002
6380
|
}
|
|
6003
6381
|
// src/generators/integration-types.ts
|
|
6004
|
-
import {
|
|
6382
|
+
import { z as z3 } from "@botpress/sdk";
|
|
6005
6383
|
import crypto2 from "crypto";
|
|
6006
6384
|
import path18 from "path";
|
|
6007
6385
|
|
|
@@ -6029,6 +6407,7 @@ function getPluginAlias(pluginName) {
|
|
|
6029
6407
|
}
|
|
6030
6408
|
|
|
6031
6409
|
// src/generators/integration-types.ts
|
|
6410
|
+
var { transforms } = z3;
|
|
6032
6411
|
var getIntegrationHash = (integration) => {
|
|
6033
6412
|
return crypto2.createHash("sha256").update(`${integration.alias}|${integration.definition?.id}|${integration.definition?.version}|${integration.definition?.updatedAt}`).digest("hex");
|
|
6034
6413
|
};
|
|
@@ -6261,9 +6640,10 @@ Description: ${tag?.description}`);
|
|
|
6261
6640
|
}
|
|
6262
6641
|
if (integration.definition?.configurations) {
|
|
6263
6642
|
for (const [key, config] of Object.entries(integration.definition.configurations)) {
|
|
6264
|
-
const
|
|
6265
|
-
const
|
|
6266
|
-
const
|
|
6643
|
+
const configRecord = config;
|
|
6644
|
+
const title = configRecord.title || key;
|
|
6645
|
+
const description = configRecord.description || "";
|
|
6646
|
+
const schema = configRecord.schema;
|
|
6267
6647
|
let tsType = "{}";
|
|
6268
6648
|
if (schema) {
|
|
6269
6649
|
tsType = transforms.fromJSONSchema(schema).toTypescriptType();
|
|
@@ -6380,12 +6760,14 @@ async function generateClientWrapper(project) {
|
|
|
6380
6760
|
let schema;
|
|
6381
6761
|
let computed = false;
|
|
6382
6762
|
if (typeof colDef === "object" && colDef !== null && "schema" in colDef) {
|
|
6383
|
-
|
|
6384
|
-
|
|
6763
|
+
const colDefRecord = colDef;
|
|
6764
|
+
schema = colDefRecord.schema;
|
|
6765
|
+
computed = colDefRecord.computed || false;
|
|
6385
6766
|
} else {
|
|
6386
6767
|
schema = colDef;
|
|
6387
6768
|
}
|
|
6388
|
-
const
|
|
6769
|
+
const schemaObj = schema;
|
|
6770
|
+
const tsType = typeof schemaObj.toTypescriptType === "function" ? schemaObj.toTypescriptType({ treatDefaultAsOptional: true }) : "any";
|
|
6389
6771
|
if (!computed) {
|
|
6390
6772
|
inputColumns.push(`${colName}: ${tsType}`);
|
|
6391
6773
|
}
|
|
@@ -6700,10 +7082,11 @@ import fs18 from "fs/promises";
|
|
|
6700
7082
|
import path38 from "path";
|
|
6701
7083
|
|
|
6702
7084
|
// src/generators/plugin-types.ts
|
|
6703
|
-
import {
|
|
7085
|
+
import { z as z4 } from "@botpress/sdk";
|
|
6704
7086
|
import crypto4 from "crypto";
|
|
6705
7087
|
import path20 from "path";
|
|
6706
7088
|
init_utils();
|
|
7089
|
+
var { transforms: transforms2 } = z4;
|
|
6707
7090
|
function stripRefs(schema) {
|
|
6708
7091
|
if (typeof schema !== "object" || schema === null) {
|
|
6709
7092
|
return schema;
|
|
@@ -6849,10 +7232,11 @@ export type PluginActions = PluginsMap<Plugins>;
|
|
|
6849
7232
|
}
|
|
6850
7233
|
|
|
6851
7234
|
// src/generators/interface-types.ts
|
|
6852
|
-
import {
|
|
7235
|
+
import { z as z5 } from "@botpress/sdk";
|
|
6853
7236
|
import crypto5 from "crypto";
|
|
6854
7237
|
import path22 from "path";
|
|
6855
7238
|
init_utils();
|
|
7239
|
+
var { transforms: transforms3 } = z5;
|
|
6856
7240
|
var sameMajorVersion = (a, b) => {
|
|
6857
7241
|
const majorA = a.split(".")[0];
|
|
6858
7242
|
const majorB = b.split(".")[0];
|
|
@@ -7638,7 +8022,7 @@ class DevIdManager {
|
|
|
7638
8022
|
if (!project.agentInfo) {
|
|
7639
8023
|
throw ValidationErrors.agentNotLinked();
|
|
7640
8024
|
}
|
|
7641
|
-
await project.
|
|
8025
|
+
await project.updateAgentLocalInfo({
|
|
7642
8026
|
devId: projectCache.devId
|
|
7643
8027
|
});
|
|
7644
8028
|
}
|
|
@@ -7665,7 +8049,7 @@ class DevIdManager {
|
|
|
7665
8049
|
const client = await this.getClient();
|
|
7666
8050
|
await client.getBot({ id: agentInfo.devId });
|
|
7667
8051
|
return true;
|
|
7668
|
-
} catch
|
|
8052
|
+
} catch {
|
|
7669
8053
|
return false;
|
|
7670
8054
|
}
|
|
7671
8055
|
}
|
|
@@ -8038,10 +8422,11 @@ class PluginSync {
|
|
|
8038
8422
|
|
|
8039
8423
|
// src/bot-generator/generator.ts
|
|
8040
8424
|
init_utils();
|
|
8041
|
-
import {
|
|
8425
|
+
import { z as z6 } from "@botpress/sdk";
|
|
8042
8426
|
init_constants();
|
|
8043
8427
|
import { BuiltInActions as BuiltInActions2, BuiltInWorkflows as BuiltInWorkflows4, Primitives as Primitives3 } from "@botpress/runtime/internal";
|
|
8044
8428
|
import { BUILT_IN_TAGS as BUILT_IN_TAGS2 } from "@botpress/runtime/definition";
|
|
8429
|
+
var { transforms: transforms4 } = z6;
|
|
8045
8430
|
var plural = (n, word) => `${n} ${word}${n === 1 ? "" : "s"}`;
|
|
8046
8431
|
function isBuiltinWorkflow3(name) {
|
|
8047
8432
|
return !!Object.values(BuiltInWorkflows4).find((x) => x.name === name);
|
|
@@ -9055,7 +9440,9 @@ export default bot;`;
|
|
|
9055
9440
|
}
|
|
9056
9441
|
{
|
|
9057
9442
|
const dest = path38.join(srcDir, "triggers.ts");
|
|
9058
|
-
const {
|
|
9443
|
+
const {
|
|
9444
|
+
z: { transforms: transforms5 }
|
|
9445
|
+
} = await import("@botpress/sdk");
|
|
9059
9446
|
const imports = new Map;
|
|
9060
9447
|
const exports = new Set;
|
|
9061
9448
|
const payloadTypes = {};
|
|
@@ -9343,7 +9730,9 @@ async function generateBotProject(options) {
|
|
|
9343
9730
|
}
|
|
9344
9731
|
// src/tables/table-manager.ts
|
|
9345
9732
|
import { Client as Client15 } from "@botpress/client";
|
|
9346
|
-
import {
|
|
9733
|
+
import { z as z7 } from "@botpress/sdk";
|
|
9734
|
+
var { transforms: transforms5 } = z7;
|
|
9735
|
+
|
|
9347
9736
|
class TableManager {
|
|
9348
9737
|
client;
|
|
9349
9738
|
botId;
|
|
@@ -9374,13 +9763,14 @@ class TableManager {
|
|
|
9374
9763
|
}
|
|
9375
9764
|
getSchemaType(schema) {
|
|
9376
9765
|
if (schema.type) {
|
|
9377
|
-
|
|
9378
|
-
|
|
9766
|
+
const items = schema.items;
|
|
9767
|
+
if (schema.type === "array" && items?.type) {
|
|
9768
|
+
return `array<${items.type}>`;
|
|
9379
9769
|
}
|
|
9380
|
-
return schema.type;
|
|
9770
|
+
return String(schema.type);
|
|
9381
9771
|
}
|
|
9382
9772
|
if (schema.$ref) {
|
|
9383
|
-
return schema.$ref.split("/").pop() || "unknown";
|
|
9773
|
+
return String(schema.$ref).split("/").pop() || "unknown";
|
|
9384
9774
|
}
|
|
9385
9775
|
return "unknown";
|
|
9386
9776
|
}
|
|
@@ -9391,8 +9781,8 @@ class TableManager {
|
|
|
9391
9781
|
} else if (Math.abs(oldPosition - newPosition) <= 1) {
|
|
9392
9782
|
score += 1;
|
|
9393
9783
|
}
|
|
9394
|
-
const oldDesc = (oldSchema?.description || "").toLowerCase();
|
|
9395
|
-
const newDesc = (newSchema?.description || "").toLowerCase();
|
|
9784
|
+
const oldDesc = String(oldSchema?.description || "").toLowerCase();
|
|
9785
|
+
const newDesc = String(newSchema?.description || "").toLowerCase();
|
|
9396
9786
|
if (oldDesc && newDesc && oldDesc === newDesc) {
|
|
9397
9787
|
score += 5;
|
|
9398
9788
|
} else if (oldDesc && newDesc && oldDesc.length > 5 && newDesc.length > 5) {
|
|
@@ -9407,8 +9797,10 @@ class TableManager {
|
|
|
9407
9797
|
}
|
|
9408
9798
|
}
|
|
9409
9799
|
}
|
|
9410
|
-
const
|
|
9411
|
-
const
|
|
9800
|
+
const oldType = oldSchema?.type;
|
|
9801
|
+
const newType = newSchema?.type;
|
|
9802
|
+
const oldOptional = typeof oldType === "string" && oldType.includes("null") || oldSchema?.nullable === true;
|
|
9803
|
+
const newOptional = typeof newType === "string" && newType.includes("null") || newSchema?.nullable === true;
|
|
9412
9804
|
if (oldOptional === newOptional) {
|
|
9413
9805
|
score += 1;
|
|
9414
9806
|
}
|
|
@@ -10636,7 +11028,7 @@ class KBSyncFormatter {
|
|
|
10636
11028
|
}
|
|
10637
11029
|
}
|
|
10638
11030
|
// src/file-watcher/watcher.ts
|
|
10639
|
-
import { watch as watch2, readdirSync as readdirSync2 } from "fs";
|
|
11031
|
+
import { watch as watch2, readdirSync as readdirSync2, statSync } from "fs";
|
|
10640
11032
|
import { EventEmitter as EventEmitter3 } from "events";
|
|
10641
11033
|
import { join as join9, relative as relative3 } from "path";
|
|
10642
11034
|
import { existsSync as existsSync9 } from "fs";
|
|
@@ -10678,7 +11070,7 @@ class FileWatcher2 extends EventEmitter3 {
|
|
|
10678
11070
|
this.updateFileState(fullPath);
|
|
10679
11071
|
}
|
|
10680
11072
|
}
|
|
10681
|
-
} catch
|
|
11073
|
+
} catch {}
|
|
10682
11074
|
}
|
|
10683
11075
|
watchFile(filePath) {
|
|
10684
11076
|
if (this.watchers.has(filePath)) {
|
|
@@ -10711,6 +11103,12 @@ class FileWatcher2 extends EventEmitter3 {
|
|
|
10711
11103
|
}
|
|
10712
11104
|
}
|
|
10713
11105
|
handleFileChange(filePath) {
|
|
11106
|
+
try {
|
|
11107
|
+
if (existsSync9(filePath) && statSync(filePath).isDirectory()) {
|
|
11108
|
+
this.scanDirectoryForChanges(filePath);
|
|
11109
|
+
return;
|
|
11110
|
+
}
|
|
11111
|
+
} catch {}
|
|
10714
11112
|
const fileExists = existsSync9(filePath);
|
|
10715
11113
|
const previousState = this.fileStates.get(filePath);
|
|
10716
11114
|
let changeType;
|
|
@@ -10731,12 +11129,7 @@ class FileWatcher2 extends EventEmitter3 {
|
|
|
10731
11129
|
path: relativePath,
|
|
10732
11130
|
type: changeType
|
|
10733
11131
|
});
|
|
10734
|
-
|
|
10735
|
-
clearTimeout(this.debounceTimer);
|
|
10736
|
-
}
|
|
10737
|
-
this.debounceTimer = setTimeout(() => {
|
|
10738
|
-
this.emitPendingChanges();
|
|
10739
|
-
}, this.debounceMs);
|
|
11132
|
+
this.scheduleDebouncedEmit();
|
|
10740
11133
|
}
|
|
10741
11134
|
emitPendingChanges() {
|
|
10742
11135
|
if (this.pendingChanges.size === 0) {
|
|
@@ -10750,6 +11143,44 @@ class FileWatcher2 extends EventEmitter3 {
|
|
|
10750
11143
|
};
|
|
10751
11144
|
this.emit("change", event);
|
|
10752
11145
|
}
|
|
11146
|
+
scanDirectoryForChanges(dirPath) {
|
|
11147
|
+
try {
|
|
11148
|
+
const entries = readdirSync2(dirPath, { withFileTypes: true });
|
|
11149
|
+
const currentFiles = new Set;
|
|
11150
|
+
for (const entry of entries) {
|
|
11151
|
+
const fullPath = join9(dirPath, entry.name);
|
|
11152
|
+
if (entry.isFile()) {
|
|
11153
|
+
currentFiles.add(fullPath);
|
|
11154
|
+
if (!this.fileStates.has(fullPath)) {
|
|
11155
|
+
this.updateFileState(fullPath);
|
|
11156
|
+
const relativePath = relative3(this.projectPath, fullPath);
|
|
11157
|
+
this.pendingChanges.set(relativePath, { path: relativePath, type: "added" });
|
|
11158
|
+
this.scheduleDebouncedEmit();
|
|
11159
|
+
}
|
|
11160
|
+
} else if (entry.isDirectory()) {
|
|
11161
|
+
this.scanDirectoryForChanges(fullPath);
|
|
11162
|
+
}
|
|
11163
|
+
}
|
|
11164
|
+
for (const [trackedPath] of this.fileStates) {
|
|
11165
|
+
if (trackedPath.startsWith(dirPath) && !trackedPath.includes("/", dirPath.length + 1)) {
|
|
11166
|
+
if (!currentFiles.has(trackedPath)) {
|
|
11167
|
+
this.fileStates.delete(trackedPath);
|
|
11168
|
+
const relativePath = relative3(this.projectPath, trackedPath);
|
|
11169
|
+
this.pendingChanges.set(relativePath, { path: relativePath, type: "deleted" });
|
|
11170
|
+
this.scheduleDebouncedEmit();
|
|
11171
|
+
}
|
|
11172
|
+
}
|
|
11173
|
+
}
|
|
11174
|
+
} catch {}
|
|
11175
|
+
}
|
|
11176
|
+
scheduleDebouncedEmit() {
|
|
11177
|
+
if (this.debounceTimer) {
|
|
11178
|
+
clearTimeout(this.debounceTimer);
|
|
11179
|
+
}
|
|
11180
|
+
this.debounceTimer = setTimeout(() => {
|
|
11181
|
+
this.emitPendingChanges();
|
|
11182
|
+
}, this.debounceMs);
|
|
11183
|
+
}
|
|
10753
11184
|
updateFileState(filePath) {
|
|
10754
11185
|
if (existsSync9(filePath)) {
|
|
10755
11186
|
this.fileStates.set(filePath, Date.now());
|
|
@@ -11529,6 +11960,7 @@ function filterEvals(evals, filter) {
|
|
|
11529
11960
|
}
|
|
11530
11961
|
// src/eval/runner.ts
|
|
11531
11962
|
import { Client as BpClient2 } from "@botpress/client";
|
|
11963
|
+
import { BUILT_IN_STATES as BUILT_IN_STATES2 } from "@botpress/runtime/internal";
|
|
11532
11964
|
|
|
11533
11965
|
// src/eval/client.ts
|
|
11534
11966
|
import { Client as BpClient } from "@botpress/client";
|
|
@@ -11549,20 +11981,21 @@ class ChatSession {
|
|
|
11549
11981
|
}
|
|
11550
11982
|
return this.client.user.id;
|
|
11551
11983
|
}
|
|
11552
|
-
async
|
|
11984
|
+
async ensureConversation() {
|
|
11553
11985
|
if (!this.client) {
|
|
11554
11986
|
throw new Error("ChatSession not connected. Call connect() first.");
|
|
11555
11987
|
}
|
|
11556
|
-
const { timeout = 30000, idleTimeout = 3000 } = options;
|
|
11557
11988
|
if (!this.conversationId) {
|
|
11558
11989
|
const conv = await this.client.createConversation({});
|
|
11559
11990
|
this.conversationId = conv.conversation.id;
|
|
11991
|
+
return conv.conversation.id;
|
|
11560
11992
|
}
|
|
11561
|
-
|
|
11993
|
+
return this.conversationId;
|
|
11994
|
+
}
|
|
11995
|
+
async _awaitResponses(conversationId, trigger, options = {}) {
|
|
11996
|
+
const { timeout = 30000, idleTimeout = 3000 } = options;
|
|
11562
11997
|
const responses = [];
|
|
11563
|
-
const listener = await this.client.listenConversation({
|
|
11564
|
-
id: conversationId
|
|
11565
|
-
});
|
|
11998
|
+
const listener = await this.client.listenConversation({ id: conversationId });
|
|
11566
11999
|
return new Promise((resolve4, reject) => {
|
|
11567
12000
|
let idleTimer = null;
|
|
11568
12001
|
let resolved = false;
|
|
@@ -11582,7 +12015,7 @@ class ChatSession {
|
|
|
11582
12015
|
};
|
|
11583
12016
|
const overallTimer = setTimeout(() => {
|
|
11584
12017
|
if (!resolved) {
|
|
11585
|
-
if (responses.length > 0) {
|
|
12018
|
+
if (responses.length > 0 || options.expectSilence) {
|
|
11586
12019
|
done();
|
|
11587
12020
|
} else {
|
|
11588
12021
|
resolved = true;
|
|
@@ -11605,10 +12038,7 @@ class ChatSession {
|
|
|
11605
12038
|
done();
|
|
11606
12039
|
}
|
|
11607
12040
|
});
|
|
11608
|
-
|
|
11609
|
-
conversationId,
|
|
11610
|
-
payload: { type: "text", text: message }
|
|
11611
|
-
}).then(() => {
|
|
12041
|
+
trigger().then(() => {
|
|
11612
12042
|
resetIdle();
|
|
11613
12043
|
}).catch((err) => {
|
|
11614
12044
|
clearTimeout(overallTimer);
|
|
@@ -11619,6 +12049,20 @@ class ChatSession {
|
|
|
11619
12049
|
});
|
|
11620
12050
|
});
|
|
11621
12051
|
}
|
|
12052
|
+
async sendMessage(message, options = {}) {
|
|
12053
|
+
if (!this.client) {
|
|
12054
|
+
throw new Error("ChatSession not connected. Call connect() first.");
|
|
12055
|
+
}
|
|
12056
|
+
const conversationId = await this.ensureConversation();
|
|
12057
|
+
return this._awaitResponses(conversationId, () => this.client.createMessage({ conversationId, payload: { type: "text", text: message } }), options);
|
|
12058
|
+
}
|
|
12059
|
+
async sendEvent(type, payload, options = {}) {
|
|
12060
|
+
if (!this.client) {
|
|
12061
|
+
throw new Error("ChatSession not connected. Call connect() first.");
|
|
12062
|
+
}
|
|
12063
|
+
const conversationId = await this.ensureConversation();
|
|
12064
|
+
return this._awaitResponses(conversationId, () => this.client.createEvent({ type, payload, conversationId }), options);
|
|
12065
|
+
}
|
|
11622
12066
|
}
|
|
11623
12067
|
async function discoverWebhookId(botId, token, apiUrl) {
|
|
11624
12068
|
const client = new BpClient({ token, botId, apiUrl });
|
|
@@ -11626,14 +12070,14 @@ async function discoverWebhookId(botId, token, apiUrl) {
|
|
|
11626
12070
|
const integrations = bot.integrations || {};
|
|
11627
12071
|
const chat = Object.values(integrations).find((int) => int.name === "chat");
|
|
11628
12072
|
const webhookId = chat?.webhookId;
|
|
11629
|
-
if (!webhookId) {
|
|
12073
|
+
if (!webhookId || typeof webhookId !== "string") {
|
|
11630
12074
|
throw new Error("No chat integration found on bot. Make sure the bot has the chat integration enabled.");
|
|
11631
12075
|
}
|
|
11632
12076
|
return webhookId;
|
|
11633
12077
|
}
|
|
11634
12078
|
|
|
11635
12079
|
// src/eval/traces.ts
|
|
11636
|
-
async function
|
|
12080
|
+
async function fetchSpans(conversationId, devServerUrl) {
|
|
11637
12081
|
const url = `${devServerUrl}/api/traces/query?attributeName=conversationId&attributeValue=${encodeURIComponent(conversationId)}&count=1000`;
|
|
11638
12082
|
const res = await fetch(url);
|
|
11639
12083
|
if (!res.ok) {
|
|
@@ -11643,25 +12087,26 @@ async function fetchTraceSpans(conversationId, devServerUrl) {
|
|
|
11643
12087
|
return Array.isArray(data) ? data : data.spans || [];
|
|
11644
12088
|
}
|
|
11645
12089
|
function extractToolCalls(spans) {
|
|
11646
|
-
const
|
|
12090
|
+
const data = (span) => span.data && typeof span.data === "object" ? span.data : {};
|
|
12091
|
+
const toolEndSpans = spans.filter((span) => span.name === "autonomous.tool" && (span.status === "ok" || span.status === "error") && data(span)["autonomous.tool.name"]);
|
|
11647
12092
|
const seen = new Set;
|
|
11648
12093
|
const unique = toolEndSpans.filter((span) => {
|
|
11649
|
-
if (seen.has(span.
|
|
12094
|
+
if (seen.has(span.id.span))
|
|
11650
12095
|
return false;
|
|
11651
|
-
seen.add(span.
|
|
12096
|
+
seen.add(span.id.span);
|
|
11652
12097
|
return true;
|
|
11653
12098
|
});
|
|
11654
|
-
return unique.sort((a, b) => (a.
|
|
11655
|
-
const
|
|
12099
|
+
return unique.sort((a, b) => (a.timing.endedAt ?? 0) - (b.timing.endedAt ?? 0)).map((span) => {
|
|
12100
|
+
const d = data(span);
|
|
11656
12101
|
let input = {};
|
|
11657
12102
|
try {
|
|
11658
|
-
input = JSON.parse(
|
|
12103
|
+
input = JSON.parse(d["autonomous.tool.input"]);
|
|
11659
12104
|
} catch {}
|
|
11660
12105
|
return {
|
|
11661
|
-
name:
|
|
12106
|
+
name: d["autonomous.tool.name"],
|
|
11662
12107
|
input,
|
|
11663
|
-
output:
|
|
11664
|
-
status:
|
|
12108
|
+
output: d["autonomous.tool.output"] || "",
|
|
12109
|
+
status: d["autonomous.tool.status"] || "unknown"
|
|
11665
12110
|
};
|
|
11666
12111
|
});
|
|
11667
12112
|
}
|
|
@@ -11676,7 +12121,7 @@ async function getTraceData(conversationId, devServerUrl, options = {}) {
|
|
|
11676
12121
|
if (attempt > 0) {
|
|
11677
12122
|
await new Promise((resolve4) => setTimeout(resolve4, retryDelay));
|
|
11678
12123
|
}
|
|
11679
|
-
spans = await
|
|
12124
|
+
spans = await fetchSpans(conversationId, devServerUrl);
|
|
11680
12125
|
allToolCalls = extractToolCalls(spans);
|
|
11681
12126
|
if (!expectNew || allToolCalls.length > previousCount) {
|
|
11682
12127
|
break;
|
|
@@ -11687,9 +12132,11 @@ async function getTraceData(conversationId, devServerUrl, options = {}) {
|
|
|
11687
12132
|
}
|
|
11688
12133
|
|
|
11689
12134
|
// src/eval/graders/llm.ts
|
|
11690
|
-
import { Cognitive } from "@botpress/
|
|
12135
|
+
import { Cognitive } from "@botpress/runtime";
|
|
11691
12136
|
import { Client as Client18 } from "@botpress/client";
|
|
11692
|
-
var
|
|
12137
|
+
var DEFAULT_PASS_THRESHOLD = 3;
|
|
12138
|
+
function buildJudgeSystemPrompt(passThreshold) {
|
|
12139
|
+
return `You are an evaluation judge for a chatbot. You will be given:
|
|
11693
12140
|
- The user's message
|
|
11694
12141
|
- The bot's response
|
|
11695
12142
|
- Grading criteria
|
|
@@ -11710,32 +12157,44 @@ Scoring guide:
|
|
|
11710
12157
|
- 2: Barely meets criteria, significant issues
|
|
11711
12158
|
- 1: Does not meet criteria
|
|
11712
12159
|
|
|
11713
|
-
A score of
|
|
12160
|
+
A score of ${passThreshold} or above is a pass.`;
|
|
12161
|
+
}
|
|
12162
|
+
var MODEL_ALIASES = ["fast", "best"];
|
|
11714
12163
|
var _cognitive = null;
|
|
11715
|
-
|
|
11716
|
-
|
|
11717
|
-
|
|
11718
|
-
|
|
11719
|
-
|
|
11720
|
-
|
|
11721
|
-
|
|
11722
|
-
|
|
11723
|
-
const client = new Client18({ token, apiUrl, botId });
|
|
11724
|
-
_cognitive = new Cognitive({ client, __experimental_beta: true });
|
|
11725
|
-
return _cognitive;
|
|
12164
|
+
var _availableModels = [];
|
|
12165
|
+
var _judgeModel = "fast";
|
|
12166
|
+
function _isModelValid(model) {
|
|
12167
|
+
if (MODEL_ALIASES.includes(model))
|
|
12168
|
+
return true;
|
|
12169
|
+
if (_availableModels.length === 0)
|
|
12170
|
+
return false;
|
|
12171
|
+
return _availableModels.includes(model);
|
|
11726
12172
|
}
|
|
11727
|
-
function initLLMJudge(credentials) {
|
|
12173
|
+
async function initLLMJudge(credentials, options) {
|
|
12174
|
+
const log = options?.logger ?? console;
|
|
11728
12175
|
const client = new Client18({
|
|
11729
12176
|
token: credentials.token,
|
|
11730
12177
|
apiUrl: credentials.apiUrl,
|
|
11731
12178
|
botId: credentials.botId
|
|
11732
12179
|
});
|
|
11733
12180
|
_cognitive = new Cognitive({ client, __experimental_beta: true });
|
|
12181
|
+
try {
|
|
12182
|
+
_availableModels = Array.from((await _cognitive.fetchRemoteModels()).keys());
|
|
12183
|
+
} catch (err) {
|
|
12184
|
+
log.warn(`Failed to fetch available models: ${err.message}. LLM judge will be unavailable.`);
|
|
12185
|
+
_availableModels = [];
|
|
12186
|
+
}
|
|
12187
|
+
_judgeModel = options?.model ?? "fast";
|
|
12188
|
+
if (_availableModels.length === 0) {
|
|
12189
|
+
log.warn("No available Cognitive models: cannot validate judge model.");
|
|
12190
|
+
} else if (!_isModelValid(_judgeModel)) {
|
|
12191
|
+
log.warn(`Configured LLM judge model "${_judgeModel}" is invalid. Run "adk models" to list available models.`);
|
|
12192
|
+
}
|
|
11734
12193
|
}
|
|
11735
12194
|
async function gradeLLMJudge(botResponse, criteria, context) {
|
|
12195
|
+
const threshold = Math.max(1, Math.min(5, context.passThreshold ?? DEFAULT_PASS_THRESHOLD));
|
|
11736
12196
|
try {
|
|
11737
|
-
|
|
11738
|
-
if (!cognitive) {
|
|
12197
|
+
if (!_cognitive) {
|
|
11739
12198
|
return {
|
|
11740
12199
|
assertion: `llm_judge: "${criteria}"`,
|
|
11741
12200
|
pass: true,
|
|
@@ -11743,11 +12202,19 @@ async function gradeLLMJudge(botResponse, criteria, context) {
|
|
|
11743
12202
|
actual: "SKIPPED — LLM judge unavailable: no credentials configured"
|
|
11744
12203
|
};
|
|
11745
12204
|
}
|
|
11746
|
-
|
|
11747
|
-
|
|
12205
|
+
if (!_isModelValid(_judgeModel)) {
|
|
12206
|
+
return {
|
|
12207
|
+
assertion: `llm_judge: "${criteria}"`,
|
|
12208
|
+
pass: false,
|
|
12209
|
+
expected: criteria,
|
|
12210
|
+
actual: "FAILED — invalid LLM judge model"
|
|
12211
|
+
};
|
|
12212
|
+
}
|
|
12213
|
+
const { output } = await _cognitive.generateContent({
|
|
12214
|
+
model: _judgeModel,
|
|
11748
12215
|
temperature: 0,
|
|
11749
12216
|
responseFormat: "json_object",
|
|
11750
|
-
systemPrompt:
|
|
12217
|
+
systemPrompt: buildJudgeSystemPrompt(threshold),
|
|
11751
12218
|
messages: [
|
|
11752
12219
|
{
|
|
11753
12220
|
role: "user",
|
|
@@ -11772,9 +12239,9 @@ Criteria: ${criteria}`
|
|
|
11772
12239
|
const verdict = JSON.parse(content);
|
|
11773
12240
|
return {
|
|
11774
12241
|
assertion: `llm_judge: "${criteria}"`,
|
|
11775
|
-
pass: verdict.score >=
|
|
12242
|
+
pass: verdict.score >= threshold,
|
|
11776
12243
|
expected: criteria,
|
|
11777
|
-
actual: `Score ${verdict.score}/5 — ${verdict.reason}`
|
|
12244
|
+
actual: `Score ${verdict.score}/5 (threshold: ${threshold}) — ${verdict.reason}`
|
|
11778
12245
|
};
|
|
11779
12246
|
} catch (err) {
|
|
11780
12247
|
return {
|
|
@@ -11822,7 +12289,10 @@ async function gradeResponse(botResponse, assertions, context) {
|
|
|
11822
12289
|
continue;
|
|
11823
12290
|
}
|
|
11824
12291
|
if ("llm_judge" in assertion) {
|
|
11825
|
-
const result = await gradeLLMJudge(botResponse, assertion.llm_judge,
|
|
12292
|
+
const result = await gradeLLMJudge(botResponse, assertion.llm_judge, {
|
|
12293
|
+
userMessage: context.userMessage,
|
|
12294
|
+
passThreshold: context.judgePassThreshold
|
|
12295
|
+
});
|
|
11826
12296
|
results.push(result);
|
|
11827
12297
|
continue;
|
|
11828
12298
|
}
|
|
@@ -11974,6 +12444,7 @@ function gradeTools(toolCalls, assertions) {
|
|
|
11974
12444
|
}
|
|
11975
12445
|
|
|
11976
12446
|
// src/eval/graders/state.ts
|
|
12447
|
+
import { BUILT_IN_STATES } from "@botpress/runtime/internal";
|
|
11977
12448
|
function parseStatePath(path42) {
|
|
11978
12449
|
const dot = path42.indexOf(".");
|
|
11979
12450
|
if (dot === -1) {
|
|
@@ -11983,11 +12454,16 @@ function parseStatePath(path42) {
|
|
|
11983
12454
|
const field = path42.slice(dot + 1);
|
|
11984
12455
|
switch (prefix) {
|
|
11985
12456
|
case "bot":
|
|
11986
|
-
return { type: "bot", stateName:
|
|
12457
|
+
return { type: "bot", stateName: BUILT_IN_STATES.bot, stateId: (ctx) => ctx.botId, field };
|
|
11987
12458
|
case "user":
|
|
11988
|
-
return { type: "user", stateName:
|
|
12459
|
+
return { type: "user", stateName: BUILT_IN_STATES.user, stateId: (ctx) => ctx.userId, field };
|
|
11989
12460
|
case "conversation":
|
|
11990
|
-
return {
|
|
12461
|
+
return {
|
|
12462
|
+
type: "conversation",
|
|
12463
|
+
stateName: BUILT_IN_STATES.conversation,
|
|
12464
|
+
stateId: (ctx) => ctx.conversationId,
|
|
12465
|
+
field
|
|
12466
|
+
};
|
|
11991
12467
|
default:
|
|
11992
12468
|
throw new Error(`Unknown state type "${prefix}" in path "${path42}" — expected bot, user, or conversation`);
|
|
11993
12469
|
}
|
|
@@ -11998,7 +12474,9 @@ async function fetchState(client, type, id, name) {
|
|
|
11998
12474
|
const payload = result.state?.payload;
|
|
11999
12475
|
return payload?.value ?? payload ?? null;
|
|
12000
12476
|
} catch (err) {
|
|
12001
|
-
|
|
12477
|
+
const code = err != null && typeof err === "object" && "code" in err ? err.code : undefined;
|
|
12478
|
+
const message = err instanceof Error ? err.message : "";
|
|
12479
|
+
if (code === 404 || message.includes("404") || message.includes("doesn't exist")) {
|
|
12002
12480
|
return null;
|
|
12003
12481
|
}
|
|
12004
12482
|
throw err;
|
|
@@ -12022,7 +12500,7 @@ async function snapshotState(client, assertions, ctx) {
|
|
|
12022
12500
|
if (assertion.changed === undefined)
|
|
12023
12501
|
continue;
|
|
12024
12502
|
const parsed = parseStatePath(assertion.path);
|
|
12025
|
-
if (parsed.type === "conversation")
|
|
12503
|
+
if (parsed.type === "conversation" && !ctx.conversationId)
|
|
12026
12504
|
continue;
|
|
12027
12505
|
const payload = await fetchState(client, parsed.type, parsed.stateId(ctx), parsed.stateName);
|
|
12028
12506
|
snapshots.set(assertion.path, payload ? payload[parsed.field] : undefined);
|
|
@@ -12199,9 +12677,11 @@ async function gradeTables(client, assertions) {
|
|
|
12199
12677
|
// src/eval/graders/workflow.ts
|
|
12200
12678
|
function gradeWorkflows(spans, assertions) {
|
|
12201
12679
|
const results = [];
|
|
12680
|
+
const data = (span) => span.data && typeof span.data === "object" ? span.data : {};
|
|
12202
12681
|
for (const assertion of assertions) {
|
|
12203
12682
|
const workflowSpans = spans.filter((span) => {
|
|
12204
|
-
const
|
|
12683
|
+
const d = data(span);
|
|
12684
|
+
const wfName = d["workflow.name"] || d["workflowName"];
|
|
12205
12685
|
return wfName === assertion.name;
|
|
12206
12686
|
});
|
|
12207
12687
|
if (assertion.entered !== undefined) {
|
|
@@ -12216,8 +12696,9 @@ function gradeWorkflows(spans, assertions) {
|
|
|
12216
12696
|
}
|
|
12217
12697
|
if (assertion.completed !== undefined) {
|
|
12218
12698
|
const completedSpans = workflowSpans.filter((span) => {
|
|
12219
|
-
const
|
|
12220
|
-
|
|
12699
|
+
const d = data(span);
|
|
12700
|
+
const status = d["workflow.status.final"];
|
|
12701
|
+
return status === "completed" || (span.status === "ok" || span.status === "error") && span.name?.includes("workflow");
|
|
12221
12702
|
});
|
|
12222
12703
|
const didComplete = completedSpans.length > 0;
|
|
12223
12704
|
const pass = assertion.completed ? didComplete : !didComplete;
|
|
@@ -12232,6 +12713,22 @@ function gradeWorkflows(spans, assertions) {
|
|
|
12232
12713
|
return results;
|
|
12233
12714
|
}
|
|
12234
12715
|
|
|
12716
|
+
// src/eval/graders/timing.ts
|
|
12717
|
+
function gradeTiming(botDuration, assertions) {
|
|
12718
|
+
const results = [];
|
|
12719
|
+
for (const assertion of assertions) {
|
|
12720
|
+
const pass = matchValue(assertion.response_time, botDuration);
|
|
12721
|
+
const expected = operatorToString(assertion.response_time);
|
|
12722
|
+
results.push({
|
|
12723
|
+
assertion: `response_time ${expected}`,
|
|
12724
|
+
pass,
|
|
12725
|
+
expected: `Response time ${expected}`,
|
|
12726
|
+
actual: `${botDuration}ms`
|
|
12727
|
+
});
|
|
12728
|
+
}
|
|
12729
|
+
return results;
|
|
12730
|
+
}
|
|
12731
|
+
|
|
12235
12732
|
// src/eval/graders/outcome.ts
|
|
12236
12733
|
async function snapshotOutcomeState(client, evalDef, ctx) {
|
|
12237
12734
|
if (!evalDef.outcome?.state) {
|
|
@@ -12261,8 +12758,65 @@ async function gradeOutcome(client, evalDef, ctx, traceSpans, preSnapshots) {
|
|
|
12261
12758
|
|
|
12262
12759
|
// src/eval/runner.ts
|
|
12263
12760
|
import { randomUUID } from "crypto";
|
|
12761
|
+
var DEFAULT_IDLE_TIMEOUT = 15000;
|
|
12762
|
+
var WORKFLOW_TRIGGER_TIMEOUT_MS = 5 * 60 * 1000;
|
|
12763
|
+
function buildStatePayload(value) {
|
|
12764
|
+
return {
|
|
12765
|
+
value,
|
|
12766
|
+
location: { type: "state" }
|
|
12767
|
+
};
|
|
12768
|
+
}
|
|
12769
|
+
async function seedEvalState(client, ctx, setup) {
|
|
12770
|
+
const state = setup?.state;
|
|
12771
|
+
if (!state)
|
|
12772
|
+
return;
|
|
12773
|
+
const writes = [];
|
|
12774
|
+
if (state.bot) {
|
|
12775
|
+
writes.push(client.setState({
|
|
12776
|
+
type: "bot",
|
|
12777
|
+
id: ctx.botId,
|
|
12778
|
+
name: BUILT_IN_STATES2.bot,
|
|
12779
|
+
payload: buildStatePayload(state.bot)
|
|
12780
|
+
}));
|
|
12781
|
+
}
|
|
12782
|
+
if (state.user) {
|
|
12783
|
+
writes.push(client.setState({
|
|
12784
|
+
type: "user",
|
|
12785
|
+
id: ctx.userId,
|
|
12786
|
+
name: BUILT_IN_STATES2.user,
|
|
12787
|
+
payload: buildStatePayload(state.user)
|
|
12788
|
+
}));
|
|
12789
|
+
}
|
|
12790
|
+
if (state.conversation) {
|
|
12791
|
+
if (!ctx.conversationId) {
|
|
12792
|
+
throw new Error("Cannot seed conversation state before a conversation is created.");
|
|
12793
|
+
}
|
|
12794
|
+
writes.push(client.setState({
|
|
12795
|
+
type: "conversation",
|
|
12796
|
+
id: ctx.conversationId,
|
|
12797
|
+
name: BUILT_IN_STATES2.conversation,
|
|
12798
|
+
payload: buildStatePayload(state.conversation)
|
|
12799
|
+
}));
|
|
12800
|
+
}
|
|
12801
|
+
await Promise.all(writes);
|
|
12802
|
+
}
|
|
12803
|
+
async function triggerEvalWorkflow(client, ctx, setup) {
|
|
12804
|
+
const workflow = setup?.workflow;
|
|
12805
|
+
if (!workflow)
|
|
12806
|
+
return;
|
|
12807
|
+
await client.createWorkflow({
|
|
12808
|
+
name: workflow.trigger,
|
|
12809
|
+
input: workflow.input ?? {},
|
|
12810
|
+
status: "pending",
|
|
12811
|
+
conversationId: ctx.conversationId,
|
|
12812
|
+
userId: ctx.userId,
|
|
12813
|
+
timeoutAt: new Date(Date.now() + WORKFLOW_TRIGGER_TIMEOUT_MS).toISOString()
|
|
12814
|
+
});
|
|
12815
|
+
}
|
|
12264
12816
|
async function runEval(evalDef, connection, options = {}) {
|
|
12265
12817
|
const devServerUrl = options.devServerUrl || "http://localhost:3001";
|
|
12818
|
+
const idleTimeout = evalDef.options?.idleTimeout ?? options.idleTimeout ?? DEFAULT_IDLE_TIMEOUT;
|
|
12819
|
+
const judgePassThreshold = evalDef.options?.judgePassThreshold ?? options.judgePassThreshold;
|
|
12266
12820
|
const start = Date.now();
|
|
12267
12821
|
const turns = [];
|
|
12268
12822
|
let outcomeAssertions = [];
|
|
@@ -12280,34 +12834,67 @@ async function runEval(evalDef, connection, options = {}) {
|
|
|
12280
12834
|
}
|
|
12281
12835
|
return bpClient;
|
|
12282
12836
|
};
|
|
12837
|
+
let lastConversationId = "";
|
|
12838
|
+
if (evalDef.setup?.state?.conversation || evalDef.setup?.workflow) {
|
|
12839
|
+
lastConversationId = await session.ensureConversation();
|
|
12840
|
+
}
|
|
12841
|
+
await seedEvalState(getBpClient(), {
|
|
12842
|
+
botId: connection.botId,
|
|
12843
|
+
userId: session.userId,
|
|
12844
|
+
conversationId: lastConversationId || undefined
|
|
12845
|
+
}, evalDef.setup);
|
|
12846
|
+
await triggerEvalWorkflow(getBpClient(), {
|
|
12847
|
+
userId: session.userId,
|
|
12848
|
+
conversationId: lastConversationId || undefined
|
|
12849
|
+
}, evalDef.setup);
|
|
12283
12850
|
let preSnapshots = new Map;
|
|
12284
12851
|
if (evalDef.outcome?.state) {
|
|
12285
12852
|
const ctx = {
|
|
12286
12853
|
botId: connection.botId,
|
|
12287
12854
|
userId: session.userId,
|
|
12288
|
-
conversationId:
|
|
12855
|
+
conversationId: lastConversationId
|
|
12289
12856
|
};
|
|
12290
12857
|
preSnapshots = await snapshotOutcomeState(getBpClient(), evalDef, ctx);
|
|
12291
12858
|
}
|
|
12292
12859
|
let previousToolCallCount = 0;
|
|
12293
|
-
let
|
|
12294
|
-
let allTraceSpans = [];
|
|
12860
|
+
let allSpans = [];
|
|
12295
12861
|
for (let i = 0;i < evalDef.conversation.length; i++) {
|
|
12296
12862
|
const turn = evalDef.conversation[i];
|
|
12297
12863
|
const turnStart = Date.now();
|
|
12298
|
-
|
|
12299
|
-
|
|
12300
|
-
|
|
12301
|
-
|
|
12864
|
+
if (turn.expectSilence && turn.assert?.response) {
|
|
12865
|
+
throw new Error(`Turn ${i + 1}: 'expectSilence' and 'assert.response' are mutually exclusive.`);
|
|
12866
|
+
}
|
|
12867
|
+
if (turn.user && turn.event) {
|
|
12868
|
+
throw new Error(`Turn ${i + 1}: 'user' and 'event' are mutually exclusive.`);
|
|
12869
|
+
}
|
|
12870
|
+
if (!turn.user && !turn.event) {
|
|
12871
|
+
throw new Error(`Turn ${i + 1}: must have either 'user' or 'event'.`);
|
|
12872
|
+
}
|
|
12873
|
+
const sendOptions = { timeout: Math.max(30000, idleTimeout * 2), idleTimeout, expectSilence: turn.expectSilence };
|
|
12874
|
+
const result = turn.event ? await session.sendEvent(turn.event.type, turn.event.payload ?? {}, sendOptions) : await session.sendMessage(turn.user, sendOptions);
|
|
12302
12875
|
const botDuration = Date.now() - turnStart;
|
|
12876
|
+
if (!turn.expectSilence && result.responses.length === 0) {
|
|
12877
|
+
throw new Error(`Turn ${i + 1}: bot produced no response.`);
|
|
12878
|
+
}
|
|
12303
12879
|
lastConversationId = result.conversationId;
|
|
12304
12880
|
const botResponse = result.responses.map((r) => r.text).join(`
|
|
12305
12881
|
`);
|
|
12882
|
+
const turnLabel = turn.event ? `[event: ${turn.event.type}]` : turn.user;
|
|
12306
12883
|
const evalStart = Date.now();
|
|
12307
12884
|
let assertions = [];
|
|
12885
|
+
if (turn.expectSilence) {
|
|
12886
|
+
const wasSilent = result.responses.length === 0;
|
|
12887
|
+
assertions.push({
|
|
12888
|
+
assertion: "no_response",
|
|
12889
|
+
pass: wasSilent,
|
|
12890
|
+
expected: "No response",
|
|
12891
|
+
actual: wasSilent ? "No response" : `Bot responded: "${botResponse}"`
|
|
12892
|
+
});
|
|
12893
|
+
}
|
|
12308
12894
|
if (turn.assert?.response) {
|
|
12309
12895
|
assertions = await gradeResponse(botResponse, turn.assert.response, {
|
|
12310
|
-
userMessage:
|
|
12896
|
+
userMessage: turnLabel,
|
|
12897
|
+
judgePassThreshold
|
|
12311
12898
|
});
|
|
12312
12899
|
}
|
|
12313
12900
|
if (turn.assert?.tools) {
|
|
@@ -12318,7 +12905,7 @@ async function runEval(evalDef, connection, options = {}) {
|
|
|
12318
12905
|
expectNewCalls
|
|
12319
12906
|
});
|
|
12320
12907
|
previousToolCallCount = traceData.totalToolCallCount;
|
|
12321
|
-
|
|
12908
|
+
allSpans = traceData.raw;
|
|
12322
12909
|
const toolResults = gradeTools(traceData.toolCalls, turn.assert.tools);
|
|
12323
12910
|
assertions = [...assertions, ...toolResults];
|
|
12324
12911
|
} catch (err) {
|
|
@@ -12365,20 +12952,24 @@ async function runEval(evalDef, connection, options = {}) {
|
|
|
12365
12952
|
}
|
|
12366
12953
|
}
|
|
12367
12954
|
if (turn.assert?.workflow) {
|
|
12368
|
-
if (
|
|
12955
|
+
if (allSpans.length === 0) {
|
|
12369
12956
|
try {
|
|
12370
12957
|
const traceData = await getTraceData(result.conversationId, devServerUrl);
|
|
12371
|
-
|
|
12958
|
+
allSpans = traceData.raw;
|
|
12372
12959
|
} catch {}
|
|
12373
12960
|
}
|
|
12374
|
-
const workflowResults = gradeWorkflows(
|
|
12961
|
+
const workflowResults = gradeWorkflows(allSpans, turn.assert.workflow);
|
|
12375
12962
|
assertions.push(...workflowResults);
|
|
12376
12963
|
}
|
|
12964
|
+
if (turn.assert?.timing) {
|
|
12965
|
+
const timingResults = gradeTiming(botDuration, turn.assert.timing);
|
|
12966
|
+
assertions.push(...timingResults);
|
|
12967
|
+
}
|
|
12377
12968
|
const turnPass = assertions.every((a) => a.pass);
|
|
12378
12969
|
const evalDuration = Date.now() - evalStart;
|
|
12379
12970
|
turns.push({
|
|
12380
12971
|
turnNumber: i + 1,
|
|
12381
|
-
userMessage:
|
|
12972
|
+
userMessage: turnLabel,
|
|
12382
12973
|
botResponse,
|
|
12383
12974
|
assertions,
|
|
12384
12975
|
pass: turnPass,
|
|
@@ -12387,10 +12978,10 @@ async function runEval(evalDef, connection, options = {}) {
|
|
|
12387
12978
|
});
|
|
12388
12979
|
}
|
|
12389
12980
|
if (evalDef.outcome) {
|
|
12390
|
-
if (
|
|
12981
|
+
if (allSpans.length === 0 && lastConversationId && evalDef.outcome.workflow) {
|
|
12391
12982
|
try {
|
|
12392
12983
|
const traceData = await getTraceData(lastConversationId, devServerUrl);
|
|
12393
|
-
|
|
12984
|
+
allSpans = traceData.raw;
|
|
12394
12985
|
} catch {}
|
|
12395
12986
|
}
|
|
12396
12987
|
const ctx = {
|
|
@@ -12399,7 +12990,7 @@ async function runEval(evalDef, connection, options = {}) {
|
|
|
12399
12990
|
conversationId: lastConversationId
|
|
12400
12991
|
};
|
|
12401
12992
|
try {
|
|
12402
|
-
outcomeAssertions = await gradeOutcome(getBpClient(), evalDef, ctx,
|
|
12993
|
+
outcomeAssertions = await gradeOutcome(getBpClient(), evalDef, ctx, allSpans, preSnapshots);
|
|
12403
12994
|
} catch (err) {
|
|
12404
12995
|
outcomeAssertions = [
|
|
12405
12996
|
{
|
|
@@ -12440,11 +13031,11 @@ async function runEval(evalDef, connection, options = {}) {
|
|
|
12440
13031
|
async function runEvalSuite(config, filter) {
|
|
12441
13032
|
const start = Date.now();
|
|
12442
13033
|
const runId = randomUUID().replace(/-/g, "").slice(0, 26);
|
|
12443
|
-
initLLMJudge({
|
|
13034
|
+
await initLLMJudge({
|
|
12444
13035
|
token: config.credentials.token,
|
|
12445
13036
|
apiUrl: config.credentials.apiUrl,
|
|
12446
13037
|
botId: config.credentials.botId
|
|
12447
|
-
});
|
|
13038
|
+
}, { model: config.evalOptions?.judgeModel, logger: config.logger });
|
|
12448
13039
|
const evalsDir = `${config.agentPath}/evals`;
|
|
12449
13040
|
const allEvals = await loadEvalsFromDir(evalsDir);
|
|
12450
13041
|
const evals = filterEvals(allEvals, filter);
|
|
@@ -12476,7 +13067,11 @@ async function runEvalSuite(config, filter) {
|
|
|
12476
13067
|
for (let i = 0;i < evals.length; i++) {
|
|
12477
13068
|
const evalDef = evals[i];
|
|
12478
13069
|
config.onProgress?.({ type: "eval_start", evalName: evalDef.name, index: i });
|
|
12479
|
-
const report = await runEval(evalDef, connection, {
|
|
13070
|
+
const report = await runEval(evalDef, connection, {
|
|
13071
|
+
devServerUrl,
|
|
13072
|
+
idleTimeout: config.evalOptions?.idleTimeout,
|
|
13073
|
+
judgePassThreshold: config.evalOptions?.judgePassThreshold
|
|
13074
|
+
});
|
|
12480
13075
|
reports.push(report);
|
|
12481
13076
|
config.onProgress?.({ type: "eval_complete", evalName: evalDef.name, index: i, report });
|
|
12482
13077
|
}
|
|
@@ -12564,8 +13159,10 @@ export {
|
|
|
12564
13159
|
dependenciesKeyOrder,
|
|
12565
13160
|
defineEval,
|
|
12566
13161
|
coerceConfigValue,
|
|
13162
|
+
buildOpenCodeConfig,
|
|
12567
13163
|
bpCliImporter,
|
|
12568
13164
|
auth,
|
|
13165
|
+
agentLocalInfoKeyOrder,
|
|
12569
13166
|
agentInfoKeyOrder,
|
|
12570
13167
|
ValidationSeverity,
|
|
12571
13168
|
ValidationErrors,
|
|
@@ -12576,6 +13173,7 @@ export {
|
|
|
12576
13173
|
PreflightFormatter,
|
|
12577
13174
|
PreflightChecker,
|
|
12578
13175
|
PluginParser,
|
|
13176
|
+
OpenCodeCommand,
|
|
12579
13177
|
KnowledgeManager,
|
|
12580
13178
|
KBSyncOperation,
|
|
12581
13179
|
KBSyncFormatter,
|
|
@@ -12611,4 +13209,4 @@ export {
|
|
|
12611
13209
|
AgentProject
|
|
12612
13210
|
};
|
|
12613
13211
|
|
|
12614
|
-
//# debugId=
|
|
13212
|
+
//# debugId=984405F8F441F45F64756E2164756E21
|