@botpress/runtime 1.2.4 → 1.2.5

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 (42) hide show
  1. package/dist/_types/channels.d.ts +18 -0
  2. package/dist/_types/channels.d.ts.map +1 -0
  3. package/dist/_types/conversations.d.ts +9 -0
  4. package/dist/_types/conversations.d.ts.map +1 -0
  5. package/dist/_types/integrations.d.ts +13 -0
  6. package/dist/_types/integrations.d.ts.map +1 -0
  7. package/dist/definition.d.ts +1 -0
  8. package/dist/definition.d.ts.map +1 -1
  9. package/dist/definition.js +45914 -9
  10. package/dist/definition.js.map +4 -4
  11. package/dist/internal.d.ts +1 -0
  12. package/dist/internal.d.ts.map +1 -1
  13. package/dist/internal.js +277 -164
  14. package/dist/internal.js.map +4 -4
  15. package/dist/library.d.ts +5 -1
  16. package/dist/library.d.ts.map +1 -1
  17. package/dist/library.js +276 -164
  18. package/dist/library.js.map +4 -4
  19. package/dist/primitives/conversation-instance.d.ts +42 -0
  20. package/dist/primitives/conversation-instance.d.ts.map +1 -0
  21. package/dist/primitives/conversation.d.ts +30 -64
  22. package/dist/primitives/conversation.d.ts.map +1 -1
  23. package/dist/primitives/definition.d.ts +1 -1
  24. package/dist/primitives/definition.d.ts.map +1 -1
  25. package/dist/primitives/index.d.ts +3 -0
  26. package/dist/primitives/index.d.ts.map +1 -1
  27. package/dist/primitives/workflow-instance.d.ts +0 -2
  28. package/dist/primitives/workflow-instance.d.ts.map +1 -1
  29. package/dist/primitives/workflow.d.ts +1 -2
  30. package/dist/primitives/workflow.d.ts.map +1 -1
  31. package/dist/runtime/adk.d.ts +1 -1
  32. package/dist/runtime/adk.d.ts.map +1 -1
  33. package/dist/runtime/autonomous.d.ts.map +1 -1
  34. package/dist/runtime/handlers/conversation-matching.d.ts +17 -0
  35. package/dist/runtime/handlers/conversation-matching.d.ts.map +1 -0
  36. package/dist/runtime/handlers/conversation.d.ts.map +1 -1
  37. package/dist/runtime/handlers/event.d.ts.map +1 -1
  38. package/dist/runtime/tracked-state.d.ts +16 -5
  39. package/dist/runtime/tracked-state.d.ts.map +1 -1
  40. package/dist/runtime.js +311 -207
  41. package/dist/runtime.js.map +4 -4
  42. package/package.json +1 -1
package/dist/runtime.js CHANGED
@@ -48,7 +48,7 @@ var init_define_BUILD = __esm({
48
48
  var define_PACKAGE_VERSIONS_default;
49
49
  var init_define_PACKAGE_VERSIONS = __esm({
50
50
  "<define:__PACKAGE_VERSIONS__>"() {
51
- define_PACKAGE_VERSIONS_default = { runtime: "1.2.4", adk: "not-installed", sdk: "4.16.0", llmz: "0.0.26", zai: "2.1.16", cognitive: "0.1.47" };
51
+ define_PACKAGE_VERSIONS_default = { runtime: "1.2.5", adk: "not-installed", sdk: "4.16.0", llmz: "0.0.26", zai: "2.1.16", cognitive: "0.1.47" };
52
52
  }
53
53
  });
54
54
 
@@ -27463,6 +27463,47 @@ var require_indexv2 = __commonJS({
27463
27463
  }
27464
27464
  });
27465
27465
 
27466
+ // src/utilities/trigger-tags.ts
27467
+ var trigger_tags_exports = {};
27468
+ __export(trigger_tags_exports, {
27469
+ getTriggerSubscriptionTags: () => getTriggerSubscriptionTags,
27470
+ getTriggerTagName: () => getTriggerTagName,
27471
+ getTriggerTagValue: () => getTriggerTagValue,
27472
+ isConversationSubscribedToTrigger: () => isConversationSubscribedToTrigger
27473
+ });
27474
+ import crypto2 from "crypto";
27475
+ var hashString, getTriggerTagName, getTriggerTagValue, getTriggerSubscriptionTags, isConversationSubscribedToTrigger;
27476
+ var init_trigger_tags = __esm({
27477
+ "src/utilities/trigger-tags.ts"() {
27478
+ "use strict";
27479
+ init_define_BUILD();
27480
+ init_define_PACKAGE_VERSIONS();
27481
+ hashString = (str) => {
27482
+ return crypto2.createHash("md5").update(str).digest("hex").substring(0, 5).toUpperCase();
27483
+ };
27484
+ getTriggerTagName = (triggerName) => {
27485
+ return `trigger${hashString(triggerName)}`;
27486
+ };
27487
+ getTriggerTagValue = (key) => {
27488
+ return key ?? "*";
27489
+ };
27490
+ getTriggerSubscriptionTags = (triggerName, key) => {
27491
+ return {
27492
+ name: getTriggerTagName(triggerName),
27493
+ value: getTriggerTagValue(key)
27494
+ };
27495
+ };
27496
+ isConversationSubscribedToTrigger = (conversationTags, triggerName, triggerKey) => {
27497
+ const tagName = getTriggerTagName(triggerName);
27498
+ const tagValue = conversationTags[tagName];
27499
+ if (!tagValue) {
27500
+ return false;
27501
+ }
27502
+ return tagValue === "*" || tagValue === triggerKey;
27503
+ };
27504
+ }
27505
+ });
27506
+
27466
27507
  // ../../node_modules/.bun/@isaacs+balanced-match@4.0.1/node_modules/@isaacs/balanced-match/dist/esm/index.js
27467
27508
  var balanced, maybeMatch, range;
27468
27509
  var init_esm3 = __esm({
@@ -39692,9 +39733,6 @@ var Autonomous;
39692
39733
  Autonomous2.DefaultExit = _DefaultExit;
39693
39734
  function createKnowledgeSearchTool(knowledgeBases) {
39694
39735
  const kbNames = knowledgeBases.map((kb) => kb.name);
39695
- for (const kb of knowledgeBases) {
39696
- console.log(kb.name, kb.description);
39697
- }
39698
39736
  const description = knowledgeBases.map((kb) => `- "${kb.name}": ${kb.description || "No description"}`).join("\n");
39699
39737
  return new LlmzTool({
39700
39738
  name: "search_knowledge",
@@ -39719,6 +39757,8 @@ If the question is not related to the knowledge bases, do NOT use this tool.`.tr
39719
39757
  const { passages } = await client.searchFiles({
39720
39758
  query,
39721
39759
  withContext: true,
39760
+ includeBreadcrumb: true,
39761
+ contextDepth: 4,
39722
39762
  tags: {
39723
39763
  [WellKnownTags.knowledge.KNOWLEDGE]: "true",
39724
39764
  [WellKnownTags.knowledge.KNOWLEDGE_BASE_NAME]: kbNames
@@ -39762,12 +39802,12 @@ If the question is not related to the knowledge bases, do NOT use this tool.`.tr
39762
39802
  citationMetadata.sourceId = tags[WellKnownTags.knowledge.KNOWLEDGE_SOURCE_ID];
39763
39803
  }
39764
39804
  const { tag } = citations.registerSource(citationMetadata);
39765
- message.push(`<${tag} file="${p.file.key}">`);
39766
- message.push(`**${citationMetadata.title || p.file.key}**`);
39805
+ message.push(
39806
+ `<${tag} file="${p.file.key}" title="${citationMetadata.title || p.file.key}">`
39807
+ );
39767
39808
  message.push(p.content);
39768
39809
  message.push(`</${tag}>`);
39769
39810
  }
39770
- console.log(message.join("\n").trim());
39771
39811
  throw new Autonomous2.ThinkSignal(
39772
39812
  `We got the search results. When answering the question, you MUST add inline the citations used (eg: "Yes, the price is $10${example} ...")`,
39773
39813
  message.join("\n").trim()
@@ -40363,6 +40403,129 @@ init_define_PACKAGE_VERSIONS();
40363
40403
  init_define_BUILD();
40364
40404
  init_define_PACKAGE_VERSIONS();
40365
40405
 
40406
+ // src/primitives/conversation-instance.ts
40407
+ init_define_BUILD();
40408
+ init_define_PACKAGE_VERSIONS();
40409
+ var BaseConversationInstance = class {
40410
+ id;
40411
+ channel;
40412
+ integration;
40413
+ tags;
40414
+ conversation;
40415
+ // @internal
40416
+ client;
40417
+ // @internal
40418
+ TrackedState;
40419
+ constructor(conversation, client) {
40420
+ this.id = conversation.id;
40421
+ this.channel = conversation.channel;
40422
+ this.integration = conversation.integration;
40423
+ this.tags = conversation.tags;
40424
+ this.conversation = conversation;
40425
+ this.client = client;
40426
+ const states = context2.get("states", { optional: true });
40427
+ const existingState = states?.find(
40428
+ (s) => s.type === "conversation" && s.id === conversation.id && s.name === BUILT_IN_STATES.conversation
40429
+ );
40430
+ if (!existingState) {
40431
+ throw new Error(
40432
+ `Conversation state not found for conversation ${conversation.id}. Make sure TrackedState.loadAll() is called before creating conversation instances.`
40433
+ );
40434
+ }
40435
+ this.TrackedState = existingState;
40436
+ }
40437
+ /**
40438
+ * Send a message to this conversation
40439
+ */
40440
+ async send(message) {
40441
+ try {
40442
+ const chat = context2.get("chat");
40443
+ await trackPromise(
40444
+ chat.sendMessage({
40445
+ type: message.type,
40446
+ payload: message.payload
40447
+ })
40448
+ );
40449
+ } catch (err) {
40450
+ console.error("Error sending message in conversation:", err);
40451
+ }
40452
+ }
40453
+ /**
40454
+ * Start typing indicator
40455
+ */
40456
+ async startTyping() {
40457
+ const mapping = InterfaceMappings.getIntegrationAction(
40458
+ "typingIndicator",
40459
+ "startTypingIndicator",
40460
+ this.integration
40461
+ );
40462
+ if (mapping) {
40463
+ const message = context2.get("message", { optional: true });
40464
+ await this.client.callAction({
40465
+ type: mapping,
40466
+ input: {
40467
+ conversationId: this.id,
40468
+ messageId: message?.id
40469
+ }
40470
+ }).catch(() => {
40471
+ });
40472
+ }
40473
+ }
40474
+ /**
40475
+ * Stop typing indicator
40476
+ */
40477
+ async stopTyping() {
40478
+ const mapping = InterfaceMappings.getIntegrationAction(
40479
+ "typingIndicator",
40480
+ "stopTypingIndicator",
40481
+ this.integration
40482
+ );
40483
+ if (mapping) {
40484
+ const message = context2.get("message", { optional: true });
40485
+ await this.client.callAction({
40486
+ type: mapping,
40487
+ input: {
40488
+ conversationId: this.id,
40489
+ messageId: message?.id
40490
+ }
40491
+ }).catch(() => {
40492
+ });
40493
+ }
40494
+ }
40495
+ /**
40496
+ * Subscribe to a trigger
40497
+ */
40498
+ async subscribeToTrigger(triggerName, key) {
40499
+ const { getTriggerSubscriptionTags: getTriggerSubscriptionTags2, isConversationSubscribedToTrigger: isConversationSubscribedToTrigger2 } = await Promise.resolve().then(() => (init_trigger_tags(), trigger_tags_exports));
40500
+ if (isConversationSubscribedToTrigger2(this.tags, triggerName, key)) {
40501
+ return;
40502
+ }
40503
+ const { name, value } = getTriggerSubscriptionTags2(triggerName, key);
40504
+ await this.client.updateConversation({
40505
+ id: this.id,
40506
+ tags: {
40507
+ [name]: value
40508
+ }
40509
+ });
40510
+ }
40511
+ /**
40512
+ * Unsubscribe from a trigger
40513
+ */
40514
+ async unsubscribeFromTrigger(triggerName, key) {
40515
+ const { getTriggerSubscriptionTags: getTriggerSubscriptionTags2, isConversationSubscribedToTrigger: isConversationSubscribedToTrigger2 } = await Promise.resolve().then(() => (init_trigger_tags(), trigger_tags_exports));
40516
+ if (!isConversationSubscribedToTrigger2(this.tags, triggerName, key)) {
40517
+ return;
40518
+ }
40519
+ const { name } = getTriggerSubscriptionTags2(triggerName, key);
40520
+ await this.client.updateConversation({
40521
+ id: this.id,
40522
+ tags: {
40523
+ [name]: ""
40524
+ }
40525
+ });
40526
+ }
40527
+ };
40528
+
40366
40529
  // src/primitives/definition.ts
40367
40530
  init_define_BUILD();
40368
40531
  init_define_PACKAGE_VERSIONS();
@@ -40371,7 +40534,12 @@ var Definitions;
40371
40534
  ((Definitions2) => {
40372
40535
  const conversationDefinitionSchema = z3.object({
40373
40536
  type: z3.literal("conversation"),
40374
- channel: z3.string().min(1, "Channel must be a non-empty string").max(255, "Channel must be less than 255 characters").regex(/^[a-zA-Z0-9._-]+$/, "Channel must be a valid identifier")
40537
+ channel: z3.union([
40538
+ z3.string().min(1, "Channel must be a non-empty string").max(255, "Channel must be less than 255 characters").regex(/^(\*|[a-zA-Z0-9._-]+)$/, "Channel must be a valid identifier or glob '*'"),
40539
+ z3.array(
40540
+ z3.string().min(1, "Channel must be a non-empty string").max(255, "Channel must be less than 255 characters").regex(/^[a-zA-Z0-9._-]+$/, "Channel must be a valid identifier")
40541
+ )
40542
+ ])
40375
40543
  });
40376
40544
  const workflowDefinitionSchema = z3.object({
40377
40545
  type: z3.literal("workflow"),
@@ -42668,34 +42836,6 @@ init_define_PACKAGE_VERSIONS();
42668
42836
  import { z as z8 } from "@botpress/sdk";
42669
42837
  import { setTimeout as setTimeout2 } from "node:timers/promises";
42670
42838
 
42671
- // src/utilities/trigger-tags.ts
42672
- init_define_BUILD();
42673
- init_define_PACKAGE_VERSIONS();
42674
- import crypto2 from "crypto";
42675
- var hashString = (str) => {
42676
- return crypto2.createHash("md5").update(str).digest("hex").substring(0, 5).toUpperCase();
42677
- };
42678
- var getTriggerTagName = (triggerName) => {
42679
- return `trigger${hashString(triggerName)}`;
42680
- };
42681
- var getTriggerTagValue = (key) => {
42682
- return key ?? "*";
42683
- };
42684
- var getTriggerSubscriptionTags = (triggerName, key) => {
42685
- return {
42686
- name: getTriggerTagName(triggerName),
42687
- value: getTriggerTagValue(key)
42688
- };
42689
- };
42690
- var isConversationSubscribedToTrigger = (conversationTags, triggerName, triggerKey) => {
42691
- const tagName = getTriggerTagName(triggerName);
42692
- const tagValue = conversationTags[tagName];
42693
- if (!tagValue) {
42694
- return false;
42695
- }
42696
- return tagValue === "*" || tagValue === triggerKey;
42697
- };
42698
-
42699
42839
  // src/utilities/events.ts
42700
42840
  init_define_BUILD();
42701
42841
  init_define_PACKAGE_VERSIONS();
@@ -42720,18 +42860,14 @@ var Typings2;
42720
42860
  Typings8.Primitive = "conversation";
42721
42861
  })(Typings2 || (Typings2 = {}));
42722
42862
  var BaseConversation = class {
42723
- integration;
42724
42863
  channel;
42725
42864
  /** @internal */
42726
42865
  schema;
42727
42866
  #handler;
42728
- #state;
42729
42867
  #startFromTrigger;
42730
- #interruptionSignal;
42731
42868
  constructor(props) {
42732
42869
  this.channel = props.channel;
42733
42870
  this.schema = props.state ?? z8.object({}).passthrough();
42734
- this.integration = props.channel.split(".")[0];
42735
42871
  this.#handler = props.handler;
42736
42872
  if (props.startFromTrigger) {
42737
42873
  this.#startFromTrigger = props.startFromTrigger;
@@ -42743,31 +42879,34 @@ var BaseConversation = class {
42743
42879
  }
42744
42880
  /** @internal */
42745
42881
  getDefinition() {
42746
- return {
42747
- type: "conversation",
42748
- channel: this.channel
42749
- };
42750
- }
42751
- set state(state) {
42752
- this.#state = state;
42753
- }
42754
- get state() {
42755
- return this.#state;
42756
- }
42757
- get id() {
42758
- return context2.get("conversation").id;
42759
- }
42760
- get tags() {
42761
- return context2.get("conversation").tags;
42882
+ if (this.channel === "*") {
42883
+ return {
42884
+ type: "conversation",
42885
+ channel: "*"
42886
+ };
42887
+ } else if (Array.isArray(this.channel)) {
42888
+ return {
42889
+ type: "conversation",
42890
+ channel: this.channel
42891
+ };
42892
+ } else {
42893
+ return {
42894
+ type: "conversation",
42895
+ channel: this.channel
42896
+ };
42897
+ }
42762
42898
  }
42763
- // TODO: separate the handler from the conversation definition
42764
- // TODO: each execution should have its own instance to avoid state conflicts etc
42899
+ /** @internal */
42765
42900
  async [ConversationHandler]() {
42766
42901
  const message = context2.get("message", { optional: true });
42767
42902
  const event = context2.get("event", { optional: true });
42768
42903
  const chat = context2.get("chat");
42769
42904
  const client = context2.get("client");
42770
- const conversationId = this.id;
42905
+ const botpressConversation = context2.get("conversation");
42906
+ const conversationInstance = new BaseConversationInstance(
42907
+ botpressConversation,
42908
+ client
42909
+ );
42771
42910
  let type;
42772
42911
  let requestObject = void 0;
42773
42912
  if (message) {
@@ -42792,11 +42931,10 @@ var BaseConversation = class {
42792
42931
  type = "event";
42793
42932
  }
42794
42933
  const controller = new AbortController();
42795
- this.#interruptionSignal = controller.signal;
42796
42934
  void span(
42797
42935
  "interruption.check",
42798
42936
  {
42799
- conversationId
42937
+ conversationId: conversationInstance.id
42800
42938
  },
42801
42939
  async (s) => {
42802
42940
  async function checkNewUserMessage() {
@@ -42804,7 +42942,7 @@ var BaseConversation = class {
42804
42942
  return;
42805
42943
  }
42806
42944
  const { events } = await client.listEvents({
42807
- conversationId,
42945
+ conversationId: conversationInstance.id,
42808
42946
  status: "pending"
42809
42947
  });
42810
42948
  const newEvents = events.filter(
@@ -42860,98 +42998,30 @@ var BaseConversation = class {
42860
42998
  const execute = Autonomous.createExecute({
42861
42999
  mode: "chat",
42862
43000
  defaultModel: adk.project.config.defaultModels.autonomous,
42863
- ...this.#interruptionSignal && {
42864
- interruption: this.#interruptionSignal
43001
+ interruption: controller.signal
43002
+ });
43003
+ if (!conversationInstance.TrackedState.value) {
43004
+ conversationInstance.TrackedState.value = {};
43005
+ }
43006
+ const stateProxy = new Proxy(conversationInstance.TrackedState.value, {
43007
+ set(target, prop, value) {
43008
+ const result = Reflect.set(target, prop, value);
43009
+ conversationInstance.TrackedState.markDirty();
43010
+ return result;
42865
43011
  }
42866
43012
  });
42867
- await this.#handler.call(this, {
43013
+ await this.#handler({
42868
43014
  type,
42869
43015
  message,
42870
43016
  event,
42871
43017
  request: requestObject,
43018
+ conversation: conversationInstance,
43019
+ state: stateProxy,
43020
+ client,
42872
43021
  execute
42873
43022
  });
42874
43023
  controller.abort();
42875
43024
  }
42876
- async subscribeToTrigger(triggerName, key) {
42877
- if (isConversationSubscribedToTrigger(this.tags, triggerName, key)) {
42878
- return;
42879
- }
42880
- const conversation = context2.get("conversation");
42881
- const client = context2.get("client");
42882
- const { name, value } = getTriggerSubscriptionTags(triggerName, key);
42883
- await client.updateConversation({
42884
- id: conversation.id,
42885
- tags: {
42886
- [name]: value
42887
- }
42888
- });
42889
- }
42890
- async unsubscribeFromTrigger(triggerName, key) {
42891
- if (!isConversationSubscribedToTrigger(this.tags, triggerName, key)) {
42892
- return;
42893
- }
42894
- const conversation = context2.get("conversation");
42895
- const client = context2.get("client");
42896
- const { name } = getTriggerSubscriptionTags(triggerName, key);
42897
- await client.updateConversation({
42898
- id: conversation.id,
42899
- tags: {
42900
- [name]: ""
42901
- }
42902
- });
42903
- }
42904
- async startTyping() {
42905
- const conversation = context2.get("conversation", { optional: true });
42906
- const message = context2.get("message", { optional: true });
42907
- const mapping = InterfaceMappings.getIntegrationAction(
42908
- "typingIndicator",
42909
- "startTypingIndicator",
42910
- conversation?.integration
42911
- );
42912
- if (conversation && mapping) {
42913
- await context2.get("client").callAction({
42914
- type: mapping,
42915
- input: {
42916
- conversationId: conversation.id,
42917
- messageId: message?.id
42918
- }
42919
- }).catch(() => {
42920
- });
42921
- }
42922
- }
42923
- async stopTyping() {
42924
- const conversation = context2.get("conversation", { optional: true });
42925
- const message = context2.get("message", { optional: true });
42926
- const mapping = InterfaceMappings.getIntegrationAction(
42927
- "typingIndicator",
42928
- "stopTypingIndicator",
42929
- conversation?.integration
42930
- );
42931
- if (conversation && mapping) {
42932
- await context2.get("client").callAction({
42933
- type: mapping,
42934
- input: {
42935
- conversationId: conversation.id,
42936
- messageId: message?.id
42937
- }
42938
- }).catch(() => {
42939
- });
42940
- }
42941
- }
42942
- async send(message) {
42943
- try {
42944
- const chat = context2.get("chat");
42945
- await trackPromise(
42946
- chat.sendMessage({
42947
- type: message.type,
42948
- payload: message.payload
42949
- })
42950
- );
42951
- } catch (err) {
42952
- console.error("Error getting context in conversation.send:", err);
42953
- }
42954
- }
42955
43025
  };
42956
43026
 
42957
43027
  // src/primitives/knowledge.ts
@@ -43342,6 +43412,7 @@ var Primitives;
43342
43412
  ((Primitives2) => {
43343
43413
  Primitives2.Definitions = Definitions;
43344
43414
  Primitives2.BaseConversation = BaseConversation;
43415
+ Primitives2.BaseConversationInstance = BaseConversationInstance;
43345
43416
  Primitives2.Conversation = Typings2;
43346
43417
  Primitives2.BaseKnowledge = BaseKnowledge;
43347
43418
  Primitives2.Knowledge = Typings3;
@@ -43951,22 +44022,16 @@ var BaseWorkflowInstance = class _BaseWorkflowInstance {
43951
44022
  workflow;
43952
44023
  // @internal
43953
44024
  TrackedState;
43954
- set state(state) {
43955
- this.TrackedState.value = state;
43956
- }
43957
- get state() {
43958
- return this.TrackedState.value;
43959
- }
43960
44025
  constructor(workflow, client) {
43961
44026
  const definition = adk.project.workflows.find(
43962
44027
  (w) => w.name === workflow.name
43963
44028
  );
43964
- this.TrackedState = TrackedState.create({
44029
+ this.TrackedState = TrackedState2.create({
43965
44030
  type: "workflow",
43966
44031
  client: client._inner,
43967
44032
  id: workflow.id,
43968
44033
  schema: definition?.stateSchema,
43969
- name: "workflowState"
44034
+ name: BUILT_IN_STATES.workflowState
43970
44035
  });
43971
44036
  this.id = workflow.id;
43972
44037
  this.name = workflow.name;
@@ -44050,7 +44115,7 @@ var BaseWorkflowInstance = class _BaseWorkflowInstance {
44050
44115
  `No ADK Workflow handler found for "${this.name}"`
44051
44116
  );
44052
44117
  }
44053
- await TrackedState.loadAll();
44118
+ await TrackedState2.loadAll();
44054
44119
  const workflowControlContext = {
44055
44120
  workflow: this.workflow,
44056
44121
  aborted: false,
@@ -44097,14 +44162,25 @@ var BaseWorkflowInstance = class _BaseWorkflowInstance {
44097
44162
  "Workflow execution state is not loaded"
44098
44163
  );
44099
44164
  workflowExecutionState.value.executionCount++;
44165
+ if (!this.TrackedState.value) {
44166
+ this.TrackedState.value = {};
44167
+ }
44168
+ const trackedState = this.TrackedState;
44169
+ const stateProxy = new Proxy(this.TrackedState.value, {
44170
+ set(target, prop, value) {
44171
+ const result2 = Reflect.set(target, prop, value);
44172
+ trackedState.markDirty();
44173
+ return result2;
44174
+ }
44175
+ });
44100
44176
  const result = await context2.run(
44101
44177
  {
44102
44178
  ...ctx,
44103
44179
  workflowControlContext
44104
44180
  },
44105
- async () => handler.call(this, {
44181
+ async () => handler({
44106
44182
  input: this.input,
44107
- state: this.state,
44183
+ state: stateProxy,
44108
44184
  step,
44109
44185
  client: this.client,
44110
44186
  execute: this.execute.bind(this)
@@ -44133,7 +44209,7 @@ var BaseWorkflowInstance = class _BaseWorkflowInstance {
44133
44209
  };
44134
44210
  }
44135
44211
  } finally {
44136
- await TrackedState.saveAllDirty();
44212
+ await TrackedState2.saveAllDirty();
44137
44213
  }
44138
44214
  }
44139
44215
  /**
@@ -44165,12 +44241,12 @@ var BaseWorkflowInstance = class _BaseWorkflowInstance {
44165
44241
  }
44166
44242
  };
44167
44243
  function createWorkflowExecutionState(client, workflowId) {
44168
- return TrackedState.create({
44244
+ return TrackedState2.create({
44169
44245
  type: "workflow",
44170
44246
  client,
44171
44247
  id: workflowId,
44172
44248
  schema: workflowExecutionContextSchema,
44173
- name: "workflowExecutionContext"
44249
+ name: BUILT_IN_STATES.workflowSteps
44174
44250
  });
44175
44251
  }
44176
44252
 
@@ -44197,8 +44273,6 @@ var BaseWorkflow = class {
44197
44273
  /** @internal */
44198
44274
  schedule;
44199
44275
  timeout = (0, import_ms.default)("5m");
44200
- // Runtime state
44201
- state;
44202
44276
  constructor(props) {
44203
44277
  this.name = props.name;
44204
44278
  if (props.description !== void 0) {
@@ -44566,13 +44640,18 @@ var EMPTY_STATE = {
44566
44640
  };
44567
44641
  var MAX_SWAP_FILE_SIZE = import_bytes2.default.parse("100MB");
44568
44642
  var BUILT_IN_STATES = {
44569
- user: "userState",
44643
+ /** Generic conversation-specific state (user-defined per conversation) */
44570
44644
  conversation: "state",
44645
+ /** User-specific state (persists across conversations per user) */
44646
+ user: "userState",
44647
+ /** Bot-wide global state (persists across all conversations) */
44571
44648
  bot: "botState",
44649
+ /** Workflow-specific state (persists across workflow executions) */
44572
44650
  workflowState: "workflowState",
44651
+ /** Workflow cached steps executions */
44573
44652
  workflowSteps: "workflowSteps"
44574
44653
  };
44575
- var TrackedState = class _TrackedState {
44654
+ var TrackedState2 = class _TrackedState {
44576
44655
  type;
44577
44656
  id;
44578
44657
  name;
@@ -44642,6 +44721,7 @@ var TrackedState = class _TrackedState {
44642
44721
  const client = context2.get("client")._inner;
44643
44722
  const botId = context2.get("botId", { optional: true });
44644
44723
  const user2 = context2.get("user", { optional: true });
44724
+ const conversation = context2.get("conversation", { optional: true });
44645
44725
  if (botId) {
44646
44726
  _TrackedState.create({
44647
44727
  client,
@@ -44660,6 +44740,23 @@ var TrackedState = class _TrackedState {
44660
44740
  schema: adk.project.config.user?.state || z20.object({})
44661
44741
  });
44662
44742
  }
44743
+ if (conversation) {
44744
+ const definition = adk.project.conversations.find((c) => {
44745
+ const def = c.getDefinition();
44746
+ if (typeof def.channel === "string") {
44747
+ return def.channel === conversation.channel || def.channel === "*";
44748
+ } else {
44749
+ return def.channel.includes(conversation.channel);
44750
+ }
44751
+ });
44752
+ _TrackedState.create({
44753
+ client,
44754
+ name: BUILT_IN_STATES.conversation,
44755
+ type: "conversation",
44756
+ id: conversation.id,
44757
+ schema: definition?.schema || z20.object({})
44758
+ });
44759
+ }
44663
44760
  const states = context2.get("states", { optional: true });
44664
44761
  const promises = Promise.allSettled(
44665
44762
  states?.map((state) => state.load()) ?? []
@@ -44706,16 +44803,23 @@ var TrackedState = class _TrackedState {
44706
44803
  } else {
44707
44804
  this.value = value;
44708
44805
  }
44709
- if ((this.value == null || this.value === void 0) && this.state && "parse" in this.state) {
44710
- try {
44711
- this.value = this.state.parse({});
44712
- this._isDirty = true;
44713
- } catch (error) {
44806
+ if (this.value == null || this.value === void 0) {
44807
+ if (this.state && "parse" in this.state) {
44714
44808
  try {
44715
- this.value = this.state.parse(void 0);
44809
+ this.value = this.state.parse({});
44716
44810
  this._isDirty = true;
44717
- } catch {
44811
+ } catch (error) {
44812
+ try {
44813
+ this.value = this.state.parse(void 0);
44814
+ this._isDirty = true;
44815
+ } catch {
44816
+ this.value = {};
44817
+ this._isDirty = true;
44818
+ }
44718
44819
  }
44820
+ } else {
44821
+ this.value = {};
44822
+ this._isDirty = true;
44719
44823
  }
44720
44824
  }
44721
44825
  try {
@@ -45117,12 +45221,12 @@ var patchHandlers = (bot2) => {
45117
45221
  reject(error);
45118
45222
  } finally {
45119
45223
  clearTimeout(timeout);
45120
- await TrackedState.saveAllDirty();
45224
+ await TrackedState2.saveAllDirty();
45121
45225
  }
45122
45226
  });
45123
45227
  } finally {
45124
- await TrackedState.saveAllDirty();
45125
- TrackedState.unloadAll();
45228
+ await TrackedState2.saveAllDirty();
45229
+ TrackedState2.unloadAll();
45126
45230
  await shutdownPromiseTracker();
45127
45231
  }
45128
45232
  }
@@ -46065,6 +46169,31 @@ __export(conversation_exports, {
46065
46169
  });
46066
46170
  init_define_BUILD();
46067
46171
  init_define_PACKAGE_VERSIONS();
46172
+
46173
+ // src/runtime/handlers/conversation-matching.ts
46174
+ init_define_BUILD();
46175
+ init_define_PACKAGE_VERSIONS();
46176
+ function matchesChannel(handlerChannel, incomingChannel) {
46177
+ if (handlerChannel === "*") {
46178
+ return true;
46179
+ } else if (Array.isArray(handlerChannel)) {
46180
+ return handlerChannel.includes(incomingChannel);
46181
+ } else {
46182
+ return handlerChannel === incomingChannel;
46183
+ }
46184
+ }
46185
+ function findMatchingHandler(handlers2, incomingChannel) {
46186
+ const matchingHandlers = handlers2.filter(
46187
+ (h) => matchesChannel(h.channel, incomingChannel)
46188
+ );
46189
+ return matchingHandlers.sort((a, b) => {
46190
+ const aScore = a.channel === "*" ? 0 : Array.isArray(a.channel) ? 1 : 2;
46191
+ const bScore = b.channel === "*" ? 0 : Array.isArray(b.channel) ? 1 : 2;
46192
+ return bScore - aScore;
46193
+ })[0];
46194
+ }
46195
+
46196
+ // src/runtime/handlers/conversation.ts
46068
46197
  var setup = (bot2) => {
46069
46198
  bot2.on.message(
46070
46199
  "*",
@@ -46086,38 +46215,25 @@ var setup = (bot2) => {
46086
46215
  },
46087
46216
  async () => {
46088
46217
  const handlerName = conversation.integration + "." + conversation.channel;
46089
- const handler = adk.project.conversations.find(
46090
- (x) => x.channel === handlerName
46091
- );
46218
+ const handler = findMatchingHandler(adk.project.conversations, handlerName);
46092
46219
  if (!handler) {
46093
46220
  logger.debug(
46094
46221
  `Skipping message, no ADK Conversation defined for "${handlerName}"`
46095
46222
  );
46096
46223
  return;
46097
46224
  }
46098
- const startTyping = trackPromise(handler.startTyping());
46099
46225
  const chat = new BotpressChat(context2.getAll());
46100
46226
  context2.set("chat", chat);
46101
- const state = TrackedState.create({
46102
- type: "conversation",
46103
- client: client._inner,
46104
- id: conversation.id,
46105
- schema: handler.state,
46106
- name: "state"
46107
- });
46108
46227
  const [transcript, _statesLoaded] = await Promise.all([
46109
46228
  chat.fetchTranscript(),
46110
- TrackedState.loadAll()
46229
+ TrackedState2.loadAll()
46111
46230
  ]);
46112
46231
  if (transcript.find((x) => x.id === message.id)) {
46113
46232
  return;
46114
46233
  }
46115
46234
  await chat.addMessage(message);
46116
- handler.state = state.value;
46117
46235
  await handler[ConversationHandler]();
46118
- state.value = handler.state;
46119
- trackPromise(TrackedState.saveAllDirty());
46120
- trackPromise(startTyping.then(() => handler.stopTyping()));
46236
+ await TrackedState2.saveAllDirty();
46121
46237
  await chat.saveTranscript();
46122
46238
  }
46123
46239
  );
@@ -46236,7 +46352,7 @@ var setup3 = (bot2) => {
46236
46352
  });
46237
46353
  try {
46238
46354
  const interval = setInterval(async () => {
46239
- await TrackedState.saveAllDirty();
46355
+ await TrackedState2.saveAllDirty();
46240
46356
  }, 2e4);
46241
46357
  const result = await new Promise((resolve, reject) => {
46242
46358
  const remainingTime = context2.get("runtime").getRemainingExecutionTimeInMs();
@@ -46259,7 +46375,7 @@ var setup3 = (bot2) => {
46259
46375
  });
46260
46376
  if (result.status === "continue") {
46261
46377
  s.setAttribute("workflow.status.final", "continue");
46262
- await TrackedState.saveAllDirty();
46378
+ await TrackedState2.saveAllDirty();
46263
46379
  } else if (result.status === "done") {
46264
46380
  s.setAttribute("workflow.status.final", "completed");
46265
46381
  await updateWorkflow({
@@ -46373,9 +46489,7 @@ var setup4 = (bot2) => {
46373
46489
  return;
46374
46490
  }
46375
46491
  const handlerName = conversation.integration + "." + conversation.channel;
46376
- const handler = adk.project.conversations.find(
46377
- (c) => c.channel === handlerName
46378
- );
46492
+ const handler = findMatchingHandler(adk.project.conversations, handlerName);
46379
46493
  if (!handler) {
46380
46494
  logger.debug(
46381
46495
  `Skipping message, no ADK Conversation defined for "${handlerName}"`
@@ -46395,28 +46509,17 @@ var setup4 = (bot2) => {
46395
46509
  workflowId: payload.workflowId
46396
46510
  },
46397
46511
  async () => {
46398
- const startTyping = trackPromise(handler.startTyping());
46399
46512
  const chat = new BotpressChat(context2.getAll());
46400
46513
  context2.set("chat", chat);
46401
- const state = TrackedState.create({
46402
- type: "conversation",
46403
- client: client._inner,
46404
- id: conversation.id,
46405
- schema: handler.state,
46406
- name: "state"
46407
- });
46408
46514
  const transcript = await chat.fetchTranscript();
46409
46515
  if (transcript.find((x) => x.id === event.id)) {
46410
46516
  logger.debug(`Message ${event.id} already processed`);
46411
46517
  return;
46412
46518
  }
46413
46519
  await chat.addEvent(event);
46414
- await TrackedState.loadAll();
46415
- handler.state = state.value;
46520
+ await TrackedState2.loadAll();
46416
46521
  await handler[ConversationHandler]();
46417
- state.value = handler.state;
46418
- trackPromise(TrackedState.saveAllDirty());
46419
- trackPromise(startTyping.then(() => handler.stopTyping()));
46522
+ await TrackedState2.saveAllDirty();
46420
46523
  await chat.saveTranscript();
46421
46524
  }
46422
46525
  );
@@ -47454,6 +47557,7 @@ function installStructuredLogging() {
47454
47557
  }
47455
47558
 
47456
47559
  // src/runtime.ts
47560
+ init_trigger_tags();
47457
47561
  import { z as z24 } from "@botpress/sdk";
47458
47562
  if (Environment.isDevelopment() || Environment.isProduction()) {
47459
47563
  installStructuredLogging();
@@ -47466,7 +47570,7 @@ export {
47466
47570
  Message,
47467
47571
  PromiseTracker,
47468
47572
  SubworkflowFinished,
47469
- TrackedState,
47573
+ TrackedState2 as TrackedState,
47470
47574
  TrackedStateSchema,
47471
47575
  TranscriptSchema,
47472
47576
  WorkflowCallbackEvent,