@botpress/adk 1.16.7 → 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.
Files changed (87) hide show
  1. package/dist/agent-init/agent-project-generator.d.ts.map +1 -1
  2. package/dist/agent-project/agent-project.d.ts +9 -1
  3. package/dist/agent-project/agent-project.d.ts.map +1 -1
  4. package/dist/agent-project/agent-resolver.d.ts.map +1 -1
  5. package/dist/agent-project/dependencies-parser.d.ts.map +1 -1
  6. package/dist/agent-project/types.d.ts +27 -19
  7. package/dist/agent-project/types.d.ts.map +1 -1
  8. package/dist/agent-project/validation-errors.d.ts.map +1 -1
  9. package/dist/auth/credentials.d.ts +15 -1
  10. package/dist/auth/credentials.d.ts.map +1 -1
  11. package/dist/auth/index.d.ts +2 -0
  12. package/dist/auth/index.d.ts.map +1 -1
  13. package/dist/bot-generator/generator.d.ts.map +1 -1
  14. package/dist/commands/base-command.d.ts.map +1 -1
  15. package/dist/commands/bp-add-command.d.ts.map +1 -1
  16. package/dist/commands/bp-build-command.d.ts.map +1 -1
  17. package/dist/commands/bp-chat-command.d.ts.map +1 -1
  18. package/dist/commands/bp-deploy-command.d.ts.map +1 -1
  19. package/dist/commands/bp-dev-command.d.ts +2 -2
  20. package/dist/commands/bp-dev-command.d.ts.map +1 -1
  21. package/dist/commands/opencode-command.d.ts +2 -2
  22. package/dist/commands/opencode-command.d.ts.map +1 -1
  23. package/dist/commands/opencode-config.d.ts +1 -1
  24. package/dist/commands/opencode-config.d.ts.map +1 -1
  25. package/dist/config/coerce-config-value.d.ts.map +1 -1
  26. package/dist/config/manager.d.ts +5 -5
  27. package/dist/config/manager.d.ts.map +1 -1
  28. package/dist/eval/client.d.ts +8 -0
  29. package/dist/eval/client.d.ts.map +1 -1
  30. package/dist/eval/graders/index.d.ts +1 -0
  31. package/dist/eval/graders/index.d.ts.map +1 -1
  32. package/dist/eval/graders/llm.d.ts +6 -2
  33. package/dist/eval/graders/llm.d.ts.map +1 -1
  34. package/dist/eval/graders/response.d.ts +1 -0
  35. package/dist/eval/graders/response.d.ts.map +1 -1
  36. package/dist/eval/graders/state.d.ts +1 -1
  37. package/dist/eval/graders/state.d.ts.map +1 -1
  38. package/dist/eval/graders/tables.d.ts.map +1 -1
  39. package/dist/eval/graders/timing.d.ts +7 -0
  40. package/dist/eval/graders/timing.d.ts.map +1 -0
  41. package/dist/eval/graders/workflow.d.ts.map +1 -1
  42. package/dist/eval/index.d.ts +2 -2
  43. package/dist/eval/index.d.ts.map +1 -1
  44. package/dist/eval/runner.d.ts +1 -0
  45. package/dist/eval/runner.d.ts.map +1 -1
  46. package/dist/eval/traces.d.ts.map +1 -1
  47. package/dist/eval/types.d.ts +47 -2
  48. package/dist/eval/types.d.ts.map +1 -1
  49. package/dist/file-watcher/watcher.d.ts +9 -0
  50. package/dist/file-watcher/watcher.d.ts.map +1 -1
  51. package/dist/generators/client-wrapper.d.ts.map +1 -1
  52. package/dist/generators/conversation-types.d.ts.map +1 -1
  53. package/dist/generators/integration-types.d.ts.map +1 -1
  54. package/dist/generators/interface-types.d.ts.map +1 -1
  55. package/dist/generators/plugin-types.d.ts.map +1 -1
  56. package/dist/generators/table-types.d.ts.map +1 -1
  57. package/dist/generators/tests.d.ts.map +1 -1
  58. package/dist/generators/workflow-types.d.ts.map +1 -1
  59. package/dist/index.d.ts +3 -3
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +522 -158
  62. package/dist/index.js.map +58 -57
  63. package/dist/integrations/checker.d.ts +2 -2
  64. package/dist/integrations/checker.d.ts.map +1 -1
  65. package/dist/integrations/config-utils.d.ts +3 -3
  66. package/dist/integrations/config-utils.d.ts.map +1 -1
  67. package/dist/integrations/types.d.ts +1 -1
  68. package/dist/integrations/types.d.ts.map +1 -1
  69. package/dist/interfaces/manager.d.ts.map +1 -1
  70. package/dist/interfaces/types.d.ts +1 -1
  71. package/dist/interfaces/types.d.ts.map +1 -1
  72. package/dist/knowledge/manager.d.ts.map +1 -1
  73. package/dist/plugins/types.d.ts +1 -1
  74. package/dist/plugins/types.d.ts.map +1 -1
  75. package/dist/preflight/agent-config-sync.d.ts +2 -1
  76. package/dist/preflight/agent-config-sync.d.ts.map +1 -1
  77. package/dist/preflight/types.d.ts +8 -8
  78. package/dist/preflight/types.d.ts.map +1 -1
  79. package/dist/runner/index.d.ts +1 -1
  80. package/dist/runner/script-runner.d.ts +1 -1
  81. package/dist/runner/script-runner.d.ts.map +1 -1
  82. package/dist/tables/table-manager.d.ts.map +1 -1
  83. package/dist/tables/types.d.ts +2 -1
  84. package/dist/tables/types.d.ts.map +1 -1
  85. package/dist/utils/json-ordering.d.ts +5 -4
  86. package/dist/utils/json-ordering.d.ts.map +1 -1
  87. package/package.json +32 -31
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 envProfile = process.env.ADK_PROFILE;
648
- const credentials = await this.getCredentials(envProfile);
663
+ const profileName = this.profileOverride || process.env.ADK_PROFILE;
664
+ const credentials = await this.getCredentials(profileName);
649
665
  if (!credentials) {
650
- const profileName = envProfile || "default";
651
- throw new Error(`No credentials found for profile '${profileName}'. ` + `Please run 'adk login' to authenticate.`);
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: agentInfo.apiUrl || baseCredentials.apiUrl,
710
+ apiUrl: agentApiUrl,
664
711
  workspaceId: agentInfo.workspaceId,
665
712
  botId: agentInfo.botId
666
713
  };
@@ -729,7 +776,7 @@ var _format = null, _formatLoaded = false, formatCode = async (code, filepath) =
729
776
  `));
730
777
  return code;
731
778
  }
732
- }, ADK_VERSION = "1.16.7", relative2 = (from, to) => {
779
+ }, ADK_VERSION = "1.17.0", relative2 = (from, to) => {
733
780
  const fromDir = path10.dirname(from);
734
781
  const relative3 = path10.relative(fromDir, to);
735
782
  return relative3.startsWith(".") ? relative3 : `./${relative3}`;
@@ -860,16 +907,31 @@ var init_integration_action_types = __esm(() => {
860
907
  var require_package = __commonJS((exports, module) => {
861
908
  module.exports = {
862
909
  name: "@botpress/adk",
863
- version: "1.16.7",
910
+ version: "1.17.0",
864
911
  description: "Core ADK library for building AI agents on Botpress",
865
- type: "module",
866
- main: "dist/index.js",
867
- types: "dist/index.d.ts",
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
+ },
868
927
  files: [
869
928
  "dist/**/*",
870
929
  "package.json",
871
930
  "README.md"
872
931
  ],
932
+ type: "module",
933
+ main: "dist/index.js",
934
+ types: "dist/index.d.ts",
873
935
  exports: {
874
936
  ".": {
875
937
  types: "./dist/index.d.ts",
@@ -884,33 +946,18 @@ var require_package = __commonJS((exports, module) => {
884
946
  watch: "bun run build:types && bun build ./src/index.ts --outdir ./dist --target node --format esm --sourcemap --watch",
885
947
  clean: "rm -rf dist",
886
948
  prepublishOnly: "bun run clean && bun run build",
887
- test: "vitest run",
888
- "test:watch": "vitest",
889
- "test:ui": "vitest --ui",
890
- "test:coverage": "vitest run --coverage"
891
- },
892
- keywords: [
893
- "botpress",
894
- "adk",
895
- "agent",
896
- "ai",
897
- "chatbot",
898
- "conversational-ai",
899
- "development-kit"
900
- ],
901
- author: "Botpress",
902
- license: "MIT",
903
- repository: {
904
- type: "git",
905
- 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"
906
953
  },
907
954
  dependencies: {
908
- "@botpress/chat": "^0.5.5",
909
- "@botpress/cli": "5.2.0",
910
- "@botpress/client": "1.35.0",
911
- "@botpress/cognitive": "0.3.14",
912
- "@botpress/runtime": "^1.16.7",
913
- "@botpress/sdk": "5.4.3",
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",
914
961
  "@bpinternal/jex": "^1.2.4",
915
962
  "@bpinternal/yargs-extra": "^0.0.21",
916
963
  "@parcel/watcher": "^2.5.1",
@@ -924,6 +971,7 @@ var require_package = __commonJS((exports, module) => {
924
971
  "ts-morph": "^27.0.2"
925
972
  },
926
973
  devDependencies: {
974
+ "@bpinternal/zui": "2.1.0",
927
975
  "@types/debug": "^4.1.12",
928
976
  "@types/glob": "^9.0.0",
929
977
  "@types/luxon": "^3.7.1",
@@ -934,8 +982,8 @@ var require_package = __commonJS((exports, module) => {
934
982
  typescript: ">=4.5.0"
935
983
  },
936
984
  engines: {
937
- node: ">=22.0.0",
938
- bun: ">=1.3.9"
985
+ bun: ">=1.3.9",
986
+ node: ">=22.0.0"
939
987
  },
940
988
  packageManager: "bun@1.3.9"
941
989
  };
@@ -1104,6 +1152,9 @@ class Auth {
1104
1152
  async setCurrentProfile(profileName) {
1105
1153
  return this.credentialsManager.setCurrentProfile(profileName);
1106
1154
  }
1155
+ setProfileOverride(profile) {
1156
+ this.credentialsManager.setProfileOverride(profile);
1157
+ }
1107
1158
  async getActiveCredentials() {
1108
1159
  return this.credentialsManager.getActiveCredentials();
1109
1160
  }
@@ -1153,7 +1204,7 @@ import os3 from "os";
1153
1204
  import path4 from "path";
1154
1205
  import createDebug from "debug";
1155
1206
  var debug = createDebug("adk:bp-cli");
1156
- var BP_CLI_VERSION = "5.2.0";
1207
+ var BP_CLI_VERSION = "6.2.2";
1157
1208
  var BP_CLI_INSTALL_ALL = path4.join(os3.homedir(), ".adk", `bp-cli`);
1158
1209
  var BP_CLI_INSTALL_DIR = path4.join(BP_CLI_INSTALL_ALL, BP_CLI_VERSION);
1159
1210
  var BP_CLI_BIN_PATH = path4.join(BP_CLI_INSTALL_DIR, "node_modules", "@botpress", "cli", "bin.js");
@@ -1648,9 +1699,9 @@ class BpDevCommand extends BaseCommand {
1648
1699
  if (sourceMap) {
1649
1700
  bpArgs.push("--sourceMap");
1650
1701
  }
1651
- const consoleUrl = `http://localhost:${this.options.internalOtlpPort}`;
1702
+ const spanIngestUrl = `http://localhost:${this.options.spanIngestPort}`;
1652
1703
  const otlpEndpoint = this.options.otlpPort ? `http://localhost:${this.options.otlpPort}` : undefined;
1653
- const traceLines = [`[bp-dev] Trace endpoints:`, ` ADK_CONSOLE_URL=${consoleUrl}`];
1704
+ const traceLines = [`[bp-dev] Trace endpoints:`, ` ADK_SPAN_INGEST_URL=${spanIngestUrl}`];
1654
1705
  if (otlpEndpoint) {
1655
1706
  traceLines.push(` OTEL_EXPORTER_OTLP_ENDPOINT=${otlpEndpoint}`);
1656
1707
  }
@@ -1673,7 +1724,7 @@ class BpDevCommand extends BaseCommand {
1673
1724
  },
1674
1725
  WORKER_MODE: "true",
1675
1726
  WORKER_LIFETIME_MS: process.env.WORKER_LIFETIME_MS || "120000",
1676
- ADK_CONSOLE_URL: consoleUrl,
1727
+ ADK_SPAN_INGEST_URL: spanIngestUrl,
1677
1728
  ...otlpEndpoint && { OTEL_EXPORTER_OTLP_ENDPOINT: otlpEndpoint },
1678
1729
  ...this.options.botName && { ADK_BOT_NAME: this.options.botName },
1679
1730
  ADK_DIRECTORY: join2(botPath, ".."),
@@ -1902,10 +1953,11 @@ class BpChatCommand extends BaseCommand {
1902
1953
  try {
1903
1954
  await this.childProcess;
1904
1955
  } catch (error) {
1956
+ const errObj = error != null && typeof error === "object" ? error : {};
1905
1957
  this.emit("error", {
1906
- exitCode: error.exitCode || 1,
1907
- stderr: error.stderr || "",
1908
- 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"
1909
1961
  });
1910
1962
  throw error;
1911
1963
  }
@@ -1986,8 +2038,8 @@ You also have access to Botpress documentation search for platform-level questio
1986
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.`;
1987
2039
  function buildOpenCodeConfig(options) {
1988
2040
  const command = [options.adkBinPath, "mcp", "--cwd", options.agentPath];
1989
- if (options.devServerPort)
1990
- command.push("--port", String(options.devServerPort));
2041
+ if (options.uiServerPort)
2042
+ command.push("--port", String(options.uiServerPort));
1991
2043
  return {
1992
2044
  ...options.openCodePort && {
1993
2045
  server: {
@@ -2060,7 +2112,7 @@ class OpenCodeCommand extends BaseCommand {
2060
2112
  const opencodeConfig = JSON.stringify(buildOpenCodeConfig({
2061
2113
  adkBinPath: adkBin,
2062
2114
  agentPath: cwd,
2063
- devServerPort: this.options.devServerPort,
2115
+ uiServerPort: this.options.uiServerPort,
2064
2116
  openCodePort: port,
2065
2117
  corsOrigins
2066
2118
  }));
@@ -2122,7 +2174,13 @@ class OpenCodeCommand extends BaseCommand {
2122
2174
  } catch {}
2123
2175
  await new Promise((r) => setTimeout(r, 500));
2124
2176
  }
2125
- this.emitReady();
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
+ }
2126
2184
  }
2127
2185
  kill(signal = "SIGTERM") {
2128
2186
  this.killed = true;
@@ -2207,7 +2265,8 @@ function getChatClient(cwd = process.cwd()) {
2207
2265
  return Client4;
2208
2266
  }
2209
2267
  // src/utils/json-ordering.ts
2210
- var agentInfoKeyOrder = ["botId", "workspaceId", "apiUrl", "devId"];
2268
+ var agentInfoKeyOrder = ["botId", "workspaceId", "apiUrl"];
2269
+ var agentLocalInfoKeyOrder = ["devId"];
2211
2270
  var dependenciesKeyOrder = ["integrations"];
2212
2271
  var integrationKeyOrder = ["version", "enabled", "configurationType", "config"];
2213
2272
  function orderKeys(obj, keyOrder) {
@@ -2292,7 +2351,7 @@ class AssetsCacheManager {
2292
2351
  const content = await fs4.readFile(this.cachePath, "utf-8");
2293
2352
  this.cache = JSON.parse(content);
2294
2353
  return this.cache;
2295
- } catch (error) {
2354
+ } catch {
2296
2355
  this.cache = {
2297
2356
  version: "1.0",
2298
2357
  entries: {}
@@ -2825,7 +2884,7 @@ class EnhancedIntegrationCache {
2825
2884
 
2826
2885
  // src/agent-project/dependencies-parser.ts
2827
2886
  init_validation_errors();
2828
- import { z as z2, ZodIssueCode } from "@botpress/sdk";
2887
+ import { z as z2 } from "@botpress/sdk";
2829
2888
  var INTEGRATION_ALIAS_MIN_LENGTH = 2;
2830
2889
  var INTEGRATION_ALIAS_MAX_LENGTH = 100;
2831
2890
  var INTEGRATION_ALIAS_REGEX = /^(?:[a-z][a-z0-9_-]*\/)?[a-z][a-z0-9_-]*$/;
@@ -2836,10 +2895,10 @@ var integrationRefSchema = z2.string().transform((val, ctx) => {
2836
2895
  const match = val.match(/^(?:([^/]+)\/)?([^@]+)@(.+)$/);
2837
2896
  if (!match) {
2838
2897
  ctx.addIssue({
2839
- code: ZodIssueCode.custom,
2898
+ code: "custom",
2840
2899
  message: `Invalid integration version format: ${val}. Expected format: 'name@version' or 'workspace/name@version'`
2841
2900
  });
2842
- return z2.NEVER;
2901
+ return;
2843
2902
  }
2844
2903
  const [, workspace, name, version] = match;
2845
2904
  return {
@@ -2938,10 +2997,10 @@ var pluginRefSchema = z2.string().transform((val, ctx) => {
2938
2997
  const match = val.match(/^([^/@]+)@(.+)$/);
2939
2998
  if (!match) {
2940
2999
  ctx.addIssue({
2941
- code: ZodIssueCode.custom,
3000
+ code: "custom",
2942
3001
  message: `Invalid plugin version format: ${val}. Expected format: 'name@version' (no workspace prefix)`
2943
3002
  });
2944
- return z2.NEVER;
3003
+ return;
2945
3004
  }
2946
3005
  const [, name, version] = match;
2947
3006
  return {
@@ -2998,7 +3057,7 @@ class PluginParser {
2998
3057
  if (!pluginConfig.dependencies) {
2999
3058
  continue;
3000
3059
  }
3001
- for (const [depAlias, depMapping] of Object.entries(pluginConfig.dependencies)) {
3060
+ for (const [_depAlias, depMapping] of Object.entries(pluginConfig.dependencies)) {
3002
3061
  if (!integrationAliases.includes(depMapping.integrationAlias)) {
3003
3062
  errors.push(ValidationErrors.invalidPluginDependency(alias, depMapping.integrationAlias, integrationAliases));
3004
3063
  }
@@ -3269,7 +3328,7 @@ class IntegrationCache {
3269
3328
  }
3270
3329
  }
3271
3330
  return cached.definition;
3272
- } catch (error) {
3331
+ } catch {
3273
3332
  return null;
3274
3333
  }
3275
3334
  }
@@ -4658,7 +4717,7 @@ async function expandExports(options) {
4658
4717
  });
4659
4718
  return {};
4660
4719
  }
4661
- currentError = currentError.cause;
4720
+ currentError = currentError instanceof Error ? currentError.cause : undefined;
4662
4721
  }
4663
4722
  throw importError;
4664
4723
  }
@@ -4924,20 +4983,62 @@ class AgentProject {
4924
4983
  return this._assetsManager;
4925
4984
  }
4926
4985
  async createAgentInfo(info) {
4986
+ const { devId, ...agentJsonInfo } = info;
4927
4987
  const agentPath = path13.join(this._path, "agent.json");
4928
- const agentContent = stringifyWithOrder(info, agentInfoKeyOrder);
4988
+ const agentContent = stringifyWithOrder(agentJsonInfo, agentInfoKeyOrder);
4929
4989
  await fs10.writeFile(agentPath, agentContent);
4930
4990
  this._agentInfo = info;
4991
+ if (devId) {
4992
+ await this.createAgentLocalInfo({ devId });
4993
+ }
4931
4994
  }
4932
4995
  async updateAgentInfo(updates) {
4933
4996
  if (!this._agentInfo) {
4934
4997
  throw new Error("No agent.json found. Use createAgentInfo() first.");
4935
4998
  }
4936
- const updatedInfo = { ...this._agentInfo, ...updates };
4999
+ const { devId, ...agentJsonUpdates } = updates;
5000
+ const updatedInfo = { ...this._agentInfo, ...agentJsonUpdates };
5001
+ const { devId: _devId, ...agentJsonData } = updatedInfo;
4937
5002
  const agentPath = path13.join(this._path, "agent.json");
4938
- const agentContent = stringifyWithOrder(updatedInfo, agentInfoKeyOrder);
5003
+ const agentContent = stringifyWithOrder(agentJsonData, agentInfoKeyOrder);
4939
5004
  await fs10.writeFile(agentPath, agentContent);
4940
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
+ }
4941
5042
  }
4942
5043
  requiresAgentInfo(operation) {
4943
5044
  if (!this._agentInfo?.botId) {
@@ -5128,6 +5229,19 @@ ${err.stack?.split(`
5128
5229
  console.warn(`Failed to register data source workflows for ${kbPath}:`, error);
5129
5230
  }
5130
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
+ }
5131
5245
  getChannelsList(channelSpec) {
5132
5246
  if (channelSpec === "*") {
5133
5247
  return ["*"];
@@ -5210,6 +5324,9 @@ ${err.stack?.split(`
5210
5324
  return existingChannels.some((ch) => newChannels.includes(ch));
5211
5325
  });
5212
5326
  if (overlapping) {
5327
+ if (this.isBarrelReexport(overlapping, relPath, key, definition)) {
5328
+ continue;
5329
+ }
5213
5330
  this._warnings.push({
5214
5331
  $type: "ValidationError",
5215
5332
  code: "DUPLICATE_PRIMITIVE" /* DUPLICATE_PRIMITIVE */,
@@ -5227,6 +5344,9 @@ ${err.stack?.split(`
5227
5344
  } else if (Primitives2.Definitions.isKnowledgeDefinition(definition)) {
5228
5345
  const existing = this._knowledge.find((p) => p.definition.name === definition.name);
5229
5346
  if (existing) {
5347
+ if (this.isBarrelReexport(existing, relPath, key, definition)) {
5348
+ continue;
5349
+ }
5230
5350
  this._warnings.push({
5231
5351
  $type: "ValidationError",
5232
5352
  code: "DUPLICATE_PRIMITIVE" /* DUPLICATE_PRIMITIVE */,
@@ -5245,6 +5365,9 @@ ${err.stack?.split(`
5245
5365
  } else if (Primitives2.Definitions.isTriggerDefinition(definition)) {
5246
5366
  const existing = this._triggers.find((p) => p.definition.name === definition.name);
5247
5367
  if (existing) {
5368
+ if (this.isBarrelReexport(existing, relPath, key, definition)) {
5369
+ continue;
5370
+ }
5248
5371
  this._warnings.push({
5249
5372
  $type: "ValidationError",
5250
5373
  code: "DUPLICATE_PRIMITIVE" /* DUPLICATE_PRIMITIVE */,
@@ -5262,6 +5385,9 @@ ${err.stack?.split(`
5262
5385
  } else if (Primitives2.Definitions.isWorkflowDefinition(definition)) {
5263
5386
  const existing = this._workflows.find((p) => p.definition.name === definition.name);
5264
5387
  if (existing) {
5388
+ if (this.isBarrelReexport(existing, relPath, key, definition)) {
5389
+ continue;
5390
+ }
5265
5391
  this._warnings.push({
5266
5392
  $type: "ValidationError",
5267
5393
  code: "DUPLICATE_PRIMITIVE" /* DUPLICATE_PRIMITIVE */,
@@ -5279,6 +5405,9 @@ ${err.stack?.split(`
5279
5405
  } else if (Primitives2.Definitions.isActionDefinition(definition)) {
5280
5406
  const existing = this._actions.find((p) => p.definition.name === definition.name);
5281
5407
  if (existing) {
5408
+ if (this.isBarrelReexport(existing, relPath, key, definition)) {
5409
+ continue;
5410
+ }
5282
5411
  this._warnings.push({
5283
5412
  $type: "ValidationError",
5284
5413
  code: "DUPLICATE_PRIMITIVE" /* DUPLICATE_PRIMITIVE */,
@@ -5296,6 +5425,9 @@ ${err.stack?.split(`
5296
5425
  } else if (Primitives2.Definitions.isTableDefinition(definition)) {
5297
5426
  const existing = this._tables.find((p) => p.definition.name === definition.name);
5298
5427
  if (existing) {
5428
+ if (this.isBarrelReexport(existing, relPath, key, definition)) {
5429
+ continue;
5430
+ }
5299
5431
  this._warnings.push({
5300
5432
  $type: "ValidationError",
5301
5433
  code: "DUPLICATE_PRIMITIVE" /* DUPLICATE_PRIMITIVE */,
@@ -5619,22 +5751,36 @@ adk deploy # Deploy to Botpress Cloud
5619
5751
  adk chat # Chat with your agent in the terminal
5620
5752
  \`\`\`
5621
5753
 
5622
- ## AI Coding Assistant Skills
5754
+ ## MCP Tools (ADK Dev Server)
5623
5755
 
5624
- This project uses the Botpress ADK. Before making changes, use the relevant skill:
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.
5625
5758
 
5626
- | Skill | Use for |
5627
- | ------------------ | ------------------------------------------------ |
5628
- | \`/adk\` | ADK concepts, patterns, and API reference |
5629
- | \`/adk-integration\` | Finding and using Botpress integrations |
5630
- | \`/adk-debugger\` | Debugging with traces and test conversations |
5631
- | \`/adk-frontend\` | Building frontends that connect to ADK bots |
5759
+ ### Debugging & Testing
5632
5760
 
5633
- If these skills are not installed, install them:
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 |
5634
5766
 
5635
- \`\`\`
5636
- npx skills add botpress/skills --skill adk
5637
- \`\`\`
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.
5638
5784
 
5639
5785
  ## Project Overview
5640
5786
 
@@ -5694,7 +5840,7 @@ class AgentProjectGenerator {
5694
5840
  deploy: "adk deploy"
5695
5841
  },
5696
5842
  dependencies: {
5697
- "@botpress/runtime": `^${"1.16.7"}`
5843
+ "@botpress/runtime": `^${"1.17.0"}`
5698
5844
  },
5699
5845
  devDependencies: {
5700
5846
  typescript: "^5.9.3"
@@ -5797,6 +5943,12 @@ dist/
5797
5943
  .env.local
5798
5944
  .env.production
5799
5945
 
5946
+ # Local development
5947
+ agent.local.json
5948
+
5949
+ # MCP configuration (auto-generated by adk mcp:init)
5950
+ .mcp.json
5951
+
5800
5952
  # IDE files
5801
5953
  .vscode/
5802
5954
  .idea/
@@ -6227,7 +6379,7 @@ if (typeof globalThis !== 'undefined') {
6227
6379
  }
6228
6380
  }
6229
6381
  // src/generators/integration-types.ts
6230
- import { transforms } from "@botpress/sdk";
6382
+ import { z as z3 } from "@botpress/sdk";
6231
6383
  import crypto2 from "crypto";
6232
6384
  import path18 from "path";
6233
6385
 
@@ -6255,6 +6407,7 @@ function getPluginAlias(pluginName) {
6255
6407
  }
6256
6408
 
6257
6409
  // src/generators/integration-types.ts
6410
+ var { transforms } = z3;
6258
6411
  var getIntegrationHash = (integration) => {
6259
6412
  return crypto2.createHash("sha256").update(`${integration.alias}|${integration.definition?.id}|${integration.definition?.version}|${integration.definition?.updatedAt}`).digest("hex");
6260
6413
  };
@@ -6487,9 +6640,10 @@ Description: ${tag?.description}`);
6487
6640
  }
6488
6641
  if (integration.definition?.configurations) {
6489
6642
  for (const [key, config] of Object.entries(integration.definition.configurations)) {
6490
- const title = config.title || key;
6491
- const description = config.description || "";
6492
- const schema = config.schema;
6643
+ const configRecord = config;
6644
+ const title = configRecord.title || key;
6645
+ const description = configRecord.description || "";
6646
+ const schema = configRecord.schema;
6493
6647
  let tsType = "{}";
6494
6648
  if (schema) {
6495
6649
  tsType = transforms.fromJSONSchema(schema).toTypescriptType();
@@ -6606,12 +6760,14 @@ async function generateClientWrapper(project) {
6606
6760
  let schema;
6607
6761
  let computed = false;
6608
6762
  if (typeof colDef === "object" && colDef !== null && "schema" in colDef) {
6609
- schema = colDef.schema;
6610
- computed = colDef.computed || false;
6763
+ const colDefRecord = colDef;
6764
+ schema = colDefRecord.schema;
6765
+ computed = colDefRecord.computed || false;
6611
6766
  } else {
6612
6767
  schema = colDef;
6613
6768
  }
6614
- const tsType = schema.toTypescriptType ? schema.toTypescriptType({ treatDefaultAsOptional: true }) : "any";
6769
+ const schemaObj = schema;
6770
+ const tsType = typeof schemaObj.toTypescriptType === "function" ? schemaObj.toTypescriptType({ treatDefaultAsOptional: true }) : "any";
6615
6771
  if (!computed) {
6616
6772
  inputColumns.push(`${colName}: ${tsType}`);
6617
6773
  }
@@ -6926,10 +7082,11 @@ import fs18 from "fs/promises";
6926
7082
  import path38 from "path";
6927
7083
 
6928
7084
  // src/generators/plugin-types.ts
6929
- import { transforms as transforms2 } from "@botpress/sdk";
7085
+ import { z as z4 } from "@botpress/sdk";
6930
7086
  import crypto4 from "crypto";
6931
7087
  import path20 from "path";
6932
7088
  init_utils();
7089
+ var { transforms: transforms2 } = z4;
6933
7090
  function stripRefs(schema) {
6934
7091
  if (typeof schema !== "object" || schema === null) {
6935
7092
  return schema;
@@ -7075,10 +7232,11 @@ export type PluginActions = PluginsMap<Plugins>;
7075
7232
  }
7076
7233
 
7077
7234
  // src/generators/interface-types.ts
7078
- import { transforms as transforms3 } from "@botpress/sdk";
7235
+ import { z as z5 } from "@botpress/sdk";
7079
7236
  import crypto5 from "crypto";
7080
7237
  import path22 from "path";
7081
7238
  init_utils();
7239
+ var { transforms: transforms3 } = z5;
7082
7240
  var sameMajorVersion = (a, b) => {
7083
7241
  const majorA = a.split(".")[0];
7084
7242
  const majorB = b.split(".")[0];
@@ -7864,7 +8022,7 @@ class DevIdManager {
7864
8022
  if (!project.agentInfo) {
7865
8023
  throw ValidationErrors.agentNotLinked();
7866
8024
  }
7867
- await project.updateAgentInfo({
8025
+ await project.updateAgentLocalInfo({
7868
8026
  devId: projectCache.devId
7869
8027
  });
7870
8028
  }
@@ -7891,7 +8049,7 @@ class DevIdManager {
7891
8049
  const client = await this.getClient();
7892
8050
  await client.getBot({ id: agentInfo.devId });
7893
8051
  return true;
7894
- } catch (error) {
8052
+ } catch {
7895
8053
  return false;
7896
8054
  }
7897
8055
  }
@@ -8264,10 +8422,11 @@ class PluginSync {
8264
8422
 
8265
8423
  // src/bot-generator/generator.ts
8266
8424
  init_utils();
8267
- import { transforms as transforms4 } from "@botpress/sdk";
8425
+ import { z as z6 } from "@botpress/sdk";
8268
8426
  init_constants();
8269
8427
  import { BuiltInActions as BuiltInActions2, BuiltInWorkflows as BuiltInWorkflows4, Primitives as Primitives3 } from "@botpress/runtime/internal";
8270
8428
  import { BUILT_IN_TAGS as BUILT_IN_TAGS2 } from "@botpress/runtime/definition";
8429
+ var { transforms: transforms4 } = z6;
8271
8430
  var plural = (n, word) => `${n} ${word}${n === 1 ? "" : "s"}`;
8272
8431
  function isBuiltinWorkflow3(name) {
8273
8432
  return !!Object.values(BuiltInWorkflows4).find((x) => x.name === name);
@@ -9281,7 +9440,9 @@ export default bot;`;
9281
9440
  }
9282
9441
  {
9283
9442
  const dest = path38.join(srcDir, "triggers.ts");
9284
- const { transforms: transforms5 } = await import("@botpress/sdk");
9443
+ const {
9444
+ z: { transforms: transforms5 }
9445
+ } = await import("@botpress/sdk");
9285
9446
  const imports = new Map;
9286
9447
  const exports = new Set;
9287
9448
  const payloadTypes = {};
@@ -9569,7 +9730,9 @@ async function generateBotProject(options) {
9569
9730
  }
9570
9731
  // src/tables/table-manager.ts
9571
9732
  import { Client as Client15 } from "@botpress/client";
9572
- import { transforms as transforms5 } from "@botpress/sdk";
9733
+ import { z as z7 } from "@botpress/sdk";
9734
+ var { transforms: transforms5 } = z7;
9735
+
9573
9736
  class TableManager {
9574
9737
  client;
9575
9738
  botId;
@@ -9600,13 +9763,14 @@ class TableManager {
9600
9763
  }
9601
9764
  getSchemaType(schema) {
9602
9765
  if (schema.type) {
9603
- if (schema.type === "array" && schema.items?.type) {
9604
- return `array<${schema.items.type}>`;
9766
+ const items = schema.items;
9767
+ if (schema.type === "array" && items?.type) {
9768
+ return `array<${items.type}>`;
9605
9769
  }
9606
- return schema.type;
9770
+ return String(schema.type);
9607
9771
  }
9608
9772
  if (schema.$ref) {
9609
- return schema.$ref.split("/").pop() || "unknown";
9773
+ return String(schema.$ref).split("/").pop() || "unknown";
9610
9774
  }
9611
9775
  return "unknown";
9612
9776
  }
@@ -9617,8 +9781,8 @@ class TableManager {
9617
9781
  } else if (Math.abs(oldPosition - newPosition) <= 1) {
9618
9782
  score += 1;
9619
9783
  }
9620
- const oldDesc = (oldSchema?.description || "").toLowerCase();
9621
- const newDesc = (newSchema?.description || "").toLowerCase();
9784
+ const oldDesc = String(oldSchema?.description || "").toLowerCase();
9785
+ const newDesc = String(newSchema?.description || "").toLowerCase();
9622
9786
  if (oldDesc && newDesc && oldDesc === newDesc) {
9623
9787
  score += 5;
9624
9788
  } else if (oldDesc && newDesc && oldDesc.length > 5 && newDesc.length > 5) {
@@ -9633,8 +9797,10 @@ class TableManager {
9633
9797
  }
9634
9798
  }
9635
9799
  }
9636
- const oldOptional = oldSchema?.type?.includes("null") || oldSchema?.nullable === true;
9637
- const newOptional = newSchema?.type?.includes("null") || newSchema?.nullable === true;
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;
9638
9804
  if (oldOptional === newOptional) {
9639
9805
  score += 1;
9640
9806
  }
@@ -10862,7 +11028,7 @@ class KBSyncFormatter {
10862
11028
  }
10863
11029
  }
10864
11030
  // src/file-watcher/watcher.ts
10865
- import { watch as watch2, readdirSync as readdirSync2 } from "fs";
11031
+ import { watch as watch2, readdirSync as readdirSync2, statSync } from "fs";
10866
11032
  import { EventEmitter as EventEmitter3 } from "events";
10867
11033
  import { join as join9, relative as relative3 } from "path";
10868
11034
  import { existsSync as existsSync9 } from "fs";
@@ -10904,7 +11070,7 @@ class FileWatcher2 extends EventEmitter3 {
10904
11070
  this.updateFileState(fullPath);
10905
11071
  }
10906
11072
  }
10907
- } catch (error) {}
11073
+ } catch {}
10908
11074
  }
10909
11075
  watchFile(filePath) {
10910
11076
  if (this.watchers.has(filePath)) {
@@ -10937,6 +11103,12 @@ class FileWatcher2 extends EventEmitter3 {
10937
11103
  }
10938
11104
  }
10939
11105
  handleFileChange(filePath) {
11106
+ try {
11107
+ if (existsSync9(filePath) && statSync(filePath).isDirectory()) {
11108
+ this.scanDirectoryForChanges(filePath);
11109
+ return;
11110
+ }
11111
+ } catch {}
10940
11112
  const fileExists = existsSync9(filePath);
10941
11113
  const previousState = this.fileStates.get(filePath);
10942
11114
  let changeType;
@@ -10957,12 +11129,7 @@ class FileWatcher2 extends EventEmitter3 {
10957
11129
  path: relativePath,
10958
11130
  type: changeType
10959
11131
  });
10960
- if (this.debounceTimer) {
10961
- clearTimeout(this.debounceTimer);
10962
- }
10963
- this.debounceTimer = setTimeout(() => {
10964
- this.emitPendingChanges();
10965
- }, this.debounceMs);
11132
+ this.scheduleDebouncedEmit();
10966
11133
  }
10967
11134
  emitPendingChanges() {
10968
11135
  if (this.pendingChanges.size === 0) {
@@ -10976,6 +11143,44 @@ class FileWatcher2 extends EventEmitter3 {
10976
11143
  };
10977
11144
  this.emit("change", event);
10978
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
+ }
10979
11184
  updateFileState(filePath) {
10980
11185
  if (existsSync9(filePath)) {
10981
11186
  this.fileStates.set(filePath, Date.now());
@@ -11755,6 +11960,7 @@ function filterEvals(evals, filter) {
11755
11960
  }
11756
11961
  // src/eval/runner.ts
11757
11962
  import { Client as BpClient2 } from "@botpress/client";
11963
+ import { BUILT_IN_STATES as BUILT_IN_STATES2 } from "@botpress/runtime/internal";
11758
11964
 
11759
11965
  // src/eval/client.ts
11760
11966
  import { Client as BpClient } from "@botpress/client";
@@ -11775,20 +11981,21 @@ class ChatSession {
11775
11981
  }
11776
11982
  return this.client.user.id;
11777
11983
  }
11778
- async sendMessage(message, options = {}) {
11984
+ async ensureConversation() {
11779
11985
  if (!this.client) {
11780
11986
  throw new Error("ChatSession not connected. Call connect() first.");
11781
11987
  }
11782
- const { timeout = 30000, idleTimeout = 3000 } = options;
11783
11988
  if (!this.conversationId) {
11784
11989
  const conv = await this.client.createConversation({});
11785
11990
  this.conversationId = conv.conversation.id;
11991
+ return conv.conversation.id;
11786
11992
  }
11787
- const conversationId = this.conversationId;
11993
+ return this.conversationId;
11994
+ }
11995
+ async _awaitResponses(conversationId, trigger, options = {}) {
11996
+ const { timeout = 30000, idleTimeout = 3000 } = options;
11788
11997
  const responses = [];
11789
- const listener = await this.client.listenConversation({
11790
- id: conversationId
11791
- });
11998
+ const listener = await this.client.listenConversation({ id: conversationId });
11792
11999
  return new Promise((resolve4, reject) => {
11793
12000
  let idleTimer = null;
11794
12001
  let resolved = false;
@@ -11808,7 +12015,7 @@ class ChatSession {
11808
12015
  };
11809
12016
  const overallTimer = setTimeout(() => {
11810
12017
  if (!resolved) {
11811
- if (responses.length > 0) {
12018
+ if (responses.length > 0 || options.expectSilence) {
11812
12019
  done();
11813
12020
  } else {
11814
12021
  resolved = true;
@@ -11831,10 +12038,7 @@ class ChatSession {
11831
12038
  done();
11832
12039
  }
11833
12040
  });
11834
- this.client.createMessage({
11835
- conversationId,
11836
- payload: { type: "text", text: message }
11837
- }).then(() => {
12041
+ trigger().then(() => {
11838
12042
  resetIdle();
11839
12043
  }).catch((err) => {
11840
12044
  clearTimeout(overallTimer);
@@ -11845,6 +12049,20 @@ class ChatSession {
11845
12049
  });
11846
12050
  });
11847
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
+ }
11848
12066
  }
11849
12067
  async function discoverWebhookId(botId, token, apiUrl) {
11850
12068
  const client = new BpClient({ token, botId, apiUrl });
@@ -11852,7 +12070,7 @@ async function discoverWebhookId(botId, token, apiUrl) {
11852
12070
  const integrations = bot.integrations || {};
11853
12071
  const chat = Object.values(integrations).find((int) => int.name === "chat");
11854
12072
  const webhookId = chat?.webhookId;
11855
- if (!webhookId) {
12073
+ if (!webhookId || typeof webhookId !== "string") {
11856
12074
  throw new Error("No chat integration found on bot. Make sure the bot has the chat integration enabled.");
11857
12075
  }
11858
12076
  return webhookId;
@@ -11914,9 +12132,11 @@ async function getTraceData(conversationId, devServerUrl, options = {}) {
11914
12132
  }
11915
12133
 
11916
12134
  // src/eval/graders/llm.ts
11917
- import { Cognitive } from "@botpress/cognitive";
12135
+ import { Cognitive } from "@botpress/runtime";
11918
12136
  import { Client as Client18 } from "@botpress/client";
11919
- var JUDGE_SYSTEM_PROMPT = `You are an evaluation judge for a chatbot. You will be given:
12137
+ var DEFAULT_PASS_THRESHOLD = 3;
12138
+ function buildJudgeSystemPrompt(passThreshold) {
12139
+ return `You are an evaluation judge for a chatbot. You will be given:
11920
12140
  - The user's message
11921
12141
  - The bot's response
11922
12142
  - Grading criteria
@@ -11937,32 +12157,44 @@ Scoring guide:
11937
12157
  - 2: Barely meets criteria, significant issues
11938
12158
  - 1: Does not meet criteria
11939
12159
 
11940
- A score of 3 or above is a pass.`;
12160
+ A score of ${passThreshold} or above is a pass.`;
12161
+ }
12162
+ var MODEL_ALIASES = ["fast", "best"];
11941
12163
  var _cognitive = null;
11942
- function getCognitive() {
11943
- if (_cognitive)
11944
- return _cognitive;
11945
- const token = process.env.BP_TOKEN || process.env.ADK_TOKEN;
11946
- const botId = process.env.ADK_BOT_ID;
11947
- const apiUrl = process.env.ADK_API_URL || "https://api.botpress.cloud";
11948
- if (!token || !botId)
11949
- return null;
11950
- const client = new Client18({ token, apiUrl, botId });
11951
- _cognitive = new Cognitive({ client, __experimental_beta: true });
11952
- 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);
11953
12172
  }
11954
- function initLLMJudge(credentials) {
12173
+ async function initLLMJudge(credentials, options) {
12174
+ const log = options?.logger ?? console;
11955
12175
  const client = new Client18({
11956
12176
  token: credentials.token,
11957
12177
  apiUrl: credentials.apiUrl,
11958
12178
  botId: credentials.botId
11959
12179
  });
11960
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
+ }
11961
12193
  }
11962
12194
  async function gradeLLMJudge(botResponse, criteria, context) {
12195
+ const threshold = Math.max(1, Math.min(5, context.passThreshold ?? DEFAULT_PASS_THRESHOLD));
11963
12196
  try {
11964
- const cognitive = getCognitive();
11965
- if (!cognitive) {
12197
+ if (!_cognitive) {
11966
12198
  return {
11967
12199
  assertion: `llm_judge: "${criteria}"`,
11968
12200
  pass: true,
@@ -11970,11 +12202,19 @@ async function gradeLLMJudge(botResponse, criteria, context) {
11970
12202
  actual: "SKIPPED — LLM judge unavailable: no credentials configured"
11971
12203
  };
11972
12204
  }
11973
- const { output } = await cognitive.generateContent({
11974
- model: "fast",
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,
11975
12215
  temperature: 0,
11976
12216
  responseFormat: "json_object",
11977
- systemPrompt: JUDGE_SYSTEM_PROMPT,
12217
+ systemPrompt: buildJudgeSystemPrompt(threshold),
11978
12218
  messages: [
11979
12219
  {
11980
12220
  role: "user",
@@ -11999,9 +12239,9 @@ Criteria: ${criteria}`
11999
12239
  const verdict = JSON.parse(content);
12000
12240
  return {
12001
12241
  assertion: `llm_judge: "${criteria}"`,
12002
- pass: verdict.score >= 3,
12242
+ pass: verdict.score >= threshold,
12003
12243
  expected: criteria,
12004
- actual: `Score ${verdict.score}/5 — ${verdict.reason}`
12244
+ actual: `Score ${verdict.score}/5 (threshold: ${threshold}) — ${verdict.reason}`
12005
12245
  };
12006
12246
  } catch (err) {
12007
12247
  return {
@@ -12049,7 +12289,10 @@ async function gradeResponse(botResponse, assertions, context) {
12049
12289
  continue;
12050
12290
  }
12051
12291
  if ("llm_judge" in assertion) {
12052
- const result = await gradeLLMJudge(botResponse, assertion.llm_judge, context);
12292
+ const result = await gradeLLMJudge(botResponse, assertion.llm_judge, {
12293
+ userMessage: context.userMessage,
12294
+ passThreshold: context.judgePassThreshold
12295
+ });
12053
12296
  results.push(result);
12054
12297
  continue;
12055
12298
  }
@@ -12201,6 +12444,7 @@ function gradeTools(toolCalls, assertions) {
12201
12444
  }
12202
12445
 
12203
12446
  // src/eval/graders/state.ts
12447
+ import { BUILT_IN_STATES } from "@botpress/runtime/internal";
12204
12448
  function parseStatePath(path42) {
12205
12449
  const dot = path42.indexOf(".");
12206
12450
  if (dot === -1) {
@@ -12210,11 +12454,16 @@ function parseStatePath(path42) {
12210
12454
  const field = path42.slice(dot + 1);
12211
12455
  switch (prefix) {
12212
12456
  case "bot":
12213
- return { type: "bot", stateName: "botState", stateId: (ctx) => ctx.botId, field };
12457
+ return { type: "bot", stateName: BUILT_IN_STATES.bot, stateId: (ctx) => ctx.botId, field };
12214
12458
  case "user":
12215
- return { type: "user", stateName: "userState", stateId: (ctx) => ctx.userId, field };
12459
+ return { type: "user", stateName: BUILT_IN_STATES.user, stateId: (ctx) => ctx.userId, field };
12216
12460
  case "conversation":
12217
- return { type: "conversation", stateName: "conversationState", stateId: (ctx) => ctx.conversationId, field };
12461
+ return {
12462
+ type: "conversation",
12463
+ stateName: BUILT_IN_STATES.conversation,
12464
+ stateId: (ctx) => ctx.conversationId,
12465
+ field
12466
+ };
12218
12467
  default:
12219
12468
  throw new Error(`Unknown state type "${prefix}" in path "${path42}" — expected bot, user, or conversation`);
12220
12469
  }
@@ -12225,7 +12474,9 @@ async function fetchState(client, type, id, name) {
12225
12474
  const payload = result.state?.payload;
12226
12475
  return payload?.value ?? payload ?? null;
12227
12476
  } catch (err) {
12228
- if (err?.code === 404 || err?.message?.includes("404") || err?.message?.includes("doesn't exist")) {
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")) {
12229
12480
  return null;
12230
12481
  }
12231
12482
  throw err;
@@ -12249,7 +12500,7 @@ async function snapshotState(client, assertions, ctx) {
12249
12500
  if (assertion.changed === undefined)
12250
12501
  continue;
12251
12502
  const parsed = parseStatePath(assertion.path);
12252
- if (parsed.type === "conversation")
12503
+ if (parsed.type === "conversation" && !ctx.conversationId)
12253
12504
  continue;
12254
12505
  const payload = await fetchState(client, parsed.type, parsed.stateId(ctx), parsed.stateName);
12255
12506
  snapshots.set(assertion.path, payload ? payload[parsed.field] : undefined);
@@ -12462,6 +12713,22 @@ function gradeWorkflows(spans, assertions) {
12462
12713
  return results;
12463
12714
  }
12464
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
+
12465
12732
  // src/eval/graders/outcome.ts
12466
12733
  async function snapshotOutcomeState(client, evalDef, ctx) {
12467
12734
  if (!evalDef.outcome?.state) {
@@ -12492,9 +12759,64 @@ async function gradeOutcome(client, evalDef, ctx, traceSpans, preSnapshots) {
12492
12759
  // src/eval/runner.ts
12493
12760
  import { randomUUID } from "crypto";
12494
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
+ }
12495
12816
  async function runEval(evalDef, connection, options = {}) {
12496
12817
  const devServerUrl = options.devServerUrl || "http://localhost:3001";
12497
12818
  const idleTimeout = evalDef.options?.idleTimeout ?? options.idleTimeout ?? DEFAULT_IDLE_TIMEOUT;
12819
+ const judgePassThreshold = evalDef.options?.judgePassThreshold ?? options.judgePassThreshold;
12498
12820
  const start = Date.now();
12499
12821
  const turns = [];
12500
12822
  let outcomeAssertions = [];
@@ -12512,34 +12834,67 @@ async function runEval(evalDef, connection, options = {}) {
12512
12834
  }
12513
12835
  return bpClient;
12514
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);
12515
12850
  let preSnapshots = new Map;
12516
12851
  if (evalDef.outcome?.state) {
12517
12852
  const ctx = {
12518
12853
  botId: connection.botId,
12519
12854
  userId: session.userId,
12520
- conversationId: ""
12855
+ conversationId: lastConversationId
12521
12856
  };
12522
12857
  preSnapshots = await snapshotOutcomeState(getBpClient(), evalDef, ctx);
12523
12858
  }
12524
12859
  let previousToolCallCount = 0;
12525
- let lastConversationId = "";
12526
12860
  let allSpans = [];
12527
12861
  for (let i = 0;i < evalDef.conversation.length; i++) {
12528
12862
  const turn = evalDef.conversation[i];
12529
12863
  const turnStart = Date.now();
12530
- const result = await session.sendMessage(turn.user, {
12531
- timeout: Math.max(30000, idleTimeout * 2),
12532
- idleTimeout
12533
- });
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);
12534
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
+ }
12535
12879
  lastConversationId = result.conversationId;
12536
12880
  const botResponse = result.responses.map((r) => r.text).join(`
12537
12881
  `);
12882
+ const turnLabel = turn.event ? `[event: ${turn.event.type}]` : turn.user;
12538
12883
  const evalStart = Date.now();
12539
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
+ }
12540
12894
  if (turn.assert?.response) {
12541
12895
  assertions = await gradeResponse(botResponse, turn.assert.response, {
12542
- userMessage: turn.user
12896
+ userMessage: turnLabel,
12897
+ judgePassThreshold
12543
12898
  });
12544
12899
  }
12545
12900
  if (turn.assert?.tools) {
@@ -12606,11 +12961,15 @@ async function runEval(evalDef, connection, options = {}) {
12606
12961
  const workflowResults = gradeWorkflows(allSpans, turn.assert.workflow);
12607
12962
  assertions.push(...workflowResults);
12608
12963
  }
12964
+ if (turn.assert?.timing) {
12965
+ const timingResults = gradeTiming(botDuration, turn.assert.timing);
12966
+ assertions.push(...timingResults);
12967
+ }
12609
12968
  const turnPass = assertions.every((a) => a.pass);
12610
12969
  const evalDuration = Date.now() - evalStart;
12611
12970
  turns.push({
12612
12971
  turnNumber: i + 1,
12613
- userMessage: turn.user,
12972
+ userMessage: turnLabel,
12614
12973
  botResponse,
12615
12974
  assertions,
12616
12975
  pass: turnPass,
@@ -12672,11 +13031,11 @@ async function runEval(evalDef, connection, options = {}) {
12672
13031
  async function runEvalSuite(config, filter) {
12673
13032
  const start = Date.now();
12674
13033
  const runId = randomUUID().replace(/-/g, "").slice(0, 26);
12675
- initLLMJudge({
13034
+ await initLLMJudge({
12676
13035
  token: config.credentials.token,
12677
13036
  apiUrl: config.credentials.apiUrl,
12678
13037
  botId: config.credentials.botId
12679
- });
13038
+ }, { model: config.evalOptions?.judgeModel, logger: config.logger });
12680
13039
  const evalsDir = `${config.agentPath}/evals`;
12681
13040
  const allEvals = await loadEvalsFromDir(evalsDir);
12682
13041
  const evals = filterEvals(allEvals, filter);
@@ -12708,7 +13067,11 @@ async function runEvalSuite(config, filter) {
12708
13067
  for (let i = 0;i < evals.length; i++) {
12709
13068
  const evalDef = evals[i];
12710
13069
  config.onProgress?.({ type: "eval_start", evalName: evalDef.name, index: i });
12711
- const report = await runEval(evalDef, connection, { devServerUrl, idleTimeout: config.evalOptions?.idleTimeout });
13070
+ const report = await runEval(evalDef, connection, {
13071
+ devServerUrl,
13072
+ idleTimeout: config.evalOptions?.idleTimeout,
13073
+ judgePassThreshold: config.evalOptions?.judgePassThreshold
13074
+ });
12712
13075
  reports.push(report);
12713
13076
  config.onProgress?.({ type: "eval_complete", evalName: evalDef.name, index: i, report });
12714
13077
  }
@@ -12799,6 +13162,7 @@ export {
12799
13162
  buildOpenCodeConfig,
12800
13163
  bpCliImporter,
12801
13164
  auth,
13165
+ agentLocalInfoKeyOrder,
12802
13166
  agentInfoKeyOrder,
12803
13167
  ValidationSeverity,
12804
13168
  ValidationErrors,
@@ -12845,4 +13209,4 @@ export {
12845
13209
  AgentProject
12846
13210
  };
12847
13211
 
12848
- //# debugId=BA9CF8B5F775A63B64756E2164756E21
13212
+ //# debugId=984405F8F441F45F64756E2164756E21