@botpress/runtime 1.13.9 → 1.13.10

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 (34) 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 +400 -290
  4. package/dist/definition.js.map +4 -4
  5. package/dist/internal.js +494 -384
  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 +427 -284
  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 +3 -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/workflow.d.ts.map +1 -1
  27. package/dist/runtime/tracked-tags.d.ts.map +1 -1
  28. package/dist/runtime.js +451 -302
  29. package/dist/runtime.js.map +4 -4
  30. package/dist/utilities/events.d.ts +28 -0
  31. package/dist/utilities/events.d.ts.map +1 -1
  32. package/dist/utilities/validate-event-name.d.ts +20 -0
  33. package/dist/utilities/validate-event-name.d.ts.map +1 -0
  34. package/package.json +1 -1
@@ -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.10", adk: "1.13.10", sdk: "5.0.2", llmz: "0.0.35", zai: "2.5.6", cognitive: "0.3.3" };
52
52
  }
53
53
  });
54
54
 
@@ -12138,41 +12138,41 @@ var require_ms = __commonJS({
12138
12138
  return void 0;
12139
12139
  }
12140
12140
  }
12141
- function fmtShort(ms3) {
12142
- var msAbs = Math.abs(ms3);
12141
+ function fmtShort(ms4) {
12142
+ var msAbs = Math.abs(ms4);
12143
12143
  if (msAbs >= d) {
12144
- return Math.round(ms3 / d) + "d";
12144
+ return Math.round(ms4 / d) + "d";
12145
12145
  }
12146
12146
  if (msAbs >= h) {
12147
- return Math.round(ms3 / h) + "h";
12147
+ return Math.round(ms4 / h) + "h";
12148
12148
  }
12149
12149
  if (msAbs >= m) {
12150
- return Math.round(ms3 / m) + "m";
12150
+ return Math.round(ms4 / m) + "m";
12151
12151
  }
12152
12152
  if (msAbs >= s) {
12153
- return Math.round(ms3 / s) + "s";
12153
+ return Math.round(ms4 / s) + "s";
12154
12154
  }
12155
- return ms3 + "ms";
12155
+ return ms4 + "ms";
12156
12156
  }
12157
- function fmtLong(ms3) {
12158
- var msAbs = Math.abs(ms3);
12157
+ function fmtLong(ms4) {
12158
+ var msAbs = Math.abs(ms4);
12159
12159
  if (msAbs >= d) {
12160
- return plural(ms3, msAbs, d, "day");
12160
+ return plural(ms4, msAbs, d, "day");
12161
12161
  }
12162
12162
  if (msAbs >= h) {
12163
- return plural(ms3, msAbs, h, "hour");
12163
+ return plural(ms4, msAbs, h, "hour");
12164
12164
  }
12165
12165
  if (msAbs >= m) {
12166
- return plural(ms3, msAbs, m, "minute");
12166
+ return plural(ms4, msAbs, m, "minute");
12167
12167
  }
12168
12168
  if (msAbs >= s) {
12169
- return plural(ms3, msAbs, s, "second");
12169
+ return plural(ms4, msAbs, s, "second");
12170
12170
  }
12171
- return ms3 + " ms";
12171
+ return ms4 + " ms";
12172
12172
  }
12173
- function plural(ms3, msAbs, n, name) {
12173
+ function plural(ms4, msAbs, n, name) {
12174
12174
  var isPlural = msAbs >= n * 1.5;
12175
- return Math.round(ms3 / n) + " " + name + (isPlural ? "s" : "");
12175
+ return Math.round(ms4 / n) + " " + name + (isPlural ? "s" : "");
12176
12176
  }
12177
12177
  }
12178
12178
  });
@@ -12217,8 +12217,8 @@ var require_common = __commonJS({
12217
12217
  }
12218
12218
  const self2 = debug;
12219
12219
  const curr = Number(/* @__PURE__ */ new Date());
12220
- const ms3 = curr - (prevTime || curr);
12221
- self2.diff = ms3;
12220
+ const ms4 = curr - (prevTime || curr);
12221
+ self2.diff = ms4;
12222
12222
  self2.prev = prevTime;
12223
12223
  self2.curr = curr;
12224
12224
  prevTime = curr;
@@ -32944,6 +32944,259 @@ var init_agent_registry = __esm({
32944
32944
  }
32945
32945
  });
32946
32946
 
32947
+ // src/runtime/tracked-tags.ts
32948
+ var TrackedTags;
32949
+ var init_tracked_tags = __esm({
32950
+ "src/runtime/tracked-tags.ts"() {
32951
+ "use strict";
32952
+ init_define_BUILD();
32953
+ init_define_PACKAGE_VERSIONS();
32954
+ init_context3();
32955
+ init_tracing();
32956
+ TrackedTags = class _TrackedTags {
32957
+ type;
32958
+ id;
32959
+ client;
32960
+ _tags = {};
32961
+ _initialTags = {};
32962
+ _loaded = false;
32963
+ _saving = false;
32964
+ _saveAgain = false;
32965
+ _saveAgainCount = 0;
32966
+ static _savingAll = false;
32967
+ static _saveAllAgain = false;
32968
+ static _saveAllCount = 0;
32969
+ constructor(props) {
32970
+ this.type = props.type;
32971
+ this.id = props.id;
32972
+ this.client = props.client;
32973
+ }
32974
+ static create(props) {
32975
+ const tags = context2.get("tags", { optional: true });
32976
+ const executionFinished = context2.get("executionFinished", { optional: true });
32977
+ if (executionFinished) {
32978
+ throw new Error(`Cannot create new TrackedTags "${props.type}/${props.id}" after execution has finished.`);
32979
+ }
32980
+ const match2 = tags?.find((x) => x.id === props.id && x.type === props.type);
32981
+ if (match2) {
32982
+ return match2;
32983
+ }
32984
+ const instance = new _TrackedTags(props);
32985
+ if (props.initialTags) {
32986
+ instance._tags = { ...props.initialTags };
32987
+ instance._initialTags = { ...props.initialTags };
32988
+ instance._loaded = true;
32989
+ }
32990
+ tags?.push(instance);
32991
+ return instance;
32992
+ }
32993
+ static async saveAllDirty() {
32994
+ if (this._savingAll) {
32995
+ this._saveAllAgain = true;
32996
+ return;
32997
+ }
32998
+ try {
32999
+ this._savingAll = true;
33000
+ const tags = context2.get("tags", { optional: true });
33001
+ const dirtyTags = tags?.filter((t) => t.isDirty()) || [];
33002
+ if (!dirtyTags.length) {
33003
+ return;
33004
+ }
33005
+ await span(
33006
+ "tags.saveAllDirty",
33007
+ {
33008
+ tags_count: tags?.length || 0,
33009
+ tags: tags.map((t) => `${t.type}/${t.id}`)
33010
+ },
33011
+ () => Promise.allSettled(dirtyTags.map((t) => t.save()))
33012
+ );
33013
+ } finally {
33014
+ this._savingAll = false;
33015
+ if (this._saveAllAgain && this._saveAllCount++ <= 5) {
33016
+ this._saveAllAgain = false;
33017
+ await this.saveAllDirty();
33018
+ } else {
33019
+ this._saveAllCount = 0;
33020
+ }
33021
+ }
33022
+ }
33023
+ static async loadAll() {
33024
+ await span("tags.loadAll", {}, async () => {
33025
+ const client2 = context2.get("client")._inner;
33026
+ const bot2 = context2.get("bot", { optional: true });
33027
+ const user2 = context2.get("user", { optional: true });
33028
+ const conversation = context2.get("conversation", { optional: true });
33029
+ const workflow = context2.get("workflow", { optional: true });
33030
+ if (bot2) {
33031
+ const botTags = bot2.tags;
33032
+ _TrackedTags.create({
33033
+ client: client2,
33034
+ type: "bot",
33035
+ id: bot2.id,
33036
+ ...botTags && { initialTags: botTags }
33037
+ });
33038
+ }
33039
+ if (user2) {
33040
+ const userTags = user2.tags;
33041
+ _TrackedTags.create({
33042
+ client: client2,
33043
+ type: "user",
33044
+ id: user2.id,
33045
+ ...userTags && { initialTags: userTags }
33046
+ });
33047
+ }
33048
+ if (conversation) {
33049
+ const conversationTags = conversation.tags;
33050
+ _TrackedTags.create({
33051
+ client: client2,
33052
+ type: "conversation",
33053
+ id: conversation.id,
33054
+ ...conversationTags && { initialTags: conversationTags }
33055
+ });
33056
+ }
33057
+ if (workflow) {
33058
+ const workflowTags = workflow.tags;
33059
+ _TrackedTags.create({
33060
+ client: client2,
33061
+ type: "workflow",
33062
+ id: workflow.id,
33063
+ ...workflowTags && { initialTags: workflowTags }
33064
+ });
33065
+ }
33066
+ const tags = context2.get("tags", { optional: true });
33067
+ const unloadedTags = tags?.filter((tag) => !tag._loaded) ?? [];
33068
+ if (unloadedTags.length > 0) {
33069
+ await Promise.allSettled(unloadedTags.map((tag) => tag.load()));
33070
+ }
33071
+ });
33072
+ }
33073
+ static unloadAll() {
33074
+ context2.get("tags", { optional: true })?.splice(0);
33075
+ }
33076
+ async load(force = false) {
33077
+ if (this._loaded && !force) {
33078
+ return;
33079
+ }
33080
+ await span(
33081
+ "tags.load",
33082
+ {
33083
+ type: this.type,
33084
+ id: this.id
33085
+ },
33086
+ async () => {
33087
+ const tags = await this.fetchTags();
33088
+ this._tags = { ...tags };
33089
+ this._initialTags = { ...tags };
33090
+ this._loaded = true;
33091
+ }
33092
+ );
33093
+ }
33094
+ async save() {
33095
+ if (this._saving) {
33096
+ this._saveAgain = true;
33097
+ return;
33098
+ }
33099
+ const executionFinished = context2.get("executionFinished", { optional: true });
33100
+ if (executionFinished) {
33101
+ throw new Error(`Cannot save TrackedTags "${this.type}/${this.id}" after execution has finished.`);
33102
+ }
33103
+ try {
33104
+ this._saving = true;
33105
+ await span(
33106
+ "tags.save",
33107
+ {
33108
+ type: this.type,
33109
+ id: this.id
33110
+ },
33111
+ async () => {
33112
+ await this.persistTags(this._tags);
33113
+ this._initialTags = { ...this._tags };
33114
+ }
33115
+ );
33116
+ } finally {
33117
+ this._saving = false;
33118
+ if (this._saveAgain && this._saveAgainCount++ <= 5) {
33119
+ this._saveAgain = false;
33120
+ await this.save();
33121
+ } else {
33122
+ this._saveAgainCount = 0;
33123
+ }
33124
+ }
33125
+ }
33126
+ isDirty() {
33127
+ const currentKeys = Object.keys(this._tags).filter((k) => !k.includes(":")).sort();
33128
+ const initialKeys = Object.keys(this._initialTags).filter((k) => !k.includes(":")).sort();
33129
+ if (currentKeys.length !== initialKeys.length) {
33130
+ return true;
33131
+ }
33132
+ for (const key of currentKeys) {
33133
+ if (this._tags[key] !== this._initialTags[key]) {
33134
+ return true;
33135
+ }
33136
+ }
33137
+ return false;
33138
+ }
33139
+ get tags() {
33140
+ return new Proxy(this._tags, {
33141
+ set: (target, prop, value) => {
33142
+ target[prop] = value;
33143
+ return true;
33144
+ },
33145
+ deleteProperty: (target, prop) => {
33146
+ target[prop] = void 0;
33147
+ return true;
33148
+ }
33149
+ });
33150
+ }
33151
+ set tags(value) {
33152
+ this._tags = { ...value };
33153
+ }
33154
+ async fetchTags() {
33155
+ try {
33156
+ if (this.type === "bot") {
33157
+ const { bot: bot2 } = await this.client.getBot({ id: this.id });
33158
+ return bot2.tags || {};
33159
+ } else if (this.type === "user") {
33160
+ const { user: user2 } = await this.client.getUser({ id: this.id });
33161
+ return user2.tags || {};
33162
+ } else if (this.type === "conversation") {
33163
+ const { conversation } = await this.client.getConversation({ id: this.id });
33164
+ return conversation.tags || {};
33165
+ } else if (this.type === "workflow") {
33166
+ const { workflow } = await this.client.getWorkflow({ id: this.id });
33167
+ return workflow.tags || {};
33168
+ }
33169
+ } catch (err) {
33170
+ console.error(`Failed to fetch tags for ${this.type}/${this.id}:`, err);
33171
+ }
33172
+ return {};
33173
+ }
33174
+ async persistTags(tags) {
33175
+ const tagsForApi = {};
33176
+ for (const [key, value] of Object.entries(tags)) {
33177
+ if (value !== void 0 && !key.includes(":")) {
33178
+ tagsForApi[key] = value;
33179
+ }
33180
+ }
33181
+ try {
33182
+ if (this.type === "bot") {
33183
+ await this.client.updateBot({ id: this.id, tags: tagsForApi });
33184
+ } else if (this.type === "user") {
33185
+ await this.client.updateUser({ id: this.id, tags: tagsForApi });
33186
+ } else if (this.type === "conversation") {
33187
+ await this.client.updateConversation({ id: this.id, tags: tagsForApi });
33188
+ } else if (this.type === "workflow") {
33189
+ await this.client.updateWorkflow({ id: this.id, tags: tagsForApi });
33190
+ }
33191
+ } catch (err) {
33192
+ console.error(`Failed to persist tags for ${this.type}/${this.id}:`, err);
33193
+ throw err;
33194
+ }
33195
+ }
33196
+ };
33197
+ }
33198
+ });
33199
+
32947
33200
  // src/runtime/heavy-imports.ts
32948
33201
  var HEAVY_IMPORTS, clearScheduledHeavyImports, importScheduledHeavyImports;
32949
33202
  var init_heavy_imports = __esm({
@@ -33058,6 +33311,7 @@ var init_handlers = __esm({
33058
33311
  init_http2();
33059
33312
  init_agent_registry();
33060
33313
  init_tracked_state();
33314
+ init_tracked_tags();
33061
33315
  init_tracing();
33062
33316
  init_heavy_imports();
33063
33317
  init_environment();
@@ -33854,6 +34108,9 @@ Always prefer information from the knowledge bases over general knowledge when a
33854
34108
  ...props.hooks?.onBeforeTool && {
33855
34109
  onBeforeTool: asyncResource.bind(props.hooks.onBeforeTool)
33856
34110
  },
34111
+ ...props.hooks?.onIterationStart && {
34112
+ onIterationStart: asyncResource.bind(props.hooks.onIterationStart)
34113
+ },
33857
34114
  ...props.hooks?.onAfterTool && {
33858
34115
  onAfterTool: asyncResource.bind(props.hooks.onAfterTool)
33859
34116
  },
@@ -44353,15 +44610,25 @@ var init_validate_tag_name = __esm({
44353
44610
  }
44354
44611
  });
44355
44612
 
44613
+ // src/utilities/validate-event-name.ts
44614
+ var init_validate_event_name = __esm({
44615
+ "src/utilities/validate-event-name.ts"() {
44616
+ "use strict";
44617
+ init_define_BUILD();
44618
+ init_define_PACKAGE_VERSIONS();
44619
+ }
44620
+ });
44621
+
44356
44622
  // src/define-config.ts
44357
44623
  import { z as z14 } from "@botpress/sdk";
44358
- var zuiSchema, modelSchema, tagDefinitionSchema, configSchema, AGENT_CONFIG_BRAND;
44624
+ var zuiSchema, modelSchema, tagDefinitionSchema, eventDefinitionSchema, configSchema, AGENT_CONFIG_BRAND;
44359
44625
  var init_define_config = __esm({
44360
44626
  "src/define-config.ts"() {
44361
44627
  "use strict";
44362
44628
  init_define_BUILD();
44363
44629
  init_define_PACKAGE_VERSIONS();
44364
44630
  init_validate_tag_name();
44631
+ init_validate_event_name();
44365
44632
  zuiSchema = z14.custom(
44366
44633
  (val) => {
44367
44634
  if (typeof val === "object" && val !== null && "parse" in val) {
@@ -44386,6 +44653,13 @@ var init_define_config = __esm({
44386
44653
  description: z14.string().optional()
44387
44654
  })
44388
44655
  );
44656
+ eventDefinitionSchema = z14.record(
44657
+ z14.string(),
44658
+ z14.object({
44659
+ schema: zuiSchema.optional(),
44660
+ description: z14.string().optional()
44661
+ })
44662
+ );
44389
44663
  configSchema = z14.object({
44390
44664
  name: z14.string().optional(),
44391
44665
  description: z14.string().optional(),
@@ -44426,7 +44700,8 @@ var init_define_config = __esm({
44426
44700
  zai: val?.zai ?? "openai:gpt-4.1-2025-04-14",
44427
44701
  autonomous: val?.autonomous ?? "openai:gpt-4.1-mini-2025-04-14"
44428
44702
  })),
44429
- dependencies: z14.custom()
44703
+ dependencies: z14.custom(),
44704
+ events: eventDefinitionSchema.optional()
44430
44705
  });
44431
44706
  AGENT_CONFIG_BRAND = Symbol.for("@botpress/runtime/AgentConfig");
44432
44707
  }
@@ -44917,12 +45192,12 @@ var init_workflow_step = __esm({
44917
45192
  workflowControlContext.abort();
44918
45193
  throw createStepSignal();
44919
45194
  };
44920
- step.sleep = async (name, ms3) => {
45195
+ step.sleep = async (name, ms4) => {
44921
45196
  await _step(
44922
45197
  name,
44923
45198
  async () => {
44924
45199
  const remainingTime = context2.get("runtime").getRemainingExecutionTimeInMs();
44925
- if (remainingTime - MIN_STEP_REMAINING_TIME_MS <= ms3 || ms3 >= 1e4) {
45200
+ if (remainingTime - MIN_STEP_REMAINING_TIME_MS <= ms4 || ms4 >= 1e4) {
44926
45201
  const client2 = context2.get("client");
44927
45202
  const workflowControlContext = context2.get("workflowControlContext");
44928
45203
  await client2.createEvent({
@@ -44930,7 +45205,7 @@ var init_workflow_step = __esm({
44930
45205
  payload: {},
44931
45206
  workflowId: workflowControlContext.workflow.id,
44932
45207
  schedule: {
44933
- delay: ms3
45208
+ delay: ms4
44934
45209
  }
44935
45210
  });
44936
45211
  await updateWorkflow({
@@ -44939,7 +45214,7 @@ var init_workflow_step = __esm({
44939
45214
  });
44940
45215
  workflowControlContext.abort();
44941
45216
  } else {
44942
- await new Promise((resolve) => void setTimeout(resolve, ms3));
45217
+ await new Promise((resolve) => void setTimeout(resolve, ms4));
44943
45218
  context2.get("workflowControlContext").signal.throwIfAborted();
44944
45219
  }
44945
45220
  },
@@ -44950,8 +45225,8 @@ var init_workflow_step = __esm({
44950
45225
  );
44951
45226
  };
44952
45227
  step.sleepUntil = async (name, date) => {
44953
- const ms3 = Math.max(0, new Date(date).getTime() - Date.now() - MIN_STEP_REMAINING_TIME_MS);
44954
- await step.sleep(name, ms3);
45228
+ const ms4 = Math.max(0, new Date(date).getTime() - Date.now() - MIN_STEP_REMAINING_TIME_MS);
45229
+ await step.sleep(name, ms4);
44955
45230
  };
44956
45231
  step.waitForWorkflow = async (name, workflowId) => {
44957
45232
  const workflowControlContext = context2.get("workflowControlContext");
@@ -45170,12 +45445,13 @@ function createWorkflowExecutionState(client2, workflowId) {
45170
45445
  name: BUILT_IN_STATES.workflowSteps
45171
45446
  });
45172
45447
  }
45173
- var workflowStepContextSchema, workflowExecutionContextSchema, StepSymbol, BaseWorkflowInstance;
45448
+ var import_ms, workflowStepContextSchema, workflowExecutionContextSchema, StepSymbol, BaseWorkflowInstance;
45174
45449
  var init_workflow_instance = __esm({
45175
45450
  "src/primitives/workflow-instance.ts"() {
45176
45451
  "use strict";
45177
45452
  init_define_BUILD();
45178
45453
  init_define_PACKAGE_VERSIONS();
45454
+ import_ms = __toESM(require_ms(), 1);
45179
45455
  init_errors();
45180
45456
  init_library();
45181
45457
  init_autonomous();
@@ -45302,6 +45578,81 @@ var init_workflow_instance = __esm({
45302
45578
  });
45303
45579
  Object.assign(this.workflow, workflow);
45304
45580
  }
45581
+ /**
45582
+ * Extend the workflow timeout by setting a new timeout.
45583
+ * This is useful for long-running workflows that need more time to complete.
45584
+ *
45585
+ * @param options - Either `{ in: string }` for relative duration or `{ at: string }` for absolute ISO timestamp
45586
+ * @returns A promise that resolves when the timeout is updated (can be awaited or not)
45587
+ * @example
45588
+ * // Relative timeout (duration from now):
45589
+ * workflow.setTimeout({ in: '30m' }) // Timeout in 30 minutes
45590
+ * workflow.setTimeout({ in: '6 hours' }) // Timeout in 6 hours
45591
+ *
45592
+ * // Absolute timeout (ISO timestamp):
45593
+ * workflow.setTimeout({ at: '2024-12-25T00:00:00Z' })
45594
+ *
45595
+ * // Optionally await if you need to ensure the update completes:
45596
+ * await workflow.setTimeout({ in: '1h' })
45597
+ */
45598
+ setTimeout(options) {
45599
+ let newTimeoutAt;
45600
+ if ("in" in options) {
45601
+ const durationMs = (0, import_ms.default)(options.in);
45602
+ if (!durationMs) {
45603
+ throw new Error(`Invalid duration format: "${options.in}". Use formats like "30m", "1h", "6 hours".`);
45604
+ }
45605
+ newTimeoutAt = new Date(Date.now() + durationMs).toISOString();
45606
+ } else {
45607
+ const date = new Date(options.at);
45608
+ if (isNaN(date.getTime())) {
45609
+ throw new Error(`Invalid ISO date format: "${options.at}".`);
45610
+ }
45611
+ newTimeoutAt = date.toISOString();
45612
+ }
45613
+ return updateWorkflow({
45614
+ id: this.id,
45615
+ timeoutAt: newTimeoutAt
45616
+ }).then(({ workflow }) => {
45617
+ Object.assign(this.workflow, workflow);
45618
+ });
45619
+ }
45620
+ /**
45621
+ * Fail the workflow with an error reason.
45622
+ * This immediately interrupts the workflow handler and marks the workflow as failed.
45623
+ * Can only be called from within a workflow handler.
45624
+ *
45625
+ * @param reason - The error reason for the failure
45626
+ * @throws Never returns - always throws to interrupt the handler
45627
+ * @example
45628
+ * workflow.fail('Invalid input data')
45629
+ */
45630
+ fail(reason) {
45631
+ const controlContext = context2.get("workflowControlContext", { optional: true });
45632
+ if (!controlContext || controlContext.workflow.id !== this.id) {
45633
+ throw new Error("workflow.fail() can only be called from within the workflow handler");
45634
+ }
45635
+ controlContext.fail(reason);
45636
+ throw createStepSignal();
45637
+ }
45638
+ /**
45639
+ * Complete the workflow early with the given output.
45640
+ * This immediately interrupts the workflow handler and marks the workflow as completed.
45641
+ * Can only be called from within a workflow handler.
45642
+ *
45643
+ * @param output - The workflow output (typed according to workflow definition)
45644
+ * @throws Never returns - always throws to interrupt the handler
45645
+ * @example
45646
+ * workflow.complete({ result: 'success', data: processedData })
45647
+ */
45648
+ complete(output2) {
45649
+ const controlContext = context2.get("workflowControlContext", { optional: true });
45650
+ if (!controlContext || controlContext.workflow.id !== this.id) {
45651
+ throw new Error("workflow.complete() can only be called from within the workflow handler");
45652
+ }
45653
+ controlContext.complete(output2);
45654
+ throw createStepSignal();
45655
+ }
45305
45656
  /**
45306
45657
  * Provide data in response to a workflow data request (instance method).
45307
45658
  * Call this method from a conversation handler when you receive a WorkflowDataRequestEvent.
@@ -45352,6 +45703,7 @@ var init_workflow_instance = __esm({
45352
45703
  workflow: this.workflow,
45353
45704
  aborted: false,
45354
45705
  failed: false,
45706
+ completed: false,
45355
45707
  acked: false,
45356
45708
  restarted: false,
45357
45709
  signal: abortSignal,
@@ -45366,6 +45718,10 @@ var init_workflow_instance = __esm({
45366
45718
  workflowControlContext.failed = true;
45367
45719
  workflowControlContext.failedReason = reason;
45368
45720
  },
45721
+ complete: (result) => {
45722
+ workflowControlContext.completed = true;
45723
+ workflowControlContext.completedResult = result;
45724
+ },
45369
45725
  ack: async () => {
45370
45726
  if (workflowControlContext.acked) {
45371
45727
  return;
@@ -45419,7 +45775,8 @@ var init_workflow_instance = __esm({
45419
45775
  step,
45420
45776
  client: this.client,
45421
45777
  execute: this.execute.bind(this),
45422
- signal: abortSignal
45778
+ signal: abortSignal,
45779
+ workflow: this
45423
45780
  });
45424
45781
  return {
45425
45782
  status: "done",
@@ -45430,6 +45787,12 @@ var init_workflow_instance = __esm({
45430
45787
  }
45431
45788
  } catch (err) {
45432
45789
  if (isStepSignal(err)) {
45790
+ if (workflowControlContext.completed) {
45791
+ return {
45792
+ status: "done",
45793
+ result: workflowControlContext.completedResult
45794
+ };
45795
+ }
45433
45796
  if (workflowControlContext.failed) {
45434
45797
  return {
45435
45798
  status: "error",
@@ -45484,7 +45847,7 @@ var init_workflow_instance = __esm({
45484
45847
 
45485
45848
  // src/primitives/workflow.ts
45486
45849
  import { z as z23 } from "@botpress/sdk";
45487
- var import_ms, WorkflowHandler, Typings7, BaseWorkflow;
45850
+ var import_ms2, WorkflowHandler, Typings7, BaseWorkflow;
45488
45851
  var init_workflow = __esm({
45489
45852
  "src/primitives/workflow.ts"() {
45490
45853
  "use strict";
@@ -45492,7 +45855,7 @@ var init_workflow = __esm({
45492
45855
  init_define_PACKAGE_VERSIONS();
45493
45856
  init_workflow_instance();
45494
45857
  init_context3();
45495
- import_ms = __toESM(require_ms(), 1);
45858
+ import_ms2 = __toESM(require_ms(), 1);
45496
45859
  init_autonomous();
45497
45860
  init_runtime();
45498
45861
  WorkflowHandler = Symbol.for("workflow.handler");
@@ -45514,7 +45877,7 @@ var init_workflow = __esm({
45514
45877
  _handler;
45515
45878
  /** @internal */
45516
45879
  schedule;
45517
- timeout = (0, import_ms.default)("5m");
45880
+ timeout = (0, import_ms2.default)("5m");
45518
45881
  constructor(props) {
45519
45882
  this.name = props.name;
45520
45883
  if (props.description !== void 0) {
@@ -45527,7 +45890,7 @@ var init_workflow = __esm({
45527
45890
  this._handler = props.handler;
45528
45891
  this.schedule = props.schedule;
45529
45892
  if (props.timeout) {
45530
- this.timeout = (0, import_ms.default)(props.timeout);
45893
+ this.timeout = (0, import_ms2.default)(props.timeout);
45531
45894
  }
45532
45895
  }
45533
45896
  // @internal
@@ -45583,7 +45946,7 @@ var init_workflow = __esm({
45583
45946
  tags,
45584
45947
  conversationId: context2.get("conversation", { optional: true })?.id,
45585
45948
  parentWorkflowId: context2.get("workflow", { optional: true })?.id,
45586
- timeoutAt: new Date(Date.now() + (this.timeout ?? (0, import_ms.default)("5m"))).toISOString(),
45949
+ timeoutAt: new Date(Date.now() + (this.timeout ?? (0, import_ms2.default)("5m"))).toISOString(),
45587
45950
  ...discriminator && { discriminateBy: { tags: discriminator } }
45588
45951
  };
45589
45952
  let { workflow } = await client2._inner.getOrCreateWorkflow(createArgs);
@@ -45646,7 +46009,7 @@ var init_workflow = __esm({
45646
46009
  input: validatedInput,
45647
46010
  parentWorkflowId: workflow?.id,
45648
46011
  conversationId: context2.get("conversation", { optional: true })?.id,
45649
- timeoutAt: new Date(Date.now() + (this.timeout ?? (0, import_ms.default)("5m"))).toISOString()
46012
+ timeoutAt: new Date(Date.now() + (this.timeout ?? (0, import_ms2.default)("5m"))).toISOString()
45650
46013
  });
45651
46014
  return await BaseWorkflowInstance.load({
45652
46015
  id: res.workflow.id,
@@ -46461,7 +46824,7 @@ var init_trigger2 = __esm({
46461
46824
  });
46462
46825
 
46463
46826
  // src/runtime/handlers/workflow.ts
46464
- var import_ms2;
46827
+ var import_ms3;
46465
46828
  var init_workflow2 = __esm({
46466
46829
  "src/runtime/handlers/workflow.ts"() {
46467
46830
  "use strict";
@@ -46473,7 +46836,7 @@ var init_workflow2 = __esm({
46473
46836
  init_tracing();
46474
46837
  init_adk();
46475
46838
  init_workflow_utils();
46476
- import_ms2 = __toESM(require_ms(), 1);
46839
+ import_ms3 = __toESM(require_ms(), 1);
46477
46840
  }
46478
46841
  });
46479
46842
 
@@ -46517,259 +46880,6 @@ var init_handlers2 = __esm({
46517
46880
  }
46518
46881
  });
46519
46882
 
46520
- // src/runtime/tracked-tags.ts
46521
- var TrackedTags;
46522
- var init_tracked_tags = __esm({
46523
- "src/runtime/tracked-tags.ts"() {
46524
- "use strict";
46525
- init_define_BUILD();
46526
- init_define_PACKAGE_VERSIONS();
46527
- init_context3();
46528
- init_tracing();
46529
- TrackedTags = class _TrackedTags {
46530
- type;
46531
- id;
46532
- client;
46533
- _tags = {};
46534
- _initialTags = {};
46535
- _loaded = false;
46536
- _saving = false;
46537
- _saveAgain = false;
46538
- _saveAgainCount = 0;
46539
- static _savingAll = false;
46540
- static _saveAllAgain = false;
46541
- static _saveAllCount = 0;
46542
- constructor(props) {
46543
- this.type = props.type;
46544
- this.id = props.id;
46545
- this.client = props.client;
46546
- }
46547
- static create(props) {
46548
- const tags = context2.get("tags", { optional: true });
46549
- const executionFinished = context2.get("executionFinished", { optional: true });
46550
- if (executionFinished) {
46551
- throw new Error(`Cannot create new TrackedTags "${props.type}/${props.id}" after execution has finished.`);
46552
- }
46553
- const match2 = tags?.find((x) => x.id === props.id && x.type === props.type);
46554
- if (match2) {
46555
- return match2;
46556
- }
46557
- const instance = new _TrackedTags(props);
46558
- if (props.initialTags) {
46559
- instance._tags = { ...props.initialTags };
46560
- instance._initialTags = { ...props.initialTags };
46561
- instance._loaded = true;
46562
- }
46563
- tags?.push(instance);
46564
- return instance;
46565
- }
46566
- static async saveAllDirty() {
46567
- if (this._savingAll) {
46568
- this._saveAllAgain = true;
46569
- return;
46570
- }
46571
- try {
46572
- this._savingAll = true;
46573
- const tags = context2.get("tags", { optional: true });
46574
- const dirtyTags = tags?.filter((t) => t.isDirty()) || [];
46575
- if (!dirtyTags.length) {
46576
- return;
46577
- }
46578
- await span(
46579
- "tags.saveAllDirty",
46580
- {
46581
- tags_count: tags?.length || 0,
46582
- tags: tags.map((t) => `${t.type}/${t.id}`)
46583
- },
46584
- () => Promise.allSettled(dirtyTags.map((t) => t.save()))
46585
- );
46586
- } finally {
46587
- this._savingAll = false;
46588
- if (this._saveAllAgain && this._saveAllCount++ <= 5) {
46589
- this._saveAllAgain = false;
46590
- await this.saveAllDirty();
46591
- } else {
46592
- this._saveAllCount = 0;
46593
- }
46594
- }
46595
- }
46596
- static async loadAll() {
46597
- await span("tags.loadAll", {}, async () => {
46598
- const client2 = context2.get("client")._inner;
46599
- const bot2 = context2.get("bot", { optional: true });
46600
- const user2 = context2.get("user", { optional: true });
46601
- const conversation = context2.get("conversation", { optional: true });
46602
- const workflow = context2.get("workflow", { optional: true });
46603
- if (bot2) {
46604
- const botTags = bot2.tags;
46605
- _TrackedTags.create({
46606
- client: client2,
46607
- type: "bot",
46608
- id: bot2.id,
46609
- ...botTags && { initialTags: botTags }
46610
- });
46611
- }
46612
- if (user2) {
46613
- const userTags = user2.tags;
46614
- _TrackedTags.create({
46615
- client: client2,
46616
- type: "user",
46617
- id: user2.id,
46618
- ...userTags && { initialTags: userTags }
46619
- });
46620
- }
46621
- if (conversation) {
46622
- const conversationTags = conversation.tags;
46623
- _TrackedTags.create({
46624
- client: client2,
46625
- type: "conversation",
46626
- id: conversation.id,
46627
- ...conversationTags && { initialTags: conversationTags }
46628
- });
46629
- }
46630
- if (workflow) {
46631
- const workflowTags = workflow.tags;
46632
- _TrackedTags.create({
46633
- client: client2,
46634
- type: "workflow",
46635
- id: workflow.id,
46636
- ...workflowTags && { initialTags: workflowTags }
46637
- });
46638
- }
46639
- const tags = context2.get("tags", { optional: true });
46640
- const unloadedTags = tags?.filter((tag) => !tag._loaded) ?? [];
46641
- if (unloadedTags.length > 0) {
46642
- await Promise.allSettled(unloadedTags.map((tag) => tag.load()));
46643
- }
46644
- });
46645
- }
46646
- static unloadAll() {
46647
- context2.get("tags", { optional: true })?.splice(0);
46648
- }
46649
- async load(force = false) {
46650
- if (this._loaded && !force) {
46651
- return;
46652
- }
46653
- await span(
46654
- "tags.load",
46655
- {
46656
- type: this.type,
46657
- id: this.id
46658
- },
46659
- async () => {
46660
- const tags = await this.fetchTags();
46661
- this._tags = { ...tags };
46662
- this._initialTags = { ...tags };
46663
- this._loaded = true;
46664
- }
46665
- );
46666
- }
46667
- async save() {
46668
- if (this._saving) {
46669
- this._saveAgain = true;
46670
- return;
46671
- }
46672
- const executionFinished = context2.get("executionFinished", { optional: true });
46673
- if (executionFinished) {
46674
- throw new Error(`Cannot save TrackedTags "${this.type}/${this.id}" after execution has finished.`);
46675
- }
46676
- try {
46677
- this._saving = true;
46678
- await span(
46679
- "tags.save",
46680
- {
46681
- type: this.type,
46682
- id: this.id
46683
- },
46684
- async () => {
46685
- await this.persistTags(this._tags);
46686
- this._initialTags = { ...this._tags };
46687
- }
46688
- );
46689
- } finally {
46690
- this._saving = false;
46691
- if (this._saveAgain && this._saveAgainCount++ <= 5) {
46692
- this._saveAgain = false;
46693
- await this.save();
46694
- } else {
46695
- this._saveAgainCount = 0;
46696
- }
46697
- }
46698
- }
46699
- isDirty() {
46700
- const currentKeys = Object.keys(this._tags).sort();
46701
- const initialKeys = Object.keys(this._initialTags).sort();
46702
- if (currentKeys.length !== initialKeys.length) {
46703
- return true;
46704
- }
46705
- for (const key of currentKeys) {
46706
- if (this._tags[key] !== this._initialTags[key]) {
46707
- return true;
46708
- }
46709
- }
46710
- return false;
46711
- }
46712
- get tags() {
46713
- return new Proxy(this._tags, {
46714
- set: (target, prop, value) => {
46715
- target[prop] = value;
46716
- return true;
46717
- },
46718
- deleteProperty: (target, prop) => {
46719
- target[prop] = void 0;
46720
- return true;
46721
- }
46722
- });
46723
- }
46724
- set tags(value) {
46725
- this._tags = { ...value };
46726
- }
46727
- async fetchTags() {
46728
- try {
46729
- if (this.type === "bot") {
46730
- const { bot: bot2 } = await this.client.getBot({ id: this.id });
46731
- return bot2.tags || {};
46732
- } else if (this.type === "user") {
46733
- const { user: user2 } = await this.client.getUser({ id: this.id });
46734
- return user2.tags || {};
46735
- } else if (this.type === "conversation") {
46736
- const { conversation } = await this.client.getConversation({ id: this.id });
46737
- return conversation.tags || {};
46738
- } else if (this.type === "workflow") {
46739
- const { workflow } = await this.client.getWorkflow({ id: this.id });
46740
- return workflow.tags || {};
46741
- }
46742
- } catch (err) {
46743
- console.error(`Failed to fetch tags for ${this.type}/${this.id}:`, err);
46744
- }
46745
- return {};
46746
- }
46747
- async persistTags(tags) {
46748
- const tagsForApi = {};
46749
- for (const [key, value] of Object.entries(tags)) {
46750
- if (value !== void 0) {
46751
- tagsForApi[key] = value;
46752
- }
46753
- }
46754
- try {
46755
- if (this.type === "bot") {
46756
- await this.client.updateBot({ id: this.id, tags: tagsForApi });
46757
- } else if (this.type === "user") {
46758
- await this.client.updateUser({ id: this.id, tags: tagsForApi });
46759
- } else if (this.type === "conversation") {
46760
- await this.client.updateConversation({ id: this.id, tags: tagsForApi });
46761
- } else if (this.type === "workflow") {
46762
- await this.client.updateWorkflow({ id: this.id, tags: tagsForApi });
46763
- }
46764
- } catch (err) {
46765
- console.error(`Failed to persist tags for ${this.type}/${this.id}:`, err);
46766
- throw err;
46767
- }
46768
- }
46769
- };
46770
- }
46771
- });
46772
-
46773
46883
  // src/runtime/index.ts
46774
46884
  var init_runtime2 = __esm({
46775
46885
  "src/runtime/index.ts"() {