@botpress/runtime 1.13.9 → 1.13.11

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 (36) hide show
  1. package/dist/define-config.d.ts +23 -1
  2. package/dist/define-config.d.ts.map +1 -1
  3. package/dist/definition.js +438 -293
  4. package/dist/definition.js.map +4 -4
  5. package/dist/internal.js +532 -387
  6. package/dist/internal.js.map +4 -4
  7. package/dist/library.d.ts +4 -2
  8. package/dist/library.d.ts.map +1 -1
  9. package/dist/library.js +465 -287
  10. package/dist/library.js.map +4 -4
  11. package/dist/primitives/conversation.d.ts +24 -11
  12. package/dist/primitives/conversation.d.ts.map +1 -1
  13. package/dist/primitives/data-sources/source-base.d.ts +1 -1
  14. package/dist/primitives/data-sources/source-base.d.ts.map +1 -1
  15. package/dist/primitives/index.d.ts +1 -1
  16. package/dist/primitives/workflow-instance.d.ts +45 -1
  17. package/dist/primitives/workflow-instance.d.ts.map +1 -1
  18. package/dist/primitives/workflow.d.ts +3 -2
  19. package/dist/primitives/workflow.d.ts.map +1 -1
  20. package/dist/runtime/autonomous.d.ts +1 -0
  21. package/dist/runtime/autonomous.d.ts.map +1 -1
  22. package/dist/runtime/context/context.d.ts +21 -0
  23. package/dist/runtime/context/context.d.ts.map +1 -1
  24. package/dist/runtime/context/handlers.d.ts.map +1 -1
  25. package/dist/runtime/handlers/event.d.ts.map +1 -1
  26. package/dist/runtime/handlers/trigger.d.ts.map +1 -1
  27. package/dist/runtime/handlers/workflow.d.ts.map +1 -1
  28. package/dist/runtime/tracked-tags.d.ts +2 -0
  29. package/dist/runtime/tracked-tags.d.ts.map +1 -1
  30. package/dist/runtime.js +503 -317
  31. package/dist/runtime.js.map +4 -4
  32. package/dist/utilities/events.d.ts +28 -0
  33. package/dist/utilities/events.d.ts.map +1 -1
  34. package/dist/utilities/validate-event-name.d.ts +20 -0
  35. package/dist/utilities/validate-event-name.d.ts.map +1 -0
  36. package/package.json +1 -1
package/dist/internal.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.13.9", adk: "1.13.9", sdk: "5.0.2", llmz: "0.0.35", zai: "2.5.6", cognitive: "0.3.3" };
51
+ define_PACKAGE_VERSIONS_default = { runtime: "1.13.11", adk: "1.13.11", sdk: "5.0.2", llmz: "0.0.37", zai: "2.5.6", cognitive: "0.3.3" };
52
52
  }
53
53
  });
54
54
 
@@ -61,6 +61,124 @@ var init_asset = __esm({
61
61
  }
62
62
  });
63
63
 
64
+ // ../../node_modules/ms/index.js
65
+ var require_ms = __commonJS({
66
+ "../../node_modules/ms/index.js"(exports2, module) {
67
+ init_define_BUILD();
68
+ init_define_PACKAGE_VERSIONS();
69
+ var s = 1e3;
70
+ var m = s * 60;
71
+ var h = m * 60;
72
+ var d = h * 24;
73
+ var w = d * 7;
74
+ var y = d * 365.25;
75
+ module.exports = function(val, options) {
76
+ options = options || {};
77
+ var type = typeof val;
78
+ if (type === "string" && val.length > 0) {
79
+ return parse(val);
80
+ } else if (type === "number" && isFinite(val)) {
81
+ return options.long ? fmtLong(val) : fmtShort(val);
82
+ }
83
+ throw new Error(
84
+ "val is not a non-empty string or a valid number. val=" + JSON.stringify(val)
85
+ );
86
+ };
87
+ function parse(str) {
88
+ str = String(str);
89
+ if (str.length > 100) {
90
+ return;
91
+ }
92
+ var match2 = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
93
+ str
94
+ );
95
+ if (!match2) {
96
+ return;
97
+ }
98
+ var n = parseFloat(match2[1]);
99
+ var type = (match2[2] || "ms").toLowerCase();
100
+ switch (type) {
101
+ case "years":
102
+ case "year":
103
+ case "yrs":
104
+ case "yr":
105
+ case "y":
106
+ return n * y;
107
+ case "weeks":
108
+ case "week":
109
+ case "w":
110
+ return n * w;
111
+ case "days":
112
+ case "day":
113
+ case "d":
114
+ return n * d;
115
+ case "hours":
116
+ case "hour":
117
+ case "hrs":
118
+ case "hr":
119
+ case "h":
120
+ return n * h;
121
+ case "minutes":
122
+ case "minute":
123
+ case "mins":
124
+ case "min":
125
+ case "m":
126
+ return n * m;
127
+ case "seconds":
128
+ case "second":
129
+ case "secs":
130
+ case "sec":
131
+ case "s":
132
+ return n * s;
133
+ case "milliseconds":
134
+ case "millisecond":
135
+ case "msecs":
136
+ case "msec":
137
+ case "ms":
138
+ return n;
139
+ default:
140
+ return void 0;
141
+ }
142
+ }
143
+ function fmtShort(ms4) {
144
+ var msAbs = Math.abs(ms4);
145
+ if (msAbs >= d) {
146
+ return Math.round(ms4 / d) + "d";
147
+ }
148
+ if (msAbs >= h) {
149
+ return Math.round(ms4 / h) + "h";
150
+ }
151
+ if (msAbs >= m) {
152
+ return Math.round(ms4 / m) + "m";
153
+ }
154
+ if (msAbs >= s) {
155
+ return Math.round(ms4 / s) + "s";
156
+ }
157
+ return ms4 + "ms";
158
+ }
159
+ function fmtLong(ms4) {
160
+ var msAbs = Math.abs(ms4);
161
+ if (msAbs >= d) {
162
+ return plural(ms4, msAbs, d, "day");
163
+ }
164
+ if (msAbs >= h) {
165
+ return plural(ms4, msAbs, h, "hour");
166
+ }
167
+ if (msAbs >= m) {
168
+ return plural(ms4, msAbs, m, "minute");
169
+ }
170
+ if (msAbs >= s) {
171
+ return plural(ms4, msAbs, s, "second");
172
+ }
173
+ return ms4 + " ms";
174
+ }
175
+ function plural(ms4, msAbs, n, name) {
176
+ var isPlural = msAbs >= n * 1.5;
177
+ return Math.round(ms4 / n) + " " + name + (isPlural ? "s" : "");
178
+ }
179
+ }
180
+ });
181
+
64
182
  // src/errors.ts
65
183
  import { z } from "@botpress/sdk";
66
184
  var Errors;
@@ -262,7 +380,7 @@ var init_singletons = __esm({
262
380
 
263
381
  // src/runtime/context/context.ts
264
382
  import { AsyncLocalStorage } from "async_hooks";
265
- var storage, context;
383
+ var storage, defaultContext, context;
266
384
  var init_context = __esm({
267
385
  "src/runtime/context/context.ts"() {
268
386
  "use strict";
@@ -270,6 +388,7 @@ var init_context = __esm({
270
388
  init_define_PACKAGE_VERSIONS();
271
389
  init_singletons();
272
390
  storage = getSingleton("__ADK_GLOBAL_CTX_STORAGE", () => new AsyncLocalStorage());
391
+ defaultContext = getSingleton("__ADK_GLOBAL_DEFAULT_CTX", () => ({ value: null }));
273
392
  context = {
274
393
  enterWith: (data) => {
275
394
  storage.enterWith(data);
@@ -288,7 +407,10 @@ var init_context = __esm({
288
407
  return store;
289
408
  },
290
409
  get: (key, opts) => {
291
- const store = storage.getStore();
410
+ let store = storage.getStore();
411
+ if (!store && defaultContext.value) {
412
+ store = defaultContext.value;
413
+ }
292
414
  if (store) {
293
415
  store.states ??= [];
294
416
  store.tags ??= [];
@@ -304,6 +426,28 @@ var init_context = __esm({
304
426
  const store = storage.getStore();
305
427
  if (!store) throw new Error("Cannot set context outside of `run`");
306
428
  store[key] = value;
429
+ },
430
+ /**
431
+ * Set a default context that will be used as a fallback when no AsyncLocalStorage context is active.
432
+ * This is useful for testing and script execution where code runs outside of request handlers.
433
+ *
434
+ * @example
435
+ * ```typescript
436
+ * context.setDefaultContext({
437
+ * botId: 'my-bot',
438
+ * integrations: agentRegistry.integrations,
439
+ * interfaces: agentRegistry.interfaces,
440
+ * })
441
+ * ```
442
+ */
443
+ setDefaultContext: (data) => {
444
+ defaultContext.value = data;
445
+ },
446
+ /**
447
+ * Clear the default context.
448
+ */
449
+ clearDefaultContext: () => {
450
+ defaultContext.value = null;
307
451
  }
308
452
  };
309
453
  }
@@ -27909,124 +28053,6 @@ var require_proxy_from_env = __commonJS({
27909
28053
  }
27910
28054
  });
27911
28055
 
27912
- // ../../node_modules/ms/index.js
27913
- var require_ms = __commonJS({
27914
- "../../node_modules/ms/index.js"(exports2, module) {
27915
- init_define_BUILD();
27916
- init_define_PACKAGE_VERSIONS();
27917
- var s = 1e3;
27918
- var m = s * 60;
27919
- var h = m * 60;
27920
- var d = h * 24;
27921
- var w = d * 7;
27922
- var y = d * 365.25;
27923
- module.exports = function(val, options) {
27924
- options = options || {};
27925
- var type = typeof val;
27926
- if (type === "string" && val.length > 0) {
27927
- return parse(val);
27928
- } else if (type === "number" && isFinite(val)) {
27929
- return options.long ? fmtLong(val) : fmtShort(val);
27930
- }
27931
- throw new Error(
27932
- "val is not a non-empty string or a valid number. val=" + JSON.stringify(val)
27933
- );
27934
- };
27935
- function parse(str) {
27936
- str = String(str);
27937
- if (str.length > 100) {
27938
- return;
27939
- }
27940
- var match2 = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
27941
- str
27942
- );
27943
- if (!match2) {
27944
- return;
27945
- }
27946
- var n = parseFloat(match2[1]);
27947
- var type = (match2[2] || "ms").toLowerCase();
27948
- switch (type) {
27949
- case "years":
27950
- case "year":
27951
- case "yrs":
27952
- case "yr":
27953
- case "y":
27954
- return n * y;
27955
- case "weeks":
27956
- case "week":
27957
- case "w":
27958
- return n * w;
27959
- case "days":
27960
- case "day":
27961
- case "d":
27962
- return n * d;
27963
- case "hours":
27964
- case "hour":
27965
- case "hrs":
27966
- case "hr":
27967
- case "h":
27968
- return n * h;
27969
- case "minutes":
27970
- case "minute":
27971
- case "mins":
27972
- case "min":
27973
- case "m":
27974
- return n * m;
27975
- case "seconds":
27976
- case "second":
27977
- case "secs":
27978
- case "sec":
27979
- case "s":
27980
- return n * s;
27981
- case "milliseconds":
27982
- case "millisecond":
27983
- case "msecs":
27984
- case "msec":
27985
- case "ms":
27986
- return n;
27987
- default:
27988
- return void 0;
27989
- }
27990
- }
27991
- function fmtShort(ms3) {
27992
- var msAbs = Math.abs(ms3);
27993
- if (msAbs >= d) {
27994
- return Math.round(ms3 / d) + "d";
27995
- }
27996
- if (msAbs >= h) {
27997
- return Math.round(ms3 / h) + "h";
27998
- }
27999
- if (msAbs >= m) {
28000
- return Math.round(ms3 / m) + "m";
28001
- }
28002
- if (msAbs >= s) {
28003
- return Math.round(ms3 / s) + "s";
28004
- }
28005
- return ms3 + "ms";
28006
- }
28007
- function fmtLong(ms3) {
28008
- var msAbs = Math.abs(ms3);
28009
- if (msAbs >= d) {
28010
- return plural(ms3, msAbs, d, "day");
28011
- }
28012
- if (msAbs >= h) {
28013
- return plural(ms3, msAbs, h, "hour");
28014
- }
28015
- if (msAbs >= m) {
28016
- return plural(ms3, msAbs, m, "minute");
28017
- }
28018
- if (msAbs >= s) {
28019
- return plural(ms3, msAbs, s, "second");
28020
- }
28021
- return ms3 + " ms";
28022
- }
28023
- function plural(ms3, msAbs, n, name) {
28024
- var isPlural = msAbs >= n * 1.5;
28025
- return Math.round(ms3 / n) + " " + name + (isPlural ? "s" : "");
28026
- }
28027
- }
28028
- });
28029
-
28030
28056
  // ../../node_modules/debug/src/common.js
28031
28057
  var require_common = __commonJS({
28032
28058
  "../../node_modules/debug/src/common.js"(exports2, module) {
@@ -28067,8 +28093,8 @@ var require_common = __commonJS({
28067
28093
  }
28068
28094
  const self2 = debug;
28069
28095
  const curr = Number(/* @__PURE__ */ new Date());
28070
- const ms3 = curr - (prevTime || curr);
28071
- self2.diff = ms3;
28096
+ const ms4 = curr - (prevTime || curr);
28097
+ self2.diff = ms4;
28072
28098
  self2.prev = prevTime;
28073
28099
  self2.curr = curr;
28074
28100
  prevTime = curr;
@@ -34676,6 +34702,9 @@ Always prefer information from the knowledge bases over general knowledge when a
34676
34702
  ...props.hooks?.onBeforeTool && {
34677
34703
  onBeforeTool: asyncResource.bind(props.hooks.onBeforeTool)
34678
34704
  },
34705
+ ...props.hooks?.onIterationStart && {
34706
+ onIterationStart: asyncResource.bind(props.hooks.onIterationStart)
34707
+ },
34679
34708
  ...props.hooks?.onAfterTool && {
34680
34709
  onAfterTool: asyncResource.bind(props.hooks.onAfterTool)
34681
34710
  },
@@ -34805,7 +34834,7 @@ var init_actions = __esm({
34805
34834
  }
34806
34835
  integrations ??= context.get("integrations", { optional: true });
34807
34836
  client2 ??= context.get("client", { optional: true });
34808
- const integration = integrations.find((i) => i.alias === integrationName);
34837
+ const integration = integrations?.find((i) => i.alias === integrationName);
34809
34838
  const actionDef = integration?.definition.actions?.[actionName];
34810
34839
  const handler = async (params) => {
34811
34840
  integrations ??= context.get("integrations", { optional: true });
@@ -35120,15 +35149,25 @@ var init_validate_tag_name = __esm({
35120
35149
  }
35121
35150
  });
35122
35151
 
35152
+ // src/utilities/validate-event-name.ts
35153
+ var init_validate_event_name = __esm({
35154
+ "src/utilities/validate-event-name.ts"() {
35155
+ "use strict";
35156
+ init_define_BUILD();
35157
+ init_define_PACKAGE_VERSIONS();
35158
+ }
35159
+ });
35160
+
35123
35161
  // src/define-config.ts
35124
35162
  import { z as z4 } from "@botpress/sdk";
35125
- var zuiSchema, modelSchema, tagDefinitionSchema, configSchema, AGENT_CONFIG_BRAND, isAgentConfig;
35163
+ var zuiSchema, modelSchema, tagDefinitionSchema, eventDefinitionSchema, configSchema, AGENT_CONFIG_BRAND, isAgentConfig;
35126
35164
  var init_define_config = __esm({
35127
35165
  "src/define-config.ts"() {
35128
35166
  "use strict";
35129
35167
  init_define_BUILD();
35130
35168
  init_define_PACKAGE_VERSIONS();
35131
35169
  init_validate_tag_name();
35170
+ init_validate_event_name();
35132
35171
  zuiSchema = z4.custom(
35133
35172
  (val) => {
35134
35173
  if (typeof val === "object" && val !== null && "parse" in val) {
@@ -35153,6 +35192,13 @@ var init_define_config = __esm({
35153
35192
  description: z4.string().optional()
35154
35193
  })
35155
35194
  );
35195
+ eventDefinitionSchema = z4.record(
35196
+ z4.string(),
35197
+ z4.object({
35198
+ schema: zuiSchema.optional(),
35199
+ description: z4.string().optional()
35200
+ })
35201
+ );
35156
35202
  configSchema = z4.object({
35157
35203
  name: z4.string().optional(),
35158
35204
  description: z4.string().optional(),
@@ -35193,7 +35239,8 @@ var init_define_config = __esm({
35193
35239
  zai: val?.zai ?? "openai:gpt-4.1-2025-04-14",
35194
35240
  autonomous: val?.autonomous ?? "openai:gpt-4.1-mini-2025-04-14"
35195
35241
  })),
35196
- dependencies: z4.custom()
35242
+ dependencies: z4.custom(),
35243
+ events: eventDefinitionSchema.optional()
35197
35244
  });
35198
35245
  AGENT_CONFIG_BRAND = Symbol.for("@botpress/runtime/AgentConfig");
35199
35246
  isAgentConfig = (value) => {
@@ -36335,6 +36382,268 @@ var init_tracked_state = __esm({
36335
36382
  }
36336
36383
  });
36337
36384
 
36385
+ // src/runtime/tracked-tags.ts
36386
+ function isSystemTag(key) {
36387
+ return key.includes(":");
36388
+ }
36389
+ var TrackedTags;
36390
+ var init_tracked_tags = __esm({
36391
+ "src/runtime/tracked-tags.ts"() {
36392
+ "use strict";
36393
+ init_define_BUILD();
36394
+ init_define_PACKAGE_VERSIONS();
36395
+ init_context();
36396
+ init_tracing();
36397
+ TrackedTags = class _TrackedTags {
36398
+ type;
36399
+ id;
36400
+ client;
36401
+ _tags = {};
36402
+ _initialTags = {};
36403
+ _loaded = false;
36404
+ _saving = false;
36405
+ _saveAgain = false;
36406
+ _saveAgainCount = 0;
36407
+ static _savingAll = false;
36408
+ static _saveAllAgain = false;
36409
+ static _saveAllCount = 0;
36410
+ constructor(props) {
36411
+ this.type = props.type;
36412
+ this.id = props.id;
36413
+ this.client = props.client;
36414
+ }
36415
+ static create(props) {
36416
+ const tags = context.get("tags", { optional: true });
36417
+ const executionFinished = context.get("executionFinished", { optional: true });
36418
+ if (executionFinished) {
36419
+ throw new Error(`Cannot create new TrackedTags "${props.type}/${props.id}" after execution has finished.`);
36420
+ }
36421
+ const match2 = tags?.find((x) => x.id === props.id && x.type === props.type);
36422
+ if (match2) {
36423
+ return match2;
36424
+ }
36425
+ const instance = new _TrackedTags(props);
36426
+ if (props.initialTags) {
36427
+ instance._tags = { ...props.initialTags };
36428
+ instance._initialTags = { ...props.initialTags };
36429
+ instance._loaded = true;
36430
+ }
36431
+ tags?.push(instance);
36432
+ return instance;
36433
+ }
36434
+ static async saveAllDirty() {
36435
+ if (this._savingAll) {
36436
+ this._saveAllAgain = true;
36437
+ return;
36438
+ }
36439
+ try {
36440
+ this._savingAll = true;
36441
+ const tags = context.get("tags", { optional: true });
36442
+ const dirtyTags = tags?.filter((t) => t.isDirty()) || [];
36443
+ if (!dirtyTags.length) {
36444
+ return;
36445
+ }
36446
+ await span(
36447
+ "tags.saveAllDirty",
36448
+ {
36449
+ tags_count: tags?.length || 0,
36450
+ tags: tags.map((t) => `${t.type}/${t.id}`)
36451
+ },
36452
+ () => Promise.allSettled(dirtyTags.map((t) => t.save()))
36453
+ );
36454
+ } finally {
36455
+ this._savingAll = false;
36456
+ if (this._saveAllAgain && this._saveAllCount++ <= 5) {
36457
+ this._saveAllAgain = false;
36458
+ await this.saveAllDirty();
36459
+ } else {
36460
+ this._saveAllCount = 0;
36461
+ }
36462
+ }
36463
+ }
36464
+ static async loadAll() {
36465
+ await span("tags.loadAll", {}, async () => {
36466
+ const client2 = context.get("client")._inner;
36467
+ const bot2 = context.get("bot", { optional: true });
36468
+ const user2 = context.get("user", { optional: true });
36469
+ const conversation = context.get("conversation", { optional: true });
36470
+ const workflow = context.get("workflow", { optional: true });
36471
+ if (bot2) {
36472
+ const botTags = bot2.tags;
36473
+ _TrackedTags.create({
36474
+ client: client2,
36475
+ type: "bot",
36476
+ id: bot2.id,
36477
+ ...botTags && { initialTags: botTags }
36478
+ });
36479
+ }
36480
+ if (user2) {
36481
+ const userTags = user2.tags;
36482
+ _TrackedTags.create({
36483
+ client: client2,
36484
+ type: "user",
36485
+ id: user2.id,
36486
+ ...userTags && { initialTags: userTags }
36487
+ });
36488
+ }
36489
+ if (conversation) {
36490
+ const conversationTags = conversation.tags;
36491
+ _TrackedTags.create({
36492
+ client: client2,
36493
+ type: "conversation",
36494
+ id: conversation.id,
36495
+ ...conversationTags && { initialTags: conversationTags }
36496
+ });
36497
+ }
36498
+ if (workflow) {
36499
+ const workflowTags = workflow.tags;
36500
+ _TrackedTags.create({
36501
+ client: client2,
36502
+ type: "workflow",
36503
+ id: workflow.id,
36504
+ ...workflowTags && { initialTags: workflowTags }
36505
+ });
36506
+ }
36507
+ const tags = context.get("tags", { optional: true });
36508
+ const unloadedTags = tags?.filter((tag) => !tag._loaded) ?? [];
36509
+ if (unloadedTags.length > 0) {
36510
+ await Promise.allSettled(unloadedTags.map((tag) => tag.load()));
36511
+ }
36512
+ });
36513
+ }
36514
+ static unloadAll() {
36515
+ context.get("tags", { optional: true })?.splice(0);
36516
+ }
36517
+ async load(force = false) {
36518
+ if (this._loaded && !force) {
36519
+ return;
36520
+ }
36521
+ await span(
36522
+ "tags.load",
36523
+ {
36524
+ type: this.type,
36525
+ id: this.id
36526
+ },
36527
+ async () => {
36528
+ const tags = await this.fetchTags();
36529
+ this._tags = { ...tags };
36530
+ this._initialTags = { ...tags };
36531
+ this._loaded = true;
36532
+ }
36533
+ );
36534
+ }
36535
+ async save() {
36536
+ if (this._saving) {
36537
+ this._saveAgain = true;
36538
+ return;
36539
+ }
36540
+ const executionFinished = context.get("executionFinished", { optional: true });
36541
+ if (executionFinished) {
36542
+ throw new Error(`Cannot save TrackedTags "${this.type}/${this.id}" after execution has finished.`);
36543
+ }
36544
+ try {
36545
+ this._saving = true;
36546
+ await span(
36547
+ "tags.save",
36548
+ {
36549
+ type: this.type,
36550
+ id: this.id
36551
+ },
36552
+ async () => {
36553
+ await this.persistTags(this._tags);
36554
+ this._initialTags = { ...this._tags };
36555
+ }
36556
+ );
36557
+ } finally {
36558
+ this._saving = false;
36559
+ if (this._saveAgain && this._saveAgainCount++ <= 5) {
36560
+ this._saveAgain = false;
36561
+ await this.save();
36562
+ } else {
36563
+ this._saveAgainCount = 0;
36564
+ }
36565
+ }
36566
+ }
36567
+ isDirty() {
36568
+ const currentKeys = Object.keys(this._tags).filter((k) => !isSystemTag(k)).sort();
36569
+ const initialKeys = Object.keys(this._initialTags).filter((k) => !isSystemTag(k)).sort();
36570
+ if (currentKeys.length !== initialKeys.length) {
36571
+ return true;
36572
+ }
36573
+ for (const key of currentKeys) {
36574
+ if (this._tags[key] !== this._initialTags[key]) {
36575
+ return true;
36576
+ }
36577
+ }
36578
+ return false;
36579
+ }
36580
+ get tags() {
36581
+ return new Proxy(this._tags, {
36582
+ set: (target, prop, value) => {
36583
+ if (isSystemTag(prop)) {
36584
+ return true;
36585
+ }
36586
+ target[prop] = value;
36587
+ return true;
36588
+ },
36589
+ deleteProperty: (target, prop) => {
36590
+ if (isSystemTag(prop)) {
36591
+ return true;
36592
+ }
36593
+ target[prop] = void 0;
36594
+ return true;
36595
+ }
36596
+ });
36597
+ }
36598
+ set tags(value) {
36599
+ this._tags = { ...value };
36600
+ }
36601
+ async fetchTags() {
36602
+ try {
36603
+ if (this.type === "bot") {
36604
+ const { bot: bot2 } = await this.client.getBot({ id: this.id });
36605
+ return bot2.tags || {};
36606
+ } else if (this.type === "user") {
36607
+ const { user: user2 } = await this.client.getUser({ id: this.id });
36608
+ return user2.tags || {};
36609
+ } else if (this.type === "conversation") {
36610
+ const { conversation } = await this.client.getConversation({ id: this.id });
36611
+ return conversation.tags || {};
36612
+ } else if (this.type === "workflow") {
36613
+ const { workflow } = await this.client.getWorkflow({ id: this.id });
36614
+ return workflow.tags || {};
36615
+ }
36616
+ } catch (err) {
36617
+ console.error(`Failed to fetch tags for ${this.type}/${this.id}:`, err);
36618
+ }
36619
+ return {};
36620
+ }
36621
+ async persistTags(tags) {
36622
+ const tagsForApi = {};
36623
+ for (const [key, value] of Object.entries(tags)) {
36624
+ if (value !== void 0 && !isSystemTag(key)) {
36625
+ tagsForApi[key] = value;
36626
+ }
36627
+ }
36628
+ try {
36629
+ if (this.type === "bot") {
36630
+ await this.client.updateBot({ id: this.id, tags: tagsForApi });
36631
+ } else if (this.type === "user") {
36632
+ await this.client.updateUser({ id: this.id, tags: tagsForApi });
36633
+ } else if (this.type === "conversation") {
36634
+ await this.client.updateConversation({ id: this.id, tags: tagsForApi });
36635
+ } else if (this.type === "workflow") {
36636
+ await this.client.updateWorkflow({ id: this.id, tags: tagsForApi });
36637
+ }
36638
+ } catch (err) {
36639
+ console.error(`Failed to persist tags for ${this.type}/${this.id}:`, err);
36640
+ throw err;
36641
+ }
36642
+ }
36643
+ };
36644
+ }
36645
+ });
36646
+
36338
36647
  // src/runtime/context/inspector-handler.ts
36339
36648
  var init_inspector_handler = __esm({
36340
36649
  "src/runtime/context/inspector-handler.ts"() {
@@ -36416,6 +36725,7 @@ var init_handlers = __esm({
36416
36725
  init_http();
36417
36726
  init_agent_registry();
36418
36727
  init_tracked_state();
36728
+ init_tracked_tags();
36419
36729
  init_tracing();
36420
36730
  init_heavy_imports();
36421
36731
  init_environment();
@@ -37588,259 +37898,6 @@ var init_handlers2 = __esm({
37588
37898
  }
37589
37899
  });
37590
37900
 
37591
- // src/runtime/tracked-tags.ts
37592
- var TrackedTags;
37593
- var init_tracked_tags = __esm({
37594
- "src/runtime/tracked-tags.ts"() {
37595
- "use strict";
37596
- init_define_BUILD();
37597
- init_define_PACKAGE_VERSIONS();
37598
- init_context();
37599
- init_tracing();
37600
- TrackedTags = class _TrackedTags {
37601
- type;
37602
- id;
37603
- client;
37604
- _tags = {};
37605
- _initialTags = {};
37606
- _loaded = false;
37607
- _saving = false;
37608
- _saveAgain = false;
37609
- _saveAgainCount = 0;
37610
- static _savingAll = false;
37611
- static _saveAllAgain = false;
37612
- static _saveAllCount = 0;
37613
- constructor(props) {
37614
- this.type = props.type;
37615
- this.id = props.id;
37616
- this.client = props.client;
37617
- }
37618
- static create(props) {
37619
- const tags = context.get("tags", { optional: true });
37620
- const executionFinished = context.get("executionFinished", { optional: true });
37621
- if (executionFinished) {
37622
- throw new Error(`Cannot create new TrackedTags "${props.type}/${props.id}" after execution has finished.`);
37623
- }
37624
- const match2 = tags?.find((x) => x.id === props.id && x.type === props.type);
37625
- if (match2) {
37626
- return match2;
37627
- }
37628
- const instance = new _TrackedTags(props);
37629
- if (props.initialTags) {
37630
- instance._tags = { ...props.initialTags };
37631
- instance._initialTags = { ...props.initialTags };
37632
- instance._loaded = true;
37633
- }
37634
- tags?.push(instance);
37635
- return instance;
37636
- }
37637
- static async saveAllDirty() {
37638
- if (this._savingAll) {
37639
- this._saveAllAgain = true;
37640
- return;
37641
- }
37642
- try {
37643
- this._savingAll = true;
37644
- const tags = context.get("tags", { optional: true });
37645
- const dirtyTags = tags?.filter((t) => t.isDirty()) || [];
37646
- if (!dirtyTags.length) {
37647
- return;
37648
- }
37649
- await span(
37650
- "tags.saveAllDirty",
37651
- {
37652
- tags_count: tags?.length || 0,
37653
- tags: tags.map((t) => `${t.type}/${t.id}`)
37654
- },
37655
- () => Promise.allSettled(dirtyTags.map((t) => t.save()))
37656
- );
37657
- } finally {
37658
- this._savingAll = false;
37659
- if (this._saveAllAgain && this._saveAllCount++ <= 5) {
37660
- this._saveAllAgain = false;
37661
- await this.saveAllDirty();
37662
- } else {
37663
- this._saveAllCount = 0;
37664
- }
37665
- }
37666
- }
37667
- static async loadAll() {
37668
- await span("tags.loadAll", {}, async () => {
37669
- const client2 = context.get("client")._inner;
37670
- const bot2 = context.get("bot", { optional: true });
37671
- const user2 = context.get("user", { optional: true });
37672
- const conversation = context.get("conversation", { optional: true });
37673
- const workflow = context.get("workflow", { optional: true });
37674
- if (bot2) {
37675
- const botTags = bot2.tags;
37676
- _TrackedTags.create({
37677
- client: client2,
37678
- type: "bot",
37679
- id: bot2.id,
37680
- ...botTags && { initialTags: botTags }
37681
- });
37682
- }
37683
- if (user2) {
37684
- const userTags = user2.tags;
37685
- _TrackedTags.create({
37686
- client: client2,
37687
- type: "user",
37688
- id: user2.id,
37689
- ...userTags && { initialTags: userTags }
37690
- });
37691
- }
37692
- if (conversation) {
37693
- const conversationTags = conversation.tags;
37694
- _TrackedTags.create({
37695
- client: client2,
37696
- type: "conversation",
37697
- id: conversation.id,
37698
- ...conversationTags && { initialTags: conversationTags }
37699
- });
37700
- }
37701
- if (workflow) {
37702
- const workflowTags = workflow.tags;
37703
- _TrackedTags.create({
37704
- client: client2,
37705
- type: "workflow",
37706
- id: workflow.id,
37707
- ...workflowTags && { initialTags: workflowTags }
37708
- });
37709
- }
37710
- const tags = context.get("tags", { optional: true });
37711
- const unloadedTags = tags?.filter((tag) => !tag._loaded) ?? [];
37712
- if (unloadedTags.length > 0) {
37713
- await Promise.allSettled(unloadedTags.map((tag) => tag.load()));
37714
- }
37715
- });
37716
- }
37717
- static unloadAll() {
37718
- context.get("tags", { optional: true })?.splice(0);
37719
- }
37720
- async load(force = false) {
37721
- if (this._loaded && !force) {
37722
- return;
37723
- }
37724
- await span(
37725
- "tags.load",
37726
- {
37727
- type: this.type,
37728
- id: this.id
37729
- },
37730
- async () => {
37731
- const tags = await this.fetchTags();
37732
- this._tags = { ...tags };
37733
- this._initialTags = { ...tags };
37734
- this._loaded = true;
37735
- }
37736
- );
37737
- }
37738
- async save() {
37739
- if (this._saving) {
37740
- this._saveAgain = true;
37741
- return;
37742
- }
37743
- const executionFinished = context.get("executionFinished", { optional: true });
37744
- if (executionFinished) {
37745
- throw new Error(`Cannot save TrackedTags "${this.type}/${this.id}" after execution has finished.`);
37746
- }
37747
- try {
37748
- this._saving = true;
37749
- await span(
37750
- "tags.save",
37751
- {
37752
- type: this.type,
37753
- id: this.id
37754
- },
37755
- async () => {
37756
- await this.persistTags(this._tags);
37757
- this._initialTags = { ...this._tags };
37758
- }
37759
- );
37760
- } finally {
37761
- this._saving = false;
37762
- if (this._saveAgain && this._saveAgainCount++ <= 5) {
37763
- this._saveAgain = false;
37764
- await this.save();
37765
- } else {
37766
- this._saveAgainCount = 0;
37767
- }
37768
- }
37769
- }
37770
- isDirty() {
37771
- const currentKeys = Object.keys(this._tags).sort();
37772
- const initialKeys = Object.keys(this._initialTags).sort();
37773
- if (currentKeys.length !== initialKeys.length) {
37774
- return true;
37775
- }
37776
- for (const key of currentKeys) {
37777
- if (this._tags[key] !== this._initialTags[key]) {
37778
- return true;
37779
- }
37780
- }
37781
- return false;
37782
- }
37783
- get tags() {
37784
- return new Proxy(this._tags, {
37785
- set: (target, prop, value) => {
37786
- target[prop] = value;
37787
- return true;
37788
- },
37789
- deleteProperty: (target, prop) => {
37790
- target[prop] = void 0;
37791
- return true;
37792
- }
37793
- });
37794
- }
37795
- set tags(value) {
37796
- this._tags = { ...value };
37797
- }
37798
- async fetchTags() {
37799
- try {
37800
- if (this.type === "bot") {
37801
- const { bot: bot2 } = await this.client.getBot({ id: this.id });
37802
- return bot2.tags || {};
37803
- } else if (this.type === "user") {
37804
- const { user: user2 } = await this.client.getUser({ id: this.id });
37805
- return user2.tags || {};
37806
- } else if (this.type === "conversation") {
37807
- const { conversation } = await this.client.getConversation({ id: this.id });
37808
- return conversation.tags || {};
37809
- } else if (this.type === "workflow") {
37810
- const { workflow } = await this.client.getWorkflow({ id: this.id });
37811
- return workflow.tags || {};
37812
- }
37813
- } catch (err) {
37814
- console.error(`Failed to fetch tags for ${this.type}/${this.id}:`, err);
37815
- }
37816
- return {};
37817
- }
37818
- async persistTags(tags) {
37819
- const tagsForApi = {};
37820
- for (const [key, value] of Object.entries(tags)) {
37821
- if (value !== void 0) {
37822
- tagsForApi[key] = value;
37823
- }
37824
- }
37825
- try {
37826
- if (this.type === "bot") {
37827
- await this.client.updateBot({ id: this.id, tags: tagsForApi });
37828
- } else if (this.type === "user") {
37829
- await this.client.updateUser({ id: this.id, tags: tagsForApi });
37830
- } else if (this.type === "conversation") {
37831
- await this.client.updateConversation({ id: this.id, tags: tagsForApi });
37832
- } else if (this.type === "workflow") {
37833
- await this.client.updateWorkflow({ id: this.id, tags: tagsForApi });
37834
- }
37835
- } catch (err) {
37836
- console.error(`Failed to persist tags for ${this.type}/${this.id}:`, err);
37837
- throw err;
37838
- }
37839
- }
37840
- };
37841
- }
37842
- });
37843
-
37844
37901
  // src/runtime/client.ts
37845
37902
  import { Client as Client3 } from "@botpress/client";
37846
37903
  function getStandaloneClient() {
@@ -38157,12 +38214,12 @@ var init_workflow_step = __esm({
38157
38214
  workflowControlContext.abort();
38158
38215
  throw createStepSignal();
38159
38216
  };
38160
- step.sleep = async (name, ms3) => {
38217
+ step.sleep = async (name, ms4) => {
38161
38218
  await _step(
38162
38219
  name,
38163
38220
  async () => {
38164
38221
  const remainingTime = context.get("runtime").getRemainingExecutionTimeInMs();
38165
- if (remainingTime - MIN_STEP_REMAINING_TIME_MS <= ms3 || ms3 >= 1e4) {
38222
+ if (remainingTime - MIN_STEP_REMAINING_TIME_MS <= ms4 || ms4 >= 1e4) {
38166
38223
  const client2 = context.get("client");
38167
38224
  const workflowControlContext = context.get("workflowControlContext");
38168
38225
  await client2.createEvent({
@@ -38170,7 +38227,7 @@ var init_workflow_step = __esm({
38170
38227
  payload: {},
38171
38228
  workflowId: workflowControlContext.workflow.id,
38172
38229
  schedule: {
38173
- delay: ms3
38230
+ delay: ms4
38174
38231
  }
38175
38232
  });
38176
38233
  await updateWorkflow({
@@ -38179,7 +38236,7 @@ var init_workflow_step = __esm({
38179
38236
  });
38180
38237
  workflowControlContext.abort();
38181
38238
  } else {
38182
- await new Promise((resolve) => void setTimeout(resolve, ms3));
38239
+ await new Promise((resolve) => void setTimeout(resolve, ms4));
38183
38240
  context.get("workflowControlContext").signal.throwIfAborted();
38184
38241
  }
38185
38242
  },
@@ -38190,8 +38247,8 @@ var init_workflow_step = __esm({
38190
38247
  );
38191
38248
  };
38192
38249
  step.sleepUntil = async (name, date) => {
38193
- const ms3 = Math.max(0, new Date(date).getTime() - Date.now() - MIN_STEP_REMAINING_TIME_MS);
38194
- await step.sleep(name, ms3);
38250
+ const ms4 = Math.max(0, new Date(date).getTime() - Date.now() - MIN_STEP_REMAINING_TIME_MS);
38251
+ await step.sleep(name, ms4);
38195
38252
  };
38196
38253
  step.waitForWorkflow = async (name, workflowId) => {
38197
38254
  const workflowControlContext = context.get("workflowControlContext");
@@ -38410,12 +38467,13 @@ function createWorkflowExecutionState(client2, workflowId) {
38410
38467
  name: BUILT_IN_STATES.workflowSteps
38411
38468
  });
38412
38469
  }
38413
- var workflowStepContextSchema, workflowExecutionContextSchema, StepSymbol, BaseWorkflowInstance;
38470
+ var import_ms3, workflowStepContextSchema, workflowExecutionContextSchema, StepSymbol, BaseWorkflowInstance;
38414
38471
  var init_workflow_instance = __esm({
38415
38472
  "src/primitives/workflow-instance.ts"() {
38416
38473
  "use strict";
38417
38474
  init_define_BUILD();
38418
38475
  init_define_PACKAGE_VERSIONS();
38476
+ import_ms3 = __toESM(require_ms(), 1);
38419
38477
  init_errors();
38420
38478
  init_library();
38421
38479
  init_autonomous();
@@ -38542,6 +38600,81 @@ var init_workflow_instance = __esm({
38542
38600
  });
38543
38601
  Object.assign(this.workflow, workflow);
38544
38602
  }
38603
+ /**
38604
+ * Extend the workflow timeout by setting a new timeout.
38605
+ * This is useful for long-running workflows that need more time to complete.
38606
+ *
38607
+ * @param options - Either `{ in: string }` for relative duration or `{ at: string }` for absolute ISO timestamp
38608
+ * @returns A promise that resolves when the timeout is updated (can be awaited or not)
38609
+ * @example
38610
+ * // Relative timeout (duration from now):
38611
+ * workflow.setTimeout({ in: '30m' }) // Timeout in 30 minutes
38612
+ * workflow.setTimeout({ in: '6 hours' }) // Timeout in 6 hours
38613
+ *
38614
+ * // Absolute timeout (ISO timestamp):
38615
+ * workflow.setTimeout({ at: '2024-12-25T00:00:00Z' })
38616
+ *
38617
+ * // Optionally await if you need to ensure the update completes:
38618
+ * await workflow.setTimeout({ in: '1h' })
38619
+ */
38620
+ setTimeout(options) {
38621
+ let newTimeoutAt;
38622
+ if ("in" in options) {
38623
+ const durationMs = (0, import_ms3.default)(options.in);
38624
+ if (!durationMs) {
38625
+ throw new Error(`Invalid duration format: "${options.in}". Use formats like "30m", "1h", "6 hours".`);
38626
+ }
38627
+ newTimeoutAt = new Date(Date.now() + durationMs).toISOString();
38628
+ } else {
38629
+ const date = new Date(options.at);
38630
+ if (isNaN(date.getTime())) {
38631
+ throw new Error(`Invalid ISO date format: "${options.at}".`);
38632
+ }
38633
+ newTimeoutAt = date.toISOString();
38634
+ }
38635
+ return updateWorkflow({
38636
+ id: this.id,
38637
+ timeoutAt: newTimeoutAt
38638
+ }).then(({ workflow }) => {
38639
+ Object.assign(this.workflow, workflow);
38640
+ });
38641
+ }
38642
+ /**
38643
+ * Fail the workflow with an error reason.
38644
+ * This immediately interrupts the workflow handler and marks the workflow as failed.
38645
+ * Can only be called from within a workflow handler.
38646
+ *
38647
+ * @param reason - The error reason for the failure
38648
+ * @throws Never returns - always throws to interrupt the handler
38649
+ * @example
38650
+ * workflow.fail('Invalid input data')
38651
+ */
38652
+ fail(reason) {
38653
+ const controlContext = context.get("workflowControlContext", { optional: true });
38654
+ if (!controlContext || controlContext.workflow.id !== this.id) {
38655
+ throw new Error("workflow.fail() can only be called from within the workflow handler");
38656
+ }
38657
+ controlContext.fail(reason);
38658
+ throw createStepSignal();
38659
+ }
38660
+ /**
38661
+ * Complete the workflow early with the given output.
38662
+ * This immediately interrupts the workflow handler and marks the workflow as completed.
38663
+ * Can only be called from within a workflow handler.
38664
+ *
38665
+ * @param output - The workflow output (typed according to workflow definition)
38666
+ * @throws Never returns - always throws to interrupt the handler
38667
+ * @example
38668
+ * workflow.complete({ result: 'success', data: processedData })
38669
+ */
38670
+ complete(output2) {
38671
+ const controlContext = context.get("workflowControlContext", { optional: true });
38672
+ if (!controlContext || controlContext.workflow.id !== this.id) {
38673
+ throw new Error("workflow.complete() can only be called from within the workflow handler");
38674
+ }
38675
+ controlContext.complete(output2);
38676
+ throw createStepSignal();
38677
+ }
38545
38678
  /**
38546
38679
  * Provide data in response to a workflow data request (instance method).
38547
38680
  * Call this method from a conversation handler when you receive a WorkflowDataRequestEvent.
@@ -38592,6 +38725,7 @@ var init_workflow_instance = __esm({
38592
38725
  workflow: this.workflow,
38593
38726
  aborted: false,
38594
38727
  failed: false,
38728
+ completed: false,
38595
38729
  acked: false,
38596
38730
  restarted: false,
38597
38731
  signal: abortSignal,
@@ -38606,6 +38740,10 @@ var init_workflow_instance = __esm({
38606
38740
  workflowControlContext.failed = true;
38607
38741
  workflowControlContext.failedReason = reason;
38608
38742
  },
38743
+ complete: (result) => {
38744
+ workflowControlContext.completed = true;
38745
+ workflowControlContext.completedResult = result;
38746
+ },
38609
38747
  ack: async () => {
38610
38748
  if (workflowControlContext.acked) {
38611
38749
  return;
@@ -38659,7 +38797,8 @@ var init_workflow_instance = __esm({
38659
38797
  step,
38660
38798
  client: this.client,
38661
38799
  execute: this.execute.bind(this),
38662
- signal: abortSignal
38800
+ signal: abortSignal,
38801
+ workflow: this
38663
38802
  });
38664
38803
  return {
38665
38804
  status: "done",
@@ -38670,6 +38809,12 @@ var init_workflow_instance = __esm({
38670
38809
  }
38671
38810
  } catch (err) {
38672
38811
  if (isStepSignal(err)) {
38812
+ if (workflowControlContext.completed) {
38813
+ return {
38814
+ status: "done",
38815
+ result: workflowControlContext.completedResult
38816
+ };
38817
+ }
38673
38818
  if (workflowControlContext.failed) {
38674
38819
  return {
38675
38820
  status: "error",