@botpress/adk 1.16.7 → 1.18.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-init/agent-project-generator.d.ts +32 -8
- package/dist/agent-init/agent-project-generator.d.ts.map +1 -1
- package/dist/agent-init/index.d.ts +1 -0
- package/dist/agent-init/index.d.ts.map +1 -1
- package/dist/agent-project/agent-project.d.ts +13 -1
- package/dist/agent-project/agent-project.d.ts.map +1 -1
- package/dist/agent-project/agent-resolver.d.ts +4 -3
- package/dist/agent-project/agent-resolver.d.ts.map +1 -1
- package/dist/agent-project/config-writer.d.ts +33 -0
- package/dist/agent-project/config-writer.d.ts.map +1 -1
- package/dist/agent-project/dependencies-parser.d.ts.map +1 -1
- package/dist/agent-project/index.d.ts +1 -1
- package/dist/agent-project/index.d.ts.map +1 -1
- package/dist/agent-project/types.d.ts +48 -22
- 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/dev-id-manager.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 +2 -2
- package/dist/commands/bp-dev-command.d.ts.map +1 -1
- package/dist/commands/opencode-command.d.ts +2 -2
- package/dist/commands/opencode-command.d.ts.map +1 -1
- package/dist/commands/opencode-config.d.ts +1 -1
- package/dist/commands/opencode-config.d.ts.map +1 -1
- 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/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.map +1 -1
- package/dist/eval/index.d.ts +3 -3
- package/dist/eval/index.d.ts.map +1 -1
- package/dist/eval/loader.d.ts +2 -1
- package/dist/eval/loader.d.ts.map +1 -1
- package/dist/eval/runner.d.ts +1 -0
- package/dist/eval/runner.d.ts.map +1 -1
- package/dist/eval/traces.d.ts.map +1 -1
- package/dist/eval/types.d.ts +62 -4
- 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/workflow-types.d.ts.map +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1194 -594
- package/dist/index.js.map +62 -61
- package/dist/integrations/checker.d.ts +2 -2
- package/dist/integrations/checker.d.ts.map +1 -1
- package/dist/integrations/config-utils.d.ts +4 -3
- package/dist/integrations/config-utils.d.ts.map +1 -1
- package/dist/integrations/operations.d.ts +19 -6
- package/dist/integrations/operations.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/checker.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/templates/README.md +101 -0
- package/dist/templates/blank/README.md +36 -0
- package/dist/templates/blank/agent.config.ts +49 -0
- package/dist/templates/blank/package.json +17 -0
- package/dist/templates/blank/src/actions/index.ts +19 -0
- package/dist/templates/blank/src/conversations/index.ts +16 -0
- package/dist/templates/blank/src/knowledge/index.ts +17 -0
- package/dist/templates/blank/src/tables/index.ts +19 -0
- package/dist/templates/blank/src/triggers/index.ts +20 -0
- package/dist/templates/blank/src/workflows/index.ts +23 -0
- package/dist/templates/blank/tsconfig.json +22 -0
- package/dist/templates/crm-enrichment/README.md +85 -0
- package/dist/templates/crm-enrichment/agent.config.ts +33 -0
- package/dist/templates/crm-enrichment/package.json +17 -0
- package/dist/templates/crm-enrichment/src/actions/enrich-contact.ts +81 -0
- package/dist/templates/crm-enrichment/src/conversations/index.ts +14 -0
- package/dist/templates/crm-enrichment/src/knowledge/index.ts +17 -0
- package/dist/templates/crm-enrichment/src/tables/contacts.ts +43 -0
- package/dist/templates/crm-enrichment/src/triggers/daily-enrichment.ts +30 -0
- package/dist/templates/crm-enrichment/src/workflows/enrichment-pipeline.ts +171 -0
- package/dist/templates/crm-enrichment/tsconfig.json +22 -0
- package/dist/templates/hello-world/README.md +46 -0
- package/dist/templates/hello-world/agent.config.ts +48 -0
- package/dist/templates/hello-world/package.json +17 -0
- package/dist/templates/hello-world/src/actions/index.ts +19 -0
- package/dist/templates/hello-world/src/conversations/index.ts +10 -0
- package/dist/templates/hello-world/src/knowledge/index.ts +17 -0
- package/dist/templates/hello-world/src/tables/index.ts +19 -0
- package/dist/templates/hello-world/src/triggers/index.ts +20 -0
- package/dist/templates/hello-world/src/workflows/index.ts +23 -0
- package/dist/templates/hello-world/tsconfig.json +22 -0
- package/dist/templates/knowledge-assistant/README.md +66 -0
- package/dist/templates/knowledge-assistant/agent.config.ts +26 -0
- package/dist/templates/knowledge-assistant/package.json +17 -0
- package/dist/templates/knowledge-assistant/src/actions/index.ts +19 -0
- package/dist/templates/knowledge-assistant/src/actions/search-docs.ts +50 -0
- package/dist/templates/knowledge-assistant/src/conversations/index.ts +33 -0
- package/dist/templates/knowledge-assistant/src/knowledge/docs.ts +23 -0
- package/dist/templates/knowledge-assistant/src/knowledge/getting-started.md +49 -0
- package/dist/templates/knowledge-assistant/src/tables/index.ts +21 -0
- package/dist/templates/knowledge-assistant/src/triggers/index.ts +17 -0
- package/dist/templates/knowledge-assistant/src/workflows/index.ts +28 -0
- package/dist/templates/knowledge-assistant/tsconfig.json +22 -0
- package/dist/templates/slack-triage/README.md +74 -0
- package/dist/templates/slack-triage/agent.config.ts +35 -0
- package/dist/templates/slack-triage/evals/triage-basic.eval.ts +55 -0
- package/dist/templates/slack-triage/package.json +17 -0
- package/dist/templates/slack-triage/src/actions/classify-request.ts +65 -0
- package/dist/templates/slack-triage/src/conversations/slack-dm.ts +72 -0
- package/dist/templates/slack-triage/src/knowledge/team-directory.md +33 -0
- package/dist/templates/slack-triage/src/tables/routing-rules.ts +38 -0
- package/dist/templates/slack-triage/src/triggers/new-message.ts +44 -0
- package/dist/templates/slack-triage/src/workflows/triage-flow.ts +104 -0
- package/dist/templates/slack-triage/tsconfig.json +22 -0
- package/dist/templates/template.config.json +47 -0
- package/dist/utils/json-ordering.d.ts +5 -4
- package/dist/utils/json-ordering.d.ts.map +1 -1
- package/package.json +31 -38
package/dist/index.js
CHANGED
|
@@ -15,19 +15,22 @@ 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(),
|
|
22
22
|
integrationInterfaceAlias: z.string().optional()
|
|
23
23
|
});
|
|
24
24
|
dependenciesSchema = z.object({
|
|
25
|
-
integrations: z.record(z.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
integrations: z.record(z.union([
|
|
26
|
+
z.string(),
|
|
27
|
+
z.object({
|
|
28
|
+
version: z.string(),
|
|
29
|
+
enabled: z.boolean(),
|
|
30
|
+
configurationType: z.string().optional(),
|
|
31
|
+
config: z.record(z.any()).optional()
|
|
32
|
+
})
|
|
33
|
+
])).optional(),
|
|
31
34
|
plugins: z.record(z.object({
|
|
32
35
|
version: z.string(),
|
|
33
36
|
config: z.record(z.any()).optional(),
|
|
@@ -40,6 +43,12 @@ var init_types = __esm(() => {
|
|
|
40
43
|
apiUrl: z.string().optional().describe("The Botpress API URL (e.g., https://api.botpress.cloud)"),
|
|
41
44
|
devId: z.string().optional().describe("The development ID used during local development")
|
|
42
45
|
});
|
|
46
|
+
agentLocalInfoSchema = z.object({
|
|
47
|
+
botId: z.string().optional().describe("The bot ID (overrides agent.json for local development)"),
|
|
48
|
+
workspaceId: z.string().optional().describe("The workspace ID (overrides agent.json for local development)"),
|
|
49
|
+
apiUrl: z.string().optional().describe("The Botpress API URL (overrides agent.json for local development)"),
|
|
50
|
+
devId: z.string().optional().describe("The development bot ID used during local development")
|
|
51
|
+
});
|
|
43
52
|
((ValidationErrorCode2) => {
|
|
44
53
|
ValidationErrorCode2["DIRECTORY_NOT_FOUND"] = "DIRECTORY_NOT_FOUND";
|
|
45
54
|
ValidationErrorCode2["DIRECTORY_ACCESS_ERROR"] = "DIRECTORY_ACCESS_ERROR";
|
|
@@ -467,9 +476,46 @@ var init_constants = __esm(() => {
|
|
|
467
476
|
// src/agent-project/agent-resolver.ts
|
|
468
477
|
import fs from "fs/promises";
|
|
469
478
|
import path from "path";
|
|
479
|
+
async function readLocalInfo(agentPath) {
|
|
480
|
+
const localPath = path.join(agentPath, "agent.local.json");
|
|
481
|
+
try {
|
|
482
|
+
const localContent = await fs.readFile(localPath, "utf-8");
|
|
483
|
+
const localData = JSON.parse(localContent);
|
|
484
|
+
const localResult = agentLocalInfoSchema.safeParse(localData);
|
|
485
|
+
if (!localResult.success) {
|
|
486
|
+
const issue = localResult.error.errors[0];
|
|
487
|
+
throw ValidationErrors.warning(`agent.local.json has an invalid field: ${issue?.path.join(".")} — ${issue?.message}`, "agent.local.json");
|
|
488
|
+
}
|
|
489
|
+
return localResult.data;
|
|
490
|
+
} catch (error) {
|
|
491
|
+
if (error.code === "ENOENT") {
|
|
492
|
+
return null;
|
|
493
|
+
}
|
|
494
|
+
if (ValidationErrors.isValidationError(error)) {
|
|
495
|
+
throw error;
|
|
496
|
+
}
|
|
497
|
+
throw ValidationErrors.warning(`Failed to read agent.local.json: ${error.message}`, "agent.local.json");
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
function applyLocalOverrides(agentInfo, localInfo) {
|
|
501
|
+
if (localInfo.botId) {
|
|
502
|
+
agentInfo.botId = localInfo.botId;
|
|
503
|
+
}
|
|
504
|
+
if (localInfo.workspaceId) {
|
|
505
|
+
agentInfo.workspaceId = localInfo.workspaceId;
|
|
506
|
+
}
|
|
507
|
+
if (localInfo.apiUrl) {
|
|
508
|
+
agentInfo.apiUrl = localInfo.apiUrl;
|
|
509
|
+
}
|
|
510
|
+
if (localInfo.devId) {
|
|
511
|
+
agentInfo.devId = localInfo.devId;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
470
514
|
async function resolveAgent(agentPath, options = {}) {
|
|
471
515
|
const { required = false, requireWorkspace = false, requireBot = false } = options;
|
|
472
516
|
const agentJsonPath = path.join(agentPath, "agent.json");
|
|
517
|
+
const localInfo = await readLocalInfo(agentPath);
|
|
518
|
+
let agentInfo = null;
|
|
473
519
|
try {
|
|
474
520
|
const agentJsonContent = await fs.readFile(agentJsonPath, "utf-8");
|
|
475
521
|
let agentData;
|
|
@@ -483,29 +529,42 @@ async function resolveAgent(agentPath, options = {}) {
|
|
|
483
529
|
const zodError = validationResult.error.errors[0];
|
|
484
530
|
throw ValidationErrors.invalidConfigSchema("agent.json", zodError?.path.join(".") || "unknown", zodError?.message || "Invalid schema");
|
|
485
531
|
}
|
|
486
|
-
|
|
487
|
-
if (!agentInfo.apiUrl) {
|
|
488
|
-
agentInfo.apiUrl = DEFAULT_API_URL;
|
|
489
|
-
}
|
|
490
|
-
if (requireWorkspace && !agentInfo.workspaceId) {
|
|
491
|
-
throw ValidationErrors.workspaceIdMissing();
|
|
492
|
-
}
|
|
493
|
-
if (requireBot && !agentInfo.botId) {
|
|
494
|
-
throw ValidationErrors.botIdMissing();
|
|
495
|
-
}
|
|
496
|
-
return agentInfo;
|
|
532
|
+
agentInfo = validationResult.data;
|
|
497
533
|
} catch (error) {
|
|
498
|
-
if (error.code === "ENOENT") {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
}
|
|
534
|
+
if (error.code === "ENOENT") {} else if (ValidationErrors.isValidationError(error)) {
|
|
535
|
+
throw error;
|
|
536
|
+
} else {
|
|
537
|
+
throw ValidationErrors.warning(`Failed to read agent.json: ${error.message}`, "agent.json");
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
if (!agentInfo) {
|
|
541
|
+
if (localInfo?.botId && localInfo?.workspaceId) {
|
|
542
|
+
agentInfo = {
|
|
543
|
+
botId: localInfo.botId,
|
|
544
|
+
workspaceId: localInfo.workspaceId,
|
|
545
|
+
apiUrl: localInfo.apiUrl,
|
|
546
|
+
devId: localInfo.devId
|
|
547
|
+
};
|
|
548
|
+
} else if (required || requireWorkspace || requireBot) {
|
|
549
|
+
throw ValidationErrors.requiredFileMissing("agent.json or agent.local.json");
|
|
550
|
+
} else {
|
|
502
551
|
return null;
|
|
503
552
|
}
|
|
504
|
-
|
|
505
|
-
|
|
553
|
+
} else {
|
|
554
|
+
if (localInfo) {
|
|
555
|
+
applyLocalOverrides(agentInfo, localInfo);
|
|
506
556
|
}
|
|
507
|
-
throw ValidationErrors.warning(`Failed to read agent.json: ${error.message}`, "agent.json");
|
|
508
557
|
}
|
|
558
|
+
if (!agentInfo.apiUrl) {
|
|
559
|
+
agentInfo.apiUrl = DEFAULT_API_URL;
|
|
560
|
+
}
|
|
561
|
+
if (requireWorkspace && !agentInfo.workspaceId) {
|
|
562
|
+
throw ValidationErrors.workspaceIdMissing();
|
|
563
|
+
}
|
|
564
|
+
if (requireBot && !agentInfo.botId) {
|
|
565
|
+
throw ValidationErrors.botIdMissing();
|
|
566
|
+
}
|
|
567
|
+
return agentInfo;
|
|
509
568
|
}
|
|
510
569
|
var init_agent_resolver = __esm(() => {
|
|
511
570
|
init_types();
|
|
@@ -525,10 +584,14 @@ import os from "os";
|
|
|
525
584
|
class CredentialsManager {
|
|
526
585
|
credentialsPath;
|
|
527
586
|
configDir;
|
|
587
|
+
profileOverride;
|
|
528
588
|
constructor() {
|
|
529
589
|
this.configDir = path2.join(os.homedir(), ".adk");
|
|
530
590
|
this.credentialsPath = path2.join(this.configDir, "credentials");
|
|
531
591
|
}
|
|
592
|
+
setProfileOverride(profile) {
|
|
593
|
+
this.profileOverride = profile;
|
|
594
|
+
}
|
|
532
595
|
async ensureConfigDir() {
|
|
533
596
|
try {
|
|
534
597
|
await fs2.mkdir(this.configDir, { recursive: true });
|
|
@@ -644,23 +707,53 @@ class CredentialsManager {
|
|
|
644
707
|
await this.writeCredentials(store);
|
|
645
708
|
}
|
|
646
709
|
async getActiveCredentials() {
|
|
647
|
-
const
|
|
648
|
-
const credentials = await this.getCredentials(
|
|
710
|
+
const profileName = this.profileOverride || process.env.ADK_PROFILE;
|
|
711
|
+
const credentials = await this.getCredentials(profileName);
|
|
649
712
|
if (!credentials) {
|
|
650
|
-
const
|
|
651
|
-
throw new Error(`No credentials found for profile '${
|
|
713
|
+
const displayName = profileName || "default";
|
|
714
|
+
throw new Error(`No credentials found for profile '${displayName}'. ` + `Please run 'adk login' to authenticate.`);
|
|
652
715
|
}
|
|
653
716
|
return credentials;
|
|
654
717
|
}
|
|
718
|
+
findProfileByApiUrl(store, apiUrl) {
|
|
719
|
+
const normalizedUrl = apiUrl.replace(/\/+$/, "");
|
|
720
|
+
for (const [, credentials] of Object.entries(store.profiles)) {
|
|
721
|
+
if (!credentials.apiUrl)
|
|
722
|
+
continue;
|
|
723
|
+
const profileUrl = credentials.apiUrl.replace(/\/+$/, "");
|
|
724
|
+
if (profileUrl === normalizedUrl) {
|
|
725
|
+
return credentials;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
return null;
|
|
729
|
+
}
|
|
655
730
|
async getAgentCredentials(agentPath) {
|
|
656
|
-
const baseCredentials = await this.getActiveCredentials();
|
|
657
731
|
const agentInfo = await resolveAgent(agentPath, {
|
|
658
732
|
required: true,
|
|
659
733
|
requireWorkspace: true
|
|
660
734
|
});
|
|
735
|
+
const agentApiUrl = agentInfo.apiUrl;
|
|
736
|
+
let baseCredentials;
|
|
737
|
+
const hasExplicitProfile = !!(this.profileOverride || process.env.ADK_PROFILE);
|
|
738
|
+
if (hasExplicitProfile) {
|
|
739
|
+
baseCredentials = await this.getActiveCredentials();
|
|
740
|
+
} else {
|
|
741
|
+
const store = await this.readCredentials();
|
|
742
|
+
const matchingCredentials = this.findProfileByApiUrl(store, agentApiUrl);
|
|
743
|
+
if (matchingCredentials) {
|
|
744
|
+
baseCredentials = matchingCredentials;
|
|
745
|
+
} else {
|
|
746
|
+
const profileName = store.currentProfile || "default";
|
|
747
|
+
const activeCredentials = store.profiles[profileName];
|
|
748
|
+
if (!activeCredentials) {
|
|
749
|
+
throw new Error(`No credentials found for profile '${profileName}'. ` + `Please run 'adk login' to authenticate.`);
|
|
750
|
+
}
|
|
751
|
+
baseCredentials = activeCredentials;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
661
754
|
return {
|
|
662
755
|
...baseCredentials,
|
|
663
|
-
apiUrl:
|
|
756
|
+
apiUrl: agentApiUrl,
|
|
664
757
|
workspaceId: agentInfo.workspaceId,
|
|
665
758
|
botId: agentInfo.botId
|
|
666
759
|
};
|
|
@@ -729,7 +822,7 @@ var _format = null, _formatLoaded = false, formatCode = async (code, filepath) =
|
|
|
729
822
|
`));
|
|
730
823
|
return code;
|
|
731
824
|
}
|
|
732
|
-
}, ADK_VERSION = "1.
|
|
825
|
+
}, ADK_VERSION = "1.18.0-beta.1", relative2 = (from, to) => {
|
|
733
826
|
const fromDir = path10.dirname(from);
|
|
734
827
|
const relative3 = path10.relative(fromDir, to);
|
|
735
828
|
return relative3.startsWith(".") ? relative3 : `./${relative3}`;
|
|
@@ -860,16 +953,31 @@ var init_integration_action_types = __esm(() => {
|
|
|
860
953
|
var require_package = __commonJS((exports, module) => {
|
|
861
954
|
module.exports = {
|
|
862
955
|
name: "@botpress/adk",
|
|
863
|
-
version: "1.
|
|
956
|
+
version: "1.18.0-beta.1",
|
|
864
957
|
description: "Core ADK library for building AI agents on Botpress",
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
958
|
+
keywords: [
|
|
959
|
+
"adk",
|
|
960
|
+
"agent",
|
|
961
|
+
"ai",
|
|
962
|
+
"botpress",
|
|
963
|
+
"chatbot",
|
|
964
|
+
"conversational-ai",
|
|
965
|
+
"development-kit"
|
|
966
|
+
],
|
|
967
|
+
license: "MIT",
|
|
968
|
+
author: "Botpress",
|
|
969
|
+
repository: {
|
|
970
|
+
type: "git",
|
|
971
|
+
url: "https://github.com/botpress/adk"
|
|
972
|
+
},
|
|
868
973
|
files: [
|
|
869
974
|
"dist/**/*",
|
|
870
975
|
"package.json",
|
|
871
976
|
"README.md"
|
|
872
977
|
],
|
|
978
|
+
type: "module",
|
|
979
|
+
main: "dist/index.js",
|
|
980
|
+
types: "dist/index.d.ts",
|
|
873
981
|
exports: {
|
|
874
982
|
".": {
|
|
875
983
|
types: "./dist/index.d.ts",
|
|
@@ -884,33 +992,18 @@ var require_package = __commonJS((exports, module) => {
|
|
|
884
992
|
watch: "bun run build:types && bun build ./src/index.ts --outdir ./dist --target node --format esm --sourcemap --watch",
|
|
885
993
|
clean: "rm -rf dist",
|
|
886
994
|
prepublishOnly: "bun run clean && bun run build",
|
|
887
|
-
test: "
|
|
888
|
-
"test:watch": "
|
|
889
|
-
"test:
|
|
890
|
-
"
|
|
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"
|
|
995
|
+
test: "bun test",
|
|
996
|
+
"test:watch": "bun test --watch",
|
|
997
|
+
"test:coverage": "bun test",
|
|
998
|
+
"check:type": "tsc --noEmit"
|
|
906
999
|
},
|
|
907
1000
|
dependencies: {
|
|
908
|
-
"@botpress/chat": "
|
|
909
|
-
"@botpress/cli": "
|
|
910
|
-
"@botpress/client": "1.
|
|
911
|
-
"@botpress/cognitive": "0.
|
|
912
|
-
"@botpress/runtime": "^1.
|
|
913
|
-
"@botpress/sdk": "
|
|
1001
|
+
"@botpress/chat": "0.5.5",
|
|
1002
|
+
"@botpress/cli": "6.2.2",
|
|
1003
|
+
"@botpress/client": "1.38.1",
|
|
1004
|
+
"@botpress/cognitive": "0.4.2",
|
|
1005
|
+
"@botpress/runtime": "^1.18.0-beta.1",
|
|
1006
|
+
"@botpress/sdk": "6.3.1",
|
|
914
1007
|
"@bpinternal/jex": "^1.2.4",
|
|
915
1008
|
"@bpinternal/yargs-extra": "^0.0.21",
|
|
916
1009
|
"@parcel/watcher": "^2.5.1",
|
|
@@ -923,19 +1016,12 @@ var require_package = __commonJS((exports, module) => {
|
|
|
923
1016
|
semver: "^7.7.2",
|
|
924
1017
|
"ts-morph": "^27.0.2"
|
|
925
1018
|
},
|
|
926
|
-
devDependencies: {
|
|
927
|
-
"@types/debug": "^4.1.12",
|
|
928
|
-
"@types/glob": "^9.0.0",
|
|
929
|
-
"@types/luxon": "^3.7.1",
|
|
930
|
-
"@types/semver": "^7.7.1",
|
|
931
|
-
dotenv: "^17.2.3"
|
|
932
|
-
},
|
|
933
1019
|
peerDependencies: {
|
|
934
1020
|
typescript: ">=4.5.0"
|
|
935
1021
|
},
|
|
936
1022
|
engines: {
|
|
937
|
-
|
|
938
|
-
|
|
1023
|
+
bun: ">=1.3.9",
|
|
1024
|
+
node: ">=22.0.0"
|
|
939
1025
|
},
|
|
940
1026
|
packageManager: "bun@1.3.9"
|
|
941
1027
|
};
|
|
@@ -1104,6 +1190,9 @@ class Auth {
|
|
|
1104
1190
|
async setCurrentProfile(profileName) {
|
|
1105
1191
|
return this.credentialsManager.setCurrentProfile(profileName);
|
|
1106
1192
|
}
|
|
1193
|
+
setProfileOverride(profile) {
|
|
1194
|
+
this.credentialsManager.setProfileOverride(profile);
|
|
1195
|
+
}
|
|
1107
1196
|
async getActiveCredentials() {
|
|
1108
1197
|
return this.credentialsManager.getActiveCredentials();
|
|
1109
1198
|
}
|
|
@@ -1153,7 +1242,7 @@ import os3 from "os";
|
|
|
1153
1242
|
import path4 from "path";
|
|
1154
1243
|
import createDebug from "debug";
|
|
1155
1244
|
var debug = createDebug("adk:bp-cli");
|
|
1156
|
-
var BP_CLI_VERSION = "
|
|
1245
|
+
var BP_CLI_VERSION = "6.2.2";
|
|
1157
1246
|
var BP_CLI_INSTALL_ALL = path4.join(os3.homedir(), ".adk", `bp-cli`);
|
|
1158
1247
|
var BP_CLI_INSTALL_DIR = path4.join(BP_CLI_INSTALL_ALL, BP_CLI_VERSION);
|
|
1159
1248
|
var BP_CLI_BIN_PATH = path4.join(BP_CLI_INSTALL_DIR, "node_modules", "@botpress", "cli", "bin.js");
|
|
@@ -1648,9 +1737,9 @@ class BpDevCommand extends BaseCommand {
|
|
|
1648
1737
|
if (sourceMap) {
|
|
1649
1738
|
bpArgs.push("--sourceMap");
|
|
1650
1739
|
}
|
|
1651
|
-
const
|
|
1740
|
+
const spanIngestUrl = `http://localhost:${this.options.spanIngestPort}`;
|
|
1652
1741
|
const otlpEndpoint = this.options.otlpPort ? `http://localhost:${this.options.otlpPort}` : undefined;
|
|
1653
|
-
const traceLines = [`[bp-dev] Trace endpoints:`, `
|
|
1742
|
+
const traceLines = [`[bp-dev] Trace endpoints:`, ` ADK_SPAN_INGEST_URL=${spanIngestUrl}`];
|
|
1654
1743
|
if (otlpEndpoint) {
|
|
1655
1744
|
traceLines.push(` OTEL_EXPORTER_OTLP_ENDPOINT=${otlpEndpoint}`);
|
|
1656
1745
|
}
|
|
@@ -1673,7 +1762,7 @@ class BpDevCommand extends BaseCommand {
|
|
|
1673
1762
|
},
|
|
1674
1763
|
WORKER_MODE: "true",
|
|
1675
1764
|
WORKER_LIFETIME_MS: process.env.WORKER_LIFETIME_MS || "120000",
|
|
1676
|
-
|
|
1765
|
+
ADK_SPAN_INGEST_URL: spanIngestUrl,
|
|
1677
1766
|
...otlpEndpoint && { OTEL_EXPORTER_OTLP_ENDPOINT: otlpEndpoint },
|
|
1678
1767
|
...this.options.botName && { ADK_BOT_NAME: this.options.botName },
|
|
1679
1768
|
ADK_DIRECTORY: join2(botPath, ".."),
|
|
@@ -1902,10 +1991,11 @@ class BpChatCommand extends BaseCommand {
|
|
|
1902
1991
|
try {
|
|
1903
1992
|
await this.childProcess;
|
|
1904
1993
|
} catch (error) {
|
|
1994
|
+
const errObj = error != null && typeof error === "object" ? error : {};
|
|
1905
1995
|
this.emit("error", {
|
|
1906
|
-
exitCode:
|
|
1907
|
-
stderr:
|
|
1908
|
-
message: error.message || "Chat command failed"
|
|
1996
|
+
exitCode: "exitCode" in errObj ? errObj.exitCode || 1 : 1,
|
|
1997
|
+
stderr: "stderr" in errObj ? errObj.stderr || "" : "",
|
|
1998
|
+
message: error instanceof Error ? error.message || "Chat command failed" : "Chat command failed"
|
|
1909
1999
|
});
|
|
1910
2000
|
throw error;
|
|
1911
2001
|
}
|
|
@@ -1986,8 +2076,8 @@ You also have access to Botpress documentation search for platform-level questio
|
|
|
1986
2076
|
**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
2077
|
function buildOpenCodeConfig(options) {
|
|
1988
2078
|
const command = [options.adkBinPath, "mcp", "--cwd", options.agentPath];
|
|
1989
|
-
if (options.
|
|
1990
|
-
command.push("--port", String(options.
|
|
2079
|
+
if (options.uiServerPort)
|
|
2080
|
+
command.push("--port", String(options.uiServerPort));
|
|
1991
2081
|
return {
|
|
1992
2082
|
...options.openCodePort && {
|
|
1993
2083
|
server: {
|
|
@@ -2060,7 +2150,7 @@ class OpenCodeCommand extends BaseCommand {
|
|
|
2060
2150
|
const opencodeConfig = JSON.stringify(buildOpenCodeConfig({
|
|
2061
2151
|
adkBinPath: adkBin,
|
|
2062
2152
|
agentPath: cwd,
|
|
2063
|
-
|
|
2153
|
+
uiServerPort: this.options.uiServerPort,
|
|
2064
2154
|
openCodePort: port,
|
|
2065
2155
|
corsOrigins
|
|
2066
2156
|
}));
|
|
@@ -2122,7 +2212,13 @@ class OpenCodeCommand extends BaseCommand {
|
|
|
2122
2212
|
} catch {}
|
|
2123
2213
|
await new Promise((r) => setTimeout(r, 500));
|
|
2124
2214
|
}
|
|
2125
|
-
this.
|
|
2215
|
+
if (!this.readyEmitted && !this.killed) {
|
|
2216
|
+
this.emit("progress", {
|
|
2217
|
+
type: "error",
|
|
2218
|
+
startTime: Date.now(),
|
|
2219
|
+
data: { reason: "OpenCode server did not respond in time" }
|
|
2220
|
+
});
|
|
2221
|
+
}
|
|
2126
2222
|
}
|
|
2127
2223
|
kill(signal = "SIGTERM") {
|
|
2128
2224
|
this.killed = true;
|
|
@@ -2207,7 +2303,8 @@ function getChatClient(cwd = process.cwd()) {
|
|
|
2207
2303
|
return Client4;
|
|
2208
2304
|
}
|
|
2209
2305
|
// src/utils/json-ordering.ts
|
|
2210
|
-
var agentInfoKeyOrder = ["botId", "workspaceId", "apiUrl"
|
|
2306
|
+
var agentInfoKeyOrder = ["botId", "workspaceId", "apiUrl"];
|
|
2307
|
+
var agentLocalInfoKeyOrder = ["botId", "workspaceId", "apiUrl", "devId"];
|
|
2211
2308
|
var dependenciesKeyOrder = ["integrations"];
|
|
2212
2309
|
var integrationKeyOrder = ["version", "enabled", "configurationType", "config"];
|
|
2213
2310
|
function orderKeys(obj, keyOrder) {
|
|
@@ -2258,6 +2355,7 @@ function stringifyWithOrder(obj, keyOrder, space = 2) {
|
|
|
2258
2355
|
}
|
|
2259
2356
|
// src/agent-project/agent-project.ts
|
|
2260
2357
|
import { BuiltInActions, BuiltInWorkflows, Errors as Errors2, Primitives as Primitives2, setAdkCommand } from "@botpress/runtime/internal";
|
|
2358
|
+
import { Autonomous } from "@botpress/runtime";
|
|
2261
2359
|
import createDebug2 from "debug";
|
|
2262
2360
|
import { createRequire as createRequire3 } from "module";
|
|
2263
2361
|
import fs10 from "fs/promises";
|
|
@@ -2292,7 +2390,7 @@ class AssetsCacheManager {
|
|
|
2292
2390
|
const content = await fs4.readFile(this.cachePath, "utf-8");
|
|
2293
2391
|
this.cache = JSON.parse(content);
|
|
2294
2392
|
return this.cache;
|
|
2295
|
-
} catch
|
|
2393
|
+
} catch {
|
|
2296
2394
|
this.cache = {
|
|
2297
2395
|
version: "1.0",
|
|
2298
2396
|
entries: {}
|
|
@@ -2825,7 +2923,7 @@ class EnhancedIntegrationCache {
|
|
|
2825
2923
|
|
|
2826
2924
|
// src/agent-project/dependencies-parser.ts
|
|
2827
2925
|
init_validation_errors();
|
|
2828
|
-
import { z as z2
|
|
2926
|
+
import { z as z2 } from "@botpress/sdk";
|
|
2829
2927
|
var INTEGRATION_ALIAS_MIN_LENGTH = 2;
|
|
2830
2928
|
var INTEGRATION_ALIAS_MAX_LENGTH = 100;
|
|
2831
2929
|
var INTEGRATION_ALIAS_REGEX = /^(?:[a-z][a-z0-9_-]*\/)?[a-z][a-z0-9_-]*$/;
|
|
@@ -2836,10 +2934,10 @@ var integrationRefSchema = z2.string().transform((val, ctx) => {
|
|
|
2836
2934
|
const match = val.match(/^(?:([^/]+)\/)?([^@]+)@(.+)$/);
|
|
2837
2935
|
if (!match) {
|
|
2838
2936
|
ctx.addIssue({
|
|
2839
|
-
code:
|
|
2937
|
+
code: "custom",
|
|
2840
2938
|
message: `Invalid integration version format: ${val}. Expected format: 'name@version' or 'workspace/name@version'`
|
|
2841
2939
|
});
|
|
2842
|
-
return
|
|
2940
|
+
return;
|
|
2843
2941
|
}
|
|
2844
2942
|
const [, workspace, name, version] = match;
|
|
2845
2943
|
return {
|
|
@@ -2876,7 +2974,8 @@ class IntegrationParser {
|
|
|
2876
2974
|
errors.push(ValidationErrors.invalidIntegrationAlias(alias));
|
|
2877
2975
|
continue;
|
|
2878
2976
|
}
|
|
2879
|
-
const
|
|
2977
|
+
const normalized = typeof value === "string" ? { version: value } : value;
|
|
2978
|
+
const ref = this.parseIntegrationRef(normalized.version);
|
|
2880
2979
|
const versionResult = versionSchema.safeParse(ref.version);
|
|
2881
2980
|
if (!versionResult.success) {
|
|
2882
2981
|
errors.push(ValidationErrors.invalidVersionFormat(alias, ref.version));
|
|
@@ -2884,9 +2983,9 @@ class IntegrationParser {
|
|
|
2884
2983
|
integrations.push({
|
|
2885
2984
|
alias,
|
|
2886
2985
|
ref,
|
|
2887
|
-
enabled:
|
|
2888
|
-
configurationType:
|
|
2889
|
-
config:
|
|
2986
|
+
enabled: "enabled" in normalized ? normalized.enabled : undefined,
|
|
2987
|
+
configurationType: "configurationType" in normalized ? normalized.configurationType : undefined,
|
|
2988
|
+
config: "config" in normalized ? normalized.config : undefined
|
|
2890
2989
|
});
|
|
2891
2990
|
} catch (error) {
|
|
2892
2991
|
errors.push(ValidationErrors.invalidDependenciesSyntax(`Invalid integration '${alias}': ${error instanceof Error ? error.message : String(error)}`));
|
|
@@ -2938,10 +3037,10 @@ var pluginRefSchema = z2.string().transform((val, ctx) => {
|
|
|
2938
3037
|
const match = val.match(/^([^/@]+)@(.+)$/);
|
|
2939
3038
|
if (!match) {
|
|
2940
3039
|
ctx.addIssue({
|
|
2941
|
-
code:
|
|
3040
|
+
code: "custom",
|
|
2942
3041
|
message: `Invalid plugin version format: ${val}. Expected format: 'name@version' (no workspace prefix)`
|
|
2943
3042
|
});
|
|
2944
|
-
return
|
|
3043
|
+
return;
|
|
2945
3044
|
}
|
|
2946
3045
|
const [, name, version] = match;
|
|
2947
3046
|
return {
|
|
@@ -2998,7 +3097,7 @@ class PluginParser {
|
|
|
2998
3097
|
if (!pluginConfig.dependencies) {
|
|
2999
3098
|
continue;
|
|
3000
3099
|
}
|
|
3001
|
-
for (const [
|
|
3100
|
+
for (const [_depAlias, depMapping] of Object.entries(pluginConfig.dependencies)) {
|
|
3002
3101
|
if (!integrationAliases.includes(depMapping.integrationAlias)) {
|
|
3003
3102
|
errors.push(ValidationErrors.invalidPluginDependency(alias, depMapping.integrationAlias, integrationAliases));
|
|
3004
3103
|
}
|
|
@@ -3203,7 +3302,7 @@ class IntegrationManager {
|
|
|
3203
3302
|
return { valid: false, errors, warnings };
|
|
3204
3303
|
}
|
|
3205
3304
|
const hasChannels = integration.definition.channels && Object.keys(integration.definition.channels).length > 0;
|
|
3206
|
-
if (!integration.config) {
|
|
3305
|
+
if (!integration.config && integration.enabled !== undefined) {
|
|
3207
3306
|
let requiresConfig = false;
|
|
3208
3307
|
if (integration.definition.configurations) {
|
|
3209
3308
|
requiresConfig = Object.values(integration.definition.configurations).some((config) => config.identifier?.required === true);
|
|
@@ -3269,7 +3368,7 @@ class IntegrationCache {
|
|
|
3269
3368
|
}
|
|
3270
3369
|
}
|
|
3271
3370
|
return cached.definition;
|
|
3272
|
-
} catch
|
|
3371
|
+
} catch {
|
|
3273
3372
|
return null;
|
|
3274
3373
|
}
|
|
3275
3374
|
}
|
|
@@ -3473,6 +3572,7 @@ class HubCache {
|
|
|
3473
3572
|
// src/agent-project/config-writer.ts
|
|
3474
3573
|
init_utils();
|
|
3475
3574
|
import { Project, SyntaxKind } from "ts-morph";
|
|
3575
|
+
import { readFileSync } from "fs";
|
|
3476
3576
|
import * as path11 from "path";
|
|
3477
3577
|
|
|
3478
3578
|
class ConfigWriter {
|
|
@@ -3482,7 +3582,9 @@ class ConfigWriter {
|
|
|
3482
3582
|
}
|
|
3483
3583
|
loadConfig() {
|
|
3484
3584
|
const project = new Project;
|
|
3485
|
-
const sourceFile = project.
|
|
3585
|
+
const sourceFile = project.createSourceFile(this.configPath, readFileSync(this.configPath, "utf-8"), {
|
|
3586
|
+
overwrite: true
|
|
3587
|
+
});
|
|
3486
3588
|
const defineConfigCall = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression).find((call) => {
|
|
3487
3589
|
return call.getExpression().getText() === "defineConfig";
|
|
3488
3590
|
});
|
|
@@ -3502,6 +3604,47 @@ class ConfigWriter {
|
|
|
3502
3604
|
sourceFile.replaceWithText(formatted);
|
|
3503
3605
|
await sourceFile.save();
|
|
3504
3606
|
}
|
|
3607
|
+
serializeDefaultModelSelection(value) {
|
|
3608
|
+
if (Array.isArray(value)) {
|
|
3609
|
+
return `[${value.map((entry) => `'${entry.replace(/'/g, "\\'")}'`).join(", ")}]`;
|
|
3610
|
+
}
|
|
3611
|
+
return `'${value.replace(/'/g, "\\'")}'`;
|
|
3612
|
+
}
|
|
3613
|
+
getIntegrationConfigMigrationCandidates() {
|
|
3614
|
+
const { sourceFile, configObject } = this.loadConfig();
|
|
3615
|
+
const dependenciesProp = configObject.getProperty("dependencies");
|
|
3616
|
+
if (!dependenciesProp) {
|
|
3617
|
+
return { sourceFile, candidates: [] };
|
|
3618
|
+
}
|
|
3619
|
+
const depsInit = dependenciesProp.getInitializerIfKind(SyntaxKind.ObjectLiteralExpression);
|
|
3620
|
+
if (!depsInit) {
|
|
3621
|
+
return { sourceFile, candidates: [] };
|
|
3622
|
+
}
|
|
3623
|
+
const integrationsProp = depsInit.getProperty("integrations");
|
|
3624
|
+
if (!integrationsProp) {
|
|
3625
|
+
return { sourceFile, candidates: [] };
|
|
3626
|
+
}
|
|
3627
|
+
const integrationsInit = integrationsProp.getInitializerIfKind(SyntaxKind.ObjectLiteralExpression);
|
|
3628
|
+
if (!integrationsInit) {
|
|
3629
|
+
return { sourceFile, candidates: [] };
|
|
3630
|
+
}
|
|
3631
|
+
const candidates = integrationsInit.getProperties().flatMap((prop) => {
|
|
3632
|
+
if (!prop.isKind(SyntaxKind.PropertyAssignment)) {
|
|
3633
|
+
return [];
|
|
3634
|
+
}
|
|
3635
|
+
const assignment = prop;
|
|
3636
|
+
const initializer = assignment.getInitializerIfKind(SyntaxKind.ObjectLiteralExpression);
|
|
3637
|
+
if (!initializer) {
|
|
3638
|
+
return [];
|
|
3639
|
+
}
|
|
3640
|
+
const hasConfigProperty = initializer.getProperty("config") !== undefined;
|
|
3641
|
+
const versionProp = initializer.getProperty("version");
|
|
3642
|
+
const versionInitializer = versionProp?.getInitializer();
|
|
3643
|
+
const versionInitializerText = versionInitializer && (versionInitializer.isKind(SyntaxKind.StringLiteral) || versionInitializer.isKind(SyntaxKind.NoSubstitutionTemplateLiteral)) ? versionInitializer.getText() : undefined;
|
|
3644
|
+
return [{ alias: assignment.getName(), assignment, hasConfigProperty, versionInitializerText }];
|
|
3645
|
+
});
|
|
3646
|
+
return { sourceFile, candidates };
|
|
3647
|
+
}
|
|
3505
3648
|
async updateDependencies(dependencies) {
|
|
3506
3649
|
const { sourceFile, configObject } = this.loadConfig();
|
|
3507
3650
|
let dependenciesProperty = configObject.getProperty("dependencies");
|
|
@@ -3523,6 +3666,67 @@ class ConfigWriter {
|
|
|
3523
3666
|
}
|
|
3524
3667
|
await this.saveConfig(sourceFile);
|
|
3525
3668
|
}
|
|
3669
|
+
async updateDefaultModels(updates) {
|
|
3670
|
+
const requestedEntries = Object.entries(updates).filter(([, value]) => value !== undefined);
|
|
3671
|
+
if (requestedEntries.length === 0) {
|
|
3672
|
+
return;
|
|
3673
|
+
}
|
|
3674
|
+
const { sourceFile, configObject } = this.loadConfig();
|
|
3675
|
+
let defaultModelsProperty = configObject.getProperty("defaultModels");
|
|
3676
|
+
if (!defaultModelsProperty) {
|
|
3677
|
+
defaultModelsProperty = configObject.addPropertyAssignment({
|
|
3678
|
+
name: "defaultModels",
|
|
3679
|
+
initializer: "{}"
|
|
3680
|
+
});
|
|
3681
|
+
}
|
|
3682
|
+
const defaultModelsObject = defaultModelsProperty.getInitializerIfKind(SyntaxKind.ObjectLiteralExpression);
|
|
3683
|
+
if (!defaultModelsObject) {
|
|
3684
|
+
throw new Error("defaultModels must be an object literal in agent.config.ts");
|
|
3685
|
+
}
|
|
3686
|
+
for (const [key, value] of requestedEntries) {
|
|
3687
|
+
const existingProperty = defaultModelsObject.getProperty(key);
|
|
3688
|
+
const initializer = this.serializeDefaultModelSelection(value);
|
|
3689
|
+
if (existingProperty) {
|
|
3690
|
+
existingProperty.setInitializer(initializer);
|
|
3691
|
+
} else {
|
|
3692
|
+
defaultModelsObject.addPropertyAssignment({
|
|
3693
|
+
name: key,
|
|
3694
|
+
initializer
|
|
3695
|
+
});
|
|
3696
|
+
}
|
|
3697
|
+
}
|
|
3698
|
+
await this.saveConfig(sourceFile);
|
|
3699
|
+
}
|
|
3700
|
+
async migrateIntegrationsToStringFormat() {
|
|
3701
|
+
const { sourceFile, candidates } = this.getIntegrationConfigMigrationCandidates();
|
|
3702
|
+
const migrated = [];
|
|
3703
|
+
for (const candidate of candidates) {
|
|
3704
|
+
if (!candidate.versionInitializerText || candidate.hasConfigProperty) {
|
|
3705
|
+
continue;
|
|
3706
|
+
}
|
|
3707
|
+
candidate.assignment.setInitializer(candidate.versionInitializerText);
|
|
3708
|
+
migrated.push(candidate.alias);
|
|
3709
|
+
}
|
|
3710
|
+
if (migrated.length > 0) {
|
|
3711
|
+
await this.saveConfig(sourceFile);
|
|
3712
|
+
}
|
|
3713
|
+
return migrated;
|
|
3714
|
+
}
|
|
3715
|
+
getIntegrationConfigMigrationState() {
|
|
3716
|
+
try {
|
|
3717
|
+
const { candidates } = this.getIntegrationConfigMigrationCandidates();
|
|
3718
|
+
const deprecatedAliases = candidates.map((candidate) => candidate.alias);
|
|
3719
|
+
const migratableAliases = candidates.filter((candidate) => candidate.versionInitializerText && !candidate.hasConfigProperty).map((candidate) => candidate.alias);
|
|
3720
|
+
return { deprecatedAliases, migratableAliases };
|
|
3721
|
+
} catch (error) {
|
|
3722
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3723
|
+
console.error(`Configuration update failed with error: ${message} — please verify that there are no syntax errors in your agent.config.ts`);
|
|
3724
|
+
return { deprecatedAliases: [], migratableAliases: [] };
|
|
3725
|
+
}
|
|
3726
|
+
}
|
|
3727
|
+
getObjectFormatIntegrations() {
|
|
3728
|
+
return this.getIntegrationConfigMigrationState().deprecatedAliases;
|
|
3729
|
+
}
|
|
3526
3730
|
async updateConfiguration(updates) {
|
|
3527
3731
|
const { sourceFile, configObject } = this.loadConfig();
|
|
3528
3732
|
const hasAdds = updates.some((u) => u.action === "add");
|
|
@@ -3634,6 +3838,66 @@ class IntegrationOperations {
|
|
|
3634
3838
|
}
|
|
3635
3839
|
return { name, version, fullName: name };
|
|
3636
3840
|
}
|
|
3841
|
+
isIntegrationVersionId(input) {
|
|
3842
|
+
return input.startsWith("intver_");
|
|
3843
|
+
}
|
|
3844
|
+
isResourceNotFoundError(error) {
|
|
3845
|
+
return Boolean(error && typeof error === "object" && "type" in error && error.type === "ResourceNotFound");
|
|
3846
|
+
}
|
|
3847
|
+
getCanonicalIntegrationFullName(integration) {
|
|
3848
|
+
if (integration.public) {
|
|
3849
|
+
return integration.name;
|
|
3850
|
+
}
|
|
3851
|
+
const workspaceHandle = integration.ownerWorkspace?.handle;
|
|
3852
|
+
return workspaceHandle ? `${workspaceHandle}/${integration.name}` : integration.name;
|
|
3853
|
+
}
|
|
3854
|
+
async resolveIntegrationVersionId(id) {
|
|
3855
|
+
const client = await this.getClient();
|
|
3856
|
+
try {
|
|
3857
|
+
const response = await client.getIntegration({ id });
|
|
3858
|
+
return response.integration;
|
|
3859
|
+
} catch (error) {
|
|
3860
|
+
if (!this.isResourceNotFoundError(error)) {
|
|
3861
|
+
throw error;
|
|
3862
|
+
}
|
|
3863
|
+
}
|
|
3864
|
+
try {
|
|
3865
|
+
const response = await client.getPublicIntegrationById({ id });
|
|
3866
|
+
return response.integration;
|
|
3867
|
+
} catch (error) {
|
|
3868
|
+
if (this.isResourceNotFoundError(error)) {
|
|
3869
|
+
throw new Error(`Integration "${id}" not found`);
|
|
3870
|
+
}
|
|
3871
|
+
throw error;
|
|
3872
|
+
}
|
|
3873
|
+
}
|
|
3874
|
+
async resolveAddIntegrationInput(options) {
|
|
3875
|
+
const requestedVersion = options.version || "latest";
|
|
3876
|
+
if (!this.isIntegrationVersionId(options.name)) {
|
|
3877
|
+
const ref = this.parseIntegrationRef(`${options.name}@${requestedVersion}`);
|
|
3878
|
+
return {
|
|
3879
|
+
name: ref.name,
|
|
3880
|
+
fullName: ref.fullName,
|
|
3881
|
+
version: ref.version,
|
|
3882
|
+
alias: options.alias || ref.name,
|
|
3883
|
+
ref: `${ref.fullName}@${ref.version}`,
|
|
3884
|
+
isIntegrationId: false
|
|
3885
|
+
};
|
|
3886
|
+
}
|
|
3887
|
+
if (options.version && options.version !== "latest") {
|
|
3888
|
+
throw new Error("Integration version IDs are already version-pinned and do not accept an additional @version override");
|
|
3889
|
+
}
|
|
3890
|
+
const integration = await this.resolveIntegrationVersionId(options.name);
|
|
3891
|
+
const fullName = this.getCanonicalIntegrationFullName(integration);
|
|
3892
|
+
return {
|
|
3893
|
+
name: integration.name,
|
|
3894
|
+
fullName,
|
|
3895
|
+
version: integration.version,
|
|
3896
|
+
alias: options.alias || integration.name,
|
|
3897
|
+
ref: `${fullName}@${integration.version}`,
|
|
3898
|
+
isIntegrationId: true
|
|
3899
|
+
};
|
|
3900
|
+
}
|
|
3637
3901
|
async getIntegrationVersions(name) {
|
|
3638
3902
|
const client = await this.getClient();
|
|
3639
3903
|
const ref = this.parseIntegrationRef(name);
|
|
@@ -3667,9 +3931,8 @@ class IntegrationOperations {
|
|
|
3667
3931
|
}
|
|
3668
3932
|
async addIntegration(options) {
|
|
3669
3933
|
const project = await AgentProject.load(this.projectPath || process2.cwd());
|
|
3670
|
-
const
|
|
3671
|
-
const
|
|
3672
|
-
const alias = options.alias || ref.name;
|
|
3934
|
+
const resolvedInput = await this.resolveAddIntegrationInput(options);
|
|
3935
|
+
const { alias } = resolvedInput;
|
|
3673
3936
|
const dependencies = project.dependencies || { integrations: {} };
|
|
3674
3937
|
if (!dependencies.integrations) {
|
|
3675
3938
|
dependencies.integrations = {};
|
|
@@ -3686,11 +3949,17 @@ class IntegrationOperations {
|
|
|
3686
3949
|
} else {
|
|
3687
3950
|
existingVersion = "unknown";
|
|
3688
3951
|
}
|
|
3689
|
-
|
|
3952
|
+
const effectiveVersionSpecified = Boolean(options.version) || resolvedInput.isIntegrationId;
|
|
3953
|
+
if (!effectiveVersionSpecified || resolvedInput.version === "latest" || resolvedInput.version === existingVersion) {
|
|
3690
3954
|
return {
|
|
3691
3955
|
success: false,
|
|
3692
3956
|
message: `Integration '${alias}' already exists with version ${existingVersion}. Use 'adk upgrade ${alias}' to upgrade to the latest version.`,
|
|
3693
|
-
existingVersion
|
|
3957
|
+
existingVersion,
|
|
3958
|
+
name: resolvedInput.name,
|
|
3959
|
+
fullName: resolvedInput.fullName,
|
|
3960
|
+
alias: resolvedInput.alias,
|
|
3961
|
+
version: existingVersion,
|
|
3962
|
+
ref: `${resolvedInput.fullName}@${existingVersion}`
|
|
3694
3963
|
};
|
|
3695
3964
|
}
|
|
3696
3965
|
}
|
|
@@ -3702,7 +3971,7 @@ class IntegrationOperations {
|
|
|
3702
3971
|
const loadResult = await tempManager.loadIntegrations({
|
|
3703
3972
|
integrations: {
|
|
3704
3973
|
[alias]: {
|
|
3705
|
-
version:
|
|
3974
|
+
version: resolvedInput.ref,
|
|
3706
3975
|
enabled: true
|
|
3707
3976
|
}
|
|
3708
3977
|
}
|
|
@@ -3720,88 +3989,28 @@ class IntegrationOperations {
|
|
|
3720
3989
|
throw new Error(`Failed to add integration: ${error instanceof Error ? error.message : String(error)}`);
|
|
3721
3990
|
}
|
|
3722
3991
|
const actualVersion = integrationDefinition.version;
|
|
3723
|
-
const integrationVersion = `${
|
|
3992
|
+
const integrationVersion = `${resolvedInput.fullName}@${actualVersion}`;
|
|
3724
3993
|
const existingEntry = dependencies.integrations[alias];
|
|
3725
|
-
const existingConfig = existingEntry && typeof existingEntry === "object" ? existingEntry.config : undefined;
|
|
3726
|
-
const existingConfigurationType = existingEntry && typeof existingEntry === "object" ? existingEntry.configurationType : undefined;
|
|
3727
|
-
const configurationType = existingConfigurationType || this.selectBestConfigurationType(integrationDefinition.configurations);
|
|
3728
|
-
let requiresConfiguration = false;
|
|
3729
|
-
const selectedConfigDef = configurationType && integrationDefinition.configurations?.[configurationType] || integrationDefinition.configurations?.["default"] || integrationDefinition.configuration;
|
|
3730
|
-
if (selectedConfigDef) {
|
|
3731
|
-
if (selectedConfigDef.identifier?.required === true) {
|
|
3732
|
-
requiresConfiguration = true;
|
|
3733
|
-
}
|
|
3734
|
-
if (selectedConfigDef.schema?.required && selectedConfigDef.schema.required.length > 0) {
|
|
3735
|
-
requiresConfiguration = true;
|
|
3736
|
-
}
|
|
3737
|
-
}
|
|
3738
|
-
const config = requiresConfiguration && !existingConfig ? this.getPlaceholderConfig(integrationDefinition, configurationType) : existingConfig;
|
|
3739
3994
|
if (existingEntry && typeof existingEntry === "object" && "version" in existingEntry) {
|
|
3740
|
-
const resolvedConfigType = existingEntry.configurationType || configurationType;
|
|
3741
3995
|
dependencies.integrations[alias] = {
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
...resolvedConfigType ? { configurationType: resolvedConfigType } : {},
|
|
3745
|
-
config: existingEntry.config
|
|
3996
|
+
...existingEntry,
|
|
3997
|
+
version: integrationVersion
|
|
3746
3998
|
};
|
|
3747
3999
|
} else {
|
|
3748
|
-
dependencies.integrations[alias] =
|
|
3749
|
-
version: integrationVersion,
|
|
3750
|
-
enabled: !requiresConfiguration,
|
|
3751
|
-
...configurationType ? { configurationType } : {},
|
|
3752
|
-
config
|
|
3753
|
-
};
|
|
4000
|
+
dependencies.integrations[alias] = integrationVersion;
|
|
3754
4001
|
}
|
|
3755
4002
|
const configWriter = new ConfigWriter(project.path);
|
|
3756
4003
|
await configWriter.updateDependencies(dependencies);
|
|
3757
4004
|
return {
|
|
3758
4005
|
success: true,
|
|
3759
|
-
|
|
3760
|
-
|
|
4006
|
+
newVersion: actualVersion,
|
|
4007
|
+
name: resolvedInput.name,
|
|
4008
|
+
fullName: resolvedInput.fullName,
|
|
4009
|
+
alias: resolvedInput.alias,
|
|
4010
|
+
version: actualVersion,
|
|
4011
|
+
ref: integrationVersion
|
|
3761
4012
|
};
|
|
3762
4013
|
}
|
|
3763
|
-
selectBestConfigurationType(configurations) {
|
|
3764
|
-
if (!configurations || Object.keys(configurations).length === 0) {
|
|
3765
|
-
return;
|
|
3766
|
-
}
|
|
3767
|
-
const keys = Object.keys(configurations);
|
|
3768
|
-
if (keys.length === 1) {
|
|
3769
|
-
return keys[0];
|
|
3770
|
-
}
|
|
3771
|
-
const priority = ["apiKey", "api", "api_key", "token", "default", "refreshToken", "oauth", "oauth2"];
|
|
3772
|
-
for (const preferred of priority) {
|
|
3773
|
-
const match = keys.find((k) => k.toLowerCase() === preferred.toLowerCase());
|
|
3774
|
-
if (match)
|
|
3775
|
-
return match;
|
|
3776
|
-
}
|
|
3777
|
-
return keys[0];
|
|
3778
|
-
}
|
|
3779
|
-
getPlaceholderConfig(integrationDefinition, configurationType) {
|
|
3780
|
-
const configPlaceholder = {};
|
|
3781
|
-
const configDef = configurationType && integrationDefinition.configurations?.[configurationType] || integrationDefinition.configurations?.["default"] || integrationDefinition.configuration;
|
|
3782
|
-
if (configDef) {
|
|
3783
|
-
const schema = configDef.schema;
|
|
3784
|
-
if (schema?.required && schema.required.length > 0) {
|
|
3785
|
-
const properties = schema.properties || {};
|
|
3786
|
-
for (const fieldName of schema.required) {
|
|
3787
|
-
const fieldDef = properties[fieldName];
|
|
3788
|
-
if (fieldDef?.type === "string") {
|
|
3789
|
-
configPlaceholder[fieldName] = `YOUR_${fieldName.toUpperCase()}_HERE`;
|
|
3790
|
-
} else if (fieldDef?.type === "number" || fieldDef?.type === "integer") {
|
|
3791
|
-
configPlaceholder[fieldName] = 0;
|
|
3792
|
-
} else if (fieldDef?.type === "boolean") {
|
|
3793
|
-
configPlaceholder[fieldName] = false;
|
|
3794
|
-
} else {
|
|
3795
|
-
configPlaceholder[fieldName] = null;
|
|
3796
|
-
}
|
|
3797
|
-
}
|
|
3798
|
-
if (Object.keys(configPlaceholder).length > 0) {
|
|
3799
|
-
return configPlaceholder;
|
|
3800
|
-
}
|
|
3801
|
-
}
|
|
3802
|
-
}
|
|
3803
|
-
return;
|
|
3804
|
-
}
|
|
3805
4014
|
async removeIntegration(name) {
|
|
3806
4015
|
const project = await AgentProject.load(this.projectPath || process2.cwd());
|
|
3807
4016
|
const dependencies = project.dependencies;
|
|
@@ -3840,10 +4049,8 @@ class IntegrationOperations {
|
|
|
3840
4049
|
}
|
|
3841
4050
|
const versionInfo = await this.getIntegrationVersions(ref.fullName);
|
|
3842
4051
|
if (versionInfo.latestVersion && versionInfo.latestVersion !== currentVersion) {
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
version: `${ref.fullName}@${versionInfo.latestVersion}`
|
|
3846
|
-
};
|
|
4052
|
+
const newVersion = `${ref.fullName}@${versionInfo.latestVersion}`;
|
|
4053
|
+
dependencies.integrations[alias] = typeof value === "string" ? newVersion : { ...value, version: newVersion };
|
|
3847
4054
|
upgraded.push(`${alias} (${currentVersion} → ${versionInfo.latestVersion})`);
|
|
3848
4055
|
}
|
|
3849
4056
|
} catch {
|
|
@@ -3932,7 +4139,7 @@ async function fetchServerIntegrationConfigs(project, targetBotId) {
|
|
|
3932
4139
|
const { devId, botId } = project.agentInfo ?? {};
|
|
3933
4140
|
const targetId = targetBotId || devId || botId;
|
|
3934
4141
|
if (!targetId) {
|
|
3935
|
-
return { configs: {}, fetched: false, skipped: true };
|
|
4142
|
+
return { configs: {}, enabledStates: {}, fetched: false, skipped: true };
|
|
3936
4143
|
}
|
|
3937
4144
|
try {
|
|
3938
4145
|
const credentials = await auth.getActiveCredentials();
|
|
@@ -3955,18 +4162,26 @@ async function fetchServerIntegrationConfigs(project, targetBotId) {
|
|
|
3955
4162
|
}
|
|
3956
4163
|
} catch (err) {
|
|
3957
4164
|
const message = err instanceof Error ? err.message : String(err);
|
|
3958
|
-
return {
|
|
4165
|
+
return {
|
|
4166
|
+
configs: {},
|
|
4167
|
+
enabledStates: {},
|
|
4168
|
+
fetched: false,
|
|
4169
|
+
skipped: false,
|
|
4170
|
+
error: message
|
|
4171
|
+
};
|
|
3959
4172
|
}
|
|
3960
4173
|
}
|
|
3961
4174
|
async function fetchBotConfigs(client, botId) {
|
|
3962
4175
|
const { bot } = await client.getBot({ id: botId });
|
|
3963
4176
|
const configs = {};
|
|
4177
|
+
const enabledStates = {};
|
|
3964
4178
|
for (const [alias, integration] of Object.entries(bot.integrations || {})) {
|
|
3965
4179
|
if (integration.configuration && Object.keys(integration.configuration).length > 0) {
|
|
3966
4180
|
configs[alias] = integration.configuration;
|
|
3967
4181
|
}
|
|
4182
|
+
enabledStates[alias] = integration.enabled;
|
|
3968
4183
|
}
|
|
3969
|
-
return { configs, fetched: true, skipped: false };
|
|
4184
|
+
return { configs, enabledStates, fetched: true, skipped: false };
|
|
3970
4185
|
}
|
|
3971
4186
|
|
|
3972
4187
|
// src/integrations/checker.ts
|
|
@@ -4080,7 +4295,7 @@ class IntegrationChecker {
|
|
|
4080
4295
|
}
|
|
4081
4296
|
}
|
|
4082
4297
|
}
|
|
4083
|
-
const desiredInstallStatus = enabled === false ? "disabled" : "enabled";
|
|
4298
|
+
const desiredInstallStatus = enabled === true ? "enabled" : enabled === false ? "disabled" : installedIntegration ? installedIntegration.enabled ? "enabled" : "disabled" : "disabled";
|
|
4084
4299
|
const result = {
|
|
4085
4300
|
alias,
|
|
4086
4301
|
name: ref.fullName,
|
|
@@ -4108,7 +4323,7 @@ class IntegrationChecker {
|
|
|
4108
4323
|
}
|
|
4109
4324
|
}
|
|
4110
4325
|
if (!installedIntegration) {
|
|
4111
|
-
result.needsInstall =
|
|
4326
|
+
result.needsInstall = true;
|
|
4112
4327
|
if (result.needsInstall && config) {
|
|
4113
4328
|
result.needsConfiguration = true;
|
|
4114
4329
|
}
|
|
@@ -4128,11 +4343,7 @@ class IntegrationChecker {
|
|
|
4128
4343
|
}
|
|
4129
4344
|
}
|
|
4130
4345
|
if (enabled !== undefined && enabled !== installedIntegration.enabled) {
|
|
4131
|
-
|
|
4132
|
-
result.needsRemoval = true;
|
|
4133
|
-
} else if (enabled === true && result.installStatus === "disabled") {
|
|
4134
|
-
result.needsConfiguration = true;
|
|
4135
|
-
}
|
|
4346
|
+
result.needsUpdate = true;
|
|
4136
4347
|
}
|
|
4137
4348
|
}
|
|
4138
4349
|
return result;
|
|
@@ -4658,7 +4869,7 @@ async function expandExports(options) {
|
|
|
4658
4869
|
});
|
|
4659
4870
|
return {};
|
|
4660
4871
|
}
|
|
4661
|
-
currentError = currentError.cause;
|
|
4872
|
+
currentError = currentError instanceof Error ? currentError.cause : undefined;
|
|
4662
4873
|
}
|
|
4663
4874
|
throw importError;
|
|
4664
4875
|
}
|
|
@@ -4669,6 +4880,21 @@ init_agent_resolver();
|
|
|
4669
4880
|
init_types();
|
|
4670
4881
|
init_validation_errors();
|
|
4671
4882
|
var debug2 = createDebug2("adk:agent-project");
|
|
4883
|
+
function getToolDefinition(value) {
|
|
4884
|
+
if (typeof value !== "object" || value === null) {
|
|
4885
|
+
return;
|
|
4886
|
+
}
|
|
4887
|
+
const maybeTool = value;
|
|
4888
|
+
const isAutonomousToolInstance = value instanceof Autonomous.Tool;
|
|
4889
|
+
const looksLikeAutonomousTool = maybeTool.constructor?.name === Autonomous.Tool.name && typeof maybeTool.name === "string" && typeof maybeTool.execute === "function" && typeof maybeTool.toJSON === "function";
|
|
4890
|
+
if (!isAutonomousToolInstance && !looksLikeAutonomousTool) {
|
|
4891
|
+
return;
|
|
4892
|
+
}
|
|
4893
|
+
return {
|
|
4894
|
+
name: maybeTool.name,
|
|
4895
|
+
description: maybeTool.description
|
|
4896
|
+
};
|
|
4897
|
+
}
|
|
4672
4898
|
|
|
4673
4899
|
class AgentProject {
|
|
4674
4900
|
static _projectCache = new Map;
|
|
@@ -4692,6 +4918,7 @@ class AgentProject {
|
|
|
4692
4918
|
_workflows = [];
|
|
4693
4919
|
_actions = [];
|
|
4694
4920
|
_tables = [];
|
|
4921
|
+
_tools = [];
|
|
4695
4922
|
constructor(projectPath, options = {}) {
|
|
4696
4923
|
this._options = options;
|
|
4697
4924
|
this._path = path13.resolve(projectPath);
|
|
@@ -4748,6 +4975,9 @@ class AgentProject {
|
|
|
4748
4975
|
get tables() {
|
|
4749
4976
|
return this._tables;
|
|
4750
4977
|
}
|
|
4978
|
+
get tools() {
|
|
4979
|
+
return this._tools;
|
|
4980
|
+
}
|
|
4751
4981
|
get config() {
|
|
4752
4982
|
return this._config;
|
|
4753
4983
|
}
|
|
@@ -4786,6 +5016,7 @@ class AgentProject {
|
|
|
4786
5016
|
this._workflows = [];
|
|
4787
5017
|
this._actions = [];
|
|
4788
5018
|
this._tables = [];
|
|
5019
|
+
this._tools = [];
|
|
4789
5020
|
this._errors = [];
|
|
4790
5021
|
this._warnings = [];
|
|
4791
5022
|
const validation = await this.validate();
|
|
@@ -4924,20 +5155,84 @@ class AgentProject {
|
|
|
4924
5155
|
return this._assetsManager;
|
|
4925
5156
|
}
|
|
4926
5157
|
async createAgentInfo(info) {
|
|
5158
|
+
const { devId, ...agentJsonInfo } = info;
|
|
4927
5159
|
const agentPath = path13.join(this._path, "agent.json");
|
|
4928
|
-
const agentContent = stringifyWithOrder(
|
|
5160
|
+
const agentContent = stringifyWithOrder(agentJsonInfo, agentInfoKeyOrder);
|
|
4929
5161
|
await fs10.writeFile(agentPath, agentContent);
|
|
4930
5162
|
this._agentInfo = info;
|
|
5163
|
+
if (devId) {
|
|
5164
|
+
await this.createAgentLocalInfo({ devId });
|
|
5165
|
+
}
|
|
4931
5166
|
}
|
|
4932
5167
|
async updateAgentInfo(updates) {
|
|
4933
5168
|
if (!this._agentInfo) {
|
|
4934
5169
|
throw new Error("No agent.json found. Use createAgentInfo() first.");
|
|
4935
5170
|
}
|
|
4936
|
-
const
|
|
5171
|
+
const { devId, ...agentJsonUpdates } = updates;
|
|
5172
|
+
const updatedInfo = { ...this._agentInfo, ...agentJsonUpdates };
|
|
5173
|
+
const { devId: _devId, ...agentJsonData } = updatedInfo;
|
|
4937
5174
|
const agentPath = path13.join(this._path, "agent.json");
|
|
4938
|
-
const agentContent = stringifyWithOrder(
|
|
5175
|
+
const agentContent = stringifyWithOrder(agentJsonData, agentInfoKeyOrder);
|
|
4939
5176
|
await fs10.writeFile(agentPath, agentContent);
|
|
4940
5177
|
this._agentInfo = updatedInfo;
|
|
5178
|
+
if (devId !== undefined) {
|
|
5179
|
+
await this.updateAgentLocalInfo({ devId });
|
|
5180
|
+
}
|
|
5181
|
+
}
|
|
5182
|
+
async createAgentLocalInfo(info) {
|
|
5183
|
+
const localPath = path13.join(this._path, "agent.local.json");
|
|
5184
|
+
let existing = {};
|
|
5185
|
+
try {
|
|
5186
|
+
const content2 = await fs10.readFile(localPath, "utf-8");
|
|
5187
|
+
existing = JSON.parse(content2);
|
|
5188
|
+
} catch {}
|
|
5189
|
+
const merged = { ...existing, ...info };
|
|
5190
|
+
const content = stringifyWithOrder(merged, agentLocalInfoKeyOrder);
|
|
5191
|
+
await fs10.writeFile(localPath, content);
|
|
5192
|
+
if (this._agentInfo) {
|
|
5193
|
+
if (merged.botId)
|
|
5194
|
+
this._agentInfo.botId = merged.botId;
|
|
5195
|
+
if (merged.workspaceId)
|
|
5196
|
+
this._agentInfo.workspaceId = merged.workspaceId;
|
|
5197
|
+
if (merged.apiUrl)
|
|
5198
|
+
this._agentInfo.apiUrl = merged.apiUrl;
|
|
5199
|
+
if (merged.devId)
|
|
5200
|
+
this._agentInfo.devId = merged.devId;
|
|
5201
|
+
} else if (merged.botId && merged.workspaceId) {
|
|
5202
|
+
this._agentInfo = {
|
|
5203
|
+
botId: merged.botId,
|
|
5204
|
+
workspaceId: merged.workspaceId,
|
|
5205
|
+
apiUrl: merged.apiUrl,
|
|
5206
|
+
devId: merged.devId
|
|
5207
|
+
};
|
|
5208
|
+
}
|
|
5209
|
+
}
|
|
5210
|
+
async updateAgentLocalInfo(updates) {
|
|
5211
|
+
const localPath = path13.join(this._path, "agent.local.json");
|
|
5212
|
+
let existing = {};
|
|
5213
|
+
try {
|
|
5214
|
+
const content2 = await fs10.readFile(localPath, "utf-8");
|
|
5215
|
+
existing = JSON.parse(content2);
|
|
5216
|
+
} catch {}
|
|
5217
|
+
const updated = { ...existing, ...updates };
|
|
5218
|
+
for (const key of Object.keys(updated)) {
|
|
5219
|
+
if (updated[key] === undefined) {
|
|
5220
|
+
delete updated[key];
|
|
5221
|
+
}
|
|
5222
|
+
}
|
|
5223
|
+
const content = stringifyWithOrder(updated, agentLocalInfoKeyOrder);
|
|
5224
|
+
await fs10.writeFile(localPath, content);
|
|
5225
|
+
if (this._agentInfo) {
|
|
5226
|
+
const local = updated;
|
|
5227
|
+
if (local.botId)
|
|
5228
|
+
this._agentInfo.botId = local.botId;
|
|
5229
|
+
if (local.workspaceId)
|
|
5230
|
+
this._agentInfo.workspaceId = local.workspaceId;
|
|
5231
|
+
if (local.apiUrl)
|
|
5232
|
+
this._agentInfo.apiUrl = local.apiUrl;
|
|
5233
|
+
if (local.devId)
|
|
5234
|
+
this._agentInfo.devId = local.devId;
|
|
5235
|
+
}
|
|
4941
5236
|
}
|
|
4942
5237
|
requiresAgentInfo(operation) {
|
|
4943
5238
|
if (!this._agentInfo?.botId) {
|
|
@@ -5128,6 +5423,32 @@ ${err.stack?.split(`
|
|
|
5128
5423
|
console.warn(`Failed to register data source workflows for ${kbPath}:`, error);
|
|
5129
5424
|
}
|
|
5130
5425
|
}
|
|
5426
|
+
isBarrelReexport(existing, newPath, newExport, newDefinition) {
|
|
5427
|
+
const isNewBarrel = /^index\.[tj]s$/i.test(path13.basename(newPath));
|
|
5428
|
+
const isExistingBarrel = /^index\.[tj]s$/i.test(path13.basename(existing.path));
|
|
5429
|
+
if (!isNewBarrel && !isExistingBarrel) {
|
|
5430
|
+
return false;
|
|
5431
|
+
}
|
|
5432
|
+
if (isExistingBarrel && !isNewBarrel) {
|
|
5433
|
+
existing.path = newPath;
|
|
5434
|
+
existing.export = newExport;
|
|
5435
|
+
existing.definition = newDefinition;
|
|
5436
|
+
}
|
|
5437
|
+
return true;
|
|
5438
|
+
}
|
|
5439
|
+
isToolBarrelReexport(existingPath, newPath) {
|
|
5440
|
+
const isNewBarrel = /^index\.[tj]s$/i.test(path13.basename(newPath));
|
|
5441
|
+
const isExistingBarrel = /^index\.[tj]s$/i.test(path13.basename(existingPath));
|
|
5442
|
+
if (!isNewBarrel && !isExistingBarrel) {
|
|
5443
|
+
return false;
|
|
5444
|
+
}
|
|
5445
|
+
return true;
|
|
5446
|
+
}
|
|
5447
|
+
shouldPreferToolDefinition(existingPath, newPath) {
|
|
5448
|
+
const isNewBarrel = /^index\.[tj]s$/i.test(path13.basename(newPath));
|
|
5449
|
+
const isExistingBarrel = /^index\.[tj]s$/i.test(path13.basename(existingPath));
|
|
5450
|
+
return isExistingBarrel && !isNewBarrel;
|
|
5451
|
+
}
|
|
5131
5452
|
getChannelsList(channelSpec) {
|
|
5132
5453
|
if (channelSpec === "*") {
|
|
5133
5454
|
return ["*"];
|
|
@@ -5210,6 +5531,9 @@ ${err.stack?.split(`
|
|
|
5210
5531
|
return existingChannels.some((ch) => newChannels.includes(ch));
|
|
5211
5532
|
});
|
|
5212
5533
|
if (overlapping) {
|
|
5534
|
+
if (this.isBarrelReexport(overlapping, relPath, key, definition)) {
|
|
5535
|
+
continue;
|
|
5536
|
+
}
|
|
5213
5537
|
this._warnings.push({
|
|
5214
5538
|
$type: "ValidationError",
|
|
5215
5539
|
code: "DUPLICATE_PRIMITIVE" /* DUPLICATE_PRIMITIVE */,
|
|
@@ -5227,6 +5551,9 @@ ${err.stack?.split(`
|
|
|
5227
5551
|
} else if (Primitives2.Definitions.isKnowledgeDefinition(definition)) {
|
|
5228
5552
|
const existing = this._knowledge.find((p) => p.definition.name === definition.name);
|
|
5229
5553
|
if (existing) {
|
|
5554
|
+
if (this.isBarrelReexport(existing, relPath, key, definition)) {
|
|
5555
|
+
continue;
|
|
5556
|
+
}
|
|
5230
5557
|
this._warnings.push({
|
|
5231
5558
|
$type: "ValidationError",
|
|
5232
5559
|
code: "DUPLICATE_PRIMITIVE" /* DUPLICATE_PRIMITIVE */,
|
|
@@ -5245,6 +5572,9 @@ ${err.stack?.split(`
|
|
|
5245
5572
|
} else if (Primitives2.Definitions.isTriggerDefinition(definition)) {
|
|
5246
5573
|
const existing = this._triggers.find((p) => p.definition.name === definition.name);
|
|
5247
5574
|
if (existing) {
|
|
5575
|
+
if (this.isBarrelReexport(existing, relPath, key, definition)) {
|
|
5576
|
+
continue;
|
|
5577
|
+
}
|
|
5248
5578
|
this._warnings.push({
|
|
5249
5579
|
$type: "ValidationError",
|
|
5250
5580
|
code: "DUPLICATE_PRIMITIVE" /* DUPLICATE_PRIMITIVE */,
|
|
@@ -5262,6 +5592,9 @@ ${err.stack?.split(`
|
|
|
5262
5592
|
} else if (Primitives2.Definitions.isWorkflowDefinition(definition)) {
|
|
5263
5593
|
const existing = this._workflows.find((p) => p.definition.name === definition.name);
|
|
5264
5594
|
if (existing) {
|
|
5595
|
+
if (this.isBarrelReexport(existing, relPath, key, definition)) {
|
|
5596
|
+
continue;
|
|
5597
|
+
}
|
|
5265
5598
|
this._warnings.push({
|
|
5266
5599
|
$type: "ValidationError",
|
|
5267
5600
|
code: "DUPLICATE_PRIMITIVE" /* DUPLICATE_PRIMITIVE */,
|
|
@@ -5279,6 +5612,9 @@ ${err.stack?.split(`
|
|
|
5279
5612
|
} else if (Primitives2.Definitions.isActionDefinition(definition)) {
|
|
5280
5613
|
const existing = this._actions.find((p) => p.definition.name === definition.name);
|
|
5281
5614
|
if (existing) {
|
|
5615
|
+
if (this.isBarrelReexport(existing, relPath, key, definition)) {
|
|
5616
|
+
continue;
|
|
5617
|
+
}
|
|
5282
5618
|
this._warnings.push({
|
|
5283
5619
|
$type: "ValidationError",
|
|
5284
5620
|
code: "DUPLICATE_PRIMITIVE" /* DUPLICATE_PRIMITIVE */,
|
|
@@ -5296,6 +5632,9 @@ ${err.stack?.split(`
|
|
|
5296
5632
|
} else if (Primitives2.Definitions.isTableDefinition(definition)) {
|
|
5297
5633
|
const existing = this._tables.find((p) => p.definition.name === definition.name);
|
|
5298
5634
|
if (existing) {
|
|
5635
|
+
if (this.isBarrelReexport(existing, relPath, key, definition)) {
|
|
5636
|
+
continue;
|
|
5637
|
+
}
|
|
5299
5638
|
this._warnings.push({
|
|
5300
5639
|
$type: "ValidationError",
|
|
5301
5640
|
code: "DUPLICATE_PRIMITIVE" /* DUPLICATE_PRIMITIVE */,
|
|
@@ -5310,6 +5649,35 @@ ${err.stack?.split(`
|
|
|
5310
5649
|
export: key,
|
|
5311
5650
|
path: relPath
|
|
5312
5651
|
});
|
|
5652
|
+
} else {
|
|
5653
|
+
const toolDefinition = getToolDefinition(expandedExports[key]);
|
|
5654
|
+
if (!toolDefinition) {
|
|
5655
|
+
continue;
|
|
5656
|
+
}
|
|
5657
|
+
const existing = this._tools.find((tool) => tool.definition.name === toolDefinition.name);
|
|
5658
|
+
if (existing) {
|
|
5659
|
+
if (this.isToolBarrelReexport(existing.path, relPath)) {
|
|
5660
|
+
if (this.shouldPreferToolDefinition(existing.path, relPath)) {
|
|
5661
|
+
existing.path = relPath;
|
|
5662
|
+
existing.export = key;
|
|
5663
|
+
existing.definition = toolDefinition;
|
|
5664
|
+
}
|
|
5665
|
+
continue;
|
|
5666
|
+
}
|
|
5667
|
+
this._warnings.push({
|
|
5668
|
+
$type: "ValidationError",
|
|
5669
|
+
code: "DUPLICATE_PRIMITIVE" /* DUPLICATE_PRIMITIVE */,
|
|
5670
|
+
severity: "warning" /* WARNING */,
|
|
5671
|
+
message: `Duplicate tool definition found: ${filename} -> ${key} (already defined in ${existing.path} -> ${existing.export})`,
|
|
5672
|
+
file: relPath
|
|
5673
|
+
});
|
|
5674
|
+
continue;
|
|
5675
|
+
}
|
|
5676
|
+
this._tools.push({
|
|
5677
|
+
definition: toolDefinition,
|
|
5678
|
+
export: key,
|
|
5679
|
+
path: relPath
|
|
5680
|
+
});
|
|
5313
5681
|
}
|
|
5314
5682
|
}
|
|
5315
5683
|
} catch (error) {
|
|
@@ -5593,6 +5961,8 @@ class ConfigManager {
|
|
|
5593
5961
|
init_utils();
|
|
5594
5962
|
import * as fs11 from "fs";
|
|
5595
5963
|
import * as path15 from "path";
|
|
5964
|
+
import { fileURLToPath } from "url";
|
|
5965
|
+
import { createRequire as createRequire4 } from "module";
|
|
5596
5966
|
|
|
5597
5967
|
// src/agent-init/ai-assistant-instructions.template.md
|
|
5598
5968
|
var ai_assistant_instructions_template_default = `# Botpress ADK Agent
|
|
@@ -5619,22 +5989,38 @@ adk deploy # Deploy to Botpress Cloud
|
|
|
5619
5989
|
adk chat # Chat with your agent in the terminal
|
|
5620
5990
|
\`\`\`
|
|
5621
5991
|
|
|
5622
|
-
##
|
|
5992
|
+
## MCP Tools (ADK Dev Server)
|
|
5623
5993
|
|
|
5624
|
-
This project
|
|
5994
|
+
This project includes an MCP server that provides AI coding assistants with deep ADK integration.
|
|
5995
|
+
Run \`adk mcp:init --all\` to generate configuration for your editor, or use the tools below directly.
|
|
5625
5996
|
|
|
5626
|
-
|
|
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 |
|
|
5997
|
+
### Debugging & Testing
|
|
5632
5998
|
|
|
5633
|
-
|
|
5999
|
+
| Tool | Use for |
|
|
6000
|
+
| ------------------ | ------------------------------------------------------------ |
|
|
6001
|
+
| \`adk_send_message\` | Send a test message to the running bot and receive responses |
|
|
6002
|
+
| \`adk_query_traces\` | Query trace spans for debugging conversations and workflows |
|
|
6003
|
+
| \`adk_get_dev_logs\` | Get dev server logs, build output, errors, and warnings |
|
|
5634
6004
|
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
6005
|
+
### Project & Integration Management
|
|
6006
|
+
|
|
6007
|
+
| Tool | Use for |
|
|
6008
|
+
| ------------------------- | ----------------------------------------------------------- |
|
|
6009
|
+
| \`adk_get_agent_info\` | Get project info: name, version, and all primitives |
|
|
6010
|
+
| \`adk_search_integrations\` | Search available integrations on the Botpress Hub |
|
|
6011
|
+
| \`adk_get_integration\` | Get detailed info about an integration before adding it |
|
|
6012
|
+
| \`adk_add_integration\` | Add an integration to the project (updates agent.config.ts) |
|
|
6013
|
+
|
|
6014
|
+
### Workflows
|
|
6015
|
+
|
|
6016
|
+
| Tool | Use for |
|
|
6017
|
+
| -------------------- | ---------------------------------------- |
|
|
6018
|
+
| \`adk_list_workflows\` | Deprecated compat workflow discovery |
|
|
6019
|
+
| \`adk_start_workflow\` | Start a workflow or get its input schema |
|
|
6020
|
+
|
|
6021
|
+
> **Tip:** Prefer \`adk workflows\` in the terminal to discover workflow names and metadata. Keep \`adk_list_workflows\` for MCP compatibility only.
|
|
6022
|
+
|
|
6023
|
+
> **Tip:** The dev server must be running (\`adk dev\`) for debugging and testing tools to work.
|
|
5638
6024
|
|
|
5639
6025
|
## Project Overview
|
|
5640
6026
|
|
|
@@ -5650,6 +6036,30 @@ npx skills add botpress/skills --skill adk
|
|
|
5650
6036
|
`;
|
|
5651
6037
|
|
|
5652
6038
|
// src/agent-init/agent-project-generator.ts
|
|
6039
|
+
var TEXT_EXTENSIONS = new Set([
|
|
6040
|
+
".ts",
|
|
6041
|
+
".tsx",
|
|
6042
|
+
".js",
|
|
6043
|
+
".jsx",
|
|
6044
|
+
".mjs",
|
|
6045
|
+
".cjs",
|
|
6046
|
+
".json",
|
|
6047
|
+
".md",
|
|
6048
|
+
".txt",
|
|
6049
|
+
".yml",
|
|
6050
|
+
".yaml",
|
|
6051
|
+
".html",
|
|
6052
|
+
".css",
|
|
6053
|
+
".svg",
|
|
6054
|
+
".gitignore"
|
|
6055
|
+
]);
|
|
6056
|
+
function isTextFile(filename) {
|
|
6057
|
+
if (filename === ".gitignore")
|
|
6058
|
+
return true;
|
|
6059
|
+
const ext = path15.extname(filename).toLowerCase();
|
|
6060
|
+
return TEXT_EXTENSIONS.has(ext);
|
|
6061
|
+
}
|
|
6062
|
+
|
|
5653
6063
|
class AgentProjectGenerator {
|
|
5654
6064
|
projectPath;
|
|
5655
6065
|
projectName;
|
|
@@ -5661,16 +6071,125 @@ class AgentProjectGenerator {
|
|
|
5661
6071
|
this.packageManager = packageManager;
|
|
5662
6072
|
this.template = template;
|
|
5663
6073
|
}
|
|
5664
|
-
async generate() {
|
|
5665
|
-
this.ensureEmptyDirectory();
|
|
5666
|
-
this.
|
|
5667
|
-
await this.
|
|
5668
|
-
this.
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
6074
|
+
async generate() {
|
|
6075
|
+
this.ensureEmptyDirectory();
|
|
6076
|
+
const templateDir = this.resolveTemplateDir();
|
|
6077
|
+
await this.copyTemplateFiles(templateDir);
|
|
6078
|
+
if (!fs11.existsSync(path15.join(this.projectPath, "agent.json"))) {
|
|
6079
|
+
this.createAgentJson();
|
|
6080
|
+
}
|
|
6081
|
+
if (!fs11.existsSync(path15.join(this.projectPath, "CLAUDE.md"))) {
|
|
6082
|
+
this.createAIAssistantInstructions();
|
|
6083
|
+
}
|
|
6084
|
+
}
|
|
6085
|
+
static getAvailableTemplates() {
|
|
6086
|
+
try {
|
|
6087
|
+
const templatesRoot = AgentProjectGenerator.getTemplatesRoot();
|
|
6088
|
+
const configPath = path15.join(templatesRoot, "template.config.json");
|
|
6089
|
+
if (!fs11.existsSync(configPath)) {
|
|
6090
|
+
return [];
|
|
6091
|
+
}
|
|
6092
|
+
const raw = fs11.readFileSync(configPath, "utf-8");
|
|
6093
|
+
const registry = JSON.parse(raw);
|
|
6094
|
+
return registry.templates;
|
|
6095
|
+
} catch {
|
|
6096
|
+
return [];
|
|
6097
|
+
}
|
|
6098
|
+
}
|
|
6099
|
+
getPostInitCommands() {
|
|
6100
|
+
const templates = AgentProjectGenerator.getAvailableTemplates();
|
|
6101
|
+
const config = templates.find((t) => t.name === this.template);
|
|
6102
|
+
return config?.postInit ?? [];
|
|
6103
|
+
}
|
|
6104
|
+
static _templatesRootOverride = null;
|
|
6105
|
+
static setTemplatesRoot(dir) {
|
|
6106
|
+
AgentProjectGenerator._templatesRootOverride = dir;
|
|
6107
|
+
}
|
|
6108
|
+
static getTemplatesRoot() {
|
|
6109
|
+
if (AgentProjectGenerator._templatesRootOverride) {
|
|
6110
|
+
return AgentProjectGenerator._templatesRootOverride;
|
|
6111
|
+
}
|
|
6112
|
+
const candidates = [];
|
|
6113
|
+
try {
|
|
6114
|
+
const esmRequire = createRequire4(import.meta.url);
|
|
6115
|
+
const adkPkgPath = esmRequire.resolve("@botpress/adk/package.json");
|
|
6116
|
+
const adkRoot = path15.dirname(adkPkgPath);
|
|
6117
|
+
candidates.push(path15.join(adkRoot, "dist", "templates"));
|
|
6118
|
+
candidates.push(path15.join(adkRoot, "templates"));
|
|
6119
|
+
} catch {}
|
|
6120
|
+
const thisDir = path15.dirname(fileURLToPath(import.meta.url));
|
|
6121
|
+
candidates.push(path15.resolve(thisDir, "templates"));
|
|
6122
|
+
candidates.push(path15.resolve(thisDir, "../../templates"));
|
|
6123
|
+
candidates.push(path15.join(path15.dirname(process.execPath), "templates"));
|
|
6124
|
+
for (const candidate of candidates) {
|
|
6125
|
+
if (fs11.existsSync(candidate) && fs11.existsSync(path15.join(candidate, "template.config.json"))) {
|
|
6126
|
+
return candidate;
|
|
6127
|
+
}
|
|
6128
|
+
}
|
|
6129
|
+
const tried = candidates.map((c) => ` - ${c}`).join(`
|
|
6130
|
+
`);
|
|
6131
|
+
throw new Error(`Could not find templates directory.
|
|
6132
|
+
|
|
6133
|
+
Searched:
|
|
6134
|
+
${tried}
|
|
6135
|
+
|
|
6136
|
+
Ensure the ADK package is properly installed or run the CLI build.`);
|
|
6137
|
+
}
|
|
6138
|
+
resolveTemplateDir() {
|
|
6139
|
+
const templatesRoot = AgentProjectGenerator.getTemplatesRoot();
|
|
6140
|
+
const templateDir = path15.join(templatesRoot, this.template);
|
|
6141
|
+
if (!fs11.existsSync(templateDir)) {
|
|
6142
|
+
const available = AgentProjectGenerator.getAvailableTemplates();
|
|
6143
|
+
const names = available.map((t) => ` - ${t.name}: ${t.description}`).join(`
|
|
6144
|
+
`);
|
|
6145
|
+
throw new Error(`Unknown template: "${this.template}"
|
|
6146
|
+
|
|
6147
|
+
Available templates:
|
|
6148
|
+
${names || " (none found)"}`);
|
|
6149
|
+
}
|
|
6150
|
+
const configFile = path15.join(templateDir, "agent.config.ts");
|
|
6151
|
+
if (!fs11.existsSync(configFile)) {
|
|
6152
|
+
throw new Error(`Template "${this.template}" is missing agent.config.ts`);
|
|
6153
|
+
}
|
|
6154
|
+
return templateDir;
|
|
6155
|
+
}
|
|
6156
|
+
async copyTemplateFiles(templateDir) {
|
|
6157
|
+
const substitutions = {
|
|
6158
|
+
"{{projectName}}": this.projectName,
|
|
6159
|
+
"{{runtimeVersion}}": "1.18.0-beta.1",
|
|
6160
|
+
"{{packageManager}}": this.packageManager
|
|
6161
|
+
};
|
|
6162
|
+
await this.copyDirRecursive(templateDir, this.projectPath, substitutions);
|
|
6163
|
+
}
|
|
6164
|
+
async copyDirRecursive(src, dest, substitutions) {
|
|
6165
|
+
if (!fs11.existsSync(dest)) {
|
|
6166
|
+
fs11.mkdirSync(dest, { recursive: true });
|
|
6167
|
+
}
|
|
6168
|
+
const entries = fs11.readdirSync(src, { withFileTypes: true });
|
|
6169
|
+
for (const entry of entries) {
|
|
6170
|
+
const srcPath = path15.join(src, entry.name);
|
|
6171
|
+
const destPath = path15.join(dest, entry.name);
|
|
6172
|
+
if (entry.isDirectory()) {
|
|
6173
|
+
await this.copyDirRecursive(srcPath, destPath, substitutions);
|
|
6174
|
+
} else if (isTextFile(entry.name)) {
|
|
6175
|
+
let content = fs11.readFileSync(srcPath, "utf-8");
|
|
6176
|
+
for (const [placeholder, value] of Object.entries(substitutions)) {
|
|
6177
|
+
content = content.replaceAll(placeholder, value);
|
|
6178
|
+
}
|
|
6179
|
+
const remaining = content.match(/\{\{[a-zA-Z]+\}\}/g);
|
|
6180
|
+
if (remaining) {
|
|
6181
|
+
console.warn(`Warning: unresolved placeholders in ${entry.name}: ${remaining.join(", ")}`);
|
|
6182
|
+
}
|
|
6183
|
+
if (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx")) {
|
|
6184
|
+
try {
|
|
6185
|
+
content = await formatCode(content, destPath);
|
|
6186
|
+
} catch {}
|
|
6187
|
+
}
|
|
6188
|
+
fs11.writeFileSync(destPath, content);
|
|
6189
|
+
} else {
|
|
6190
|
+
fs11.copyFileSync(srcPath, destPath);
|
|
6191
|
+
}
|
|
6192
|
+
}
|
|
5674
6193
|
}
|
|
5675
6194
|
ensureEmptyDirectory() {
|
|
5676
6195
|
if (!fs11.existsSync(this.projectPath)) {
|
|
@@ -5681,229 +6200,19 @@ class AgentProjectGenerator {
|
|
|
5681
6200
|
throw new Error(`Directory ${this.projectPath} is not empty. Please use an empty directory.`);
|
|
5682
6201
|
}
|
|
5683
6202
|
}
|
|
5684
|
-
createPackageJson() {
|
|
5685
|
-
const packageJson = {
|
|
5686
|
-
name: this.projectName,
|
|
5687
|
-
version: "1.0.0",
|
|
5688
|
-
description: `A Botpress Agent built with the ADK`,
|
|
5689
|
-
type: "module",
|
|
5690
|
-
packageManager: this.packageManager === "npm" ? undefined : `${this.packageManager}@latest`,
|
|
5691
|
-
scripts: {
|
|
5692
|
-
dev: "adk dev",
|
|
5693
|
-
build: "adk build",
|
|
5694
|
-
deploy: "adk deploy"
|
|
5695
|
-
},
|
|
5696
|
-
dependencies: {
|
|
5697
|
-
"@botpress/runtime": `^${"1.16.7"}`
|
|
5698
|
-
},
|
|
5699
|
-
devDependencies: {
|
|
5700
|
-
typescript: "^5.9.3"
|
|
5701
|
-
}
|
|
5702
|
-
};
|
|
5703
|
-
if (packageJson.packageManager === undefined) {
|
|
5704
|
-
delete packageJson.packageManager;
|
|
5705
|
-
}
|
|
5706
|
-
this.writeJsonFile("package.json", packageJson);
|
|
5707
|
-
}
|
|
5708
|
-
getDefaultDependencies() {
|
|
5709
|
-
const dependencies = {
|
|
5710
|
-
integrations: {}
|
|
5711
|
-
};
|
|
5712
|
-
if (this.template === "hello-world") {
|
|
5713
|
-
dependencies.integrations = {
|
|
5714
|
-
chat: {
|
|
5715
|
-
version: "chat@latest",
|
|
5716
|
-
enabled: true
|
|
5717
|
-
},
|
|
5718
|
-
webchat: {
|
|
5719
|
-
version: "webchat@latest",
|
|
5720
|
-
enabled: true
|
|
5721
|
-
}
|
|
5722
|
-
};
|
|
5723
|
-
}
|
|
5724
|
-
return dependencies;
|
|
5725
|
-
}
|
|
5726
|
-
async createAgentConfig() {
|
|
5727
|
-
const dependencies = this.getDefaultDependencies();
|
|
5728
|
-
const integrationsJson = JSON.stringify(dependencies.integrations, null, 4).replace(/\n/g, `
|
|
5729
|
-
`);
|
|
5730
|
-
const defaultModels = this.template === "hello-world" ? `
|
|
5731
|
-
defaultModels: {
|
|
5732
|
-
autonomous: "cerebras:gpt-oss-120b",
|
|
5733
|
-
zai: "cerebras:gpt-oss-120b",
|
|
5734
|
-
},
|
|
5735
|
-
` : "";
|
|
5736
|
-
const agentConfig = `import { z, defineConfig } from '@botpress/runtime';
|
|
5737
|
-
|
|
5738
|
-
export default defineConfig({
|
|
5739
|
-
name: '${this.projectName}',
|
|
5740
|
-
description: 'An AI agent built with Botpress ADK',
|
|
5741
|
-
${defaultModels}
|
|
5742
|
-
bot: {
|
|
5743
|
-
state: z.object({}),
|
|
5744
|
-
},
|
|
5745
|
-
|
|
5746
|
-
user: {
|
|
5747
|
-
state: z.object({}),
|
|
5748
|
-
},
|
|
5749
|
-
|
|
5750
|
-
dependencies: {
|
|
5751
|
-
integrations: ${integrationsJson},
|
|
5752
|
-
},
|
|
5753
|
-
});
|
|
5754
|
-
`;
|
|
5755
|
-
await this.writeFormattedFile("agent.config.ts", agentConfig);
|
|
5756
|
-
}
|
|
5757
|
-
createTsConfig() {
|
|
5758
|
-
const tsConfig = {
|
|
5759
|
-
compilerOptions: {
|
|
5760
|
-
target: "ES2022",
|
|
5761
|
-
module: "ES2022",
|
|
5762
|
-
moduleResolution: "Bundler",
|
|
5763
|
-
lib: ["ES2022", "DOM"],
|
|
5764
|
-
outDir: "./dist",
|
|
5765
|
-
rootDir: ".",
|
|
5766
|
-
strict: true,
|
|
5767
|
-
esModuleInterop: true,
|
|
5768
|
-
allowSyntheticDefaultImports: true,
|
|
5769
|
-
skipLibCheck: true,
|
|
5770
|
-
forceConsistentCasingInFileNames: true,
|
|
5771
|
-
moduleDetection: "force",
|
|
5772
|
-
resolveJsonModule: true,
|
|
5773
|
-
paths: {
|
|
5774
|
-
"@botpress/runtime/_types/*": ["./.adk/*-types"]
|
|
5775
|
-
}
|
|
5776
|
-
},
|
|
5777
|
-
include: ["src/**/*", ".adk/**/*"],
|
|
5778
|
-
exclude: ["node_modules", "dist"]
|
|
5779
|
-
};
|
|
5780
|
-
this.writeJsonFile("tsconfig.json", tsConfig);
|
|
5781
|
-
}
|
|
5782
6203
|
createAgentJson() {
|
|
5783
6204
|
const agentJson = {};
|
|
5784
6205
|
this.writeJsonFile("agent.json", agentJson);
|
|
5785
6206
|
}
|
|
5786
|
-
createGitIgnore() {
|
|
5787
|
-
const gitIgnore = `# Dependencies
|
|
5788
|
-
node_modules/
|
|
5789
|
-
.pnpm-store/
|
|
5790
|
-
|
|
5791
|
-
# Build outputs
|
|
5792
|
-
dist/
|
|
5793
|
-
.adk/
|
|
5794
|
-
|
|
5795
|
-
# Environment files
|
|
5796
|
-
.env
|
|
5797
|
-
.env.local
|
|
5798
|
-
.env.production
|
|
5799
|
-
|
|
5800
|
-
# IDE files
|
|
5801
|
-
.vscode/
|
|
5802
|
-
.idea/
|
|
5803
|
-
*.swp
|
|
5804
|
-
*.swo
|
|
5805
|
-
|
|
5806
|
-
# OS files
|
|
5807
|
-
.DS_Store
|
|
5808
|
-
Thumbs.db
|
|
5809
|
-
|
|
5810
|
-
# Logs
|
|
5811
|
-
*.log
|
|
5812
|
-
logs/
|
|
5813
|
-
|
|
5814
|
-
# Runtime files
|
|
5815
|
-
*.pid
|
|
5816
|
-
*.seed
|
|
5817
|
-
*.pid.lock
|
|
5818
|
-
`;
|
|
5819
|
-
this.writeFile(".gitignore", gitIgnore);
|
|
5820
|
-
}
|
|
5821
|
-
async createReadme() {
|
|
5822
|
-
const installCommand = this.packageManager === "npm" ? "npm install" : this.packageManager === "yarn" ? "yarn install" : `${this.packageManager} install`;
|
|
5823
|
-
const readme = `# ${this.projectName}
|
|
5824
|
-
|
|
5825
|
-
A Botpress Agent built with the ADK.
|
|
5826
|
-
|
|
5827
|
-
## Getting Started
|
|
5828
|
-
|
|
5829
|
-
1. Install dependencies:
|
|
5830
|
-
\`\`\`bash
|
|
5831
|
-
${installCommand}
|
|
5832
|
-
\`\`\`
|
|
5833
|
-
|
|
5834
|
-
2. Start development server:
|
|
5835
|
-
\`\`\`bash
|
|
5836
|
-
adk dev
|
|
5837
|
-
\`\`\`
|
|
5838
|
-
|
|
5839
|
-
3. Deploy your agent:
|
|
5840
|
-
\`\`\`bash
|
|
5841
|
-
adk deploy
|
|
5842
|
-
\`\`\`
|
|
5843
|
-
|
|
5844
|
-
## Project Structure
|
|
5845
|
-
|
|
5846
|
-
- \`src/actions/\` - Define callable functions
|
|
5847
|
-
- \`src/workflows/\` - Define long-running processes
|
|
5848
|
-
- \`src/conversations/\` - Define conversation handlers
|
|
5849
|
-
- \`src/tables/\` - Define data storage schemas
|
|
5850
|
-
- \`src/triggers/\` - Define event subscriptions
|
|
5851
|
-
- \`src/knowledge/\` - Add knowledge base files
|
|
5852
|
-
|
|
5853
|
-
## Learn More
|
|
5854
|
-
|
|
5855
|
-
- [ADK Documentation](https://botpress.com/docs/adk)
|
|
5856
|
-
- [Botpress Platform](https://botpress.com)
|
|
5857
|
-
`;
|
|
5858
|
-
await this.writeFormattedFile("README.md", readme);
|
|
5859
|
-
}
|
|
5860
6207
|
createAIAssistantInstructions() {
|
|
5861
6208
|
const content = ai_assistant_instructions_template_default;
|
|
5862
6209
|
this.writeFile("CLAUDE.md", content);
|
|
5863
6210
|
this.writeFile("AGENTS.md", content);
|
|
5864
6211
|
}
|
|
5865
|
-
async createSourceStructure() {
|
|
5866
|
-
const srcPath = path15.join(this.projectPath, "src");
|
|
5867
|
-
fs11.mkdirSync(srcPath);
|
|
5868
|
-
const subdirectories = ["actions", "conversations", "knowledge", "tables", "triggers", "workflows"];
|
|
5869
|
-
for (const subdir of subdirectories) {
|
|
5870
|
-
const subdirPath = path15.join(srcPath, subdir);
|
|
5871
|
-
fs11.mkdirSync(subdirPath);
|
|
5872
|
-
if (subdir === "conversations" && this.template === "hello-world") {
|
|
5873
|
-
const conversationContent = `import { Conversation } from "@botpress/runtime";
|
|
5874
|
-
|
|
5875
|
-
export default new Conversation({
|
|
5876
|
-
channel: "*",
|
|
5877
|
-
handler: async ({ execute }) => {
|
|
5878
|
-
await execute({
|
|
5879
|
-
instructions: \`You are a helpful AI assistant built with Botpress ADK. You can assist users with their questions and tasks.\`,
|
|
5880
|
-
});
|
|
5881
|
-
},
|
|
5882
|
-
});
|
|
5883
|
-
`;
|
|
5884
|
-
await this.writeFormattedFile(path15.join("src", subdir, "index.ts"), conversationContent);
|
|
5885
|
-
} else {
|
|
5886
|
-
const placeholderContent = `/**
|
|
5887
|
-
* TODO: Add your ${subdir} here
|
|
5888
|
-
*
|
|
5889
|
-
* This is a placeholder file to initialize the ${subdir} directory.
|
|
5890
|
-
* You can delete this file once you add your own ${subdir}.
|
|
5891
|
-
*/
|
|
5892
|
-
|
|
5893
|
-
export default {};
|
|
5894
|
-
`;
|
|
5895
|
-
await this.writeFormattedFile(path15.join("src", subdir, "index.ts"), placeholderContent);
|
|
5896
|
-
}
|
|
5897
|
-
}
|
|
5898
|
-
}
|
|
5899
6212
|
writeFile(relativePath, content) {
|
|
5900
6213
|
const filePath = path15.join(this.projectPath, relativePath);
|
|
5901
6214
|
fs11.writeFileSync(filePath, content);
|
|
5902
6215
|
}
|
|
5903
|
-
async writeFormattedFile(relativePath, content) {
|
|
5904
|
-
const formatted = await formatCode(content, relativePath);
|
|
5905
|
-
this.writeFile(relativePath, formatted);
|
|
5906
|
-
}
|
|
5907
6216
|
writeJsonFile(relativePath, data) {
|
|
5908
6217
|
this.writeFile(relativePath, JSON.stringify(data, null, 2) + `
|
|
5909
6218
|
`);
|
|
@@ -6227,7 +6536,7 @@ if (typeof globalThis !== 'undefined') {
|
|
|
6227
6536
|
}
|
|
6228
6537
|
}
|
|
6229
6538
|
// src/generators/integration-types.ts
|
|
6230
|
-
import {
|
|
6539
|
+
import { z as z3 } from "@botpress/sdk";
|
|
6231
6540
|
import crypto2 from "crypto";
|
|
6232
6541
|
import path18 from "path";
|
|
6233
6542
|
|
|
@@ -6255,6 +6564,7 @@ function getPluginAlias(pluginName) {
|
|
|
6255
6564
|
}
|
|
6256
6565
|
|
|
6257
6566
|
// src/generators/integration-types.ts
|
|
6567
|
+
var { transforms } = z3;
|
|
6258
6568
|
var getIntegrationHash = (integration) => {
|
|
6259
6569
|
return crypto2.createHash("sha256").update(`${integration.alias}|${integration.definition?.id}|${integration.definition?.version}|${integration.definition?.updatedAt}`).digest("hex");
|
|
6260
6570
|
};
|
|
@@ -6487,9 +6797,10 @@ Description: ${tag?.description}`);
|
|
|
6487
6797
|
}
|
|
6488
6798
|
if (integration.definition?.configurations) {
|
|
6489
6799
|
for (const [key, config] of Object.entries(integration.definition.configurations)) {
|
|
6490
|
-
const
|
|
6491
|
-
const
|
|
6492
|
-
const
|
|
6800
|
+
const configRecord = config;
|
|
6801
|
+
const title = configRecord.title || key;
|
|
6802
|
+
const description = configRecord.description || "";
|
|
6803
|
+
const schema = configRecord.schema;
|
|
6493
6804
|
let tsType = "{}";
|
|
6494
6805
|
if (schema) {
|
|
6495
6806
|
tsType = transforms.fromJSONSchema(schema).toTypescriptType();
|
|
@@ -6606,12 +6917,14 @@ async function generateClientWrapper(project) {
|
|
|
6606
6917
|
let schema;
|
|
6607
6918
|
let computed = false;
|
|
6608
6919
|
if (typeof colDef === "object" && colDef !== null && "schema" in colDef) {
|
|
6609
|
-
|
|
6610
|
-
|
|
6920
|
+
const colDefRecord = colDef;
|
|
6921
|
+
schema = colDefRecord.schema;
|
|
6922
|
+
computed = colDefRecord.computed || false;
|
|
6611
6923
|
} else {
|
|
6612
6924
|
schema = colDef;
|
|
6613
6925
|
}
|
|
6614
|
-
const
|
|
6926
|
+
const schemaObj = schema;
|
|
6927
|
+
const tsType = typeof schemaObj.toTypescriptType === "function" ? schemaObj.toTypescriptType({ treatDefaultAsOptional: true }) : "any";
|
|
6615
6928
|
if (!computed) {
|
|
6616
6929
|
inputColumns.push(`${colName}: ${tsType}`);
|
|
6617
6930
|
}
|
|
@@ -6921,15 +7234,16 @@ export function createAdkClient(client: Client): AdkClient {
|
|
|
6921
7234
|
}
|
|
6922
7235
|
// src/bot-generator/generator.ts
|
|
6923
7236
|
import dedent from "dedent";
|
|
6924
|
-
import { existsSync as
|
|
7237
|
+
import { existsSync as existsSync7 } from "fs";
|
|
6925
7238
|
import fs18 from "fs/promises";
|
|
6926
7239
|
import path38 from "path";
|
|
6927
7240
|
|
|
6928
7241
|
// src/generators/plugin-types.ts
|
|
6929
|
-
import {
|
|
7242
|
+
import { z as z4 } from "@botpress/sdk";
|
|
6930
7243
|
import crypto4 from "crypto";
|
|
6931
7244
|
import path20 from "path";
|
|
6932
7245
|
init_utils();
|
|
7246
|
+
var { transforms: transforms2 } = z4;
|
|
6933
7247
|
function stripRefs(schema) {
|
|
6934
7248
|
if (typeof schema !== "object" || schema === null) {
|
|
6935
7249
|
return schema;
|
|
@@ -7075,10 +7389,11 @@ export type PluginActions = PluginsMap<Plugins>;
|
|
|
7075
7389
|
}
|
|
7076
7390
|
|
|
7077
7391
|
// src/generators/interface-types.ts
|
|
7078
|
-
import {
|
|
7392
|
+
import { z as z5 } from "@botpress/sdk";
|
|
7079
7393
|
import crypto5 from "crypto";
|
|
7080
7394
|
import path22 from "path";
|
|
7081
7395
|
init_utils();
|
|
7396
|
+
var { transforms: transforms3 } = z5;
|
|
7082
7397
|
var sameMajorVersion = (a, b) => {
|
|
7083
7398
|
const majorA = a.split(".")[0];
|
|
7084
7399
|
const majorB = b.split(".")[0];
|
|
@@ -7804,8 +8119,10 @@ async function linkSdk(agentDir, botDir) {
|
|
|
7804
8119
|
// src/bot-generator/dev-id-manager.ts
|
|
7805
8120
|
import path32 from "path";
|
|
7806
8121
|
import fs14 from "fs/promises";
|
|
7807
|
-
import
|
|
8122
|
+
import createDebug3 from "debug";
|
|
7808
8123
|
import { Client as Client14 } from "@botpress/client";
|
|
8124
|
+
var debug3 = createDebug3("adk:dev-id-manager");
|
|
8125
|
+
|
|
7809
8126
|
class DevIdManager {
|
|
7810
8127
|
projectPath;
|
|
7811
8128
|
botProjectPath;
|
|
@@ -7840,11 +8157,26 @@ class DevIdManager {
|
|
|
7840
8157
|
}
|
|
7841
8158
|
async readProjectCache() {
|
|
7842
8159
|
try {
|
|
7843
|
-
|
|
7844
|
-
|
|
7845
|
-
|
|
8160
|
+
const content = await fs14.readFile(this.projectCachePath, "utf-8");
|
|
8161
|
+
if (content.trim().length === 0) {
|
|
8162
|
+
debug3("project cache is empty, treating as bootstrap state: %s", this.projectCachePath);
|
|
8163
|
+
return {};
|
|
8164
|
+
}
|
|
8165
|
+
const parsed = JSON.parse(content);
|
|
8166
|
+
if (!isProjectCache(parsed)) {
|
|
8167
|
+
debug3("project cache contains unexpected JSON type, treating as bootstrap state: %s", this.projectCachePath);
|
|
8168
|
+
return {};
|
|
7846
8169
|
}
|
|
8170
|
+
return parsed;
|
|
7847
8171
|
} catch (error) {
|
|
8172
|
+
if (isMissingFileError(error)) {
|
|
8173
|
+
debug3("project cache missing, treating as bootstrap state: %s", this.projectCachePath);
|
|
8174
|
+
return {};
|
|
8175
|
+
}
|
|
8176
|
+
if (error instanceof SyntaxError) {
|
|
8177
|
+
debug3("project cache contains transient invalid JSON, treating as bootstrap state: %s (%O)", this.projectCachePath, error);
|
|
8178
|
+
return {};
|
|
8179
|
+
}
|
|
7848
8180
|
console.error("Error reading project.cache.json:", error);
|
|
7849
8181
|
}
|
|
7850
8182
|
return {};
|
|
@@ -7864,7 +8196,7 @@ class DevIdManager {
|
|
|
7864
8196
|
if (!project.agentInfo) {
|
|
7865
8197
|
throw ValidationErrors.agentNotLinked();
|
|
7866
8198
|
}
|
|
7867
|
-
await project.
|
|
8199
|
+
await project.updateAgentLocalInfo({
|
|
7868
8200
|
devId: projectCache.devId
|
|
7869
8201
|
});
|
|
7870
8202
|
}
|
|
@@ -7891,18 +8223,24 @@ class DevIdManager {
|
|
|
7891
8223
|
const client = await this.getClient();
|
|
7892
8224
|
await client.getBot({ id: agentInfo.devId });
|
|
7893
8225
|
return true;
|
|
7894
|
-
} catch
|
|
8226
|
+
} catch {
|
|
7895
8227
|
return false;
|
|
7896
8228
|
}
|
|
7897
8229
|
}
|
|
7898
8230
|
return false;
|
|
7899
8231
|
}
|
|
7900
8232
|
}
|
|
8233
|
+
function isMissingFileError(error) {
|
|
8234
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
8235
|
+
}
|
|
8236
|
+
function isProjectCache(value) {
|
|
8237
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8238
|
+
}
|
|
7901
8239
|
|
|
7902
8240
|
// src/bot-generator/integration-sync.ts
|
|
7903
8241
|
import path33 from "path";
|
|
7904
8242
|
import fs15 from "fs/promises";
|
|
7905
|
-
import { existsSync as
|
|
8243
|
+
import { existsSync as existsSync4 } from "fs";
|
|
7906
8244
|
class IntegrationSync {
|
|
7907
8245
|
projectPath;
|
|
7908
8246
|
botProjectPath;
|
|
@@ -7942,12 +8280,12 @@ class IntegrationSync {
|
|
|
7942
8280
|
}
|
|
7943
8281
|
async isIntegrationSynced(integration) {
|
|
7944
8282
|
const targetFolder = path33.join(this.bpModulesPath, `integration_${integration.alias}`);
|
|
7945
|
-
if (!
|
|
8283
|
+
if (!existsSync4(targetFolder)) {
|
|
7946
8284
|
return false;
|
|
7947
8285
|
}
|
|
7948
8286
|
try {
|
|
7949
8287
|
const indexPath = path33.join(targetFolder, "index.ts");
|
|
7950
|
-
if (!
|
|
8288
|
+
if (!existsSync4(indexPath)) {
|
|
7951
8289
|
return false;
|
|
7952
8290
|
}
|
|
7953
8291
|
const indexContent = await fs15.readFile(indexPath, "utf-8");
|
|
@@ -7980,17 +8318,17 @@ class IntegrationSync {
|
|
|
7980
8318
|
async renameIntegrationFolder(integration) {
|
|
7981
8319
|
const sourceFolder = path33.join(this.bpModulesPath, integration.name.replace("/", "-"));
|
|
7982
8320
|
const targetFolder = path33.join(this.bpModulesPath, `integration_${integration.alias}`);
|
|
7983
|
-
if (!
|
|
8321
|
+
if (!existsSync4(sourceFolder)) {
|
|
7984
8322
|
throw new Error(`Integration folder not found: ${sourceFolder}`);
|
|
7985
8323
|
}
|
|
7986
|
-
if (
|
|
8324
|
+
if (existsSync4(targetFolder)) {
|
|
7987
8325
|
await fs15.rm(targetFolder, { recursive: true, force: true });
|
|
7988
8326
|
}
|
|
7989
8327
|
await fs15.rename(sourceFolder, targetFolder);
|
|
7990
8328
|
}
|
|
7991
8329
|
async removeIntegrationFolder(alias) {
|
|
7992
8330
|
const targetFolder = path33.join(this.bpModulesPath, `integration_${alias}`);
|
|
7993
|
-
if (
|
|
8331
|
+
if (existsSync4(targetFolder)) {
|
|
7994
8332
|
await fs15.rm(targetFolder, { recursive: true, force: true });
|
|
7995
8333
|
}
|
|
7996
8334
|
}
|
|
@@ -8025,7 +8363,7 @@ class IntegrationSync {
|
|
|
8025
8363
|
// src/bot-generator/interface-sync.ts
|
|
8026
8364
|
import path34 from "path";
|
|
8027
8365
|
import fs16 from "fs/promises";
|
|
8028
|
-
import { existsSync as
|
|
8366
|
+
import { existsSync as existsSync5 } from "fs";
|
|
8029
8367
|
init_constants();
|
|
8030
8368
|
class InterfaceSync {
|
|
8031
8369
|
projectPath;
|
|
@@ -8053,12 +8391,12 @@ class InterfaceSync {
|
|
|
8053
8391
|
}
|
|
8054
8392
|
async isInterfaceSynced(interfaceInfo) {
|
|
8055
8393
|
const targetFolder = path34.join(this.bpModulesPath, `interface_${pascalCase(interfaceInfo.alias)}`);
|
|
8056
|
-
if (!
|
|
8394
|
+
if (!existsSync5(targetFolder)) {
|
|
8057
8395
|
return false;
|
|
8058
8396
|
}
|
|
8059
8397
|
try {
|
|
8060
8398
|
const indexPath = path34.join(targetFolder, "index.ts");
|
|
8061
|
-
if (!
|
|
8399
|
+
if (!existsSync5(indexPath)) {
|
|
8062
8400
|
return false;
|
|
8063
8401
|
}
|
|
8064
8402
|
const indexContent = await fs16.readFile(indexPath, "utf-8");
|
|
@@ -8105,17 +8443,17 @@ class InterfaceSync {
|
|
|
8105
8443
|
async renameInterfaceFolder(interfaceInfo) {
|
|
8106
8444
|
const sourceFolder = path34.join(this.bpModulesPath, interfaceInfo.name);
|
|
8107
8445
|
const targetFolder = path34.join(this.bpModulesPath, `interface_${pascalCase(interfaceInfo.alias)}`);
|
|
8108
|
-
if (!
|
|
8446
|
+
if (!existsSync5(sourceFolder)) {
|
|
8109
8447
|
throw new Error(`Interface folder not found: ${sourceFolder}`);
|
|
8110
8448
|
}
|
|
8111
|
-
if (
|
|
8449
|
+
if (existsSync5(targetFolder)) {
|
|
8112
8450
|
await fs16.rm(targetFolder, { recursive: true, force: true });
|
|
8113
8451
|
}
|
|
8114
8452
|
await fs16.rename(sourceFolder, targetFolder);
|
|
8115
8453
|
}
|
|
8116
8454
|
async removeInterfaceFolder(alias) {
|
|
8117
8455
|
const targetFolder = path34.join(this.bpModulesPath, `interface_${pascalCase(alias)}`);
|
|
8118
|
-
if (
|
|
8456
|
+
if (existsSync5(targetFolder)) {
|
|
8119
8457
|
await fs16.rm(targetFolder, { recursive: true, force: true });
|
|
8120
8458
|
}
|
|
8121
8459
|
}
|
|
@@ -8150,7 +8488,7 @@ class InterfaceSync {
|
|
|
8150
8488
|
// src/bot-generator/plugin-sync.ts
|
|
8151
8489
|
import path35 from "path";
|
|
8152
8490
|
import fs17 from "fs/promises";
|
|
8153
|
-
import { existsSync as
|
|
8491
|
+
import { existsSync as existsSync6 } from "fs";
|
|
8154
8492
|
class PluginSync {
|
|
8155
8493
|
projectPath;
|
|
8156
8494
|
botProjectPath;
|
|
@@ -8182,12 +8520,12 @@ class PluginSync {
|
|
|
8182
8520
|
}
|
|
8183
8521
|
async isPluginSynced(plugin) {
|
|
8184
8522
|
const targetFolder = path35.join(this.bpModulesPath, `plugin_${plugin.alias}`);
|
|
8185
|
-
if (!
|
|
8523
|
+
if (!existsSync6(targetFolder)) {
|
|
8186
8524
|
return false;
|
|
8187
8525
|
}
|
|
8188
8526
|
try {
|
|
8189
8527
|
const indexPath = path35.join(targetFolder, "index.ts");
|
|
8190
|
-
if (!
|
|
8528
|
+
if (!existsSync6(indexPath)) {
|
|
8191
8529
|
return false;
|
|
8192
8530
|
}
|
|
8193
8531
|
const indexContent = await fs17.readFile(indexPath, "utf-8");
|
|
@@ -8220,17 +8558,17 @@ class PluginSync {
|
|
|
8220
8558
|
async renamePluginFolder(plugin) {
|
|
8221
8559
|
const sourceFolder = path35.join(this.bpModulesPath, plugin.name.replace("/", "-"));
|
|
8222
8560
|
const targetFolder = path35.join(this.bpModulesPath, `plugin_${plugin.alias}`);
|
|
8223
|
-
if (!
|
|
8561
|
+
if (!existsSync6(sourceFolder)) {
|
|
8224
8562
|
throw new Error(`Plugin folder not found: ${sourceFolder}`);
|
|
8225
8563
|
}
|
|
8226
|
-
if (
|
|
8564
|
+
if (existsSync6(targetFolder)) {
|
|
8227
8565
|
await fs17.rm(targetFolder, { recursive: true, force: true });
|
|
8228
8566
|
}
|
|
8229
8567
|
await fs17.rename(sourceFolder, targetFolder);
|
|
8230
8568
|
}
|
|
8231
8569
|
async removePluginFolder(alias) {
|
|
8232
8570
|
const targetFolder = path35.join(this.bpModulesPath, `plugin_${alias}`);
|
|
8233
|
-
if (
|
|
8571
|
+
if (existsSync6(targetFolder)) {
|
|
8234
8572
|
await fs17.rm(targetFolder, { recursive: true, force: true });
|
|
8235
8573
|
}
|
|
8236
8574
|
}
|
|
@@ -8264,10 +8602,11 @@ class PluginSync {
|
|
|
8264
8602
|
|
|
8265
8603
|
// src/bot-generator/generator.ts
|
|
8266
8604
|
init_utils();
|
|
8267
|
-
import {
|
|
8605
|
+
import { z as z6 } from "@botpress/sdk";
|
|
8268
8606
|
init_constants();
|
|
8269
8607
|
import { BuiltInActions as BuiltInActions2, BuiltInWorkflows as BuiltInWorkflows4, Primitives as Primitives3 } from "@botpress/runtime/internal";
|
|
8270
8608
|
import { BUILT_IN_TAGS as BUILT_IN_TAGS2 } from "@botpress/runtime/definition";
|
|
8609
|
+
var { transforms: transforms4 } = z6;
|
|
8271
8610
|
var plural = (n, word) => `${n} ${word}${n === 1 ? "" : "s"}`;
|
|
8272
8611
|
function isBuiltinWorkflow3(name) {
|
|
8273
8612
|
return !!Object.values(BuiltInWorkflows4).find((x) => x.name === name);
|
|
@@ -8292,7 +8631,7 @@ class BotGenerator {
|
|
|
8292
8631
|
}
|
|
8293
8632
|
async listFilesRecursive(rootDir) {
|
|
8294
8633
|
try {
|
|
8295
|
-
if (!
|
|
8634
|
+
if (!existsSync7(rootDir))
|
|
8296
8635
|
return [];
|
|
8297
8636
|
const result = [];
|
|
8298
8637
|
const walk = async (dir, relativeBase) => {
|
|
@@ -8314,7 +8653,7 @@ class BotGenerator {
|
|
|
8314
8653
|
}
|
|
8315
8654
|
}
|
|
8316
8655
|
async removeEmptyDirectories(rootDir) {
|
|
8317
|
-
if (!
|
|
8656
|
+
if (!existsSync7(rootDir))
|
|
8318
8657
|
return;
|
|
8319
8658
|
const removeIfEmpty = async (dir) => {
|
|
8320
8659
|
const entries = await fs18.readdir(dir, { withFileTypes: true });
|
|
@@ -8520,7 +8859,7 @@ class BotGenerator {
|
|
|
8520
8859
|
const integrations = await manager3.loadIntegrations(project.dependencies || {});
|
|
8521
8860
|
const channels = [];
|
|
8522
8861
|
for (const integration of integrations.integrations) {
|
|
8523
|
-
if (integration.
|
|
8862
|
+
if (integration.definition) {
|
|
8524
8863
|
const alias = integration.alias;
|
|
8525
8864
|
for (const channelName of Object.keys(integration.definition.channels || {})) {
|
|
8526
8865
|
channels.push(`"${alias}.${channelName}"`);
|
|
@@ -8578,7 +8917,7 @@ declare module "@botpress/runtime/_types/state" {
|
|
|
8578
8917
|
const interfacesDir = path38.join(this.projectPath, ".adk", "interfaces");
|
|
8579
8918
|
const existingInterfaceFiles = await this.listFilesRecursive(interfacesDir);
|
|
8580
8919
|
const interfaces = await manager3.loadInterfaces(project.dependencies || {}).then((result) => result.interfaces.filter((int) => int.definition).map((x) => x.definition));
|
|
8581
|
-
const integrationsWithAlias = await integrationManager.loadIntegrations(project.dependencies || {}).then((result) => result.integrations.filter((int) => int.
|
|
8920
|
+
const integrationsWithAlias = await integrationManager.loadIntegrations(project.dependencies || {}).then((result) => result.integrations.filter((int) => int.definition).map((x) => ({ alias: x.alias, definition: x.definition })));
|
|
8582
8921
|
let imports = new Set;
|
|
8583
8922
|
let aliases = new Set;
|
|
8584
8923
|
let files = new Set;
|
|
@@ -8643,10 +8982,7 @@ declare module "@botpress/runtime/_types/state" {
|
|
|
8643
8982
|
const integrations = project.dependencies?.integrations || {};
|
|
8644
8983
|
const imports = [];
|
|
8645
8984
|
const integrationDefs = [];
|
|
8646
|
-
for (const [alias
|
|
8647
|
-
if (config.enabled === false) {
|
|
8648
|
-
continue;
|
|
8649
|
-
}
|
|
8985
|
+
for (const [alias] of Object.entries(integrations)) {
|
|
8650
8986
|
const normalizedAlias = getIntegrationAlias(alias);
|
|
8651
8987
|
imports.push(`import integration_${normalizedAlias} from "../bp_modules/integration_${normalizedAlias}";`);
|
|
8652
8988
|
integrationDefs.push(`"${alias}": integration_${normalizedAlias}`);
|
|
@@ -8748,21 +9084,21 @@ declare module "@botpress/runtime/_types/state" {
|
|
|
8748
9084
|
async generateBotDefinition() {
|
|
8749
9085
|
const project = await AgentProject.load(this.projectPath);
|
|
8750
9086
|
const integrations = project.integrations;
|
|
8751
|
-
const enabledIntegrations = integrations.filter((i) => i.enabled);
|
|
8752
9087
|
const isDeployOrBuild = this.adkCommand === "adk-deploy" || this.adkCommand === "adk-build";
|
|
8753
9088
|
const configTargetBotId = isDeployOrBuild ? project.agentInfo?.botId : undefined;
|
|
8754
9089
|
const serverConfigResult = await fetchServerIntegrationConfigs(project, configTargetBotId);
|
|
8755
|
-
this.reportServerConfigSync(serverConfigResult,
|
|
9090
|
+
this.reportServerConfigSync(serverConfigResult, integrations);
|
|
8756
9091
|
const imports = [];
|
|
8757
9092
|
const addIntegrations = [];
|
|
8758
|
-
for (const integration of
|
|
9093
|
+
for (const integration of integrations) {
|
|
8759
9094
|
const { alias, configurationType, config } = integration;
|
|
8760
9095
|
const importName = `integration_${getIntegrationAlias(alias)}`;
|
|
8761
9096
|
imports.push(`import ${importName} from "./bp_modules/${importName}";`);
|
|
8762
9097
|
const configType = configurationType && configurationType !== "default" ? `, configurationType: "${configurationType}"` : "";
|
|
8763
9098
|
const mergedConfig = mergeIntegrationConfig(serverConfigResult.configs[alias], config);
|
|
8764
9099
|
const configData = Object.keys(mergedConfig).length > 0 ? `, configuration: ${JSON.stringify(mergedConfig)}` : "";
|
|
8765
|
-
|
|
9100
|
+
const enabled = integration.enabled ?? serverConfigResult.enabledStates[alias] ?? false;
|
|
9101
|
+
addIntegrations.push(`bot.addIntegration(${importName}, { alias: "${alias}", enabled: ${enabled}${configType}${configData} });`);
|
|
8766
9102
|
}
|
|
8767
9103
|
const depRefErrors = PluginParser.validateDependencyReferences(project.dependencies || {});
|
|
8768
9104
|
if (depRefErrors.length > 0) {
|
|
@@ -9191,7 +9527,7 @@ export default bot;`;
|
|
|
9191
9527
|
async copyAssets() {
|
|
9192
9528
|
const assetsPath = path38.join(this.projectPath, "assets");
|
|
9193
9529
|
const targetPath = path38.join(this.outputPath, "assets");
|
|
9194
|
-
if (
|
|
9530
|
+
if (existsSync7(assetsPath)) {
|
|
9195
9531
|
await fs18.mkdir(targetPath, { recursive: true });
|
|
9196
9532
|
await this.copyDirectory(assetsPath, targetPath);
|
|
9197
9533
|
}
|
|
@@ -9281,7 +9617,9 @@ export default bot;`;
|
|
|
9281
9617
|
}
|
|
9282
9618
|
{
|
|
9283
9619
|
const dest = path38.join(srcDir, "triggers.ts");
|
|
9284
|
-
const {
|
|
9620
|
+
const {
|
|
9621
|
+
z: { transforms: transforms5 }
|
|
9622
|
+
} = await import("@botpress/sdk");
|
|
9285
9623
|
const imports = new Map;
|
|
9286
9624
|
const exports = new Set;
|
|
9287
9625
|
const payloadTypes = {};
|
|
@@ -9527,7 +9865,7 @@ export default bot;`;
|
|
|
9527
9865
|
}
|
|
9528
9866
|
async copyAssetsRuntime() {
|
|
9529
9867
|
const assetsRuntimePath = path38.join(this.projectPath, ".adk", "assets-runtime.ts");
|
|
9530
|
-
if (
|
|
9868
|
+
if (existsSync7(assetsRuntimePath)) {
|
|
9531
9869
|
const content = await fs18.readFile(assetsRuntimePath, "utf-8");
|
|
9532
9870
|
await createFile(path38.join(this.outputPath, "src", "assets-runtime.ts"), await formatCode(content));
|
|
9533
9871
|
}
|
|
@@ -9569,7 +9907,9 @@ async function generateBotProject(options) {
|
|
|
9569
9907
|
}
|
|
9570
9908
|
// src/tables/table-manager.ts
|
|
9571
9909
|
import { Client as Client15 } from "@botpress/client";
|
|
9572
|
-
import {
|
|
9910
|
+
import { z as z7 } from "@botpress/sdk";
|
|
9911
|
+
var { transforms: transforms5 } = z7;
|
|
9912
|
+
|
|
9573
9913
|
class TableManager {
|
|
9574
9914
|
client;
|
|
9575
9915
|
botId;
|
|
@@ -9600,13 +9940,14 @@ class TableManager {
|
|
|
9600
9940
|
}
|
|
9601
9941
|
getSchemaType(schema) {
|
|
9602
9942
|
if (schema.type) {
|
|
9603
|
-
|
|
9604
|
-
|
|
9943
|
+
const items = schema.items;
|
|
9944
|
+
if (schema.type === "array" && items?.type) {
|
|
9945
|
+
return `array<${items.type}>`;
|
|
9605
9946
|
}
|
|
9606
|
-
return schema.type;
|
|
9947
|
+
return String(schema.type);
|
|
9607
9948
|
}
|
|
9608
9949
|
if (schema.$ref) {
|
|
9609
|
-
return schema.$ref.split("/").pop() || "unknown";
|
|
9950
|
+
return String(schema.$ref).split("/").pop() || "unknown";
|
|
9610
9951
|
}
|
|
9611
9952
|
return "unknown";
|
|
9612
9953
|
}
|
|
@@ -9617,8 +9958,8 @@ class TableManager {
|
|
|
9617
9958
|
} else if (Math.abs(oldPosition - newPosition) <= 1) {
|
|
9618
9959
|
score += 1;
|
|
9619
9960
|
}
|
|
9620
|
-
const oldDesc = (oldSchema?.description || "").toLowerCase();
|
|
9621
|
-
const newDesc = (newSchema?.description || "").toLowerCase();
|
|
9961
|
+
const oldDesc = String(oldSchema?.description || "").toLowerCase();
|
|
9962
|
+
const newDesc = String(newSchema?.description || "").toLowerCase();
|
|
9622
9963
|
if (oldDesc && newDesc && oldDesc === newDesc) {
|
|
9623
9964
|
score += 5;
|
|
9624
9965
|
} else if (oldDesc && newDesc && oldDesc.length > 5 && newDesc.length > 5) {
|
|
@@ -9633,8 +9974,10 @@ class TableManager {
|
|
|
9633
9974
|
}
|
|
9634
9975
|
}
|
|
9635
9976
|
}
|
|
9636
|
-
const
|
|
9637
|
-
const
|
|
9977
|
+
const oldType = oldSchema?.type;
|
|
9978
|
+
const newType = newSchema?.type;
|
|
9979
|
+
const oldOptional = typeof oldType === "string" && oldType.includes("null") || oldSchema?.nullable === true;
|
|
9980
|
+
const newOptional = typeof newType === "string" && newType.includes("null") || newSchema?.nullable === true;
|
|
9638
9981
|
if (oldOptional === newOptional) {
|
|
9639
9982
|
score += 1;
|
|
9640
9983
|
}
|
|
@@ -10586,6 +10929,7 @@ class KnowledgeManager {
|
|
|
10586
10929
|
const sourcesToSync = options.force ? item.sources || [] : (item.sources || []).filter((s) => s.needsSync);
|
|
10587
10930
|
const directorySourcesToSync = sourcesToSync.filter((s) => s.dsType === "document");
|
|
10588
10931
|
const websiteSourcesToSync = sourcesToSync.filter((s) => s.dsType === "web-page");
|
|
10932
|
+
let currentTags = { ...remoteKb.tags ?? {} };
|
|
10589
10933
|
for (const sourceStatus of directorySourcesToSync) {
|
|
10590
10934
|
const source = kbRef.definition.sources?.find((s) => s.id === sourceStatus.dsId);
|
|
10591
10935
|
if (!source || !DataSource.isDirectory(source))
|
|
@@ -10598,27 +10942,52 @@ class KnowledgeManager {
|
|
|
10598
10942
|
syncOutput.deleted.push(...sourceOutput.deleted);
|
|
10599
10943
|
syncOutput.errors.push(...sourceOutput.errors);
|
|
10600
10944
|
const sourceHash = await this.computeDirectorySourceHash(source.directoryPath, source.filterFn);
|
|
10601
|
-
await this.updateSourceHash(remoteKb.id, item.kb.name, source.id, sourceHash,
|
|
10945
|
+
await this.updateSourceHash(remoteKb.id, item.kb.name, source.id, sourceHash, currentTags);
|
|
10946
|
+
currentTags = {
|
|
10947
|
+
...currentTags,
|
|
10948
|
+
[sourceTag(source.id, "hash")]: sourceHash,
|
|
10949
|
+
[sourceTag(source.id, "lastupdatedat")]: new Date().toISOString()
|
|
10950
|
+
};
|
|
10602
10951
|
}
|
|
10603
|
-
|
|
10952
|
+
for (const sourceStatus of websiteSourcesToSync) {
|
|
10953
|
+
const source = kbRef.definition.sources?.find((s) => s.id === sourceStatus.dsId);
|
|
10954
|
+
if (!source || !DataSource.isWebsite(source))
|
|
10955
|
+
continue;
|
|
10956
|
+
const config = source.getConfig();
|
|
10957
|
+
if (config.mode === "website") {
|
|
10958
|
+
console.warn(` ⚠️ Skipping website source "${source.id}": website mode requires browser integration for URL discovery. Use WebsiteSource.fromSitemap() instead.`);
|
|
10959
|
+
continue;
|
|
10960
|
+
}
|
|
10961
|
+
if (config.fetchStrategy === "integration:browser") {
|
|
10962
|
+
console.warn(` ⚠️ Skipping website source "${source.id}": integration:browser fetch strategy requires browser integration. Use fetch: 'node:fetch' or a custom fetch function instead.`);
|
|
10963
|
+
continue;
|
|
10964
|
+
}
|
|
10965
|
+
await this.deleteLegacyWebsiteFiles(item.kb.name, sourceStatus.dsId);
|
|
10604
10966
|
try {
|
|
10605
|
-
|
|
10606
|
-
|
|
10607
|
-
|
|
10608
|
-
|
|
10609
|
-
|
|
10610
|
-
|
|
10611
|
-
|
|
10612
|
-
|
|
10613
|
-
|
|
10614
|
-
|
|
10615
|
-
|
|
10616
|
-
|
|
10617
|
-
|
|
10618
|
-
|
|
10967
|
+
this.assertBotId("sync website source");
|
|
10968
|
+
console.log(` Syncing website source "${source.id}" locally...`);
|
|
10969
|
+
const sourceOutput = await source.syncDirect(client, this.botId, {
|
|
10970
|
+
dsId: source.id,
|
|
10971
|
+
kbName: item.kb.name,
|
|
10972
|
+
kbId: remoteKb.id,
|
|
10973
|
+
force: options.force || false
|
|
10974
|
+
});
|
|
10975
|
+
syncOutput.processed += sourceOutput.processed;
|
|
10976
|
+
syncOutput.added.push(...sourceOutput.added);
|
|
10977
|
+
syncOutput.updated.push(...sourceOutput.updated);
|
|
10978
|
+
syncOutput.deleted.push(...sourceOutput.deleted);
|
|
10979
|
+
syncOutput.errors.push(...sourceOutput.errors.map((e) => typeof e === "string" ? { file: source.id, error: e } : e));
|
|
10980
|
+
const configHash = this.computeConfigHash(config);
|
|
10981
|
+
await this.updateSourceHash(remoteKb.id, item.kb.name, source.id, configHash, currentTags);
|
|
10982
|
+
currentTags = {
|
|
10983
|
+
...currentTags,
|
|
10984
|
+
[sourceTag(source.id, "hash")]: configHash,
|
|
10985
|
+
[sourceTag(source.id, "lastupdatedat")]: new Date().toISOString()
|
|
10986
|
+
};
|
|
10619
10987
|
} catch (error) {
|
|
10620
10988
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
10621
|
-
console.
|
|
10989
|
+
console.error(` Failed to sync website source "${source.id}": ${errorMsg}`);
|
|
10990
|
+
syncOutput.errors.push({ file: source.id, error: errorMsg });
|
|
10622
10991
|
}
|
|
10623
10992
|
}
|
|
10624
10993
|
result.synced.push({ name: item.kb.name, result: syncOutput });
|
|
@@ -10762,7 +11131,7 @@ class KnowledgeManager {
|
|
|
10762
11131
|
}
|
|
10763
11132
|
}
|
|
10764
11133
|
// src/knowledge/sync-formatter.ts
|
|
10765
|
-
import { readFileSync } from "fs";
|
|
11134
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
10766
11135
|
import { join as join8 } from "path";
|
|
10767
11136
|
var getAdkVersion = () => {
|
|
10768
11137
|
try {
|
|
@@ -10771,7 +11140,7 @@ var getAdkVersion = () => {
|
|
|
10771
11140
|
} catch {
|
|
10772
11141
|
try {
|
|
10773
11142
|
const adkPackagePath = join8(process.cwd(), "node_modules/@botpress/adk/package.json");
|
|
10774
|
-
const pkg = JSON.parse(
|
|
11143
|
+
const pkg = JSON.parse(readFileSync3(adkPackagePath, "utf-8"));
|
|
10775
11144
|
return pkg.version;
|
|
10776
11145
|
} catch {
|
|
10777
11146
|
return "unknown";
|
|
@@ -10862,10 +11231,10 @@ class KBSyncFormatter {
|
|
|
10862
11231
|
}
|
|
10863
11232
|
}
|
|
10864
11233
|
// src/file-watcher/watcher.ts
|
|
10865
|
-
import { watch as watch2, readdirSync as readdirSync2 } from "fs";
|
|
11234
|
+
import { watch as watch2, readdirSync as readdirSync2, statSync } from "fs";
|
|
10866
11235
|
import { EventEmitter as EventEmitter3 } from "events";
|
|
10867
11236
|
import { join as join9, relative as relative3 } from "path";
|
|
10868
|
-
import { existsSync as
|
|
11237
|
+
import { existsSync as existsSync8 } from "fs";
|
|
10869
11238
|
|
|
10870
11239
|
class FileWatcher2 extends EventEmitter3 {
|
|
10871
11240
|
projectPath;
|
|
@@ -10883,12 +11252,12 @@ class FileWatcher2 extends EventEmitter3 {
|
|
|
10883
11252
|
const rootFiles = ["package.json", "agent.json", "agent.config.ts"];
|
|
10884
11253
|
for (const file of rootFiles) {
|
|
10885
11254
|
const filePath = join9(this.projectPath, file);
|
|
10886
|
-
if (
|
|
11255
|
+
if (existsSync8(filePath)) {
|
|
10887
11256
|
this.watchFile(filePath);
|
|
10888
11257
|
}
|
|
10889
11258
|
}
|
|
10890
11259
|
const srcPath = join9(this.projectPath, "src");
|
|
10891
|
-
if (
|
|
11260
|
+
if (existsSync8(srcPath)) {
|
|
10892
11261
|
this.initializeDirectoryState(srcPath);
|
|
10893
11262
|
this.watchDirectory(srcPath);
|
|
10894
11263
|
}
|
|
@@ -10904,7 +11273,7 @@ class FileWatcher2 extends EventEmitter3 {
|
|
|
10904
11273
|
this.updateFileState(fullPath);
|
|
10905
11274
|
}
|
|
10906
11275
|
}
|
|
10907
|
-
} catch
|
|
11276
|
+
} catch {}
|
|
10908
11277
|
}
|
|
10909
11278
|
watchFile(filePath) {
|
|
10910
11279
|
if (this.watchers.has(filePath)) {
|
|
@@ -10937,7 +11306,13 @@ class FileWatcher2 extends EventEmitter3 {
|
|
|
10937
11306
|
}
|
|
10938
11307
|
}
|
|
10939
11308
|
handleFileChange(filePath) {
|
|
10940
|
-
|
|
11309
|
+
try {
|
|
11310
|
+
if (existsSync8(filePath) && statSync(filePath).isDirectory()) {
|
|
11311
|
+
this.scanDirectoryForChanges(filePath);
|
|
11312
|
+
return;
|
|
11313
|
+
}
|
|
11314
|
+
} catch {}
|
|
11315
|
+
const fileExists = existsSync8(filePath);
|
|
10941
11316
|
const previousState = this.fileStates.get(filePath);
|
|
10942
11317
|
let changeType;
|
|
10943
11318
|
if (!fileExists && previousState !== undefined) {
|
|
@@ -10957,12 +11332,7 @@ class FileWatcher2 extends EventEmitter3 {
|
|
|
10957
11332
|
path: relativePath,
|
|
10958
11333
|
type: changeType
|
|
10959
11334
|
});
|
|
10960
|
-
|
|
10961
|
-
clearTimeout(this.debounceTimer);
|
|
10962
|
-
}
|
|
10963
|
-
this.debounceTimer = setTimeout(() => {
|
|
10964
|
-
this.emitPendingChanges();
|
|
10965
|
-
}, this.debounceMs);
|
|
11335
|
+
this.scheduleDebouncedEmit();
|
|
10966
11336
|
}
|
|
10967
11337
|
emitPendingChanges() {
|
|
10968
11338
|
if (this.pendingChanges.size === 0) {
|
|
@@ -10976,8 +11346,46 @@ class FileWatcher2 extends EventEmitter3 {
|
|
|
10976
11346
|
};
|
|
10977
11347
|
this.emit("change", event);
|
|
10978
11348
|
}
|
|
11349
|
+
scanDirectoryForChanges(dirPath) {
|
|
11350
|
+
try {
|
|
11351
|
+
const entries = readdirSync2(dirPath, { withFileTypes: true });
|
|
11352
|
+
const currentFiles = new Set;
|
|
11353
|
+
for (const entry of entries) {
|
|
11354
|
+
const fullPath = join9(dirPath, entry.name);
|
|
11355
|
+
if (entry.isFile()) {
|
|
11356
|
+
currentFiles.add(fullPath);
|
|
11357
|
+
if (!this.fileStates.has(fullPath)) {
|
|
11358
|
+
this.updateFileState(fullPath);
|
|
11359
|
+
const relativePath = relative3(this.projectPath, fullPath);
|
|
11360
|
+
this.pendingChanges.set(relativePath, { path: relativePath, type: "added" });
|
|
11361
|
+
this.scheduleDebouncedEmit();
|
|
11362
|
+
}
|
|
11363
|
+
} else if (entry.isDirectory()) {
|
|
11364
|
+
this.scanDirectoryForChanges(fullPath);
|
|
11365
|
+
}
|
|
11366
|
+
}
|
|
11367
|
+
for (const [trackedPath] of this.fileStates) {
|
|
11368
|
+
if (trackedPath.startsWith(dirPath) && !trackedPath.includes("/", dirPath.length + 1)) {
|
|
11369
|
+
if (!currentFiles.has(trackedPath)) {
|
|
11370
|
+
this.fileStates.delete(trackedPath);
|
|
11371
|
+
const relativePath = relative3(this.projectPath, trackedPath);
|
|
11372
|
+
this.pendingChanges.set(relativePath, { path: relativePath, type: "deleted" });
|
|
11373
|
+
this.scheduleDebouncedEmit();
|
|
11374
|
+
}
|
|
11375
|
+
}
|
|
11376
|
+
}
|
|
11377
|
+
} catch {}
|
|
11378
|
+
}
|
|
11379
|
+
scheduleDebouncedEmit() {
|
|
11380
|
+
if (this.debounceTimer) {
|
|
11381
|
+
clearTimeout(this.debounceTimer);
|
|
11382
|
+
}
|
|
11383
|
+
this.debounceTimer = setTimeout(() => {
|
|
11384
|
+
this.emitPendingChanges();
|
|
11385
|
+
}, this.debounceMs);
|
|
11386
|
+
}
|
|
10979
11387
|
updateFileState(filePath) {
|
|
10980
|
-
if (
|
|
11388
|
+
if (existsSync8(filePath)) {
|
|
10981
11389
|
this.fileStates.set(filePath, Date.now());
|
|
10982
11390
|
}
|
|
10983
11391
|
}
|
|
@@ -11059,7 +11467,7 @@ class AgentConfigSyncManager {
|
|
|
11059
11467
|
}
|
|
11060
11468
|
|
|
11061
11469
|
// src/preflight/formatter.ts
|
|
11062
|
-
import { readFileSync as
|
|
11470
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
11063
11471
|
import { join as join10 } from "path";
|
|
11064
11472
|
var getAdkVersion2 = () => {
|
|
11065
11473
|
try {
|
|
@@ -11068,7 +11476,7 @@ var getAdkVersion2 = () => {
|
|
|
11068
11476
|
} catch {
|
|
11069
11477
|
try {
|
|
11070
11478
|
const adkPackagePath = join10(process.cwd(), "node_modules/@botpress/adk/package.json");
|
|
11071
|
-
const pkg = JSON.parse(
|
|
11479
|
+
const pkg = JSON.parse(readFileSync4(adkPackagePath, "utf-8"));
|
|
11072
11480
|
return pkg.version;
|
|
11073
11481
|
} catch {
|
|
11074
11482
|
return "unknown";
|
|
@@ -11250,9 +11658,6 @@ class PreflightChecker {
|
|
|
11250
11658
|
const toRemove = [];
|
|
11251
11659
|
const toUpdate = [];
|
|
11252
11660
|
for (const result of results) {
|
|
11253
|
-
if (result.desiredInstallStatus === "disabled" && !result.needsRemoval && !result.needsConfiguration) {
|
|
11254
|
-
continue;
|
|
11255
|
-
}
|
|
11256
11661
|
if (result.needsInstall) {
|
|
11257
11662
|
toInstall.push({
|
|
11258
11663
|
alias: result.alias,
|
|
@@ -11372,7 +11777,7 @@ class PreflightChecker {
|
|
|
11372
11777
|
}
|
|
11373
11778
|
// src/runner/script-runner.ts
|
|
11374
11779
|
import dedent2 from "dedent";
|
|
11375
|
-
import { existsSync as
|
|
11780
|
+
import { existsSync as existsSync9 } from "fs";
|
|
11376
11781
|
import fs20 from "fs/promises";
|
|
11377
11782
|
import path41 from "path";
|
|
11378
11783
|
import { spawn } from "child_process";
|
|
@@ -11410,7 +11815,7 @@ class ScriptRunner {
|
|
|
11410
11815
|
const botPath = path41.join(this.projectPath, ".adk", "bot");
|
|
11411
11816
|
const runnerPath = path41.join(botPath, "src", "script-runner.ts");
|
|
11412
11817
|
const botpressTypesPath = path41.join(botPath, ".botpress", "implementation", "index.ts");
|
|
11413
|
-
const needsRegenerate = this.forceRegenerate || !
|
|
11818
|
+
const needsRegenerate = this.forceRegenerate || !existsSync9(runnerPath) || !existsSync9(botpressTypesPath);
|
|
11414
11819
|
if (needsRegenerate) {
|
|
11415
11820
|
try {
|
|
11416
11821
|
await generateAssetsTypes(project.path);
|
|
@@ -11568,7 +11973,7 @@ class ScriptRunner {
|
|
|
11568
11973
|
initialize: async () => {
|
|
11569
11974
|
const botModule = await import(runtimePath);
|
|
11570
11975
|
const runtimeModule = await import("@botpress/runtime/runtime");
|
|
11571
|
-
const { Autonomous } = await import("@botpress/runtime");
|
|
11976
|
+
const { Autonomous: Autonomous2 } = await import("@botpress/runtime");
|
|
11572
11977
|
const { context, agentRegistry } = runtimeModule;
|
|
11573
11978
|
const { Client: Client18 } = await import("@botpress/client");
|
|
11574
11979
|
const { BotSpecificClient, BotLogger } = await import("@botpress/sdk");
|
|
@@ -11590,7 +11995,7 @@ class ScriptRunner {
|
|
|
11590
11995
|
botId,
|
|
11591
11996
|
client,
|
|
11592
11997
|
cognitive,
|
|
11593
|
-
citations: new
|
|
11998
|
+
citations: new Autonomous2.CitationsManager,
|
|
11594
11999
|
logger,
|
|
11595
12000
|
configuration: configuration ?? {},
|
|
11596
12001
|
integrations: agentRegistry.integrations,
|
|
@@ -11606,7 +12011,7 @@ class ScriptRunner {
|
|
|
11606
12011
|
async run(scriptPath, options = {}) {
|
|
11607
12012
|
const { botPath, runnerPath, project } = await this.prepare();
|
|
11608
12013
|
const absoluteScriptPath = path41.isAbsolute(scriptPath) ? scriptPath : path41.resolve(this.projectPath, scriptPath);
|
|
11609
|
-
if (!
|
|
12014
|
+
if (!existsSync9(absoluteScriptPath)) {
|
|
11610
12015
|
throw new Error(`Script not found: ${absoluteScriptPath}`);
|
|
11611
12016
|
}
|
|
11612
12017
|
const botId = this.prod ? project.agentInfo?.botId : project.agentInfo?.devId || project.agentInfo?.botId;
|
|
@@ -11695,42 +12100,78 @@ Either run from within an agent project directory, or provide projectPath explic
|
|
|
11695
12100
|
return runner.setupTestRuntime({ env: options.env });
|
|
11696
12101
|
}
|
|
11697
12102
|
// src/eval/types.ts
|
|
11698
|
-
|
|
11699
|
-
|
|
12103
|
+
class Eval {
|
|
12104
|
+
name;
|
|
12105
|
+
description;
|
|
12106
|
+
tags;
|
|
12107
|
+
type;
|
|
12108
|
+
setup;
|
|
12109
|
+
conversation;
|
|
12110
|
+
outcome;
|
|
12111
|
+
options;
|
|
12112
|
+
constructor(def) {
|
|
12113
|
+
this.name = def.name;
|
|
12114
|
+
this.description = def.description;
|
|
12115
|
+
this.tags = def.tags;
|
|
12116
|
+
this.type = def.type;
|
|
12117
|
+
this.setup = def.setup;
|
|
12118
|
+
this.conversation = def.conversation;
|
|
12119
|
+
this.outcome = def.outcome;
|
|
12120
|
+
this.options = def.options;
|
|
12121
|
+
}
|
|
11700
12122
|
}
|
|
11701
12123
|
// src/eval/loader.ts
|
|
11702
|
-
import { readdirSync as readdirSync3, existsSync as
|
|
12124
|
+
import { readdirSync as readdirSync3, existsSync as existsSync10 } from "fs";
|
|
11703
12125
|
import { resolve as resolve3 } from "path";
|
|
12126
|
+
function isEvalDefinition(value) {
|
|
12127
|
+
return value !== null && typeof value === "object" && typeof value.name === "string" && value.name !== "" && Array.isArray(value.conversation);
|
|
12128
|
+
}
|
|
11704
12129
|
async function loadEvalFile(filePath) {
|
|
11705
12130
|
const absPath = resolve3(filePath);
|
|
11706
12131
|
const mod = await import(absPath);
|
|
11707
|
-
const
|
|
11708
|
-
|
|
11709
|
-
|
|
12132
|
+
const results = [];
|
|
12133
|
+
for (const [key, value] of Object.entries(mod)) {
|
|
12134
|
+
if (key === "__esModule")
|
|
12135
|
+
continue;
|
|
12136
|
+
if (value instanceof Eval || isEvalDefinition(value)) {
|
|
12137
|
+
results.push(value);
|
|
12138
|
+
}
|
|
12139
|
+
}
|
|
12140
|
+
if (results.length === 0) {
|
|
12141
|
+
throw new Error(`Invalid eval file ${filePath}: no valid evals found. Export one or more \`new Eval({...})\` instances (as default or named exports).`);
|
|
11710
12142
|
}
|
|
11711
|
-
return
|
|
12143
|
+
return results;
|
|
11712
12144
|
}
|
|
11713
12145
|
async function loadEvalsFromDir(dirPath) {
|
|
11714
12146
|
const absDir = resolve3(dirPath);
|
|
11715
|
-
if (!
|
|
12147
|
+
if (!existsSync10(absDir)) {
|
|
11716
12148
|
return [];
|
|
11717
12149
|
}
|
|
11718
12150
|
const files = readdirSync3(absDir).filter((f) => f.endsWith(".eval.ts"));
|
|
11719
12151
|
const evals = [];
|
|
11720
12152
|
for (const f of files) {
|
|
11721
|
-
|
|
12153
|
+
const defs = await loadEvalFile(`${absDir}/${f}`);
|
|
12154
|
+
evals.push(...defs);
|
|
12155
|
+
}
|
|
12156
|
+
const seen = new Set;
|
|
12157
|
+
for (const e of evals) {
|
|
12158
|
+
if (seen.has(e.name)) {
|
|
12159
|
+
throw new Error(`Duplicate eval name "${e.name}" found in ${dirPath}`);
|
|
12160
|
+
}
|
|
12161
|
+
seen.add(e.name);
|
|
11722
12162
|
}
|
|
11723
12163
|
return evals;
|
|
11724
12164
|
}
|
|
11725
12165
|
async function loadEvalByName(dirPath, name) {
|
|
11726
12166
|
const absDir = resolve3(dirPath);
|
|
11727
|
-
if (!
|
|
12167
|
+
if (!existsSync10(absDir))
|
|
11728
12168
|
return null;
|
|
11729
12169
|
const files = readdirSync3(absDir).filter((f) => f.endsWith(".eval.ts"));
|
|
11730
12170
|
for (const f of files) {
|
|
11731
|
-
const
|
|
11732
|
-
|
|
11733
|
-
|
|
12171
|
+
const defs = await loadEvalFile(`${absDir}/${f}`);
|
|
12172
|
+
const found = defs.find((d) => d.name === name);
|
|
12173
|
+
if (found)
|
|
12174
|
+
return found;
|
|
11734
12175
|
}
|
|
11735
12176
|
return null;
|
|
11736
12177
|
}
|
|
@@ -11755,6 +12196,7 @@ function filterEvals(evals, filter) {
|
|
|
11755
12196
|
}
|
|
11756
12197
|
// src/eval/runner.ts
|
|
11757
12198
|
import { Client as BpClient2 } from "@botpress/client";
|
|
12199
|
+
import { BUILT_IN_STATES as BUILT_IN_STATES2 } from "@botpress/runtime/internal";
|
|
11758
12200
|
|
|
11759
12201
|
// src/eval/client.ts
|
|
11760
12202
|
import { Client as BpClient } from "@botpress/client";
|
|
@@ -11775,20 +12217,21 @@ class ChatSession {
|
|
|
11775
12217
|
}
|
|
11776
12218
|
return this.client.user.id;
|
|
11777
12219
|
}
|
|
11778
|
-
async
|
|
12220
|
+
async ensureConversation() {
|
|
11779
12221
|
if (!this.client) {
|
|
11780
12222
|
throw new Error("ChatSession not connected. Call connect() first.");
|
|
11781
12223
|
}
|
|
11782
|
-
const { timeout = 30000, idleTimeout = 3000 } = options;
|
|
11783
12224
|
if (!this.conversationId) {
|
|
11784
12225
|
const conv = await this.client.createConversation({});
|
|
11785
12226
|
this.conversationId = conv.conversation.id;
|
|
12227
|
+
return conv.conversation.id;
|
|
11786
12228
|
}
|
|
11787
|
-
|
|
12229
|
+
return this.conversationId;
|
|
12230
|
+
}
|
|
12231
|
+
async _awaitResponses(conversationId, trigger, options = {}) {
|
|
12232
|
+
const { timeout = 30000, idleTimeout = 3000 } = options;
|
|
11788
12233
|
const responses = [];
|
|
11789
|
-
const listener = await this.client.listenConversation({
|
|
11790
|
-
id: conversationId
|
|
11791
|
-
});
|
|
12234
|
+
const listener = await this.client.listenConversation({ id: conversationId });
|
|
11792
12235
|
return new Promise((resolve4, reject) => {
|
|
11793
12236
|
let idleTimer = null;
|
|
11794
12237
|
let resolved = false;
|
|
@@ -11808,7 +12251,7 @@ class ChatSession {
|
|
|
11808
12251
|
};
|
|
11809
12252
|
const overallTimer = setTimeout(() => {
|
|
11810
12253
|
if (!resolved) {
|
|
11811
|
-
if (responses.length > 0) {
|
|
12254
|
+
if (responses.length > 0 || options.expectSilence) {
|
|
11812
12255
|
done();
|
|
11813
12256
|
} else {
|
|
11814
12257
|
resolved = true;
|
|
@@ -11831,10 +12274,7 @@ class ChatSession {
|
|
|
11831
12274
|
done();
|
|
11832
12275
|
}
|
|
11833
12276
|
});
|
|
11834
|
-
|
|
11835
|
-
conversationId,
|
|
11836
|
-
payload: { type: "text", text: message }
|
|
11837
|
-
}).then(() => {
|
|
12277
|
+
trigger().then(() => {
|
|
11838
12278
|
resetIdle();
|
|
11839
12279
|
}).catch((err) => {
|
|
11840
12280
|
clearTimeout(overallTimer);
|
|
@@ -11845,6 +12285,20 @@ class ChatSession {
|
|
|
11845
12285
|
});
|
|
11846
12286
|
});
|
|
11847
12287
|
}
|
|
12288
|
+
async sendMessage(message, options = {}) {
|
|
12289
|
+
if (!this.client) {
|
|
12290
|
+
throw new Error("ChatSession not connected. Call connect() first.");
|
|
12291
|
+
}
|
|
12292
|
+
const conversationId = await this.ensureConversation();
|
|
12293
|
+
return this._awaitResponses(conversationId, () => this.client.createMessage({ conversationId, payload: { type: "text", text: message } }), options);
|
|
12294
|
+
}
|
|
12295
|
+
async sendEvent(type, payload, options = {}) {
|
|
12296
|
+
if (!this.client) {
|
|
12297
|
+
throw new Error("ChatSession not connected. Call connect() first.");
|
|
12298
|
+
}
|
|
12299
|
+
const conversationId = await this.ensureConversation();
|
|
12300
|
+
return this._awaitResponses(conversationId, () => this.client.createEvent({ type, payload, conversationId }), options);
|
|
12301
|
+
}
|
|
11848
12302
|
}
|
|
11849
12303
|
async function discoverWebhookId(botId, token, apiUrl) {
|
|
11850
12304
|
const client = new BpClient({ token, botId, apiUrl });
|
|
@@ -11852,7 +12306,7 @@ async function discoverWebhookId(botId, token, apiUrl) {
|
|
|
11852
12306
|
const integrations = bot.integrations || {};
|
|
11853
12307
|
const chat = Object.values(integrations).find((int) => int.name === "chat");
|
|
11854
12308
|
const webhookId = chat?.webhookId;
|
|
11855
|
-
if (!webhookId) {
|
|
12309
|
+
if (!webhookId || typeof webhookId !== "string") {
|
|
11856
12310
|
throw new Error("No chat integration found on bot. Make sure the bot has the chat integration enabled.");
|
|
11857
12311
|
}
|
|
11858
12312
|
return webhookId;
|
|
@@ -11914,9 +12368,11 @@ async function getTraceData(conversationId, devServerUrl, options = {}) {
|
|
|
11914
12368
|
}
|
|
11915
12369
|
|
|
11916
12370
|
// src/eval/graders/llm.ts
|
|
11917
|
-
import { Cognitive } from "@botpress/
|
|
12371
|
+
import { Cognitive } from "@botpress/runtime";
|
|
11918
12372
|
import { Client as Client18 } from "@botpress/client";
|
|
11919
|
-
var
|
|
12373
|
+
var DEFAULT_PASS_THRESHOLD = 3;
|
|
12374
|
+
function buildJudgeSystemPrompt(passThreshold) {
|
|
12375
|
+
return `You are an evaluation judge for a chatbot. You will be given:
|
|
11920
12376
|
- The user's message
|
|
11921
12377
|
- The bot's response
|
|
11922
12378
|
- Grading criteria
|
|
@@ -11937,32 +12393,44 @@ Scoring guide:
|
|
|
11937
12393
|
- 2: Barely meets criteria, significant issues
|
|
11938
12394
|
- 1: Does not meet criteria
|
|
11939
12395
|
|
|
11940
|
-
A score of
|
|
12396
|
+
A score of ${passThreshold} or above is a pass.`;
|
|
12397
|
+
}
|
|
12398
|
+
var MODEL_ALIASES = ["fast", "best"];
|
|
11941
12399
|
var _cognitive = null;
|
|
11942
|
-
|
|
11943
|
-
|
|
11944
|
-
|
|
11945
|
-
|
|
11946
|
-
|
|
11947
|
-
|
|
11948
|
-
|
|
11949
|
-
|
|
11950
|
-
const client = new Client18({ token, apiUrl, botId });
|
|
11951
|
-
_cognitive = new Cognitive({ client, __experimental_beta: true });
|
|
11952
|
-
return _cognitive;
|
|
12400
|
+
var _availableModels = [];
|
|
12401
|
+
var _judgeModel = "fast";
|
|
12402
|
+
function _isModelValid(model) {
|
|
12403
|
+
if (MODEL_ALIASES.includes(model))
|
|
12404
|
+
return true;
|
|
12405
|
+
if (_availableModels.length === 0)
|
|
12406
|
+
return false;
|
|
12407
|
+
return _availableModels.includes(model);
|
|
11953
12408
|
}
|
|
11954
|
-
function initLLMJudge(credentials) {
|
|
12409
|
+
async function initLLMJudge(credentials, options) {
|
|
12410
|
+
const log = options?.logger ?? console;
|
|
11955
12411
|
const client = new Client18({
|
|
11956
12412
|
token: credentials.token,
|
|
11957
12413
|
apiUrl: credentials.apiUrl,
|
|
11958
12414
|
botId: credentials.botId
|
|
11959
12415
|
});
|
|
11960
12416
|
_cognitive = new Cognitive({ client, __experimental_beta: true });
|
|
12417
|
+
try {
|
|
12418
|
+
_availableModels = Array.from((await _cognitive.fetchRemoteModels()).keys());
|
|
12419
|
+
} catch (err) {
|
|
12420
|
+
log.warn(`Failed to fetch available models: ${err.message}. LLM judge will be unavailable.`);
|
|
12421
|
+
_availableModels = [];
|
|
12422
|
+
}
|
|
12423
|
+
_judgeModel = options?.model ?? "fast";
|
|
12424
|
+
if (_availableModels.length === 0) {
|
|
12425
|
+
log.warn("No available Cognitive models: cannot validate judge model.");
|
|
12426
|
+
} else if (!_isModelValid(_judgeModel)) {
|
|
12427
|
+
log.warn(`Configured LLM judge model "${_judgeModel}" is invalid. Run "adk models" to list available models.`);
|
|
12428
|
+
}
|
|
11961
12429
|
}
|
|
11962
12430
|
async function gradeLLMJudge(botResponse, criteria, context) {
|
|
12431
|
+
const threshold = Math.max(1, Math.min(5, context.passThreshold ?? DEFAULT_PASS_THRESHOLD));
|
|
11963
12432
|
try {
|
|
11964
|
-
|
|
11965
|
-
if (!cognitive) {
|
|
12433
|
+
if (!_cognitive) {
|
|
11966
12434
|
return {
|
|
11967
12435
|
assertion: `llm_judge: "${criteria}"`,
|
|
11968
12436
|
pass: true,
|
|
@@ -11970,11 +12438,19 @@ async function gradeLLMJudge(botResponse, criteria, context) {
|
|
|
11970
12438
|
actual: "SKIPPED — LLM judge unavailable: no credentials configured"
|
|
11971
12439
|
};
|
|
11972
12440
|
}
|
|
11973
|
-
|
|
11974
|
-
|
|
12441
|
+
if (!_isModelValid(_judgeModel)) {
|
|
12442
|
+
return {
|
|
12443
|
+
assertion: `llm_judge: "${criteria}"`,
|
|
12444
|
+
pass: false,
|
|
12445
|
+
expected: criteria,
|
|
12446
|
+
actual: "FAILED — invalid LLM judge model"
|
|
12447
|
+
};
|
|
12448
|
+
}
|
|
12449
|
+
const { output } = await _cognitive.generateContent({
|
|
12450
|
+
model: _judgeModel,
|
|
11975
12451
|
temperature: 0,
|
|
11976
12452
|
responseFormat: "json_object",
|
|
11977
|
-
systemPrompt:
|
|
12453
|
+
systemPrompt: buildJudgeSystemPrompt(threshold),
|
|
11978
12454
|
messages: [
|
|
11979
12455
|
{
|
|
11980
12456
|
role: "user",
|
|
@@ -11999,9 +12475,9 @@ Criteria: ${criteria}`
|
|
|
11999
12475
|
const verdict = JSON.parse(content);
|
|
12000
12476
|
return {
|
|
12001
12477
|
assertion: `llm_judge: "${criteria}"`,
|
|
12002
|
-
pass: verdict.score >=
|
|
12478
|
+
pass: verdict.score >= threshold,
|
|
12003
12479
|
expected: criteria,
|
|
12004
|
-
actual: `Score ${verdict.score}/5 — ${verdict.reason}`
|
|
12480
|
+
actual: `Score ${verdict.score}/5 (threshold: ${threshold}) — ${verdict.reason}`
|
|
12005
12481
|
};
|
|
12006
12482
|
} catch (err) {
|
|
12007
12483
|
return {
|
|
@@ -12049,7 +12525,10 @@ async function gradeResponse(botResponse, assertions, context) {
|
|
|
12049
12525
|
continue;
|
|
12050
12526
|
}
|
|
12051
12527
|
if ("llm_judge" in assertion) {
|
|
12052
|
-
const result = await gradeLLMJudge(botResponse, assertion.llm_judge,
|
|
12528
|
+
const result = await gradeLLMJudge(botResponse, assertion.llm_judge, {
|
|
12529
|
+
userMessage: context.userMessage,
|
|
12530
|
+
passThreshold: context.judgePassThreshold
|
|
12531
|
+
});
|
|
12053
12532
|
results.push(result);
|
|
12054
12533
|
continue;
|
|
12055
12534
|
}
|
|
@@ -12201,6 +12680,7 @@ function gradeTools(toolCalls, assertions) {
|
|
|
12201
12680
|
}
|
|
12202
12681
|
|
|
12203
12682
|
// src/eval/graders/state.ts
|
|
12683
|
+
import { BUILT_IN_STATES } from "@botpress/runtime/internal";
|
|
12204
12684
|
function parseStatePath(path42) {
|
|
12205
12685
|
const dot = path42.indexOf(".");
|
|
12206
12686
|
if (dot === -1) {
|
|
@@ -12210,11 +12690,16 @@ function parseStatePath(path42) {
|
|
|
12210
12690
|
const field = path42.slice(dot + 1);
|
|
12211
12691
|
switch (prefix) {
|
|
12212
12692
|
case "bot":
|
|
12213
|
-
return { type: "bot", stateName:
|
|
12693
|
+
return { type: "bot", stateName: BUILT_IN_STATES.bot, stateId: (ctx) => ctx.botId, field };
|
|
12214
12694
|
case "user":
|
|
12215
|
-
return { type: "user", stateName:
|
|
12695
|
+
return { type: "user", stateName: BUILT_IN_STATES.user, stateId: (ctx) => ctx.userId, field };
|
|
12216
12696
|
case "conversation":
|
|
12217
|
-
return {
|
|
12697
|
+
return {
|
|
12698
|
+
type: "conversation",
|
|
12699
|
+
stateName: BUILT_IN_STATES.conversation,
|
|
12700
|
+
stateId: (ctx) => ctx.conversationId,
|
|
12701
|
+
field
|
|
12702
|
+
};
|
|
12218
12703
|
default:
|
|
12219
12704
|
throw new Error(`Unknown state type "${prefix}" in path "${path42}" — expected bot, user, or conversation`);
|
|
12220
12705
|
}
|
|
@@ -12225,7 +12710,9 @@ async function fetchState(client, type, id, name) {
|
|
|
12225
12710
|
const payload = result.state?.payload;
|
|
12226
12711
|
return payload?.value ?? payload ?? null;
|
|
12227
12712
|
} catch (err) {
|
|
12228
|
-
|
|
12713
|
+
const code = err != null && typeof err === "object" && "code" in err ? err.code : undefined;
|
|
12714
|
+
const message = err instanceof Error ? err.message : "";
|
|
12715
|
+
if (code === 404 || message.includes("404") || message.includes("doesn't exist")) {
|
|
12229
12716
|
return null;
|
|
12230
12717
|
}
|
|
12231
12718
|
throw err;
|
|
@@ -12249,7 +12736,7 @@ async function snapshotState(client, assertions, ctx) {
|
|
|
12249
12736
|
if (assertion.changed === undefined)
|
|
12250
12737
|
continue;
|
|
12251
12738
|
const parsed = parseStatePath(assertion.path);
|
|
12252
|
-
if (parsed.type === "conversation")
|
|
12739
|
+
if (parsed.type === "conversation" && !ctx.conversationId)
|
|
12253
12740
|
continue;
|
|
12254
12741
|
const payload = await fetchState(client, parsed.type, parsed.stateId(ctx), parsed.stateName);
|
|
12255
12742
|
snapshots.set(assertion.path, payload ? payload[parsed.field] : undefined);
|
|
@@ -12462,6 +12949,22 @@ function gradeWorkflows(spans, assertions) {
|
|
|
12462
12949
|
return results;
|
|
12463
12950
|
}
|
|
12464
12951
|
|
|
12952
|
+
// src/eval/graders/timing.ts
|
|
12953
|
+
function gradeTiming(botDuration, assertions) {
|
|
12954
|
+
const results = [];
|
|
12955
|
+
for (const assertion of assertions) {
|
|
12956
|
+
const pass = matchValue(assertion.response_time, botDuration);
|
|
12957
|
+
const expected = operatorToString(assertion.response_time);
|
|
12958
|
+
results.push({
|
|
12959
|
+
assertion: `response_time ${expected}`,
|
|
12960
|
+
pass,
|
|
12961
|
+
expected: `Response time ${expected}`,
|
|
12962
|
+
actual: `${botDuration}ms`
|
|
12963
|
+
});
|
|
12964
|
+
}
|
|
12965
|
+
return results;
|
|
12966
|
+
}
|
|
12967
|
+
|
|
12465
12968
|
// src/eval/graders/outcome.ts
|
|
12466
12969
|
async function snapshotOutcomeState(client, evalDef, ctx) {
|
|
12467
12970
|
if (!evalDef.outcome?.state) {
|
|
@@ -12492,9 +12995,64 @@ async function gradeOutcome(client, evalDef, ctx, traceSpans, preSnapshots) {
|
|
|
12492
12995
|
// src/eval/runner.ts
|
|
12493
12996
|
import { randomUUID } from "crypto";
|
|
12494
12997
|
var DEFAULT_IDLE_TIMEOUT = 15000;
|
|
12998
|
+
var WORKFLOW_TRIGGER_TIMEOUT_MS = 5 * 60 * 1000;
|
|
12999
|
+
function buildStatePayload(value) {
|
|
13000
|
+
return {
|
|
13001
|
+
value,
|
|
13002
|
+
location: { type: "state" }
|
|
13003
|
+
};
|
|
13004
|
+
}
|
|
13005
|
+
async function seedEvalState(client, ctx, setup) {
|
|
13006
|
+
const state = setup?.state;
|
|
13007
|
+
if (!state)
|
|
13008
|
+
return;
|
|
13009
|
+
const writes = [];
|
|
13010
|
+
if (state.bot) {
|
|
13011
|
+
writes.push(client.setState({
|
|
13012
|
+
type: "bot",
|
|
13013
|
+
id: ctx.botId,
|
|
13014
|
+
name: BUILT_IN_STATES2.bot,
|
|
13015
|
+
payload: buildStatePayload(state.bot)
|
|
13016
|
+
}));
|
|
13017
|
+
}
|
|
13018
|
+
if (state.user) {
|
|
13019
|
+
writes.push(client.setState({
|
|
13020
|
+
type: "user",
|
|
13021
|
+
id: ctx.userId,
|
|
13022
|
+
name: BUILT_IN_STATES2.user,
|
|
13023
|
+
payload: buildStatePayload(state.user)
|
|
13024
|
+
}));
|
|
13025
|
+
}
|
|
13026
|
+
if (state.conversation) {
|
|
13027
|
+
if (!ctx.conversationId) {
|
|
13028
|
+
throw new Error("Cannot seed conversation state before a conversation is created.");
|
|
13029
|
+
}
|
|
13030
|
+
writes.push(client.setState({
|
|
13031
|
+
type: "conversation",
|
|
13032
|
+
id: ctx.conversationId,
|
|
13033
|
+
name: BUILT_IN_STATES2.conversation,
|
|
13034
|
+
payload: buildStatePayload(state.conversation)
|
|
13035
|
+
}));
|
|
13036
|
+
}
|
|
13037
|
+
await Promise.all(writes);
|
|
13038
|
+
}
|
|
13039
|
+
async function triggerEvalWorkflow(client, ctx, setup) {
|
|
13040
|
+
const workflow = setup?.workflow;
|
|
13041
|
+
if (!workflow)
|
|
13042
|
+
return;
|
|
13043
|
+
await client.createWorkflow({
|
|
13044
|
+
name: workflow.trigger,
|
|
13045
|
+
input: workflow.input ?? {},
|
|
13046
|
+
status: "pending",
|
|
13047
|
+
conversationId: ctx.conversationId,
|
|
13048
|
+
userId: ctx.userId,
|
|
13049
|
+
timeoutAt: new Date(Date.now() + WORKFLOW_TRIGGER_TIMEOUT_MS).toISOString()
|
|
13050
|
+
});
|
|
13051
|
+
}
|
|
12495
13052
|
async function runEval(evalDef, connection, options = {}) {
|
|
12496
13053
|
const devServerUrl = options.devServerUrl || "http://localhost:3001";
|
|
12497
13054
|
const idleTimeout = evalDef.options?.idleTimeout ?? options.idleTimeout ?? DEFAULT_IDLE_TIMEOUT;
|
|
13055
|
+
const judgePassThreshold = evalDef.options?.judgePassThreshold ?? options.judgePassThreshold;
|
|
12498
13056
|
const start = Date.now();
|
|
12499
13057
|
const turns = [];
|
|
12500
13058
|
let outcomeAssertions = [];
|
|
@@ -12512,34 +13070,67 @@ async function runEval(evalDef, connection, options = {}) {
|
|
|
12512
13070
|
}
|
|
12513
13071
|
return bpClient;
|
|
12514
13072
|
};
|
|
13073
|
+
let lastConversationId = "";
|
|
13074
|
+
if (evalDef.setup?.state?.conversation || evalDef.setup?.workflow) {
|
|
13075
|
+
lastConversationId = await session.ensureConversation();
|
|
13076
|
+
}
|
|
13077
|
+
await seedEvalState(getBpClient(), {
|
|
13078
|
+
botId: connection.botId,
|
|
13079
|
+
userId: session.userId,
|
|
13080
|
+
conversationId: lastConversationId || undefined
|
|
13081
|
+
}, evalDef.setup);
|
|
13082
|
+
await triggerEvalWorkflow(getBpClient(), {
|
|
13083
|
+
userId: session.userId,
|
|
13084
|
+
conversationId: lastConversationId || undefined
|
|
13085
|
+
}, evalDef.setup);
|
|
12515
13086
|
let preSnapshots = new Map;
|
|
12516
13087
|
if (evalDef.outcome?.state) {
|
|
12517
13088
|
const ctx = {
|
|
12518
13089
|
botId: connection.botId,
|
|
12519
13090
|
userId: session.userId,
|
|
12520
|
-
conversationId:
|
|
13091
|
+
conversationId: lastConversationId
|
|
12521
13092
|
};
|
|
12522
13093
|
preSnapshots = await snapshotOutcomeState(getBpClient(), evalDef, ctx);
|
|
12523
13094
|
}
|
|
12524
13095
|
let previousToolCallCount = 0;
|
|
12525
|
-
let lastConversationId = "";
|
|
12526
13096
|
let allSpans = [];
|
|
12527
13097
|
for (let i = 0;i < evalDef.conversation.length; i++) {
|
|
12528
13098
|
const turn = evalDef.conversation[i];
|
|
12529
13099
|
const turnStart = Date.now();
|
|
12530
|
-
|
|
12531
|
-
|
|
12532
|
-
|
|
12533
|
-
|
|
13100
|
+
if (turn.expectSilence && turn.assert?.response) {
|
|
13101
|
+
throw new Error(`Turn ${i + 1}: 'expectSilence' and 'assert.response' are mutually exclusive.`);
|
|
13102
|
+
}
|
|
13103
|
+
if (turn.user && turn.event) {
|
|
13104
|
+
throw new Error(`Turn ${i + 1}: 'user' and 'event' are mutually exclusive.`);
|
|
13105
|
+
}
|
|
13106
|
+
if (!turn.user && !turn.event) {
|
|
13107
|
+
throw new Error(`Turn ${i + 1}: must have either 'user' or 'event'.`);
|
|
13108
|
+
}
|
|
13109
|
+
const sendOptions = { timeout: Math.max(30000, idleTimeout * 2), idleTimeout, expectSilence: turn.expectSilence };
|
|
13110
|
+
const result = turn.event ? await session.sendEvent(turn.event.type, turn.event.payload ?? {}, sendOptions) : await session.sendMessage(turn.user, sendOptions);
|
|
12534
13111
|
const botDuration = Date.now() - turnStart;
|
|
13112
|
+
if (!turn.expectSilence && result.responses.length === 0) {
|
|
13113
|
+
throw new Error(`Turn ${i + 1}: bot produced no response.`);
|
|
13114
|
+
}
|
|
12535
13115
|
lastConversationId = result.conversationId;
|
|
12536
13116
|
const botResponse = result.responses.map((r) => r.text).join(`
|
|
12537
13117
|
`);
|
|
13118
|
+
const turnLabel = turn.event ? `[event: ${turn.event.type}]` : turn.user;
|
|
12538
13119
|
const evalStart = Date.now();
|
|
12539
13120
|
let assertions = [];
|
|
13121
|
+
if (turn.expectSilence) {
|
|
13122
|
+
const wasSilent = result.responses.length === 0;
|
|
13123
|
+
assertions.push({
|
|
13124
|
+
assertion: "no_response",
|
|
13125
|
+
pass: wasSilent,
|
|
13126
|
+
expected: "No response",
|
|
13127
|
+
actual: wasSilent ? "No response" : `Bot responded: "${botResponse}"`
|
|
13128
|
+
});
|
|
13129
|
+
}
|
|
12540
13130
|
if (turn.assert?.response) {
|
|
12541
13131
|
assertions = await gradeResponse(botResponse, turn.assert.response, {
|
|
12542
|
-
userMessage:
|
|
13132
|
+
userMessage: turnLabel,
|
|
13133
|
+
judgePassThreshold
|
|
12543
13134
|
});
|
|
12544
13135
|
}
|
|
12545
13136
|
if (turn.assert?.tools) {
|
|
@@ -12606,11 +13197,15 @@ async function runEval(evalDef, connection, options = {}) {
|
|
|
12606
13197
|
const workflowResults = gradeWorkflows(allSpans, turn.assert.workflow);
|
|
12607
13198
|
assertions.push(...workflowResults);
|
|
12608
13199
|
}
|
|
13200
|
+
if (turn.assert?.timing) {
|
|
13201
|
+
const timingResults = gradeTiming(botDuration, turn.assert.timing);
|
|
13202
|
+
assertions.push(...timingResults);
|
|
13203
|
+
}
|
|
12609
13204
|
const turnPass = assertions.every((a) => a.pass);
|
|
12610
13205
|
const evalDuration = Date.now() - evalStart;
|
|
12611
13206
|
turns.push({
|
|
12612
13207
|
turnNumber: i + 1,
|
|
12613
|
-
userMessage:
|
|
13208
|
+
userMessage: turnLabel,
|
|
12614
13209
|
botResponse,
|
|
12615
13210
|
assertions,
|
|
12616
13211
|
pass: turnPass,
|
|
@@ -12672,11 +13267,11 @@ async function runEval(evalDef, connection, options = {}) {
|
|
|
12672
13267
|
async function runEvalSuite(config, filter) {
|
|
12673
13268
|
const start = Date.now();
|
|
12674
13269
|
const runId = randomUUID().replace(/-/g, "").slice(0, 26);
|
|
12675
|
-
initLLMJudge({
|
|
13270
|
+
await initLLMJudge({
|
|
12676
13271
|
token: config.credentials.token,
|
|
12677
13272
|
apiUrl: config.credentials.apiUrl,
|
|
12678
13273
|
botId: config.credentials.botId
|
|
12679
|
-
});
|
|
13274
|
+
}, { model: config.evalOptions?.judgeModel, logger: config.logger });
|
|
12680
13275
|
const evalsDir = `${config.agentPath}/evals`;
|
|
12681
13276
|
const allEvals = await loadEvalsFromDir(evalsDir);
|
|
12682
13277
|
const evals = filterEvals(allEvals, filter);
|
|
@@ -12708,7 +13303,11 @@ async function runEvalSuite(config, filter) {
|
|
|
12708
13303
|
for (let i = 0;i < evals.length; i++) {
|
|
12709
13304
|
const evalDef = evals[i];
|
|
12710
13305
|
config.onProgress?.({ type: "eval_start", evalName: evalDef.name, index: i });
|
|
12711
|
-
const report = await runEval(evalDef, connection, {
|
|
13306
|
+
const report = await runEval(evalDef, connection, {
|
|
13307
|
+
devServerUrl,
|
|
13308
|
+
idleTimeout: config.evalOptions?.idleTimeout,
|
|
13309
|
+
judgePassThreshold: config.evalOptions?.judgePassThreshold
|
|
13310
|
+
});
|
|
12712
13311
|
reports.push(report);
|
|
12713
13312
|
config.onProgress?.({ type: "eval_complete", evalName: evalDef.name, index: i, report });
|
|
12714
13313
|
}
|
|
@@ -12726,11 +13325,11 @@ async function runEvalSuite(config, filter) {
|
|
|
12726
13325
|
return runReport;
|
|
12727
13326
|
}
|
|
12728
13327
|
// src/eval/store.ts
|
|
12729
|
-
import { existsSync as
|
|
13328
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, readFileSync as readFileSync5, readdirSync as readdirSync4 } from "fs";
|
|
12730
13329
|
import { join as join11 } from "path";
|
|
12731
13330
|
function getRunsDir(agentPath) {
|
|
12732
13331
|
const dir = join11(agentPath, ".adk", "evals", "runs");
|
|
12733
|
-
if (!
|
|
13332
|
+
if (!existsSync11(dir)) {
|
|
12734
13333
|
mkdirSync2(dir, { recursive: true });
|
|
12735
13334
|
}
|
|
12736
13335
|
return dir;
|
|
@@ -12748,19 +13347,19 @@ function loadRunResult(agentPath, runId) {
|
|
|
12748
13347
|
for (const file of files) {
|
|
12749
13348
|
if (file.includes(runId)) {
|
|
12750
13349
|
const filepath = join11(dir, file);
|
|
12751
|
-
return JSON.parse(
|
|
13350
|
+
return JSON.parse(readFileSync5(filepath, "utf-8"));
|
|
12752
13351
|
}
|
|
12753
13352
|
}
|
|
12754
13353
|
return null;
|
|
12755
13354
|
}
|
|
12756
13355
|
function listRunResults(agentPath, limit = 50) {
|
|
12757
13356
|
const dir = getRunsDir(agentPath);
|
|
12758
|
-
if (!
|
|
13357
|
+
if (!existsSync11(dir))
|
|
12759
13358
|
return [];
|
|
12760
13359
|
const files = readdirSync4(dir).filter((f) => f.endsWith(".json")).sort().reverse().slice(0, limit);
|
|
12761
13360
|
return files.map((file) => {
|
|
12762
13361
|
const filepath = join11(dir, file);
|
|
12763
|
-
return JSON.parse(
|
|
13362
|
+
return JSON.parse(readFileSync5(filepath, "utf-8"));
|
|
12764
13363
|
});
|
|
12765
13364
|
}
|
|
12766
13365
|
function getLatestRun(agentPath) {
|
|
@@ -12794,11 +13393,11 @@ export {
|
|
|
12794
13393
|
generateAssetsRuntime,
|
|
12795
13394
|
filterEvals,
|
|
12796
13395
|
dependenciesKeyOrder,
|
|
12797
|
-
defineEval,
|
|
12798
13396
|
coerceConfigValue,
|
|
12799
13397
|
buildOpenCodeConfig,
|
|
12800
13398
|
bpCliImporter,
|
|
12801
13399
|
auth,
|
|
13400
|
+
agentLocalInfoKeyOrder,
|
|
12802
13401
|
agentInfoKeyOrder,
|
|
12803
13402
|
ValidationSeverity,
|
|
12804
13403
|
ValidationErrors,
|
|
@@ -12825,6 +13424,7 @@ export {
|
|
|
12825
13424
|
IntegrationCache,
|
|
12826
13425
|
HubCache,
|
|
12827
13426
|
FileWatcher2 as FileWatcher,
|
|
13427
|
+
Eval,
|
|
12828
13428
|
EnhancedInterfaceCache,
|
|
12829
13429
|
DevIdManager,
|
|
12830
13430
|
CredentialsManager,
|
|
@@ -12845,4 +13445,4 @@ export {
|
|
|
12845
13445
|
AgentProject
|
|
12846
13446
|
};
|
|
12847
13447
|
|
|
12848
|
-
//# debugId=
|
|
13448
|
+
//# debugId=E3104143A79BCF1564756E2164756E21
|