@arbidocs/blocks 0.4.74 → 0.4.76

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 (84) hide show
  1. package/README.md +2 -1
  2. package/dist/agents/index.cjs +267 -254
  3. package/dist/agents/index.js +5 -4
  4. package/dist/agents/tasks/TaskActivityTimeline.d.ts +1 -1
  5. package/dist/agents/tasks/WorkflowThreadStrip.d.ts +38 -1
  6. package/dist/agents/tasks/index.d.ts +2 -1
  7. package/dist/agents/tasks/linkedRuns.d.ts +31 -0
  8. package/dist/agents/workflows/index.d.ts +1 -1
  9. package/dist/agents/workflows/planSteps.d.ts +3 -1
  10. package/dist/agents/workflows/types.d.ts +27 -0
  11. package/dist/{chunk-YWYVIQ7T.js → chunk-22P5KNIM.js} +24 -4
  12. package/dist/chunk-22P5KNIM.js.map +1 -0
  13. package/dist/{chunk-5LP54CWR.cjs → chunk-7FKARMA3.cjs} +175 -69
  14. package/dist/chunk-7FKARMA3.cjs.map +1 -0
  15. package/dist/{chunk-IA7RTPT3.cjs → chunk-IXALYQT7.cjs} +2 -200
  16. package/dist/chunk-IXALYQT7.cjs.map +1 -0
  17. package/dist/chunk-NUNKSZKU.js +203 -0
  18. package/dist/chunk-NUNKSZKU.js.map +1 -0
  19. package/dist/{chunk-6OL5S7MJ.cjs → chunk-NYBIKDWI.cjs} +5 -2
  20. package/dist/chunk-NYBIKDWI.cjs.map +1 -0
  21. package/dist/{chunk-D46ZAPEE.js → chunk-R3PDNQYT.js} +5 -2
  22. package/dist/chunk-R3PDNQYT.js.map +1 -0
  23. package/dist/{chunk-KOSGX3UK.js → chunk-TKB7TVMW.js} +134 -30
  24. package/dist/chunk-TKB7TVMW.js.map +1 -0
  25. package/dist/chunk-V4ISCZJ7.cjs +207 -0
  26. package/dist/chunk-V4ISCZJ7.cjs.map +1 -0
  27. package/dist/{chunk-P2RBE3FD.cjs → chunk-VYRKO3XU.cjs} +24 -3
  28. package/dist/chunk-VYRKO3XU.cjs.map +1 -0
  29. package/dist/{chunk-BUHKUKKB.js → chunk-ZPLG7QYF.js} +4 -199
  30. package/dist/chunk-ZPLG7QYF.js.map +1 -0
  31. package/dist/connect/index.cjs +9 -9
  32. package/dist/connect/index.js +2 -2
  33. package/dist/databases/DatabaseColumnDialog.d.ts +43 -0
  34. package/dist/databases/DatabaseList.d.ts +28 -0
  35. package/dist/databases/DatabaseTable.d.ts +38 -0
  36. package/dist/databases/DatabaseToolbar.d.ts +38 -0
  37. package/dist/databases/NewDatabaseDialog.d.ts +25 -0
  38. package/dist/databases/SelectCellEditor.d.ts +6 -0
  39. package/dist/databases/SelectChip.d.ts +4 -0
  40. package/dist/databases/column-types.d.ts +58 -0
  41. package/dist/databases/databaseColumns.d.ts +28 -0
  42. package/dist/databases/index.cjs +1081 -0
  43. package/dist/databases/index.cjs.map +1 -0
  44. package/dist/databases/index.d.ts +13 -0
  45. package/dist/databases/index.js +1055 -0
  46. package/dist/databases/index.js.map +1 -0
  47. package/dist/facts/index.cjs +8 -7
  48. package/dist/facts/index.cjs.map +1 -1
  49. package/dist/facts/index.js +4 -3
  50. package/dist/facts/index.js.map +1 -1
  51. package/dist/files/index.cjs +15 -14
  52. package/dist/files/index.cjs.map +1 -1
  53. package/dist/files/index.js +5 -3
  54. package/dist/files/index.js.map +1 -1
  55. package/dist/home/index.cjs +1 -1
  56. package/dist/home/index.js +1 -1
  57. package/dist/index.cjs +508 -495
  58. package/dist/index.cjs.map +1 -1
  59. package/dist/index.js +9 -8
  60. package/dist/index.js.map +1 -1
  61. package/dist/shell/ActionCluster.d.ts +3 -1
  62. package/dist/shell/index.cjs +46 -46
  63. package/dist/shell/index.js +2 -2
  64. package/dist/studio/index.cjs +1 -1
  65. package/dist/studio/index.js +1 -1
  66. package/dist/workflow-canvas/SignalsEditor.d.ts +41 -0
  67. package/dist/workflow-canvas/StepInspector.d.ts +4 -1
  68. package/dist/workflow-canvas/TriggerInspector.d.ts +11 -2
  69. package/dist/workflow-canvas/WorkflowBuilder.d.ts +7 -2
  70. package/dist/workflow-canvas/index.cjs +445 -150
  71. package/dist/workflow-canvas/index.cjs.map +1 -1
  72. package/dist/workflow-canvas/index.d.ts +2 -1
  73. package/dist/workflow-canvas/index.js +412 -124
  74. package/dist/workflow-canvas/index.js.map +1 -1
  75. package/dist/workflow-canvas/trigger.d.ts +20 -1
  76. package/package.json +9 -4
  77. package/dist/chunk-5LP54CWR.cjs.map +0 -1
  78. package/dist/chunk-6OL5S7MJ.cjs.map +0 -1
  79. package/dist/chunk-BUHKUKKB.js.map +0 -1
  80. package/dist/chunk-D46ZAPEE.js.map +0 -1
  81. package/dist/chunk-IA7RTPT3.cjs.map +0 -1
  82. package/dist/chunk-KOSGX3UK.js.map +0 -1
  83. package/dist/chunk-P2RBE3FD.cjs.map +0 -1
  84. package/dist/chunk-YWYVIQ7T.js.map +0 -1
@@ -1,31 +1,32 @@
1
1
  "use client";
2
2
  import { useConnection } from '../chunk-OYMWV45N.js';
3
- import { describeRRule, RecurrenceBuilder, AgentSelect, useWorkflowPreview, workflowWhen, isoToLocalInput, localInputToIso } from '../chunk-KOSGX3UK.js';
3
+ import { workflowWhen, isoToLocalInput, describeRRule, RecurrenceBuilder, AgentSelect, useWorkflowPreview, localInputToIso } from '../chunk-TKB7TVMW.js';
4
4
  import '../chunk-CKB64Z4R.js';
5
5
  import '../chunk-P6GHJSLR.js';
6
- import { workflowSteps, dependsOn, stepLevels, stepDependencies, runFields, validateWorkflowGraph, WorkflowRunner, fromPlanSteps, layoutFromPlanSteps, skillToWorkflow, orderSteps, toPlanSteps } from '../chunk-YWYVIQ7T.js';
6
+ import { workflowSteps, dependsOn, stepLevels, isIncompleteSignal, stepDependencies, runFields, fromPlanSteps, layoutFromPlanSteps, validateWorkflowGraph, WorkflowRunner, skillToWorkflow, orderSteps, toPlanSteps } from '../chunk-22P5KNIM.js';
7
7
  import '../chunk-4WWM3GQ5.js';
8
8
  import '../chunk-RFXJYIDV.js';
9
9
  import '../chunk-DPLRHEJZ.js';
10
10
  import '../chunk-EVUEIBNU.js';
11
- import '../chunk-BUHKUKKB.js';
11
+ import '../chunk-NUNKSZKU.js';
12
12
  import '../chunk-YU2KUMGE.js';
13
+ import '../chunk-ZPLG7QYF.js';
13
14
  import '../chunk-DDF5GPIJ.js';
14
15
  import '../chunk-XD2M6LIG.js';
15
16
  import '../chunk-S7PSMMRG.js';
17
+ import '../chunk-76JDDMSP.js';
16
18
  import '../chunk-HOXKR26S.js';
17
19
  import '../chunk-AA3PT6KR.js';
18
20
  import '../chunk-SLSBJRWW.js';
19
21
  import '../chunk-NPLYHR2E.js';
20
- import '../chunk-76JDDMSP.js';
21
22
  import '../chunk-OXF2IFXG.js';
22
23
  import '../chunk-TX2ZICS7.js';
23
24
  import '../chunk-7F6CBP3Z.js';
24
25
  import '../chunk-VUNV25KB.js';
25
26
  import { useMemo, useState, useEffect, useCallback, useRef } from 'react';
26
27
  import { useWorkflows, useSkills, useAgents, useConversations, useCreateWorkflow, useUpdateWorkflow, useRunWorkflow } from '@arbidocs/react';
27
- import { Input, Textarea, Checkbox, Button, cn, Label, Popover, PopoverTrigger, PopoverContent } from '@arbidocs/react/ui';
28
- import { X, Trash2, Plus, Maximize, ClipboardCheck, Bot, Upload, FileInput, PencilRuler, Eye, LayoutGrid, Settings2, Play, Loader2, Save, Zap, GitBranch, Check, AlertTriangle, MinusCircle } from 'lucide-react';
28
+ import { Label, Input, cn, Button, Textarea, Checkbox, Popover, PopoverTrigger, PopoverContent } from '@arbidocs/react/ui';
29
+ import { X, Plus, Trash2, Maximize, ClipboardCheck, Bot, Upload, FileInput, PencilRuler, Eye, LayoutGrid, Settings2, Play, Loader2, Save, Zap, GitBranch, Check, AlertTriangle, MinusCircle } from 'lucide-react';
29
30
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
30
31
  import { MarkerType, applyNodeChanges, ReactFlow, Background, BackgroundVariant, Controls, ControlButton, MiniMap, Handle, Position } from '@xyflow/react';
31
32
 
@@ -164,6 +165,222 @@ function layoutWithDefaults(workflow) {
164
165
  const auto = autoLayout(workflowSteps(workflow));
165
166
  return { ...auto, ...layoutOf(workflow) };
166
167
  }
168
+ var DEFAULT_SIGNALS_EDITOR_LABELS = {
169
+ heading: "When done, signal\u2026",
170
+ hint: "Another workflow can start on a signal (\u201CWhen a step signals\u201D), as its own thread linked to this one.",
171
+ add: "Add signal",
172
+ name: "Signal",
173
+ namePlaceholder: "e.g. risk-high",
174
+ when: "When",
175
+ always: "Whenever it is done",
176
+ fieldEquals: "A field equals",
177
+ answerContains: "The answer contains",
178
+ answerMatches: "The answer matches (regex)",
179
+ approved: "It is approved",
180
+ field: "Field",
181
+ value: "Value",
182
+ phrase: "Phrase",
183
+ phrasePlaceholder: "e.g. Risk rating: High",
184
+ pattern: "Pattern",
185
+ remove: "Remove signal"
186
+ };
187
+ function signalConditions(kind) {
188
+ switch (kind) {
189
+ case "form":
190
+ return ["always", "field"];
191
+ case "agent":
192
+ return ["always", "contains", "matches"];
193
+ case "review":
194
+ return ["approved", "always"];
195
+ default:
196
+ return ["always"];
197
+ }
198
+ }
199
+ function conditionOf(when) {
200
+ if (!when) return "always";
201
+ if ("field" in when) return "field";
202
+ if ("contains" in when) return "contains";
203
+ if ("matches" in when) return "matches";
204
+ return "approved";
205
+ }
206
+ function signalSlug(text) {
207
+ return text.toLowerCase().replace(/[^a-z0-9_.-]+/g, "-").replace(/^[^a-z0-9]+/, "").slice(0, 64);
208
+ }
209
+ function startCondition(kind, step) {
210
+ switch (kind) {
211
+ case "field":
212
+ return { field: step.kind === "form" ? step.inputs[0]?.name ?? "" : "", equals: "" };
213
+ case "contains":
214
+ return { contains: "" };
215
+ case "matches":
216
+ return { matches: "" };
217
+ case "approved":
218
+ return { approved: true };
219
+ default:
220
+ return void 0;
221
+ }
222
+ }
223
+ function newSignal(step, taken) {
224
+ const base = signalSlug(step.id) || "signal";
225
+ let name = `${base}-done`;
226
+ let n = 2;
227
+ while (taken.includes(name)) name = `${base}-done-${n++}`;
228
+ const when = startCondition(signalConditions(step.kind)[0], step);
229
+ return when ? { name, when } : { name };
230
+ }
231
+ var selectClass = "flex h-8 w-full rounded-md border border-input bg-background px-2 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring";
232
+ function SignalsEditor({
233
+ step,
234
+ onChange,
235
+ labels,
236
+ testId = "signals-editor"
237
+ }) {
238
+ const l = { ...DEFAULT_SIGNALS_EDITOR_LABELS, ...labels };
239
+ const signals = step.signals ?? [];
240
+ const conditions = signalConditions(step.kind);
241
+ const conditionLabel = {
242
+ always: l.always,
243
+ field: l.fieldEquals,
244
+ contains: l.answerContains,
245
+ matches: l.answerMatches,
246
+ approved: l.approved
247
+ };
248
+ const emit = (next) => onChange(next.length ? next : void 0);
249
+ const set = (i, signal) => emit(signals.map((s, j) => j === i ? signal : s));
250
+ const fields = step.kind === "form" ? step.inputs : [];
251
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", "data-testid": testId, children: [
252
+ /* @__PURE__ */ jsx(Label, { className: "text-xs", children: l.heading }),
253
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
254
+ signals.map((signal, i) => {
255
+ const condition = conditionOf(signal.when);
256
+ const when = signal.when;
257
+ return /* @__PURE__ */ jsxs(
258
+ "div",
259
+ {
260
+ className: cn(
261
+ "space-y-1.5 rounded-md border p-2",
262
+ isIncompleteSignal(signal) ? "border-destructive/50" : "border-border"
263
+ ),
264
+ "data-incomplete": isIncompleteSignal(signal) || void 0,
265
+ "data-testid": `${testId}-${i}`,
266
+ children: [
267
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
268
+ /* @__PURE__ */ jsx(
269
+ Input,
270
+ {
271
+ value: signal.name,
272
+ "aria-label": l.name,
273
+ placeholder: l.namePlaceholder,
274
+ onChange: (e) => set(i, { ...signal, name: signalSlug(e.target.value) }),
275
+ className: "h-8 font-mono text-xs",
276
+ "data-testid": `${testId}-${i}-name`
277
+ }
278
+ ),
279
+ /* @__PURE__ */ jsx(
280
+ "button",
281
+ {
282
+ type: "button",
283
+ "aria-label": l.remove,
284
+ onClick: () => emit(signals.filter((_, j) => j !== i)),
285
+ "data-testid": `${testId}-${i}-remove`,
286
+ children: /* @__PURE__ */ jsx(X, { className: "size-4 text-muted-foreground" })
287
+ }
288
+ )
289
+ ] }),
290
+ /* @__PURE__ */ jsx(
291
+ "select",
292
+ {
293
+ "aria-label": l.when,
294
+ className: selectClass,
295
+ value: condition,
296
+ onChange: (e) => {
297
+ const nextWhen = startCondition(e.target.value, step);
298
+ set(i, nextWhen ? { name: signal.name, when: nextWhen } : { name: signal.name });
299
+ },
300
+ "data-testid": `${testId}-${i}-when`,
301
+ children: [...conditions, ...conditions.includes(condition) ? [] : [condition]].map(
302
+ (c) => /* @__PURE__ */ jsx("option", { value: c, children: conditionLabel[c] }, c)
303
+ )
304
+ }
305
+ ),
306
+ when && "field" in when && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
307
+ /* @__PURE__ */ jsxs(
308
+ "select",
309
+ {
310
+ "aria-label": l.field,
311
+ className: cn(selectClass, "flex-1"),
312
+ value: when.field,
313
+ onChange: (e) => set(i, { ...signal, when: { ...when, field: e.target.value } }),
314
+ "data-testid": `${testId}-${i}-field`,
315
+ children: [
316
+ fields.map((f) => /* @__PURE__ */ jsx("option", { value: f.name, children: f.label }, f.name)),
317
+ !fields.some((f) => f.name === when.field) && /* @__PURE__ */ jsx("option", { value: when.field, children: when.field || "\u2014" })
318
+ ]
319
+ }
320
+ ),
321
+ /* @__PURE__ */ jsx(
322
+ Input,
323
+ {
324
+ "aria-label": l.value,
325
+ placeholder: l.value,
326
+ value: String(when.equals),
327
+ onChange: (e) => set(i, { ...signal, when: { ...when, equals: e.target.value } }),
328
+ className: "h-8 flex-1",
329
+ "data-testid": `${testId}-${i}-equals`
330
+ }
331
+ )
332
+ ] }),
333
+ when && "contains" in when && /* @__PURE__ */ jsx(
334
+ Input,
335
+ {
336
+ "aria-label": l.phrase,
337
+ placeholder: l.phrasePlaceholder,
338
+ value: when.contains,
339
+ onChange: (e) => set(i, { ...signal, when: { contains: e.target.value } }),
340
+ className: "h-8",
341
+ "data-testid": `${testId}-${i}-contains`
342
+ }
343
+ ),
344
+ when && "matches" in when && /* @__PURE__ */ jsx(
345
+ Input,
346
+ {
347
+ "aria-label": l.pattern,
348
+ placeholder: "risk rating:\\s*high",
349
+ value: when.matches,
350
+ onChange: (e) => set(i, { ...signal, when: { matches: e.target.value } }),
351
+ className: "h-8 font-mono text-xs",
352
+ "data-testid": `${testId}-${i}-matches`
353
+ }
354
+ )
355
+ ]
356
+ },
357
+ i
358
+ );
359
+ }),
360
+ /* @__PURE__ */ jsxs(
361
+ Button,
362
+ {
363
+ variant: "outline",
364
+ size: "sm",
365
+ onClick: () => emit([
366
+ ...signals,
367
+ newSignal(
368
+ step,
369
+ signals.map((s) => s.name)
370
+ )
371
+ ]),
372
+ "data-testid": `${testId}-add`,
373
+ children: [
374
+ /* @__PURE__ */ jsx(Plus, { className: "size-4" }),
375
+ " ",
376
+ l.add
377
+ ]
378
+ }
379
+ )
380
+ ] }),
381
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: l.hint })
382
+ ] });
383
+ }
167
384
  var DEFAULT_STEP_INSPECTOR_LABELS = {
168
385
  workflow: "Workflow",
169
386
  title: "Title",
@@ -196,7 +413,7 @@ var DEFAULT_STEP_INSPECTOR_LABELS = {
196
413
  deleteStep: "Delete step"
197
414
  };
198
415
  var FIELD_TYPES = ["text", "longtext", "boolean", "number", "date", "scope"];
199
- var selectClass = "flex h-9 w-full rounded-md border border-input bg-background px-2 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring";
416
+ var selectClass2 = "flex h-9 w-full rounded-md border border-input bg-background px-2 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring";
200
417
  function Field({ label, children, hint }) {
201
418
  return /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
202
419
  /* @__PURE__ */ jsx(Label, { className: "text-xs", children: label }),
@@ -218,6 +435,7 @@ function StepInspector({
218
435
  onSelect,
219
436
  workflows = [],
220
437
  labels,
438
+ signalLabels,
221
439
  testId = "step-inspector"
222
440
  }) {
223
441
  const l = { ...DEFAULT_STEP_INSPECTOR_LABELS, ...labels };
@@ -350,6 +568,15 @@ function StepInspector({
350
568
  "data-testid": `${testId}-instructions`
351
569
  }
352
570
  ) }),
571
+ /* @__PURE__ */ jsx(
572
+ SignalsEditor,
573
+ {
574
+ step,
575
+ onChange: (signals) => patch({ signals }),
576
+ labels: signalLabels,
577
+ testId: `${testId}-signals`
578
+ }
579
+ ),
353
580
  /* @__PURE__ */ jsxs(
354
581
  Button,
355
582
  {
@@ -411,7 +638,7 @@ function FormFields({
411
638
  "select",
412
639
  {
413
640
  "aria-label": l.fieldType,
414
- className: cn(selectClass, "h-8"),
641
+ className: cn(selectClass2, "h-8"),
415
642
  value: f.type,
416
643
  onChange: (e) => set(i, { type: e.target.value }),
417
644
  children: FIELD_TYPES.map((t) => /* @__PURE__ */ jsx("option", { value: t, children: t }, t))
@@ -478,7 +705,7 @@ function AgentSettings({
478
705
  /* @__PURE__ */ jsx(Field, { label: l.runs, children: /* @__PURE__ */ jsxs(
479
706
  "select",
480
707
  {
481
- className: selectClass,
708
+ className: selectClass2,
482
709
  value,
483
710
  onChange: (e) => {
484
711
  const id = e.target.value;
@@ -535,7 +762,7 @@ function AgentSettings({
535
762
  /* @__PURE__ */ jsx(Field, { label: l.thread, children: /* @__PURE__ */ jsxs(
536
763
  "select",
537
764
  {
538
- className: selectClass,
765
+ className: selectClass2,
539
766
  value: step.branch ? "branch" : "main",
540
767
  onChange: (e) => patch({ branch: e.target.value === "branch" || void 0 }),
541
768
  "data-testid": `${testId}-thread`,
@@ -548,7 +775,7 @@ function AgentSettings({
548
775
  /* @__PURE__ */ jsx(Field, { label: l.output, children: /* @__PURE__ */ jsxs(
549
776
  "select",
550
777
  {
551
- className: selectClass,
778
+ className: selectClass2,
552
779
  value: step.output ?? "answer",
553
780
  onChange: (e) => patch({ output: e.target.value === "artifact" ? "artifact" : void 0 }),
554
781
  children: [
@@ -559,6 +786,138 @@ function AgentSettings({
559
786
  ) })
560
787
  ] });
561
788
  }
789
+
790
+ // src/workflow-canvas/trigger.ts
791
+ var WORKFLOW_SIGNAL_EVENT = "workflow_signal";
792
+ var DEFAULT_WORKFLOW_TRIGGER = {
793
+ start: "manual",
794
+ runAt: "",
795
+ rrule: "",
796
+ timezone: typeof Intl !== "undefined" ? Intl.DateTimeFormat().resolvedOptions().timeZone : "UTC",
797
+ eventKind: "",
798
+ signal: "",
799
+ afterTaskId: "",
800
+ agentId: "",
801
+ access: "ask_each_run"
802
+ };
803
+ function triggerProblem(trigger) {
804
+ if (trigger.start === "once" && !trigger.runAt) return "runAt";
805
+ if (trigger.start === "repeat" && !trigger.rrule.trim()) return "rrule";
806
+ if (trigger.start === "event" && !trigger.eventKind.trim()) return "event";
807
+ if (isSignalTrigger(trigger) && !trigger.signal.trim()) return "signal";
808
+ if (trigger.start === "task" && !trigger.afterTaskId) return "task";
809
+ return null;
810
+ }
811
+ var isSignalTrigger = (trigger) => trigger.start === "event" && trigger.eventKind.trim() === WORKFLOW_SIGNAL_EVENT;
812
+ function eventFilter(trigger) {
813
+ if (trigger.start !== "event") return null;
814
+ if (isSignalTrigger(trigger)) return { signal: trigger.signal.trim() };
815
+ return trigger.eventFilter && Object.keys(trigger.eventFilter).length ? trigger.eventFilter : null;
816
+ }
817
+ function triggerFields(trigger, clearOthers) {
818
+ const none = clearOthers ? null : void 0;
819
+ const filter = eventFilter(trigger);
820
+ return {
821
+ timezone: trigger.timezone,
822
+ rrule: trigger.start === "repeat" ? trigger.rrule.trim() : none,
823
+ run_at: trigger.start === "once" ? localInputToIso(trigger.runAt) : none,
824
+ event_kind: trigger.start === "event" ? trigger.eventKind.trim() : none,
825
+ // A step signal is `workflow_signal` narrowed to one signal name.
826
+ event_filter: filter ?? none,
827
+ after_conversation_ext_id: trigger.start === "task" ? trigger.afterTaskId : none,
828
+ on_demand: trigger.start === "manual"
829
+ };
830
+ }
831
+ var authMode = (trigger) => trigger.start === "manual" ? "run_now_temp" : trigger.access === "standing" ? "scheduled_permanent" : "scheduled_require_auth";
832
+ var withoutUndefined = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
833
+ function plan(value, options) {
834
+ return {
835
+ goal: value.workflow.description,
836
+ criteria: [],
837
+ max_passes: 3,
838
+ documents: [],
839
+ steps: toPlanSteps(value.workflow, options)
840
+ };
841
+ }
842
+ function builderToWorkflowRequest(value, workspaceId, options = {}) {
843
+ return withoutUndefined({
844
+ workspace_ext_id: workspaceId,
845
+ name: value.workflow.title,
846
+ description: value.workflow.description,
847
+ active: true,
848
+ shared: true,
849
+ ...triggerFields(value.trigger, false),
850
+ prompt: "",
851
+ skill_ref: null,
852
+ skill_inputs: null,
853
+ agent_ext_id: value.trigger.agentId || null,
854
+ auth_mode: authMode(value.trigger),
855
+ plan: plan(value, options)
856
+ });
857
+ }
858
+ function builderToWorkflowUpdate(value, options = {}) {
859
+ return withoutUndefined({
860
+ name: value.workflow.title,
861
+ description: value.workflow.description,
862
+ ...triggerFields(value.trigger, true),
863
+ // The steps are what runs (a classic automation's single prompt or skill becomes its one step).
864
+ prompt: "",
865
+ skill_ref: null,
866
+ skill_inputs: null,
867
+ agent_ext_id: value.trigger.agentId || null,
868
+ auth_mode: authMode(value.trigger),
869
+ plan: plan(value, options)
870
+ });
871
+ }
872
+ function workflowRecordToBuilder(record) {
873
+ const planned = record.plan?.steps ?? [];
874
+ const steps = planned.length ? fromPlanSteps(planned) : record.prompt || record.skill_ref ? [
875
+ {
876
+ id: "work",
877
+ kind: "agent",
878
+ title: record.name,
879
+ ...record.skill_ref ? { workflow: record.skill_ref } : { run: { kind: "prompt", promptTemplate: record.prompt } }
880
+ }
881
+ ] : [];
882
+ const when = workflowWhen(record);
883
+ return {
884
+ workflow: {
885
+ id: record.external_id,
886
+ title: record.name,
887
+ description: record.description ?? "",
888
+ inputs: [],
889
+ landing: "chat",
890
+ schedulable: false,
891
+ run: { kind: "steps", steps, layout: layoutFromPlanSteps(planned ?? []) }
892
+ },
893
+ trigger: {
894
+ ...DEFAULT_WORKFLOW_TRIGGER,
895
+ start: when === "now" ? "manual" : when,
896
+ runAt: isoToLocalInput(record.run_at),
897
+ rrule: record.rrule ?? "",
898
+ timezone: record.timezone || DEFAULT_WORKFLOW_TRIGGER.timezone,
899
+ eventKind: record.event_kind ?? "",
900
+ signal: record.event_kind === WORKFLOW_SIGNAL_EVENT && typeof record.event_filter?.signal === "string" ? record.event_filter.signal : "",
901
+ eventFilter: record.event_kind && record.event_kind !== WORKFLOW_SIGNAL_EVENT && record.event_filter ? record.event_filter : void 0,
902
+ afterTaskId: record.after_conversation_ext_id ?? "",
903
+ agentId: record.agent_ext_id ?? "",
904
+ access: record.auth_mode === "scheduled_permanent" ? "standing" : "ask_each_run"
905
+ }
906
+ };
907
+ }
908
+ function declaredSignals(records, current) {
909
+ const out = /* @__PURE__ */ new Map();
910
+ const add = (workflow, steps) => {
911
+ for (const step of steps)
912
+ for (const signal of step.signals ?? [])
913
+ if (signal.name && !out.has(signal.name))
914
+ out.set(signal.name, { value: signal.name, label: `${workflow} \u203A ${step.title}` });
915
+ };
916
+ for (const record of records)
917
+ add(record.name, record.plan?.steps ?? []);
918
+ if (current?.run.kind === "steps") add(current.title, current.run.steps);
919
+ return [...out.values()];
920
+ }
562
921
  var DEFAULT_TRIGGER_INSPECTOR_LABELS = {
563
922
  heading: "Start",
564
923
  start: "Starts",
@@ -572,6 +931,11 @@ var DEFAULT_TRIGGER_INSPECTOR_LABELS = {
572
931
  runAt: "When",
573
932
  event: "Event",
574
933
  eventPlaceholder: "Pick an event",
934
+ stepSignals: "When a step signals",
935
+ signal: "Signal",
936
+ signalPlaceholder: "e.g. risk-high",
937
+ signalHint: "Starts as its own thread, linked to the thread whose step raised it, with that run\u2019s inputs.",
938
+ signalSummary: "When a step signals \u201C{signal}\u201D",
575
939
  afterTask: "After this task",
576
940
  afterTaskPlaceholder: "Pick a task",
577
941
  agent: "Runs as",
@@ -587,6 +951,8 @@ function triggerSummary(trigger, options = {}) {
587
951
  case "repeat":
588
952
  return trigger.rrule ? describeRRule(trigger.rrule) : l.starts.repeat;
589
953
  case "event":
954
+ if (isSignalTrigger(trigger))
955
+ return trigger.signal ? l.signalSummary.replace("{signal}", trigger.signal) : l.stepSignals;
590
956
  return trigger.eventKind && options.eventLabel?.(trigger.eventKind) || trigger.eventKind || l.starts.event;
591
957
  case "task":
592
958
  return trigger.afterTaskId && options.taskLabel?.(trigger.afterTaskId) || l.starts.task;
@@ -594,7 +960,7 @@ function triggerSummary(trigger, options = {}) {
594
960
  return l.starts.manual;
595
961
  }
596
962
  }
597
- var selectClass2 = "flex h-9 w-full rounded-md border border-input bg-background px-2 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring";
963
+ var selectClass3 = "flex h-9 w-full rounded-md border border-input bg-background px-2 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring";
598
964
  var STARTS = ["manual", "once", "repeat", "event", "task"];
599
965
  function TriggerInspector({
600
966
  trigger,
@@ -602,11 +968,13 @@ function TriggerInspector({
602
968
  agents = [],
603
969
  eventKinds = [],
604
970
  tasks = [],
971
+ signals = [],
605
972
  labels,
606
973
  testId = "trigger-inspector"
607
974
  }) {
608
975
  const l = { ...DEFAULT_TRIGGER_INSPECTOR_LABELS, ...labels };
609
976
  const set = (patch) => onChange({ ...trigger, ...patch });
977
+ const events = eventKinds.some((k) => k.value === WORKFLOW_SIGNAL_EVENT) ? eventKinds : [...eventKinds, { value: WORKFLOW_SIGNAL_EVENT, label: l.stepSignals }];
610
978
  return /* @__PURE__ */ jsxs("div", { className: "space-y-4", "data-testid": testId, children: [
611
979
  /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold", children: l.heading }),
612
980
  /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
@@ -646,23 +1014,39 @@ function TriggerInspector({
646
1014
  /* @__PURE__ */ jsxs(
647
1015
  "select",
648
1016
  {
649
- className: selectClass2,
1017
+ className: selectClass3,
650
1018
  value: trigger.eventKind,
651
- onChange: (e) => set({ eventKind: e.target.value }),
1019
+ onChange: (e) => set({ eventKind: e.target.value, eventFilter: void 0 }),
652
1020
  "data-testid": `${testId}-event`,
653
1021
  children: [
654
1022
  /* @__PURE__ */ jsx("option", { value: "", children: l.eventPlaceholder }),
655
- eventKinds.map((k) => /* @__PURE__ */ jsx("option", { value: k.value, children: k.label }, k.value))
1023
+ events.map((k) => /* @__PURE__ */ jsx("option", { value: k.value, children: k.label }, k.value))
656
1024
  ]
657
1025
  }
658
1026
  )
659
1027
  ] }),
1028
+ isSignalTrigger(trigger) && /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1029
+ /* @__PURE__ */ jsx(Label, { className: "text-xs", htmlFor: `${testId}-signal`, children: l.signal }),
1030
+ /* @__PURE__ */ jsx(
1031
+ Input,
1032
+ {
1033
+ id: `${testId}-signal`,
1034
+ list: `${testId}-signal-options`,
1035
+ value: trigger.signal,
1036
+ placeholder: l.signalPlaceholder,
1037
+ onChange: (e) => set({ signal: e.target.value.trim().toLowerCase() }),
1038
+ "data-testid": `${testId}-signal`
1039
+ }
1040
+ ),
1041
+ /* @__PURE__ */ jsx("datalist", { id: `${testId}-signal-options`, children: signals.map((s) => /* @__PURE__ */ jsx("option", { value: s.value, children: s.label }, s.value)) }),
1042
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: l.signalHint })
1043
+ ] }),
660
1044
  trigger.start === "task" && /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
661
1045
  /* @__PURE__ */ jsx(Label, { className: "text-xs", children: l.afterTask }),
662
1046
  /* @__PURE__ */ jsxs(
663
1047
  "select",
664
1048
  {
665
- className: selectClass2,
1049
+ className: selectClass3,
666
1050
  value: trigger.afterTaskId,
667
1051
  onChange: (e) => set({ afterTaskId: e.target.value }),
668
1052
  "data-testid": `${testId}-after-task`,
@@ -691,7 +1075,7 @@ function TriggerInspector({
691
1075
  /* @__PURE__ */ jsxs(
692
1076
  "select",
693
1077
  {
694
- className: selectClass2,
1078
+ className: selectClass3,
695
1079
  value: trigger.access,
696
1080
  onChange: (e) => set({ access: e.target.value === "standing" ? "standing" : "ask_each_run" }),
697
1081
  "data-testid": `${testId}-access`,
@@ -1187,6 +1571,7 @@ function WorkflowBuilder({
1187
1571
  agents = [],
1188
1572
  eventKinds = [],
1189
1573
  tasks = [],
1574
+ signals = [],
1190
1575
  compose,
1191
1576
  renderIcon,
1192
1577
  actions,
@@ -1369,6 +1754,12 @@ function WorkflowBuilder({
1369
1754
  agents,
1370
1755
  eventKinds,
1371
1756
  tasks,
1757
+ signals: [
1758
+ ...signals,
1759
+ ...declaredSignals([], workflow).filter(
1760
+ (d) => !signals.some((s) => s.value === d.value)
1761
+ )
1762
+ ],
1372
1763
  labels: triggerLabels,
1373
1764
  testId: `${testId}-trigger`
1374
1765
  }
@@ -1446,111 +1837,6 @@ function WorkflowPreview({
1446
1837
  }
1447
1838
  );
1448
1839
  }
1449
-
1450
- // src/workflow-canvas/trigger.ts
1451
- var DEFAULT_WORKFLOW_TRIGGER = {
1452
- start: "manual",
1453
- runAt: "",
1454
- rrule: "",
1455
- timezone: typeof Intl !== "undefined" ? Intl.DateTimeFormat().resolvedOptions().timeZone : "UTC",
1456
- eventKind: "",
1457
- afterTaskId: "",
1458
- agentId: "",
1459
- access: "ask_each_run"
1460
- };
1461
- function triggerProblem(trigger) {
1462
- if (trigger.start === "once" && !trigger.runAt) return "runAt";
1463
- if (trigger.start === "repeat" && !trigger.rrule.trim()) return "rrule";
1464
- if (trigger.start === "event" && !trigger.eventKind.trim()) return "event";
1465
- if (trigger.start === "task" && !trigger.afterTaskId) return "task";
1466
- return null;
1467
- }
1468
- function triggerFields(trigger, clearOthers) {
1469
- const none = clearOthers ? null : void 0;
1470
- return {
1471
- timezone: trigger.timezone,
1472
- rrule: trigger.start === "repeat" ? trigger.rrule.trim() : none,
1473
- run_at: trigger.start === "once" ? localInputToIso(trigger.runAt) : none,
1474
- event_kind: trigger.start === "event" ? trigger.eventKind.trim() : none,
1475
- after_conversation_ext_id: trigger.start === "task" ? trigger.afterTaskId : none,
1476
- on_demand: trigger.start === "manual"
1477
- };
1478
- }
1479
- var authMode = (trigger) => trigger.start === "manual" ? "run_now_temp" : trigger.access === "standing" ? "scheduled_permanent" : "scheduled_require_auth";
1480
- var withoutUndefined = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
1481
- function plan(value, options) {
1482
- return {
1483
- goal: value.workflow.description,
1484
- criteria: [],
1485
- max_passes: 3,
1486
- documents: [],
1487
- steps: toPlanSteps(value.workflow, options)
1488
- };
1489
- }
1490
- function builderToWorkflowRequest(value, workspaceId, options = {}) {
1491
- return withoutUndefined({
1492
- workspace_ext_id: workspaceId,
1493
- name: value.workflow.title,
1494
- description: value.workflow.description,
1495
- active: true,
1496
- shared: true,
1497
- ...triggerFields(value.trigger, false),
1498
- prompt: "",
1499
- skill_ref: null,
1500
- skill_inputs: null,
1501
- agent_ext_id: value.trigger.agentId || null,
1502
- auth_mode: authMode(value.trigger),
1503
- plan: plan(value, options)
1504
- });
1505
- }
1506
- function builderToWorkflowUpdate(value, options = {}) {
1507
- return withoutUndefined({
1508
- name: value.workflow.title,
1509
- description: value.workflow.description,
1510
- ...triggerFields(value.trigger, true),
1511
- // The steps are what runs (a classic automation's single prompt or skill becomes its one step).
1512
- prompt: "",
1513
- skill_ref: null,
1514
- skill_inputs: null,
1515
- agent_ext_id: value.trigger.agentId || null,
1516
- auth_mode: authMode(value.trigger),
1517
- plan: plan(value, options)
1518
- });
1519
- }
1520
- function workflowRecordToBuilder(record) {
1521
- const planned = record.plan?.steps ?? [];
1522
- const steps = planned.length ? fromPlanSteps(planned) : record.prompt || record.skill_ref ? [
1523
- {
1524
- id: "work",
1525
- kind: "agent",
1526
- title: record.name,
1527
- ...record.skill_ref ? { workflow: record.skill_ref } : { run: { kind: "prompt", promptTemplate: record.prompt } }
1528
- }
1529
- ] : [];
1530
- const when = workflowWhen(record);
1531
- return {
1532
- workflow: {
1533
- id: record.external_id,
1534
- title: record.name,
1535
- description: record.description ?? "",
1536
- inputs: [],
1537
- landing: "chat",
1538
- schedulable: false,
1539
- run: { kind: "steps", steps, layout: layoutFromPlanSteps(planned ?? []) }
1540
- },
1541
- trigger: {
1542
- ...DEFAULT_WORKFLOW_TRIGGER,
1543
- start: when === "now" ? "manual" : when,
1544
- runAt: isoToLocalInput(record.run_at),
1545
- rrule: record.rrule ?? "",
1546
- timezone: record.timezone || DEFAULT_WORKFLOW_TRIGGER.timezone,
1547
- eventKind: record.event_kind ?? "",
1548
- afterTaskId: record.after_conversation_ext_id ?? "",
1549
- agentId: record.agent_ext_id ?? "",
1550
- access: record.auth_mode === "scheduled_permanent" ? "standing" : "ask_each_run"
1551
- }
1552
- };
1553
- }
1554
1840
  var DEFAULT_CONNECTED_WORKFLOW_BUILDER_LABELS = {
1555
1841
  save: "Save",
1556
1842
  saving: "Saving\u2026",
@@ -1563,7 +1849,8 @@ var DEFAULT_WORKFLOW_EVENT_KINDS = [
1563
1849
  { value: "conversation_ready", label: "Work is ready for me" },
1564
1850
  { value: "mention", label: "Someone mentions me" },
1565
1851
  { value: "workflow_completed", label: "Another workflow finishes" },
1566
- { value: "workflow_failed", label: "Another workflow fails" }
1852
+ { value: "workflow_failed", label: "Another workflow fails" },
1853
+ { value: "workflow_signal", label: "When a step signals" }
1567
1854
  ];
1568
1855
  function ConnectedWorkflowBuilder({
1569
1856
  workflowId,
@@ -1640,6 +1927,7 @@ function ConnectedWorkflowBuilder({
1640
1927
  agents,
1641
1928
  eventKinds,
1642
1929
  tasks,
1930
+ signals: declaredSignals(saved.data ?? []),
1643
1931
  compose,
1644
1932
  testId,
1645
1933
  actions: /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -1684,6 +1972,6 @@ function ConnectedWorkflowBuilder({
1684
1972
  );
1685
1973
  }
1686
1974
 
1687
- export { ConnectedWorkflowBuilder, DEFAULT_CONNECTED_WORKFLOW_BUILDER_LABELS, DEFAULT_STEP_INSPECTOR_LABELS, DEFAULT_TRIGGER_INSPECTOR_LABELS, DEFAULT_WORKFLOW_BUILDER_LABELS, DEFAULT_WORKFLOW_CANVAS_LABELS, DEFAULT_WORKFLOW_EVENT_KINDS, DEFAULT_WORKFLOW_TRIGGER, StepInspector, TRIGGER_NODE, TriggerInspector, WorkflowBuilder, WorkflowCanvas, addStep, autoLayout, builderToWorkflowRequest, builderToWorkflowUpdate, connectSteps, disconnectSteps, layoutWithDefaults, moveStep, newSteppedWorkflow, removeStep, stepIdFor, triggerProblem, triggerSummary, updateStep, workflowRecordToBuilder, wouldCycle };
1975
+ export { ConnectedWorkflowBuilder, DEFAULT_CONNECTED_WORKFLOW_BUILDER_LABELS, DEFAULT_SIGNALS_EDITOR_LABELS, DEFAULT_STEP_INSPECTOR_LABELS, DEFAULT_TRIGGER_INSPECTOR_LABELS, DEFAULT_WORKFLOW_BUILDER_LABELS, DEFAULT_WORKFLOW_CANVAS_LABELS, DEFAULT_WORKFLOW_EVENT_KINDS, DEFAULT_WORKFLOW_TRIGGER, SignalsEditor, StepInspector, TRIGGER_NODE, TriggerInspector, WORKFLOW_SIGNAL_EVENT, WorkflowBuilder, WorkflowCanvas, addStep, autoLayout, builderToWorkflowRequest, builderToWorkflowUpdate, connectSteps, declaredSignals, disconnectSteps, isSignalTrigger, layoutWithDefaults, moveStep, newSteppedWorkflow, removeStep, signalConditions, signalSlug, stepIdFor, triggerProblem, triggerSummary, updateStep, workflowRecordToBuilder, wouldCycle };
1688
1976
  //# sourceMappingURL=index.js.map
1689
1977
  //# sourceMappingURL=index.js.map