@bpmnkit/core 0.1.1 → 0.1.2

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 (56) hide show
  1. package/README.md +2 -0
  2. package/dist/bpmn/agentic.d.ts +121 -0
  3. package/dist/bpmn/agentic.js +97 -0
  4. package/dist/bpmn/auto-layout.d.ts +5 -5
  5. package/dist/bpmn/auto-layout.js +592 -36
  6. package/dist/bpmn/bpmn-builder.d.ts +56 -0
  7. package/dist/bpmn/bpmn-builder.js +148 -182
  8. package/dist/bpmn/bpmn-model.d.ts +4 -0
  9. package/dist/bpmn/bpmn-parser.js +9 -1
  10. package/dist/bpmn/bpmn-serializer.js +6 -0
  11. package/dist/bpmn/optimize/agentic.d.ts +10 -0
  12. package/dist/bpmn/optimize/agentic.js +88 -0
  13. package/dist/bpmn/optimize/deploy.d.ts +16 -0
  14. package/dist/bpmn/optimize/deploy.js +143 -0
  15. package/dist/bpmn/optimize/feel-syntax.d.ts +12 -0
  16. package/dist/bpmn/optimize/feel-syntax.js +87 -0
  17. package/dist/bpmn/optimize/feel.js +5 -2
  18. package/dist/bpmn/optimize/flow.js +22 -2
  19. package/dist/bpmn/optimize/index.js +20 -9
  20. package/dist/bpmn/optimize/types.d.ts +10 -1
  21. package/dist/bpmn/zeebe-extensions.d.ts +27 -0
  22. package/dist/bpmn/zeebe-extensions.js +38 -0
  23. package/dist/index.d.ts +6 -1
  24. package/dist/index.js +2 -0
  25. package/dist/layout/annotations.js +36 -1
  26. package/dist/layout/collaboration/alignment.d.ts +26 -0
  27. package/dist/layout/collaboration/alignment.js +66 -0
  28. package/dist/layout/collaboration/ordering.d.ts +21 -0
  29. package/dist/layout/collaboration/ordering.js +102 -0
  30. package/dist/layout/index.d.ts +1 -0
  31. package/dist/layout/layout-engine.d.ts +13 -3
  32. package/dist/layout/layout-engine.js +9 -4
  33. package/dist/layout/semantic/bands.d.ts +19 -0
  34. package/dist/layout/semantic/bands.js +324 -0
  35. package/dist/layout/semantic/graph.d.ts +29 -0
  36. package/dist/layout/semantic/graph.js +217 -0
  37. package/dist/layout/semantic/index.d.ts +13 -0
  38. package/dist/layout/semantic/index.js +181 -0
  39. package/dist/layout/semantic/place.d.ts +40 -0
  40. package/dist/layout/semantic/place.js +271 -0
  41. package/dist/layout/semantic/route.d.ts +14 -0
  42. package/dist/layout/semantic/route.js +454 -0
  43. package/dist/layout/types.d.ts +17 -0
  44. package/dist/plan/compile.d.ts +39 -0
  45. package/dist/plan/compile.js +380 -0
  46. package/dist/plan/extract.d.ts +31 -0
  47. package/dist/plan/extract.js +248 -0
  48. package/dist/plan/index.d.ts +6 -0
  49. package/dist/plan/index.js +5 -0
  50. package/dist/plan/merge.d.ts +13 -0
  51. package/dist/plan/merge.js +80 -0
  52. package/dist/plan/slug.d.ts +5 -0
  53. package/dist/plan/slug.js +22 -0
  54. package/dist/plan/types.d.ts +225 -0
  55. package/dist/plan/types.js +13 -0
  56. package/package.json +2 -2
@@ -4,11 +4,15 @@ import type { RestConnectorConfig } from "./rest-connector.js";
4
4
  export interface ElementOptions {
5
5
  name?: string;
6
6
  isForCompensation?: boolean;
7
+ /** Free-text documentation (`<bpmn:documentation>`). Used by the AI Agent connector as a tool description. */
8
+ documentation?: string;
7
9
  }
8
10
  /** Options for send/receive task elements. */
9
11
  export interface MessageTaskOptions extends ElementOptions {
10
12
  /** Message name — generates or reuses a root <bpmn:message> and sets messageRef. */
11
13
  messageName?: string;
14
+ /** FEEL expression correlating this message to a specific process instance (`zeebe:subscription`). */
15
+ correlationKey?: string;
12
16
  }
13
17
  /** Options for creating a start event. */
14
18
  export interface StartEventOptions extends ElementOptions {
@@ -58,6 +62,11 @@ export interface ServiceTaskOptions {
58
62
  };
59
63
  /** Task header key-value pairs. */
60
64
  taskHeaders?: Record<string, string>;
65
+ /** Zeebe property key-value pairs (`zeebe:properties`/`zeebe:property`). */
66
+ zeebeProperties?: Array<{
67
+ name: string;
68
+ value: string;
69
+ }>;
61
70
  /** Zeebe modeler template ID. */
62
71
  modelerTemplate?: string;
63
72
  /** Zeebe modeler template version. */
@@ -66,6 +75,8 @@ export interface ServiceTaskOptions {
66
75
  modelerTemplateIcon?: string;
67
76
  /** Mark this task as a compensation handler. */
68
77
  isForCompensation?: boolean;
78
+ /** Free-text documentation (`<bpmn:documentation>`). Used by the AI Agent connector as a tool description. */
79
+ documentation?: string;
69
80
  }
70
81
  /** Options for creating a script task. */
71
82
  export interface ScriptTaskOptions {
@@ -77,6 +88,8 @@ export interface ScriptTaskOptions {
77
88
  resultVariable: string;
78
89
  /** Mark this task as a compensation handler. */
79
90
  isForCompensation?: boolean;
91
+ /** Free-text documentation (`<bpmn:documentation>`). */
92
+ documentation?: string;
80
93
  }
81
94
  /** Options for creating a user task. */
82
95
  export interface UserTaskOptions {
@@ -88,6 +101,20 @@ export interface UserTaskOptions {
88
101
  zeebeUserTask?: boolean;
89
102
  /** Mark this task as a compensation handler. */
90
103
  isForCompensation?: boolean;
104
+ /** Free-text documentation (`<bpmn:documentation>`). */
105
+ documentation?: string;
106
+ /** Static assignee (`zeebe:assignmentDefinition assignee`). FEEL expressions must start with "=". */
107
+ assignee?: string;
108
+ /** Candidate groups, comma-separated or a FEEL expression (`zeebe:assignmentDefinition candidateGroups`). */
109
+ candidateGroups?: string;
110
+ /** Candidate users, comma-separated or a FEEL expression (`zeebe:assignmentDefinition candidateUsers`). */
111
+ candidateUsers?: string;
112
+ /** Due date — ISO 8601 or FEEL expression (`zeebe:taskSchedule dueDate`). */
113
+ dueDate?: string;
114
+ /** Follow-up date — ISO 8601 or FEEL expression (`zeebe:taskSchedule followUpDate`). */
115
+ followUpDate?: string;
116
+ /** Task priority 0-100, default 50 (`zeebe:priorityDefinition`). */
117
+ priority?: number;
91
118
  }
92
119
  /** Options for creating a call activity. */
93
120
  export interface CallActivityOptions {
@@ -99,6 +126,8 @@ export interface CallActivityOptions {
99
126
  propagateAllChildVariables?: boolean;
100
127
  /** Mark this activity as a compensation handler. */
101
128
  isForCompensation?: boolean;
129
+ /** Free-text documentation (`<bpmn:documentation>`). */
130
+ documentation?: string;
102
131
  }
103
132
  /** Options for creating a business rule task. */
104
133
  export interface BusinessRuleTaskOptions {
@@ -112,6 +141,8 @@ export interface BusinessRuleTaskOptions {
112
141
  resultVariable?: string;
113
142
  /** Mark this task as a compensation handler. */
114
143
  isForCompensation?: boolean;
144
+ /** Free-text documentation (`<bpmn:documentation>`). */
145
+ documentation?: string;
115
146
  }
116
147
  /** Options for gateway elements. */
117
148
  export interface GatewayOptions extends ElementOptions {
@@ -128,6 +159,8 @@ export interface IntermediateCatchEventOptions extends ElementOptions {
128
159
  timerCycle?: string;
129
160
  /** Message name — creates a message catch event (aspirational). */
130
161
  messageName?: string;
162
+ /** FEEL expression correlating this message to a specific process instance (`zeebe:subscription`). Required for a deployable message catch when `messageName` is set. */
163
+ correlationKey?: string;
131
164
  /** Signal name — creates a signal catch event (aspirational). */
132
165
  signalName?: string;
133
166
  }
@@ -175,6 +208,8 @@ export interface BoundaryEventOptions extends ElementOptions {
175
208
  timerCycle?: string;
176
209
  /** Message name — creates a message boundary event (aspirational). */
177
210
  messageName?: string;
211
+ /** FEEL expression correlating this message to a specific process instance (`zeebe:subscription`). Required for a deployable message boundary event when `messageName` is set. */
212
+ correlationKey?: string;
178
213
  /** Signal name — creates a signal boundary event (aspirational). */
179
214
  signalName?: string;
180
215
  /** Creates a compensation boundary event. */
@@ -217,6 +252,11 @@ export interface AdHocSubProcessOptions extends ElementOptions {
217
252
  };
218
253
  /** Task header key-value pairs. */
219
254
  taskHeaders?: Record<string, string>;
255
+ /** Zeebe property key-value pairs (`zeebe:properties`/`zeebe:property`). */
256
+ zeebeProperties?: Array<{
257
+ name: string;
258
+ value: string;
259
+ }>;
220
260
  /** Multi-instance loop configuration. */
221
261
  loopCharacteristics?: {
222
262
  inputCollection: string;
@@ -231,6 +271,13 @@ export interface AdHocSubProcessOptions extends ElementOptions {
231
271
  modelerTemplateVersion?: string;
232
272
  /** Zeebe modeler template icon (data URI). */
233
273
  modelerTemplateIcon?: string;
274
+ /**
275
+ * FEEL expression evaluated after each tool activity completes; ends the
276
+ * ad-hoc scope when true (`bpmn:completionCondition`).
277
+ */
278
+ completionCondition?: string;
279
+ /** Whether still-running inner activity instances are cancelled once the completion condition is met (default true). */
280
+ cancelRemainingInstances?: boolean;
234
281
  }
235
282
  /**
236
283
  * Builder for a single named branch path from a gateway.
@@ -354,6 +401,15 @@ export declare class SubProcessContentBuilder {
354
401
  /** @internal */
355
402
  constructor(rootMessages?: BpmnMessage[]);
356
403
  private addElement;
404
+ /**
405
+ * Add an element with no sequence-flow wiring and no cursor movement.
406
+ *
407
+ * Used for ad-hoc sub-process tool activities, which the AI Agent connector
408
+ * requires to be root nodes (no incoming sequence flow, not a boundary event).
409
+ * Unlike `serviceTask()`/`userTask()`/etc., this does not auto-connect from
410
+ * the current cursor and does not move it.
411
+ */
412
+ addDisconnected(element: BpmnFlowElement): this;
357
413
  startEvent(id?: string, options?: StartEventOptions): this;
358
414
  endEvent(id?: string, options?: EndEventOptions): this;
359
415
  intermediateThrowEvent(id?: string, options?: IntermediateThrowEventOptions): this;
@@ -15,6 +15,12 @@ function resolveMessage(messageName, rootMessages) {
15
15
  }
16
16
  return existing.id;
17
17
  }
18
+ /** Builds the `zeebe:subscription` extension element for a correlated message catch. */
19
+ function buildMessageSubscriptionExt(correlationKey) {
20
+ if (!correlationKey)
21
+ return [];
22
+ return zeebeExtensionsToXmlElements({ subscription: { correlationKey } });
23
+ }
18
24
  function buildEventDefinitions(opts, rootErrors, rootMessages, rootSignals, rootEscalations) {
19
25
  const defs = [];
20
26
  if (opts.timerDuration || opts.timerDate || opts.timerCycle) {
@@ -86,6 +92,7 @@ function makeFlowElement(id, type, options) {
86
92
  name: options?.name,
87
93
  incoming: [],
88
94
  outgoing: [],
95
+ documentation: options?.documentation,
89
96
  extensionElements: options?.extensionElements ?? [],
90
97
  unknownAttributes: {},
91
98
  };
@@ -232,6 +239,9 @@ function buildServiceTaskExtensions(options) {
232
239
  })),
233
240
  };
234
241
  }
242
+ if (options.zeebeProperties) {
243
+ extensions.properties = { properties: options.zeebeProperties };
244
+ }
235
245
  return zeebeExtensionsToXmlElements(extensions);
236
246
  }
237
247
  function makeConditionExpression(expression) {
@@ -240,6 +250,72 @@ function makeConditionExpression(expression) {
240
250
  attributes: { "xsi:type": "bpmn:tFormalExpression" },
241
251
  };
242
252
  }
253
+ /** Builds the Zeebe extension elements + completion condition shared by all `adHocSubProcess()` overloads. */
254
+ function buildAdHocSubProcessExtensions(options) {
255
+ const zeebeExt = {};
256
+ if (options?.taskDefinition) {
257
+ zeebeExt.taskDefinition = options.taskDefinition;
258
+ }
259
+ if (options?.ioMapping) {
260
+ zeebeExt.ioMapping = {
261
+ inputs: options.ioMapping.inputs ?? [],
262
+ outputs: options.ioMapping.outputs ?? [],
263
+ };
264
+ }
265
+ if (options?.taskHeaders) {
266
+ zeebeExt.taskHeaders = {
267
+ headers: Object.entries(options.taskHeaders).map(([key, value]) => ({ key, value })),
268
+ };
269
+ }
270
+ if (options?.zeebeProperties) {
271
+ zeebeExt.properties = { properties: options.zeebeProperties };
272
+ }
273
+ const extensionElements = zeebeExtensionsToXmlElements(zeebeExt);
274
+ const adHocAttrs = {};
275
+ if (options?.activeElementsCollection) {
276
+ adHocAttrs.activeElementsCollection = options.activeElementsCollection;
277
+ }
278
+ if (options?.outputCollection)
279
+ adHocAttrs.outputCollection = options.outputCollection;
280
+ if (options?.outputElement)
281
+ adHocAttrs.outputElement = options.outputElement;
282
+ if (Object.keys(adHocAttrs).length > 0) {
283
+ extensionElements.push({ name: "zeebe:adHoc", attributes: adHocAttrs, children: [] });
284
+ }
285
+ return {
286
+ extensionElements,
287
+ completionCondition: options?.completionCondition
288
+ ? makeConditionExpression(options.completionCondition)
289
+ : undefined,
290
+ };
291
+ }
292
+ /** Applies modeler-template attrs, sub-process contents, loop characteristics, and completion condition. */
293
+ function finalizeAdHocSubProcessEl(element, options, sub, completionCondition) {
294
+ if (options?.modelerTemplate)
295
+ element.unknownAttributes["zeebe:modelerTemplate"] = options.modelerTemplate;
296
+ if (options?.modelerTemplateVersion) {
297
+ element.unknownAttributes["zeebe:modelerTemplateVersion"] = options.modelerTemplateVersion;
298
+ }
299
+ if (options?.modelerTemplateIcon) {
300
+ element.unknownAttributes["zeebe:modelerTemplateIcon"] = options.modelerTemplateIcon;
301
+ }
302
+ if (element.type !== "adHocSubProcess")
303
+ return;
304
+ element.flowElements = sub._elements;
305
+ element.sequenceFlows = sub._flows;
306
+ element.textAnnotations = sub._textAnnotations;
307
+ element.associations = sub._associations;
308
+ if (options?.loopCharacteristics) {
309
+ element.loopCharacteristics = buildAdHocLoopCharacteristics(options.loopCharacteristics);
310
+ }
311
+ else if (options?.multiInstance) {
312
+ element.loopCharacteristics = buildMultiInstance(options.multiInstance);
313
+ }
314
+ element.completionCondition = completionCondition;
315
+ if (options?.cancelRemainingInstances !== undefined) {
316
+ element.cancelRemainingInstances = options.cancelRemainingInstances;
317
+ }
318
+ }
243
319
  // ---------------------------------------------------------------------------
244
320
  // Element factory functions — shared by all three builder classes
245
321
  // ---------------------------------------------------------------------------
@@ -253,6 +329,7 @@ function makeServiceTaskEl(id, options) {
253
329
  unknownAttributes["zeebe:modelerTemplateIcon"] = options.modelerTemplateIcon;
254
330
  const el = makeFlowElement(id, "serviceTask", {
255
331
  name: options.name,
332
+ documentation: options.documentation,
256
333
  extensionElements: buildServiceTaskExtensions(options),
257
334
  });
258
335
  el.unknownAttributes = unknownAttributes;
@@ -263,6 +340,7 @@ function makeServiceTaskEl(id, options) {
263
340
  function makeScriptTaskEl(id, options) {
264
341
  const el = makeFlowElement(id, "scriptTask", {
265
342
  name: options.name,
343
+ documentation: options.documentation,
266
344
  extensionElements: zeebeExtensionsToXmlElements({
267
345
  unknownElements: [
268
346
  {
@@ -281,8 +359,27 @@ function makeUserTaskEl(id, options) {
281
359
  const ext = zeebeExtensionsToXmlElements({
282
360
  ...(options?.zeebeUserTask ? { userTask: true } : {}),
283
361
  ...(options?.formId ? { formDefinition: { formId: options.formId } } : {}),
362
+ ...(options?.assignee || options?.candidateGroups || options?.candidateUsers
363
+ ? {
364
+ assignmentDefinition: {
365
+ assignee: options?.assignee,
366
+ candidateGroups: options?.candidateGroups,
367
+ candidateUsers: options?.candidateUsers,
368
+ },
369
+ }
370
+ : {}),
371
+ ...(options?.dueDate || options?.followUpDate
372
+ ? { taskSchedule: { dueDate: options?.dueDate, followUpDate: options?.followUpDate } }
373
+ : {}),
374
+ ...(options?.priority !== undefined
375
+ ? { priorityDefinition: { priority: String(options.priority) } }
376
+ : {}),
377
+ });
378
+ const el = makeFlowElement(id, "userTask", {
379
+ name: options?.name,
380
+ documentation: options?.documentation,
381
+ extensionElements: ext,
284
382
  });
285
- const el = makeFlowElement(id, "userTask", { name: options?.name, extensionElements: ext });
286
383
  if (options?.isForCompensation)
287
384
  el.isForCompensation = true;
288
385
  return el;
@@ -302,6 +399,7 @@ function makeBusinessRuleTaskEl(id, options) {
302
399
  }
303
400
  const el = makeFlowElement(id, "businessRuleTask", {
304
401
  name: options?.name,
402
+ documentation: options?.documentation,
305
403
  extensionElements: ext,
306
404
  });
307
405
  if (options?.isForCompensation)
@@ -315,6 +413,7 @@ function makeCallActivityEl(id, options) {
315
413
  }
316
414
  const el = makeFlowElement(id, "callActivity", {
317
415
  name: options.name,
416
+ documentation: options.documentation,
318
417
  extensionElements: zeebeExtensionsToXmlElements({
319
418
  unknownElements: [{ name: "zeebe:calledElement", attributes: attrs, children: [] }],
320
419
  }),
@@ -667,7 +766,10 @@ export class BranchBuilder {
667
766
  return this.addElement(el);
668
767
  }
669
768
  intermediateCatchEvent(id, options) {
670
- const el = makeFlowElement(id ?? generateId("IntermediateCatchEvent"), "intermediateCatchEvent", options);
769
+ const el = makeFlowElement(id ?? generateId("IntermediateCatchEvent"), "intermediateCatchEvent", {
770
+ ...options,
771
+ extensionElements: buildMessageSubscriptionExt(options?.correlationKey),
772
+ });
671
773
  if (el.type === "intermediateCatchEvent" && options) {
672
774
  el.eventDefinitions = buildEventDefinitions(options, this.rootErrors, this.rootMessages, this.rootSignals, this.rootEscalations);
673
775
  }
@@ -698,7 +800,10 @@ export class BranchBuilder {
698
800
  * cursor to return to the task afterward.
699
801
  */
700
802
  boundaryEvent(id, options) {
701
- const element = makeFlowElement(id, "boundaryEvent", options);
803
+ const element = makeFlowElement(id, "boundaryEvent", {
804
+ ...options,
805
+ extensionElements: buildMessageSubscriptionExt(options.correlationKey),
806
+ });
702
807
  if (element.type === "boundaryEvent") {
703
808
  element.attachedToRef = options.attachedTo;
704
809
  element.cancelActivity = options.cancelActivity;
@@ -770,68 +875,13 @@ export class BranchBuilder {
770
875
  resolved.content(sub);
771
876
  insertJoinGateways(sub._elements, sub._flows);
772
877
  recomputeIncomingOutgoing(sub._elements, sub._flows);
773
- const zeebeExt = {};
774
- if (resolved.options?.taskDefinition) {
775
- zeebeExt.taskDefinition = resolved.options.taskDefinition;
776
- }
777
- if (resolved.options?.ioMapping) {
778
- zeebeExt.ioMapping = {
779
- inputs: resolved.options.ioMapping.inputs ?? [],
780
- outputs: resolved.options.ioMapping.outputs ?? [],
781
- };
782
- }
783
- if (resolved.options?.taskHeaders) {
784
- zeebeExt.taskHeaders = {
785
- headers: Object.entries(resolved.options.taskHeaders).map(([key, value]) => ({
786
- key,
787
- value,
788
- })),
789
- };
790
- }
791
- const extensionElements = zeebeExtensionsToXmlElements(zeebeExt);
792
- const adHocAttrs = {};
793
- if (resolved.options?.activeElementsCollection) {
794
- adHocAttrs.activeElementsCollection = resolved.options.activeElementsCollection;
795
- }
796
- if (resolved.options?.outputCollection) {
797
- adHocAttrs.outputCollection = resolved.options.outputCollection;
798
- }
799
- if (resolved.options?.outputElement) {
800
- adHocAttrs.outputElement = resolved.options.outputElement;
801
- }
802
- if (Object.keys(adHocAttrs).length > 0) {
803
- extensionElements.push({
804
- name: "zeebe:adHoc",
805
- attributes: adHocAttrs,
806
- children: [],
807
- });
808
- }
878
+ const { extensionElements, completionCondition } = buildAdHocSubProcessExtensions(resolved.options);
809
879
  const element = makeFlowElement(id, "adHocSubProcess", {
810
880
  name: resolved.options?.name,
881
+ documentation: resolved.options?.documentation,
811
882
  extensionElements,
812
883
  });
813
- if (resolved.options?.modelerTemplate) {
814
- element.unknownAttributes["zeebe:modelerTemplate"] = resolved.options.modelerTemplate;
815
- }
816
- if (resolved.options?.modelerTemplateVersion) {
817
- element.unknownAttributes["zeebe:modelerTemplateVersion"] =
818
- resolved.options.modelerTemplateVersion;
819
- }
820
- if (resolved.options?.modelerTemplateIcon) {
821
- element.unknownAttributes["zeebe:modelerTemplateIcon"] = resolved.options.modelerTemplateIcon;
822
- }
823
- if (element.type === "adHocSubProcess") {
824
- element.flowElements = sub._elements;
825
- element.sequenceFlows = sub._flows;
826
- element.textAnnotations = sub._textAnnotations;
827
- element.associations = sub._associations;
828
- if (resolved.options?.loopCharacteristics) {
829
- element.loopCharacteristics = buildAdHocLoopCharacteristics(resolved.options.loopCharacteristics);
830
- }
831
- else if (resolved.options?.multiInstance) {
832
- element.loopCharacteristics = buildMultiInstance(resolved.options.multiInstance);
833
- }
834
- }
884
+ finalizeAdHocSubProcessEl(element, resolved.options, sub, completionCondition);
835
885
  return this.addElement(element);
836
886
  }
837
887
  /** Add an event sub-process. Triggered by its start event — no incoming or outgoing sequence flows. */
@@ -953,6 +1003,21 @@ export class SubProcessContentBuilder {
953
1003
  this.lastNodeId = element.id;
954
1004
  return this;
955
1005
  }
1006
+ /**
1007
+ * Add an element with no sequence-flow wiring and no cursor movement.
1008
+ *
1009
+ * Used for ad-hoc sub-process tool activities, which the AI Agent connector
1010
+ * requires to be root nodes (no incoming sequence flow, not a boundary event).
1011
+ * Unlike `serviceTask()`/`userTask()`/etc., this does not auto-connect from
1012
+ * the current cursor and does not move it.
1013
+ */
1014
+ addDisconnected(element) {
1015
+ if (this._elements.some((n) => n.id === element.id)) {
1016
+ throw new Error(`Duplicate element ID "${element.id}" in sub-process`);
1017
+ }
1018
+ this._elements.push(element);
1019
+ return this;
1020
+ }
956
1021
  // ---- Events ----
957
1022
  startEvent(id, options) {
958
1023
  const el = makeFlowElement(id ?? generateId("StartEvent"), "startEvent", options);
@@ -976,7 +1041,10 @@ export class SubProcessContentBuilder {
976
1041
  return this.addElement(el);
977
1042
  }
978
1043
  intermediateCatchEvent(id, options) {
979
- const el = makeFlowElement(id ?? generateId("IntermediateCatchEvent"), "intermediateCatchEvent", options);
1044
+ const el = makeFlowElement(id ?? generateId("IntermediateCatchEvent"), "intermediateCatchEvent", {
1045
+ ...options,
1046
+ extensionElements: buildMessageSubscriptionExt(options?.correlationKey),
1047
+ });
980
1048
  if (el.type === "intermediateCatchEvent" && options)
981
1049
  el.eventDefinitions = buildEventDefinitions(options);
982
1050
  return this.addElement(el);
@@ -1131,7 +1199,10 @@ export class SubProcessContentBuilder {
1131
1199
  * cursor to return to the task afterward.
1132
1200
  */
1133
1201
  boundaryEvent(id, options) {
1134
- const element = makeFlowElement(id, "boundaryEvent", options);
1202
+ const element = makeFlowElement(id, "boundaryEvent", {
1203
+ ...options,
1204
+ extensionElements: buildMessageSubscriptionExt(options.correlationKey),
1205
+ });
1135
1206
  if (element.type === "boundaryEvent") {
1136
1207
  element.attachedToRef = options.attachedTo;
1137
1208
  element.cancelActivity = options.cancelActivity;
@@ -1200,68 +1271,13 @@ export class SubProcessContentBuilder {
1200
1271
  resolved.content(sub);
1201
1272
  insertJoinGateways(sub._elements, sub._flows);
1202
1273
  recomputeIncomingOutgoing(sub._elements, sub._flows);
1203
- const zeebeExt = {};
1204
- if (resolved.options?.taskDefinition) {
1205
- zeebeExt.taskDefinition = resolved.options.taskDefinition;
1206
- }
1207
- if (resolved.options?.ioMapping) {
1208
- zeebeExt.ioMapping = {
1209
- inputs: resolved.options.ioMapping.inputs ?? [],
1210
- outputs: resolved.options.ioMapping.outputs ?? [],
1211
- };
1212
- }
1213
- if (resolved.options?.taskHeaders) {
1214
- zeebeExt.taskHeaders = {
1215
- headers: Object.entries(resolved.options.taskHeaders).map(([key, value]) => ({
1216
- key,
1217
- value,
1218
- })),
1219
- };
1220
- }
1221
- const extensionElements = zeebeExtensionsToXmlElements(zeebeExt);
1222
- const adHocAttrs = {};
1223
- if (resolved.options?.activeElementsCollection) {
1224
- adHocAttrs.activeElementsCollection = resolved.options.activeElementsCollection;
1225
- }
1226
- if (resolved.options?.outputCollection) {
1227
- adHocAttrs.outputCollection = resolved.options.outputCollection;
1228
- }
1229
- if (resolved.options?.outputElement) {
1230
- adHocAttrs.outputElement = resolved.options.outputElement;
1231
- }
1232
- if (Object.keys(adHocAttrs).length > 0) {
1233
- extensionElements.push({
1234
- name: "zeebe:adHoc",
1235
- attributes: adHocAttrs,
1236
- children: [],
1237
- });
1238
- }
1274
+ const { extensionElements, completionCondition } = buildAdHocSubProcessExtensions(resolved.options);
1239
1275
  const element = makeFlowElement(id, "adHocSubProcess", {
1240
1276
  name: resolved.options?.name,
1277
+ documentation: resolved.options?.documentation,
1241
1278
  extensionElements,
1242
1279
  });
1243
- if (resolved.options?.modelerTemplate) {
1244
- element.unknownAttributes["zeebe:modelerTemplate"] = resolved.options.modelerTemplate;
1245
- }
1246
- if (resolved.options?.modelerTemplateVersion) {
1247
- element.unknownAttributes["zeebe:modelerTemplateVersion"] =
1248
- resolved.options.modelerTemplateVersion;
1249
- }
1250
- if (resolved.options?.modelerTemplateIcon) {
1251
- element.unknownAttributes["zeebe:modelerTemplateIcon"] = resolved.options.modelerTemplateIcon;
1252
- }
1253
- if (element.type === "adHocSubProcess") {
1254
- element.flowElements = sub._elements;
1255
- element.sequenceFlows = sub._flows;
1256
- element.textAnnotations = sub._textAnnotations;
1257
- element.associations = sub._associations;
1258
- if (resolved.options?.loopCharacteristics) {
1259
- element.loopCharacteristics = buildAdHocLoopCharacteristics(resolved.options.loopCharacteristics);
1260
- }
1261
- else if (resolved.options?.multiInstance) {
1262
- element.loopCharacteristics = buildMultiInstance(resolved.options.multiInstance);
1263
- }
1264
- }
1280
+ finalizeAdHocSubProcessEl(element, resolved.options, sub, completionCondition);
1265
1281
  return this.addElement(element);
1266
1282
  }
1267
1283
  /** Add an event sub-process. Triggered by its start event — no incoming or outgoing sequence flows. */
@@ -1421,7 +1437,10 @@ export class ProcessBuilder {
1421
1437
  /** Add an intermediate catch event (timer, message, signal). */
1422
1438
  intermediateCatchEvent(id, options) {
1423
1439
  const nodeId = id ?? generateId("IntermediateCatchEvent");
1424
- const element = makeFlowElement(nodeId, "intermediateCatchEvent", options);
1440
+ const element = makeFlowElement(nodeId, "intermediateCatchEvent", {
1441
+ ...options,
1442
+ extensionElements: buildMessageSubscriptionExt(options?.correlationKey),
1443
+ });
1425
1444
  if (element.type === "intermediateCatchEvent" && options) {
1426
1445
  element.eventDefinitions = buildEventDefinitions(options, this.rootErrors, this.rootMessages, this.rootSignals, this.rootEscalations);
1427
1446
  }
@@ -1435,7 +1454,10 @@ export class ProcessBuilder {
1435
1454
  * They start a new outgoing chain from the boundary event itself.
1436
1455
  */
1437
1456
  boundaryEvent(id, options) {
1438
- const element = makeFlowElement(id, "boundaryEvent", options);
1457
+ const element = makeFlowElement(id, "boundaryEvent", {
1458
+ ...options,
1459
+ extensionElements: buildMessageSubscriptionExt(options.correlationKey),
1460
+ });
1439
1461
  if (element.type === "boundaryEvent") {
1440
1462
  element.attachedToRef = options.attachedTo;
1441
1463
  element.cancelActivity = options.cancelActivity;
@@ -1690,69 +1712,13 @@ export class ProcessBuilder {
1690
1712
  resolved.content(sub);
1691
1713
  insertJoinGateways(sub._elements, sub._flows);
1692
1714
  recomputeIncomingOutgoing(sub._elements, sub._flows);
1693
- const zeebeExt = {};
1694
- if (resolved.options?.taskDefinition) {
1695
- zeebeExt.taskDefinition = resolved.options.taskDefinition;
1696
- }
1697
- if (resolved.options?.ioMapping) {
1698
- zeebeExt.ioMapping = {
1699
- inputs: resolved.options.ioMapping.inputs ?? [],
1700
- outputs: resolved.options.ioMapping.outputs ?? [],
1701
- };
1702
- }
1703
- if (resolved.options?.taskHeaders) {
1704
- zeebeExt.taskHeaders = {
1705
- headers: Object.entries(resolved.options.taskHeaders).map(([key, value]) => ({
1706
- key,
1707
- value,
1708
- })),
1709
- };
1710
- }
1711
- const extensionElements = zeebeExtensionsToXmlElements(zeebeExt);
1712
- // zeebe:adHoc element
1713
- const adHocAttrs = {};
1714
- if (resolved.options?.activeElementsCollection) {
1715
- adHocAttrs.activeElementsCollection = resolved.options.activeElementsCollection;
1716
- }
1717
- if (resolved.options?.outputCollection) {
1718
- adHocAttrs.outputCollection = resolved.options.outputCollection;
1719
- }
1720
- if (resolved.options?.outputElement) {
1721
- adHocAttrs.outputElement = resolved.options.outputElement;
1722
- }
1723
- if (Object.keys(adHocAttrs).length > 0) {
1724
- extensionElements.push({
1725
- name: "zeebe:adHoc",
1726
- attributes: adHocAttrs,
1727
- children: [],
1728
- });
1729
- }
1715
+ const { extensionElements, completionCondition } = buildAdHocSubProcessExtensions(resolved.options);
1730
1716
  const element = makeFlowElement(id, "adHocSubProcess", {
1731
1717
  name: resolved.options?.name,
1718
+ documentation: resolved.options?.documentation,
1732
1719
  extensionElements,
1733
1720
  });
1734
- if (resolved.options?.modelerTemplate) {
1735
- element.unknownAttributes["zeebe:modelerTemplate"] = resolved.options.modelerTemplate;
1736
- }
1737
- if (resolved.options?.modelerTemplateVersion) {
1738
- element.unknownAttributes["zeebe:modelerTemplateVersion"] =
1739
- resolved.options.modelerTemplateVersion;
1740
- }
1741
- if (resolved.options?.modelerTemplateIcon) {
1742
- element.unknownAttributes["zeebe:modelerTemplateIcon"] = resolved.options.modelerTemplateIcon;
1743
- }
1744
- if (element.type === "adHocSubProcess") {
1745
- element.flowElements = sub._elements;
1746
- element.sequenceFlows = sub._flows;
1747
- element.textAnnotations = sub._textAnnotations;
1748
- element.associations = sub._associations;
1749
- if (resolved.options?.loopCharacteristics) {
1750
- element.loopCharacteristics = buildAdHocLoopCharacteristics(resolved.options.loopCharacteristics);
1751
- }
1752
- else if (resolved.options?.multiInstance) {
1753
- element.loopCharacteristics = buildMultiInstance(resolved.options.multiInstance);
1754
- }
1755
- }
1721
+ finalizeAdHocSubProcessEl(element, resolved.options, sub, completionCondition);
1756
1722
  this.addFlowElement(element);
1757
1723
  return this;
1758
1724
  }
@@ -183,6 +183,10 @@ export interface BpmnReceiveTask extends BpmnFlowNodeBase {
183
183
  export interface BpmnAdHocSubProcess extends BpmnFlowNodeBase {
184
184
  type: "adHocSubProcess";
185
185
  loopCharacteristics?: BpmnMultiInstanceLoopCharacteristics;
186
+ /** FEEL expression evaluated after each tool activity completes; ends the ad-hoc scope when true. */
187
+ completionCondition?: BpmnConditionExpression;
188
+ /** Whether still-running inner activity instances are cancelled once the completion condition is met (default true). */
189
+ cancelRemainingInstances?: boolean;
186
190
  flowElements: BpmnFlowElement[];
187
191
  sequenceFlows: BpmnSequenceFlow[];
188
192
  textAnnotations: BpmnTextAnnotation[];
@@ -328,13 +328,21 @@ function parseFlowElement(element) {
328
328
  loopCharacteristics: parseLoopCharacteristics(element),
329
329
  isForCompensation: attr(element, "isForCompensation") === "true" ? true : undefined,
330
330
  };
331
- case "adHocSubProcess":
331
+ case "adHocSubProcess": {
332
+ const completionEl = findChild(element, "completionCondition");
332
333
  return {
333
334
  ...base,
334
335
  type: "adHocSubProcess",
335
336
  loopCharacteristics: parseLoopCharacteristics(element),
337
+ completionCondition: completionEl
338
+ ? { text: completionEl.text ?? "", attributes: { ...completionEl.attributes } }
339
+ : undefined,
340
+ cancelRemainingInstances: attr(element, "cancelRemainingInstances") !== undefined
341
+ ? attr(element, "cancelRemainingInstances") === "true"
342
+ : undefined,
336
343
  ...parseProcessContents(element),
337
344
  };
345
+ }
338
346
  case "subProcess":
339
347
  return {
340
348
  ...base,
@@ -202,8 +202,14 @@ function serializeFlowElement(fe, ns) {
202
202
  children.push(...serializeLoopCharacteristics(fe.loopCharacteristics, bp));
203
203
  break;
204
204
  case "adHocSubProcess":
205
+ if (fe.cancelRemainingInstances !== undefined) {
206
+ attrs.cancelRemainingInstances = String(fe.cancelRemainingInstances);
207
+ }
205
208
  children.push(...serializeLoopCharacteristics(fe.loopCharacteristics, bp));
206
209
  children.push(...serializeProcessContents(fe, ns));
210
+ if (fe.completionCondition) {
211
+ children.push(el(`${bp}:completionCondition`, fe.completionCondition.attributes, [], fe.completionCondition.text));
212
+ }
207
213
  break;
208
214
  case "subProcess":
209
215
  if (fe.triggeredByEvent !== undefined)
@@ -0,0 +1,10 @@
1
+ import type { BpmnProcess } from "../bpmn-model.js";
2
+ import type { OptimizationFinding } from "./types.js";
3
+ /**
4
+ * Agentic-specific checks for the Camunda 8 AI Agent Sub-process pattern:
5
+ * tools must be root nodes with a description the LLM can read, every
6
+ * `fromAi()` call must reference `toolCall.*`, and the agent should aggregate
7
+ * tool results and cap its model-call budget.
8
+ */
9
+ export declare function analyzeAgentic(p: BpmnProcess): OptimizationFinding[];
10
+ //# sourceMappingURL=agentic.d.ts.map