@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.
Files changed (156) hide show
  1. package/dist/agent-init/agent-project-generator.d.ts +32 -8
  2. package/dist/agent-init/agent-project-generator.d.ts.map +1 -1
  3. package/dist/agent-init/index.d.ts +1 -0
  4. package/dist/agent-init/index.d.ts.map +1 -1
  5. package/dist/agent-project/agent-project.d.ts +13 -1
  6. package/dist/agent-project/agent-project.d.ts.map +1 -1
  7. package/dist/agent-project/agent-resolver.d.ts +4 -3
  8. package/dist/agent-project/agent-resolver.d.ts.map +1 -1
  9. package/dist/agent-project/config-writer.d.ts +33 -0
  10. package/dist/agent-project/config-writer.d.ts.map +1 -1
  11. package/dist/agent-project/dependencies-parser.d.ts.map +1 -1
  12. package/dist/agent-project/index.d.ts +1 -1
  13. package/dist/agent-project/index.d.ts.map +1 -1
  14. package/dist/agent-project/types.d.ts +48 -22
  15. package/dist/agent-project/types.d.ts.map +1 -1
  16. package/dist/agent-project/validation-errors.d.ts.map +1 -1
  17. package/dist/auth/credentials.d.ts +15 -1
  18. package/dist/auth/credentials.d.ts.map +1 -1
  19. package/dist/auth/index.d.ts +2 -0
  20. package/dist/auth/index.d.ts.map +1 -1
  21. package/dist/bot-generator/dev-id-manager.d.ts.map +1 -1
  22. package/dist/bot-generator/generator.d.ts.map +1 -1
  23. package/dist/commands/base-command.d.ts.map +1 -1
  24. package/dist/commands/bp-add-command.d.ts.map +1 -1
  25. package/dist/commands/bp-build-command.d.ts.map +1 -1
  26. package/dist/commands/bp-chat-command.d.ts.map +1 -1
  27. package/dist/commands/bp-deploy-command.d.ts.map +1 -1
  28. package/dist/commands/bp-dev-command.d.ts +2 -2
  29. package/dist/commands/bp-dev-command.d.ts.map +1 -1
  30. package/dist/commands/opencode-command.d.ts +2 -2
  31. package/dist/commands/opencode-command.d.ts.map +1 -1
  32. package/dist/commands/opencode-config.d.ts +1 -1
  33. package/dist/commands/opencode-config.d.ts.map +1 -1
  34. package/dist/config/coerce-config-value.d.ts.map +1 -1
  35. package/dist/config/manager.d.ts +5 -5
  36. package/dist/config/manager.d.ts.map +1 -1
  37. package/dist/eval/client.d.ts +8 -0
  38. package/dist/eval/client.d.ts.map +1 -1
  39. package/dist/eval/graders/index.d.ts +1 -0
  40. package/dist/eval/graders/index.d.ts.map +1 -1
  41. package/dist/eval/graders/llm.d.ts +6 -2
  42. package/dist/eval/graders/llm.d.ts.map +1 -1
  43. package/dist/eval/graders/response.d.ts +1 -0
  44. package/dist/eval/graders/response.d.ts.map +1 -1
  45. package/dist/eval/graders/state.d.ts +1 -1
  46. package/dist/eval/graders/state.d.ts.map +1 -1
  47. package/dist/eval/graders/tables.d.ts.map +1 -1
  48. package/dist/eval/graders/timing.d.ts +7 -0
  49. package/dist/eval/graders/timing.d.ts.map +1 -0
  50. package/dist/eval/graders/workflow.d.ts.map +1 -1
  51. package/dist/eval/index.d.ts +3 -3
  52. package/dist/eval/index.d.ts.map +1 -1
  53. package/dist/eval/loader.d.ts +2 -1
  54. package/dist/eval/loader.d.ts.map +1 -1
  55. package/dist/eval/runner.d.ts +1 -0
  56. package/dist/eval/runner.d.ts.map +1 -1
  57. package/dist/eval/traces.d.ts.map +1 -1
  58. package/dist/eval/types.d.ts +62 -4
  59. package/dist/eval/types.d.ts.map +1 -1
  60. package/dist/file-watcher/watcher.d.ts +9 -0
  61. package/dist/file-watcher/watcher.d.ts.map +1 -1
  62. package/dist/generators/client-wrapper.d.ts.map +1 -1
  63. package/dist/generators/conversation-types.d.ts.map +1 -1
  64. package/dist/generators/integration-types.d.ts.map +1 -1
  65. package/dist/generators/interface-types.d.ts.map +1 -1
  66. package/dist/generators/plugin-types.d.ts.map +1 -1
  67. package/dist/generators/table-types.d.ts.map +1 -1
  68. package/dist/generators/tests.d.ts.map +1 -1
  69. package/dist/generators/workflow-types.d.ts.map +1 -1
  70. package/dist/index.d.ts +6 -5
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +1194 -594
  73. package/dist/index.js.map +62 -61
  74. package/dist/integrations/checker.d.ts +2 -2
  75. package/dist/integrations/checker.d.ts.map +1 -1
  76. package/dist/integrations/config-utils.d.ts +4 -3
  77. package/dist/integrations/config-utils.d.ts.map +1 -1
  78. package/dist/integrations/operations.d.ts +19 -6
  79. package/dist/integrations/operations.d.ts.map +1 -1
  80. package/dist/integrations/types.d.ts +1 -1
  81. package/dist/integrations/types.d.ts.map +1 -1
  82. package/dist/interfaces/manager.d.ts.map +1 -1
  83. package/dist/interfaces/types.d.ts +1 -1
  84. package/dist/interfaces/types.d.ts.map +1 -1
  85. package/dist/knowledge/manager.d.ts.map +1 -1
  86. package/dist/plugins/types.d.ts +1 -1
  87. package/dist/plugins/types.d.ts.map +1 -1
  88. package/dist/preflight/agent-config-sync.d.ts +2 -1
  89. package/dist/preflight/agent-config-sync.d.ts.map +1 -1
  90. package/dist/preflight/checker.d.ts.map +1 -1
  91. package/dist/preflight/types.d.ts +8 -8
  92. package/dist/preflight/types.d.ts.map +1 -1
  93. package/dist/runner/index.d.ts +1 -1
  94. package/dist/runner/script-runner.d.ts +1 -1
  95. package/dist/runner/script-runner.d.ts.map +1 -1
  96. package/dist/tables/table-manager.d.ts.map +1 -1
  97. package/dist/tables/types.d.ts +2 -1
  98. package/dist/tables/types.d.ts.map +1 -1
  99. package/dist/templates/README.md +101 -0
  100. package/dist/templates/blank/README.md +36 -0
  101. package/dist/templates/blank/agent.config.ts +49 -0
  102. package/dist/templates/blank/package.json +17 -0
  103. package/dist/templates/blank/src/actions/index.ts +19 -0
  104. package/dist/templates/blank/src/conversations/index.ts +16 -0
  105. package/dist/templates/blank/src/knowledge/index.ts +17 -0
  106. package/dist/templates/blank/src/tables/index.ts +19 -0
  107. package/dist/templates/blank/src/triggers/index.ts +20 -0
  108. package/dist/templates/blank/src/workflows/index.ts +23 -0
  109. package/dist/templates/blank/tsconfig.json +22 -0
  110. package/dist/templates/crm-enrichment/README.md +85 -0
  111. package/dist/templates/crm-enrichment/agent.config.ts +33 -0
  112. package/dist/templates/crm-enrichment/package.json +17 -0
  113. package/dist/templates/crm-enrichment/src/actions/enrich-contact.ts +81 -0
  114. package/dist/templates/crm-enrichment/src/conversations/index.ts +14 -0
  115. package/dist/templates/crm-enrichment/src/knowledge/index.ts +17 -0
  116. package/dist/templates/crm-enrichment/src/tables/contacts.ts +43 -0
  117. package/dist/templates/crm-enrichment/src/triggers/daily-enrichment.ts +30 -0
  118. package/dist/templates/crm-enrichment/src/workflows/enrichment-pipeline.ts +171 -0
  119. package/dist/templates/crm-enrichment/tsconfig.json +22 -0
  120. package/dist/templates/hello-world/README.md +46 -0
  121. package/dist/templates/hello-world/agent.config.ts +48 -0
  122. package/dist/templates/hello-world/package.json +17 -0
  123. package/dist/templates/hello-world/src/actions/index.ts +19 -0
  124. package/dist/templates/hello-world/src/conversations/index.ts +10 -0
  125. package/dist/templates/hello-world/src/knowledge/index.ts +17 -0
  126. package/dist/templates/hello-world/src/tables/index.ts +19 -0
  127. package/dist/templates/hello-world/src/triggers/index.ts +20 -0
  128. package/dist/templates/hello-world/src/workflows/index.ts +23 -0
  129. package/dist/templates/hello-world/tsconfig.json +22 -0
  130. package/dist/templates/knowledge-assistant/README.md +66 -0
  131. package/dist/templates/knowledge-assistant/agent.config.ts +26 -0
  132. package/dist/templates/knowledge-assistant/package.json +17 -0
  133. package/dist/templates/knowledge-assistant/src/actions/index.ts +19 -0
  134. package/dist/templates/knowledge-assistant/src/actions/search-docs.ts +50 -0
  135. package/dist/templates/knowledge-assistant/src/conversations/index.ts +33 -0
  136. package/dist/templates/knowledge-assistant/src/knowledge/docs.ts +23 -0
  137. package/dist/templates/knowledge-assistant/src/knowledge/getting-started.md +49 -0
  138. package/dist/templates/knowledge-assistant/src/tables/index.ts +21 -0
  139. package/dist/templates/knowledge-assistant/src/triggers/index.ts +17 -0
  140. package/dist/templates/knowledge-assistant/src/workflows/index.ts +28 -0
  141. package/dist/templates/knowledge-assistant/tsconfig.json +22 -0
  142. package/dist/templates/slack-triage/README.md +74 -0
  143. package/dist/templates/slack-triage/agent.config.ts +35 -0
  144. package/dist/templates/slack-triage/evals/triage-basic.eval.ts +55 -0
  145. package/dist/templates/slack-triage/package.json +17 -0
  146. package/dist/templates/slack-triage/src/actions/classify-request.ts +65 -0
  147. package/dist/templates/slack-triage/src/conversations/slack-dm.ts +72 -0
  148. package/dist/templates/slack-triage/src/knowledge/team-directory.md +33 -0
  149. package/dist/templates/slack-triage/src/tables/routing-rules.ts +38 -0
  150. package/dist/templates/slack-triage/src/triggers/new-message.ts +44 -0
  151. package/dist/templates/slack-triage/src/workflows/triage-flow.ts +104 -0
  152. package/dist/templates/slack-triage/tsconfig.json +22 -0
  153. package/dist/templates/template.config.json +47 -0
  154. package/dist/utils/json-ordering.d.ts +5 -4
  155. package/dist/utils/json-ordering.d.ts.map +1 -1
  156. package/package.json +31 -38
@@ -0,0 +1,35 @@
1
+ import { z, defineConfig } from '@botpress/runtime'
2
+
3
+ export default defineConfig({
4
+ name: '{{projectName}}',
5
+ description: 'Slack triage bot - monitors channels, classifies help requests, and routes them to the right person',
6
+
7
+ defaultModels: {
8
+ autonomous: 'openai:gpt-4.1-mini-2025-04-14', // Model used by execute() in conversations/workflows
9
+ zai: 'openai:gpt-4.1-2025-04-14', // Model used by Zai (extract, check, label, etc.)
10
+ },
11
+
12
+ // Per-bot persistent state - tracks triage statistics across all conversations.
13
+ bot: {
14
+ state: z.object({
15
+ totalTriaged: z.number().default(0).describe('Total requests triaged'),
16
+ lastTriagedAt: z.string().optional().describe('ISO timestamp of last triage'),
17
+ }),
18
+ },
19
+
20
+ // Per-user persistent state - remembers routing preferences per user.
21
+ user: {
22
+ state: z.object({
23
+ preferredCategory: z.string().optional().describe('Category this user most often submits'),
24
+ requestCount: z.number().default(0).describe('Number of requests from this user'),
25
+ }),
26
+ },
27
+
28
+ // Integrations extend your agent with actions, channels, and events.
29
+ // Browse available integrations: adk search <name> | adk list --available
30
+ // Install one: adk add <integration> (e.g. adk add browser)
31
+ // See actions/events/channels: adk info <integration>
32
+ dependencies: {
33
+ integrations: {},
34
+ },
35
+ })
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Eval: triage-basic
3
+ *
4
+ * Verifies that the triage bot correctly classifies common request types.
5
+ *
6
+ * Evals use the Eval class from @botpress/adk. Each eval defines a simulated
7
+ * conversation with assertions on the bot's responses and tool usage.
8
+ *
9
+ * Run evals with: adk eval
10
+ * Run a specific eval: adk eval --name triage-basic
11
+ */
12
+ import { Eval } from '@botpress/adk'
13
+
14
+ export default new Eval({
15
+ name: 'triage-basic',
16
+ description: 'Verify the bot classifies bug reports, feature requests, and questions correctly',
17
+ tags: ['triage', 'classification'],
18
+ type: 'regression',
19
+
20
+ conversation: [
21
+ {
22
+ user: 'The login page is showing a 500 error whenever I try to sign in with Google SSO',
23
+ assert: {
24
+ response: [
25
+ {
26
+ llm_judge:
27
+ 'Response acknowledges this is a bug or error report and indicates it will be triaged or routed to the appropriate team',
28
+ },
29
+ ],
30
+ },
31
+ },
32
+ {
33
+ user: 'It would be great if we could export dashboard data to CSV',
34
+ assert: {
35
+ response: [
36
+ {
37
+ llm_judge:
38
+ 'Response recognizes this as a feature request and indicates it will be forwarded to the product team or logged appropriately',
39
+ },
40
+ ],
41
+ },
42
+ },
43
+ {
44
+ user: 'How do I reset my password?',
45
+ assert: {
46
+ response: [
47
+ {
48
+ llm_judge:
49
+ 'Response treats this as a general question and either answers it directly or indicates it will be routed to support',
50
+ },
51
+ ],
52
+ },
53
+ },
54
+ ],
55
+ })
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "{{projectName}}",
3
+ "version": "1.0.0",
4
+ "description": "A Slack triage bot built with the ADK - classifies help requests and routes them",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "adk dev",
8
+ "build": "adk build",
9
+ "deploy": "adk deploy"
10
+ },
11
+ "dependencies": {
12
+ "@botpress/runtime": "^{{runtimeVersion}}"
13
+ },
14
+ "devDependencies": {
15
+ "typescript": "^5.9.3"
16
+ }
17
+ }
@@ -0,0 +1,65 @@
1
+ import { Action, z, adk } from '@botpress/runtime'
2
+
3
+ /**
4
+ * Classifies an incoming help request into a category using Zai.
5
+ *
6
+ * Supported categories:
7
+ * - bug: Something is broken or not working as expected
8
+ * - feature_request: A request for new functionality
9
+ * - question: A general question or "how do I..." inquiry
10
+ * - ops_issue: Infrastructure, deployment, or operational problem
11
+ *
12
+ * Customize: Add new categories by extending the enum and the label definitions below.
13
+ */
14
+ export const classifyRequest = new Action({
15
+ name: 'classifyRequest',
16
+ description: 'Classify a help request into a category using AI',
17
+
18
+ input: z.object({
19
+ message: z.string().describe('The raw help request message text'),
20
+ }),
21
+
22
+ output: z.object({
23
+ category: z.enum(['bug', 'feature_request', 'question', 'ops_issue']).describe('The classified category'),
24
+ confidence: z.string().describe('How confident the classification is: high, medium, or low'),
25
+ summary: z.string().describe('A one-sentence summary of the request'),
26
+ }),
27
+
28
+ handler: async ({ input }) => {
29
+ // Use Zai label() with .result() to get confidence scores per category.
30
+ // Each label is evaluated independently with a 5-tier confidence scale.
31
+ const { output: labels } = await adk.zai
32
+ .label(input.message, {
33
+ bug: 'reports a bug, error, crash, or something not working as expected',
34
+ feature_request: 'requests a new feature, enhancement, or improvement to existing functionality',
35
+ question: 'asks a general question, seeks guidance, or wants to know how to do something',
36
+ ops_issue: 'reports an infrastructure, deployment, uptime, or operational problem',
37
+ })
38
+ .result()
39
+
40
+ // Pick the category with the highest confidence that matched (value: true).
41
+ type Category = 'bug' | 'feature_request' | 'question' | 'ops_issue'
42
+ const categories: Category[] = ['bug', 'feature_request', 'question', 'ops_issue']
43
+
44
+ const best = categories
45
+ .filter((c) => labels[c].value)
46
+ .sort((a, b) => labels[b].confidence - labels[a].confidence)[0]
47
+
48
+ const category: Category = best ?? 'question'
49
+ const confidence = best ? (labels[best].confidence >= 0.8 ? 'high' : 'medium') : 'low'
50
+
51
+ // Use Zai extract() to generate a concise summary of the request.
52
+ const extracted = await adk.zai.extract(
53
+ input.message,
54
+ z.object({
55
+ summary: z.string().describe('A single concise sentence summarizing the help request'),
56
+ })
57
+ )
58
+
59
+ return {
60
+ category,
61
+ confidence,
62
+ summary: extracted.summary,
63
+ }
64
+ },
65
+ })
@@ -0,0 +1,72 @@
1
+ import { Conversation, Autonomous, z } from '@botpress/runtime'
2
+ import { classifyRequest } from '../actions/classify-request'
3
+
4
+ /**
5
+ * Exit that the AI uses once it has classified and responded to the request.
6
+ * The execute() call ends when the AI selects this exit.
7
+ */
8
+ const TriageComplete = new Autonomous.Exit({
9
+ name: 'triage_complete',
10
+ description: 'Classification is done and the user has been notified. Exit the conversation.',
11
+ schema: z.object({
12
+ category: z.string().describe('The category the request was classified as'),
13
+ }),
14
+ })
15
+
16
+ /**
17
+ * Handles incoming Slack DM messages.
18
+ *
19
+ * Flow: classify the request -> respond to the user -> exit.
20
+ * The AI uses the classifyRequest tool, then selects the TriageComplete exit
21
+ * to end the conversation cleanly.
22
+ *
23
+ * Customize:
24
+ * - Change the channel to "slack.channel" for public channel messages
25
+ * - Add more exits for different outcomes (e.g. needs_more_info, escalated)
26
+ * - Remove the exit to keep the conversation open for follow-ups
27
+ */
28
+ export const SlackDM = new Conversation({
29
+ channel: 'slack.dm',
30
+
31
+ async handler({ execute }) {
32
+ // Classify and respond in one shot. The AI will:
33
+ // 1. Use classifyRequest to categorize the message
34
+ // 2. Tell the user the result
35
+ // 3. Select the TriageComplete exit to end
36
+ const result = await execute({
37
+ instructions: `You are a triage assistant. The user just sent a help request.
38
+
39
+ Your job:
40
+ 1. Use the classifyRequest tool to classify their message
41
+ 2. Tell them what category it was classified as and who it's being routed to
42
+ 3. Be concise. One short paragraph max. Use Slack markdown.
43
+ 4. Then select the triage_complete exit with the category.
44
+
45
+ Do NOT ask follow-up questions. Classify, confirm, exit.`,
46
+ tools: [classifyRequest.asTool()],
47
+ exits: [TriageComplete],
48
+ })
49
+
50
+ if (result.is(TriageComplete)) {
51
+ console.log(`Triaged as: ${result.output.category}`)
52
+ }
53
+
54
+ // --- After triage, the conversation is done. ---
55
+ // Examples of what you could do next instead:
56
+ //
57
+ // // Start the full triage workflow
58
+ // import { TriageFlow } from '../workflows/triage-flow'
59
+ // await TriageFlow.start({ message: message.payload.text })
60
+ //
61
+ // // Chain another execute() for follow-up questions
62
+ // await execute({
63
+ // instructions: 'Ask the user if they want to override the priority.',
64
+ // })
65
+ //
66
+ // // Open-ended support chat (no exit = keeps going until idle)
67
+ // await execute({
68
+ // instructions: 'You are a helpful support agent.',
69
+ // tools: [classifyRequest.asTool()],
70
+ // })
71
+ },
72
+ })
@@ -0,0 +1,33 @@
1
+ # Team Directory
2
+
3
+ Replace this with your actual team info for context-aware routing.
4
+
5
+ ## Engineering
6
+
7
+ - **@oncall-eng** - Bugs, crashes, production incidents
8
+ - **@backend-team** - APIs, services, database issues
9
+ - **@frontend-team** - UI bugs, browser issues
10
+
11
+ ## Product
12
+
13
+ - **@product-team** - Feature requests, roadmap
14
+ - **@design-team** - UX issues, visual bugs
15
+
16
+ ## Operations
17
+
18
+ - **@devops** - Infrastructure, deploys, CI/CD
19
+ - **@security-team** - Vulnerabilities, access, compliance
20
+
21
+ ## Support
22
+
23
+ - **@support-team** - Questions, onboarding, docs
24
+ - **@hr-team** - People ops, policies
25
+
26
+ ## Escalation
27
+
28
+ | Priority | Response Time | Escalation |
29
+ | -------- | ------------- | --------------------- |
30
+ | Critical | 15 min | @oncall-eng + @devops |
31
+ | High | 1 hour | Category assignee |
32
+ | Medium | 4 hours | Category assignee |
33
+ | Low | 1 biz day | Category assignee |
@@ -0,0 +1,38 @@
1
+ import { Table, z } from '@botpress/runtime'
2
+
3
+ /**
4
+ * Stores routing rules that map request categories to assignees and channels.
5
+ *
6
+ * Each row defines where a specific category of request should be routed:
7
+ * - category: The request classification (e.g. "bug", "feature_request")
8
+ * - assignee: Who handles it (e.g. "@oncall-eng", "@product-team")
9
+ * - slackChannel: Slack channel to post the triage summary (e.g. "#bugs")
10
+ * - priority: Default priority for this category
11
+ *
12
+ * The `category` column is searchable so the triage workflow can look up
13
+ * the correct rule quickly.
14
+ *
15
+ * Seed this table after first deploy via the Botpress dashboard or a script:
16
+ * | category | assignee | slackChannel | priority |
17
+ * |-----------------|----------------|-------------------|----------|
18
+ * | bug | @oncall-eng | #bugs | high |
19
+ * | feature_request | @product-team | #feature_requests | medium |
20
+ * | question | @support-team | #help-desk | low |
21
+ * | ops_issue | @devops | #ops-alerts | high |
22
+ *
23
+ * Note: Do NOT define an `id` column -- it is automatically managed by the system.
24
+ */
25
+ export const RoutingRulesTable = new Table({
26
+ name: 'RoutingRulesTable',
27
+ description: 'Maps request categories to assignees and Slack channels for triage routing',
28
+
29
+ columns: {
30
+ category: {
31
+ searchable: true,
32
+ schema: z.string().describe('Request category: bug, feature_request, question, or ops_issue'),
33
+ },
34
+ assignee: z.string().describe('Person or team to assign this category to (e.g. @oncall-eng)'),
35
+ slackChannel: z.string().describe('Slack channel to post triage summaries for this category (e.g. #bugs)'),
36
+ priority: z.string().describe('Default priority level: low, medium, high, or critical'),
37
+ },
38
+ })
@@ -0,0 +1,44 @@
1
+ import { Trigger } from '@botpress/runtime'
2
+ import { TriageFlow } from '../workflows/triage-flow'
3
+
4
+ /**
5
+ * Fires when a new message arrives in a monitored Slack channel.
6
+ *
7
+ * This trigger listens for the "message.created" event and starts the
8
+ * triage workflow for each incoming message. The workflow then classifies
9
+ * the request and routes it to the appropriate person/channel.
10
+ *
11
+ * Customize:
12
+ * - Add filters to ignore bot messages or specific channels
13
+ * - Switch to "slack:reactionAdded" to triage only when someone reacts with a specific emoji
14
+ * - Add "slack:memberJoinedChannel" to welcome new members
15
+ */
16
+ export const onNewMessage = new Trigger({
17
+ name: 'onNewMessage',
18
+ description: 'Starts the triage workflow when a new message arrives in a monitored Slack channel',
19
+ events: ['message.created'],
20
+
21
+ handler: async ({ event }) => {
22
+ const payload = event.payload
23
+
24
+ // Skip empty messages
25
+ if (!payload?.text) {
26
+ return
27
+ }
28
+
29
+ // Optional: skip bot messages to avoid triage loops.
30
+ // Uncomment and adjust the condition for your workspace:
31
+ // if (payload.userId === bot.id) {
32
+ // return;
33
+ // }
34
+
35
+ // Start the triage workflow with the message content
36
+ const instance = await TriageFlow.start({
37
+ message: payload.text,
38
+ senderName: payload.userId ?? 'Unknown',
39
+ sourceChannel: payload.conversationId ?? undefined,
40
+ })
41
+
42
+ console.log(`Triage workflow started: ${instance.id} for message from ${payload.userId}`)
43
+ },
44
+ })
@@ -0,0 +1,104 @@
1
+ import { Workflow, z, actions, bot } from '@botpress/runtime'
2
+ import { RoutingRulesTable } from '../tables/routing-rules'
3
+
4
+ /**
5
+ * Triage workflow: classifies a help request, looks up routing rules,
6
+ * and posts a summary to the appropriate Slack channel.
7
+ *
8
+ * Steps:
9
+ * 1. classify - Run the classifyRequest action to categorize the message
10
+ * 2. lookup - Find the routing rule for this category from the table
11
+ * 3. notify - Post a triage summary to the target Slack channel
12
+ *
13
+ * Customize: Add steps for priority escalation, duplicate detection,
14
+ * SLA tracking, or assignment rotation.
15
+ */
16
+ export const TriageFlow = new Workflow({
17
+ name: 'triageFlow',
18
+ description: 'Classify a help request and route it to the right person',
19
+
20
+ input: z.object({
21
+ message: z.string().describe('The raw help request text'),
22
+ senderName: z.string().optional().describe('Display name of the person who sent the request'),
23
+ sourceChannel: z.string().optional().describe('Slack channel where the request originated'),
24
+ }),
25
+
26
+ output: z.object({
27
+ category: z.string().describe('The classified category'),
28
+ assignee: z.string().describe('Who the request was routed to'),
29
+ summary: z.string().describe('Summary of the request'),
30
+ routed: z.boolean().describe('Whether the request was successfully routed'),
31
+ }),
32
+
33
+ handler: async ({ input, step }) => {
34
+ // Step 1: Classify the request using the AI action
35
+ const classification = await step('classify', async () => {
36
+ return await actions.classifyRequest({ message: input.message })
37
+ })
38
+
39
+ // Step 2: Look up the routing rule for this category
40
+ const routingRule = await step('lookup', async () => {
41
+ const { rows } = await RoutingRulesTable.findRows({
42
+ filter: { category: classification.category },
43
+ limit: 1,
44
+ })
45
+
46
+ if (rows.length === 0) {
47
+ // No routing rule found -- return a sensible default
48
+ return {
49
+ assignee: 'unassigned',
50
+ slackChannel: '#general',
51
+ priority: 'medium',
52
+ }
53
+ }
54
+
55
+ return {
56
+ assignee: rows[0].assignee,
57
+ slackChannel: rows[0].slackChannel,
58
+ priority: rows[0].priority,
59
+ }
60
+ })
61
+
62
+ // Step 3: Post a triage summary to the target Slack channel
63
+ await step('notify', async () => {
64
+ const sender = input.senderName ?? 'Someone'
65
+ const source = input.sourceChannel ? ` in <#${input.sourceChannel}>` : ''
66
+
67
+ const triageMessage = [
68
+ `*New ${classification.category} request*`,
69
+ `> ${classification.summary}`,
70
+ '',
71
+ `*From:* ${sender}${source}`,
72
+ `*Priority:* ${routingRule.priority}`,
73
+ `*Assigned to:* ${routingRule.assignee}`,
74
+ `*Confidence:* ${classification.confidence}`,
75
+ ].join('\n')
76
+
77
+ // Post to the routing channel via Slack integration action.
78
+ // This requires the Slack integration to be configured with appropriate permissions.
79
+ try {
80
+ await actions.slack.addReaction({
81
+ name: 'eyes',
82
+ channel: input.sourceChannel ?? '',
83
+ timestamp: '',
84
+ })
85
+ } catch {
86
+ // Reaction may fail if we do not have the message timestamp -- that is okay
87
+ }
88
+
89
+ console.log(`Triaged: ${classification.category} -> ${routingRule.slackChannel} (${routingRule.assignee})`)
90
+ console.log(triageMessage)
91
+ })
92
+
93
+ // Update bot-level triage counter
94
+ bot.state.totalTriaged += 1
95
+ bot.state.lastTriagedAt = new Date().toISOString()
96
+
97
+ return {
98
+ category: classification.category,
99
+ assignee: routingRule.assignee,
100
+ summary: classification.summary,
101
+ routed: routingRule.assignee !== 'unassigned',
102
+ }
103
+ },
104
+ })
@@ -0,0 +1,22 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ES2022",
5
+ "moduleResolution": "Bundler",
6
+ "lib": ["ES2022", "DOM"],
7
+ "outDir": "./dist",
8
+ "rootDir": ".",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "allowSyntheticDefaultImports": true,
12
+ "skipLibCheck": true,
13
+ "forceConsistentCasingInFileNames": true,
14
+ "moduleDetection": "force",
15
+ "resolveJsonModule": true,
16
+ "paths": {
17
+ "@botpress/runtime/_types/*": ["./.adk/*-types"]
18
+ }
19
+ },
20
+ "include": ["src/**/*", ".adk/**/*"],
21
+ "exclude": ["node_modules", "dist"]
22
+ }
@@ -0,0 +1,47 @@
1
+ {
2
+ "templates": [
3
+ {
4
+ "name": "blank",
5
+ "description": "Empty project with just the folder structure",
6
+ "category": "starter",
7
+ "integrations": [],
8
+ "primitives": [],
9
+ "complexity": "beginner"
10
+ },
11
+ {
12
+ "name": "hello-world",
13
+ "description": "A working chatbot with chat and webchat integrations",
14
+ "category": "starter",
15
+ "integrations": ["chat", "webchat"],
16
+ "primitives": ["conversations"],
17
+ "complexity": "beginner",
18
+ "postInit": ["adk add chat@latest", "adk add webchat@latest"]
19
+ },
20
+ {
21
+ "name": "slack-triage",
22
+ "description": "Slack bot that monitors a channel, classifies requests, and routes to the right person",
23
+ "category": "triage",
24
+ "integrations": ["slack"],
25
+ "primitives": ["actions", "workflows", "conversations", "tables", "triggers", "knowledge"],
26
+ "complexity": "intermediate",
27
+ "postInit": ["adk add slack@latest"]
28
+ },
29
+ {
30
+ "name": "knowledge-assistant",
31
+ "description": "RAG-powered Q&A agent with knowledge base and source citations",
32
+ "category": "knowledge",
33
+ "integrations": ["chat", "webchat"],
34
+ "primitives": ["conversations", "knowledge", "actions"],
35
+ "complexity": "beginner",
36
+ "postInit": ["adk add chat@latest", "adk add webchat@latest"]
37
+ },
38
+ {
39
+ "name": "crm-enrichment",
40
+ "description": "Scheduled workflow that enriches CRM contacts with AI-driven classification",
41
+ "category": "enrichment",
42
+ "integrations": [],
43
+ "primitives": ["workflows", "tables", "actions", "triggers"],
44
+ "complexity": "intermediate"
45
+ }
46
+ ]
47
+ }
@@ -1,19 +1,20 @@
1
1
  /**
2
2
  * Utility for ensuring consistent key ordering in JSON files
3
3
  */
4
- export declare const agentInfoKeyOrder: readonly ["botId", "workspaceId", "apiUrl", "devId"];
4
+ export declare const agentInfoKeyOrder: readonly ["botId", "workspaceId", "apiUrl"];
5
+ export declare const agentLocalInfoKeyOrder: readonly ["botId", "workspaceId", "apiUrl", "devId"];
5
6
  export declare const dependenciesKeyOrder: readonly ["integrations"];
6
7
  export declare const integrationKeyOrder: readonly ["version", "enabled", "configurationType", "config"];
7
8
  /**
8
9
  * Orders object keys according to a specified order, with unspecified keys at the end alphabetically
9
10
  */
10
- export declare function orderKeys<T extends Record<string, any>>(obj: T, keyOrder?: readonly (keyof T)[]): T;
11
+ export declare function orderKeys<T extends Record<string, unknown>>(obj: T, keyOrder?: readonly (keyof T)[]): T;
11
12
  /**
12
13
  * Recursively orders keys in nested objects for integrations
13
14
  */
14
- export declare function orderIntegrationKeys(integrations: Record<string, any>): Record<string, any>;
15
+ export declare function orderIntegrationKeys(integrations: Record<string, unknown>): Record<string, unknown>;
15
16
  /**
16
17
  * Stringifies JSON with consistent key ordering and formatting
17
18
  */
18
- export declare function stringifyWithOrder<T extends Record<string, any>>(obj: T, keyOrder?: readonly (keyof T)[], space?: number | string): string;
19
+ export declare function stringifyWithOrder<T extends Record<string, unknown>>(obj: T, keyOrder?: readonly (keyof T)[], space?: number | string): string;
19
20
  //# sourceMappingURL=json-ordering.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"json-ordering.d.ts","sourceRoot":"","sources":["../../src/utils/json-ordering.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,eAAO,MAAM,iBAAiB,sDAAuD,CAAA;AACrF,eAAO,MAAM,oBAAoB,2BAA4B,CAAA;AAC7D,eAAO,MAAM,mBAAmB,gEAAiE,CAAA;AAEjG;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,QAAQ,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAgCnG;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAY3F;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC9D,GAAG,EAAE,CAAC,EACN,QAAQ,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,EAC/B,KAAK,GAAE,MAAM,GAAG,MAAU,GACzB,MAAM,CAYR"}
1
+ {"version":3,"file":"json-ordering.d.ts","sourceRoot":"","sources":["../../src/utils/json-ordering.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,eAAO,MAAM,iBAAiB,6CAA8C,CAAA;AAC5E,eAAO,MAAM,sBAAsB,sDAAuD,CAAA;AAC1F,eAAO,MAAM,oBAAoB,2BAA4B,CAAA;AAC7D,eAAO,MAAM,mBAAmB,gEAAiE,CAAA;AAEjG;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,QAAQ,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAgCvG;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAYnG;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClE,GAAG,EAAE,CAAC,EACN,QAAQ,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,EAC/B,KAAK,GAAE,MAAM,GAAG,MAAU,GACzB,MAAM,CAcR"}