@arbidocs/blocks 0.4.122 → 0.4.124
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.
- package/dist/{StreamedArtifactEditor-IZWYNFMM.cjs → StreamedArtifactEditor-DNBDUNP2.cjs} +5 -5
- package/dist/{StreamedArtifactEditor-IZWYNFMM.cjs.map → StreamedArtifactEditor-DNBDUNP2.cjs.map} +1 -1
- package/dist/{StreamedArtifactEditor-HTNPG4NB.js → StreamedArtifactEditor-WDHPTWX7.js} +3 -3
- package/dist/{StreamedArtifactEditor-HTNPG4NB.js.map → StreamedArtifactEditor-WDHPTWX7.js.map} +1 -1
- package/dist/agents/index.cjs +390 -326
- package/dist/agents/index.js +9 -9
- package/dist/agents/tasks/ConversationListView.d.ts +2 -1
- package/dist/agents/tasks/ConversationTurnSpeaker.d.ts +3 -1
- package/dist/agents/tasks/TaskFlow.d.ts +17 -0
- package/dist/agents/tasks/ThreadLauncher.d.ts +51 -0
- package/dist/agents/tasks/ThreadStatusLine.d.ts +33 -0
- package/dist/agents/tasks/WorkflowRunStatus.d.ts +32 -0
- package/dist/agents/tasks/WorkflowThreadStrip.d.ts +29 -3
- package/dist/agents/tasks/compact-thread-activity.d.ts +5 -2
- package/dist/agents/tasks/index.d.ts +3 -0
- package/dist/agents/workflows/StepBarFrame.d.ts +18 -17
- package/dist/agents/workflows/StepChip.d.ts +37 -0
- package/dist/agents/workflows/StepDocuments.d.ts +64 -0
- package/dist/agents/workflows/WorkflowStepBar.d.ts +1 -2
- package/dist/agents/workflows/index.d.ts +2 -0
- package/dist/agents/workflows/stepKinds.d.ts +24 -0
- package/dist/artifacts/VersionTimeline.d.ts +7 -0
- package/dist/artifacts/index.cjs +21 -21
- package/dist/artifacts/index.js +1 -1
- package/dist/chat/ChatPage.d.ts +1 -1
- package/dist/chat/DraftingDocChip.d.ts +22 -0
- package/dist/chat/WorkflowStepChip.d.ts +23 -5
- package/dist/chat/chat-page-types.d.ts +18 -2
- package/dist/chat/flashMessage.d.ts +6 -0
- package/dist/chat/index.cjs +144 -131
- package/dist/chat/index.d.ts +2 -0
- package/dist/chat/index.js +4 -3
- package/dist/{chunk-SHASZLGD.js → chunk-3AV7HP6G.js} +3 -3
- package/dist/{chunk-SHASZLGD.js.map → chunk-3AV7HP6G.js.map} +1 -1
- package/dist/{chunk-UDK553WP.cjs → chunk-4VCKYR4D.cjs} +4 -4
- package/dist/{chunk-UDK553WP.cjs.map → chunk-4VCKYR4D.cjs.map} +1 -1
- package/dist/chunk-7HAM7Y5U.js +907 -0
- package/dist/chunk-7HAM7Y5U.js.map +1 -0
- package/dist/{chunk-TCNYKDYE.js → chunk-CXLVI3SB.js} +73 -40
- package/dist/chunk-CXLVI3SB.js.map +1 -0
- package/dist/{chunk-N7ARMX3O.cjs → chunk-D7WCGOD4.cjs} +3 -3
- package/dist/{chunk-N7ARMX3O.cjs.map → chunk-D7WCGOD4.cjs.map} +1 -1
- package/dist/{chunk-ZP4IFW2E.js → chunk-EJSJ27HV.js} +733 -185
- package/dist/chunk-EJSJ27HV.js.map +1 -0
- package/dist/{chunk-AY32GGKU.js → chunk-ERNMU6RV.js} +132 -752
- package/dist/chunk-ERNMU6RV.js.map +1 -0
- package/dist/{chunk-XFZ7HNPG.js → chunk-ETN5EZI4.js} +3 -3
- package/dist/{chunk-XFZ7HNPG.js.map → chunk-ETN5EZI4.js.map} +1 -1
- package/dist/{chunk-Z2NSU7D5.cjs → chunk-FL5TEBTM.cjs} +770 -216
- package/dist/chunk-FL5TEBTM.cjs.map +1 -0
- package/dist/chunk-HM23LXUP.cjs +976 -0
- package/dist/chunk-HM23LXUP.cjs.map +1 -0
- package/dist/{chunk-WN64RF46.js → chunk-HQH35JWC.js} +3 -3
- package/dist/{chunk-WN64RF46.js.map → chunk-HQH35JWC.js.map} +1 -1
- package/dist/{chunk-XSUOEJB3.cjs → chunk-MRURIBBB.cjs} +163 -837
- package/dist/chunk-MRURIBBB.cjs.map +1 -0
- package/dist/{chunk-65HZ36MY.js → chunk-OTDGTBAS.js} +20 -3
- package/dist/chunk-OTDGTBAS.js.map +1 -0
- package/dist/{chunk-CK4C3IQR.cjs → chunk-VMZXFYHK.cjs} +47 -6
- package/dist/chunk-VMZXFYHK.cjs.map +1 -0
- package/dist/{chunk-SVJQWLOF.cjs → chunk-W4GXDARU.cjs} +20 -3
- package/dist/chunk-W4GXDARU.cjs.map +1 -0
- package/dist/{chunk-US5ASM4G.cjs → chunk-WEUCLOBB.cjs} +5 -5
- package/dist/{chunk-US5ASM4G.cjs.map → chunk-WEUCLOBB.cjs.map} +1 -1
- package/dist/{chunk-S2KVJYBD.cjs → chunk-WV4IDVDQ.cjs} +76 -43
- package/dist/chunk-WV4IDVDQ.cjs.map +1 -0
- package/dist/{chunk-2FUJXMGO.js → chunk-Y4X3RBFI.js} +44 -6
- package/dist/{chunk-CK4C3IQR.cjs.map → chunk-Y4X3RBFI.js.map} +1 -1
- package/dist/collaboration/index.cjs +1 -1
- package/dist/collaboration/index.js +1 -1
- package/dist/connect/docx.cjs +4 -4
- package/dist/connect/docx.js +3 -3
- package/dist/connect/index.cjs +68 -51
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/index.js +37 -20
- package/dist/connect/index.js.map +1 -1
- package/dist/connection/WorkflowRunThread.d.ts +4 -4
- package/dist/connection/ai.d.ts +2 -0
- package/dist/facts/index.cjs +1 -1
- package/dist/facts/index.js +1 -1
- package/dist/files/index.cjs +3 -3
- package/dist/files/index.js +3 -3
- package/dist/index.cjs +728 -652
- package/dist/index.js +16 -16
- package/dist/settings/index.cjs +1 -1
- package/dist/settings/index.js +1 -1
- package/dist/shell/index.cjs +10 -10
- package/dist/shell/index.js +2 -2
- package/dist/site/index.cjs +5 -5
- package/dist/site/index.js +1 -1
- package/dist/studio/index.cjs +6 -5
- package/dist/studio/index.cjs.map +1 -1
- package/dist/studio/index.js +5 -4
- package/dist/studio/index.js.map +1 -1
- package/dist/workflow-canvas/WorkflowCanvas.d.ts +0 -9
- package/dist/workflow-canvas/edit.d.ts +2 -11
- package/dist/workflow-canvas/index.cjs +63 -87
- package/dist/workflow-canvas/index.cjs.map +1 -1
- package/dist/workflow-canvas/index.js +14 -38
- package/dist/workflow-canvas/index.js.map +1 -1
- package/node_modules/@arbidocs/coedit/dist/commands.cjs +25 -13
- package/node_modules/@arbidocs/coedit/dist/commands.cjs.map +1 -1
- package/node_modules/@arbidocs/coedit/dist/commands.d.cts +3 -1
- package/node_modules/@arbidocs/coedit/dist/commands.d.ts +3 -1
- package/node_modules/@arbidocs/coedit/dist/commands.js +25 -14
- package/node_modules/@arbidocs/coedit/dist/commands.js.map +1 -1
- package/node_modules/@arbidocs/coedit/package.json +1 -1
- package/package.json +4 -4
- package/src/blocks.css +168 -0
- package/src/workflow-canvas/canvas.css +2 -40
- package/dist/chunk-2FUJXMGO.js.map +0 -1
- package/dist/chunk-65HZ36MY.js.map +0 -1
- package/dist/chunk-AY32GGKU.js.map +0 -1
- package/dist/chunk-B4SRYJLM.cjs +0 -107
- package/dist/chunk-B4SRYJLM.cjs.map +0 -1
- package/dist/chunk-HOXKR26S.js +0 -103
- package/dist/chunk-HOXKR26S.js.map +0 -1
- package/dist/chunk-S2KVJYBD.cjs.map +0 -1
- package/dist/chunk-SVJQWLOF.cjs.map +0 -1
- package/dist/chunk-TCNYKDYE.js.map +0 -1
- package/dist/chunk-XSUOEJB3.cjs.map +0 -1
- package/dist/chunk-Z2NSU7D5.cjs.map +0 -1
- package/dist/chunk-ZP4IFW2E.js.map +0 -1
|
@@ -0,0 +1,907 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { findMentionQuery, filterMentionCandidates, insertMention, useListKeyNav } from './chunk-AA3PT6KR.js';
|
|
3
|
+
import { isTone } from './chunk-AUS3KBHJ.js';
|
|
4
|
+
import { observeResize } from './chunk-NPLYHR2E.js';
|
|
5
|
+
import { Check, Loader2, Hourglass, AlertTriangle, MinusCircle, Table2, Mail, PenLine, ClipboardCheck, Bot, Upload, FileInput, FileText } from 'lucide-react';
|
|
6
|
+
import { cn, Button } from '@arbidocs/react/ui';
|
|
7
|
+
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
8
|
+
import { forwardRef, useState, useEffect, useMemo, useCallback, useLayoutEffect } from 'react';
|
|
9
|
+
|
|
10
|
+
// src/agents/workflows/types.ts
|
|
11
|
+
var EMPTY_WORKFLOW_SCOPE = { folders: [], labels: [] };
|
|
12
|
+
|
|
13
|
+
// src/agents/workflows/workflow.ts
|
|
14
|
+
var isWorkflowScope = (value) => typeof value === "object" && value !== null && Array.isArray(value.folders) && Array.isArray(value.labels);
|
|
15
|
+
var isEmptyWorkflowScope = (scope) => scope.folders.length === 0 && scope.labels.length === 0 && !scope.documents?.length;
|
|
16
|
+
var isFileField = (field) => field.type === "scope" || field.type === "documents";
|
|
17
|
+
function emptyValue(field) {
|
|
18
|
+
switch (field.type) {
|
|
19
|
+
case "boolean":
|
|
20
|
+
return false;
|
|
21
|
+
case "scope":
|
|
22
|
+
return { folders: [], labels: [] };
|
|
23
|
+
case "documents":
|
|
24
|
+
return { folders: [], labels: [], documents: [] };
|
|
25
|
+
default:
|
|
26
|
+
return "";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function defaultInputs(workflow) {
|
|
30
|
+
const inputs = {};
|
|
31
|
+
for (const field of workflow.inputs) {
|
|
32
|
+
const d = field.default;
|
|
33
|
+
inputs[field.name] = d === void 0 ? emptyValue(field) : isWorkflowScope(d) ? { ...d } : d;
|
|
34
|
+
}
|
|
35
|
+
return inputs;
|
|
36
|
+
}
|
|
37
|
+
function validateInputs(workflow, inputs) {
|
|
38
|
+
const errors = {};
|
|
39
|
+
for (const field of workflow.inputs) {
|
|
40
|
+
const value = inputs[field.name];
|
|
41
|
+
if (field.type === "number") {
|
|
42
|
+
const blank = value === "" || value === void 0;
|
|
43
|
+
if (blank) {
|
|
44
|
+
if (field.required) errors[field.name] = "required";
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const n = Number(value);
|
|
48
|
+
if (Number.isNaN(n)) errors[field.name] = "number";
|
|
49
|
+
else if (field.min !== void 0 && n < field.min) errors[field.name] = "min";
|
|
50
|
+
else if (field.max !== void 0 && n > field.max) errors[field.name] = "max";
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (!field.required) continue;
|
|
54
|
+
if (field.type === "documents") {
|
|
55
|
+
if (!isWorkflowScope(value) || !value.documents?.length) errors[field.name] = "required";
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (field.type === "boolean" || field.type === "scope") continue;
|
|
59
|
+
if (typeof value !== "string" || value.trim() === "") errors[field.name] = "required";
|
|
60
|
+
}
|
|
61
|
+
return errors;
|
|
62
|
+
}
|
|
63
|
+
function promptFieldName(workflow) {
|
|
64
|
+
return workflow.inputs.find((f) => !f.advanced && (f.type === "text" || f.type === "longtext"))?.name;
|
|
65
|
+
}
|
|
66
|
+
var quoteList = (names) => {
|
|
67
|
+
const quoted = names.map((n) => `"${n}"`);
|
|
68
|
+
return quoted.length <= 1 ? quoted[0] ?? "" : `${quoted.slice(0, -1).join(", ")} and ${quoted[quoted.length - 1]}`;
|
|
69
|
+
};
|
|
70
|
+
function fragment(field, value, ctx) {
|
|
71
|
+
switch (field.type) {
|
|
72
|
+
case "documents": {
|
|
73
|
+
const ids = isWorkflowScope(value) ? value.documents ?? [] : [];
|
|
74
|
+
const names = ids.flatMap((id) => {
|
|
75
|
+
const title = ctx?.documentTitles?.[id];
|
|
76
|
+
return title ? [title] : [];
|
|
77
|
+
});
|
|
78
|
+
return quoteList(names);
|
|
79
|
+
}
|
|
80
|
+
case "boolean":
|
|
81
|
+
return value ? field.trueText ?? "yes" : field.falseText ?? "no";
|
|
82
|
+
case "select": {
|
|
83
|
+
const option = field.options?.find((o) => o.value === value);
|
|
84
|
+
return option ? option.text ?? option.label : String(value ?? "");
|
|
85
|
+
}
|
|
86
|
+
case "scope":
|
|
87
|
+
return "";
|
|
88
|
+
default:
|
|
89
|
+
return typeof value === "string" ? value.trim() : String(value ?? "");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function composeWorkflowPrompt(workflow, inputs, ctx) {
|
|
93
|
+
if (workflow.run.kind !== "prompt") return "";
|
|
94
|
+
const byName = new Map(workflow.inputs.map((f) => [f.name, f]));
|
|
95
|
+
const template = workflow.run.promptTemplate;
|
|
96
|
+
let out = "";
|
|
97
|
+
let last = 0;
|
|
98
|
+
const append = (text, isValue) => {
|
|
99
|
+
let t = text;
|
|
100
|
+
if (!isValue) {
|
|
101
|
+
t = t.replace(/[ \t]{2,}/g, " ");
|
|
102
|
+
if (/[ \t]$/.test(out)) t = t.replace(/^[ \t]+/, "");
|
|
103
|
+
}
|
|
104
|
+
out += t;
|
|
105
|
+
};
|
|
106
|
+
for (const m of template.matchAll(/\{\{\s*([a-z][a-z0-9_]*)\s*\}\}/gi)) {
|
|
107
|
+
append(template.slice(last, m.index), false);
|
|
108
|
+
const field = byName.get(m[1]);
|
|
109
|
+
append(field ? fragment(field, inputs[m[1]], ctx) : "", true);
|
|
110
|
+
last = m.index + m[0].length;
|
|
111
|
+
}
|
|
112
|
+
append(template.slice(last), false);
|
|
113
|
+
return out.trim();
|
|
114
|
+
}
|
|
115
|
+
function buildLaunch(workflow, inputs, agentId) {
|
|
116
|
+
const scopeField = workflow.inputs.find(isFileField);
|
|
117
|
+
const raw = scopeField ? inputs[scopeField.name] : void 0;
|
|
118
|
+
const scope = isWorkflowScope(raw) ? raw : { ...EMPTY_WORKFLOW_SCOPE };
|
|
119
|
+
return { workflow, inputs, scope, agentId: agentId || workflow.defaultAgentId || void 0 };
|
|
120
|
+
}
|
|
121
|
+
function workflowAccepts(workflow) {
|
|
122
|
+
const kinds = /* @__PURE__ */ new Set();
|
|
123
|
+
for (const field of workflow.inputs) if (field.context) kinds.add(field.context);
|
|
124
|
+
return [...kinds];
|
|
125
|
+
}
|
|
126
|
+
function workflowsAccepting(workflows, supplied) {
|
|
127
|
+
return workflows.filter((w) => workflowAccepts(w).some((k) => supplied.includes(k)));
|
|
128
|
+
}
|
|
129
|
+
function workflowsForHost(workflows, host) {
|
|
130
|
+
return workflows.filter((w) => !w.host || w.host === host);
|
|
131
|
+
}
|
|
132
|
+
function inputsFromContext(workflow, context) {
|
|
133
|
+
const inputs = {};
|
|
134
|
+
for (const field of workflow.inputs) {
|
|
135
|
+
if (!field.context) continue;
|
|
136
|
+
if (field.context === "selection") {
|
|
137
|
+
if (context.selection) inputs[field.name] = context.selection;
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
const ids = field.context === "image" ? context.image ? [context.image] : [] : context.documents;
|
|
141
|
+
if (ids?.length && isFileField(field)) {
|
|
142
|
+
inputs[field.name] = { folders: [], labels: [], documents: ids.slice(0, field.max ?? 1) };
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return inputs;
|
|
146
|
+
}
|
|
147
|
+
var SKILL_PROMPT_LABEL = "What should it work on?";
|
|
148
|
+
var SKILL_PROMPT_FALLBACK_PLACEHOLDER = "Describe what you want";
|
|
149
|
+
var plainHint = (hint) => hint.replace(/^[<[]\s*|\s*[>\]]$/g, "").trim();
|
|
150
|
+
function skillToWorkflow(skill) {
|
|
151
|
+
const hint = plainHint((skill.arg_hint ?? "").trim());
|
|
152
|
+
const inputs = [
|
|
153
|
+
{
|
|
154
|
+
name: "args",
|
|
155
|
+
type: "longtext",
|
|
156
|
+
label: SKILL_PROMPT_LABEL,
|
|
157
|
+
placeholder: hint || SKILL_PROMPT_FALLBACK_PLACEHOLDER,
|
|
158
|
+
required: true
|
|
159
|
+
}
|
|
160
|
+
];
|
|
161
|
+
return {
|
|
162
|
+
id: skill.slug,
|
|
163
|
+
skill: skill.slug,
|
|
164
|
+
title: skill.name || skill.slug,
|
|
165
|
+
description: skill.description ?? "",
|
|
166
|
+
inputs,
|
|
167
|
+
run: { kind: "prompt", promptTemplate: `/${skill.slug} {{args}}` },
|
|
168
|
+
landing: "chat",
|
|
169
|
+
schedulable: true
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
var FIELD_TYPES = [
|
|
173
|
+
"text",
|
|
174
|
+
"longtext",
|
|
175
|
+
"boolean",
|
|
176
|
+
"select",
|
|
177
|
+
"number",
|
|
178
|
+
"date",
|
|
179
|
+
"scope",
|
|
180
|
+
"documents"
|
|
181
|
+
];
|
|
182
|
+
var str = (v) => typeof v === "string" ? v : void 0;
|
|
183
|
+
var num = (v) => typeof v === "number" ? v : void 0;
|
|
184
|
+
var bool = (v) => typeof v === "boolean" ? v : void 0;
|
|
185
|
+
function fieldFromFrontmatter(raw) {
|
|
186
|
+
if (typeof raw !== "object" || raw === null) return null;
|
|
187
|
+
const r = raw;
|
|
188
|
+
const name = str(r.name);
|
|
189
|
+
const type = FIELD_TYPES.find((t) => t === r.type);
|
|
190
|
+
if (!name || !/^[a-z][a-z0-9_]*$/.test(name) || !type) return null;
|
|
191
|
+
const options = Array.isArray(r.options) ? r.options.flatMap((o) => {
|
|
192
|
+
const ro = o;
|
|
193
|
+
const value = str(ro?.value);
|
|
194
|
+
const label = str(ro?.label);
|
|
195
|
+
return value && label ? [
|
|
196
|
+
{
|
|
197
|
+
value,
|
|
198
|
+
label,
|
|
199
|
+
description: str(ro.description),
|
|
200
|
+
text: str(ro.text),
|
|
201
|
+
icon: str(ro.icon),
|
|
202
|
+
tone: isTone(ro.tone) ? ro.tone : void 0
|
|
203
|
+
}
|
|
204
|
+
] : [];
|
|
205
|
+
}) : void 0;
|
|
206
|
+
return {
|
|
207
|
+
name,
|
|
208
|
+
type,
|
|
209
|
+
label: str(r.label) ?? name,
|
|
210
|
+
description: str(r.description),
|
|
211
|
+
placeholder: str(r.placeholder),
|
|
212
|
+
required: bool(r.required),
|
|
213
|
+
default: r.default,
|
|
214
|
+
options,
|
|
215
|
+
min: num(r.min),
|
|
216
|
+
max: num(r.max),
|
|
217
|
+
trueText: str(r.true_text),
|
|
218
|
+
falseText: str(r.false_text),
|
|
219
|
+
advanced: bool(r.advanced),
|
|
220
|
+
accept: r.accept === "image" ? "image" : void 0,
|
|
221
|
+
context: r.context === "documents" || r.context === "selection" || r.context === "image" ? r.context : void 0,
|
|
222
|
+
by: Array.isArray(r.by) ? r.by.filter((b) => b === "folders" || b === "labels") : void 0
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
function workflowFromFrontmatter(id, frontmatter, body) {
|
|
226
|
+
const inputs = Array.isArray(frontmatter.inputs) ? frontmatter.inputs.flatMap((f) => {
|
|
227
|
+
const field = fieldFromFrontmatter(f);
|
|
228
|
+
return field ? [field] : [];
|
|
229
|
+
}) : [];
|
|
230
|
+
return {
|
|
231
|
+
id,
|
|
232
|
+
title: str(frontmatter.name) ?? id,
|
|
233
|
+
description: str(frontmatter.description) ?? "",
|
|
234
|
+
icon: str(frontmatter.icon),
|
|
235
|
+
inputs,
|
|
236
|
+
run: { kind: "prompt", promptTemplate: body.trim() },
|
|
237
|
+
landing: frontmatter.landing === "files" ? "files" : "chat",
|
|
238
|
+
requiresFiles: bool(frontmatter.requires_files),
|
|
239
|
+
schedulable: bool(frontmatter.schedulable) ?? true
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
function fieldToFrontmatter(field) {
|
|
243
|
+
return compact({
|
|
244
|
+
name: field.name,
|
|
245
|
+
type: field.type,
|
|
246
|
+
label: field.label,
|
|
247
|
+
description: field.description,
|
|
248
|
+
placeholder: field.placeholder,
|
|
249
|
+
required: field.required,
|
|
250
|
+
default: field.default,
|
|
251
|
+
options: field.options?.map(
|
|
252
|
+
(o) => compact({
|
|
253
|
+
value: o.value,
|
|
254
|
+
label: o.label,
|
|
255
|
+
description: o.description,
|
|
256
|
+
text: o.text,
|
|
257
|
+
icon: o.icon,
|
|
258
|
+
tone: o.tone
|
|
259
|
+
})
|
|
260
|
+
),
|
|
261
|
+
min: field.min,
|
|
262
|
+
max: field.max,
|
|
263
|
+
true_text: field.trueText,
|
|
264
|
+
false_text: field.falseText,
|
|
265
|
+
advanced: field.advanced,
|
|
266
|
+
by: field.by,
|
|
267
|
+
accept: field.accept,
|
|
268
|
+
context: field.context
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
var compact = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
|
|
272
|
+
|
|
273
|
+
// src/agents/workflows/run.ts
|
|
274
|
+
function workflowSteps(workflow) {
|
|
275
|
+
return workflow.run.kind === "steps" ? workflow.run.steps : [];
|
|
276
|
+
}
|
|
277
|
+
var isSteppedWorkflow = (workflow) => workflow.run.kind === "steps";
|
|
278
|
+
function stepDependencies(steps, id) {
|
|
279
|
+
const i = steps.findIndex((s) => s.id === id);
|
|
280
|
+
if (i < 0) return [];
|
|
281
|
+
return steps[i].after ?? (i > 0 ? [steps[i - 1].id] : []);
|
|
282
|
+
}
|
|
283
|
+
function dependsOn(steps, a, b) {
|
|
284
|
+
const seen = /* @__PURE__ */ new Set();
|
|
285
|
+
const stack = [...stepDependencies(steps, a)];
|
|
286
|
+
while (stack.length) {
|
|
287
|
+
const id = stack.pop();
|
|
288
|
+
if (id === b) return true;
|
|
289
|
+
if (seen.has(id)) continue;
|
|
290
|
+
seen.add(id);
|
|
291
|
+
stack.push(...stepDependencies(steps, id));
|
|
292
|
+
}
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
function orderSteps(steps) {
|
|
296
|
+
const explicit = steps.map((s) => ({ ...s, after: stepDependencies(steps, s.id) }));
|
|
297
|
+
const known = new Set(explicit.map((s) => s.id));
|
|
298
|
+
const placed = /* @__PURE__ */ new Set();
|
|
299
|
+
const out = [];
|
|
300
|
+
let progress = true;
|
|
301
|
+
while (out.length < explicit.length && progress) {
|
|
302
|
+
progress = false;
|
|
303
|
+
for (const s of explicit) {
|
|
304
|
+
if (placed.has(s.id)) continue;
|
|
305
|
+
if (s.after.every((d) => placed.has(d) || !known.has(d))) {
|
|
306
|
+
out.push(s);
|
|
307
|
+
placed.add(s.id);
|
|
308
|
+
progress = true;
|
|
309
|
+
break;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return [...out, ...explicit.filter((s) => !placed.has(s.id))];
|
|
314
|
+
}
|
|
315
|
+
function validateWorkflowGraph(steps) {
|
|
316
|
+
const problems = [];
|
|
317
|
+
const ids = /* @__PURE__ */ new Set();
|
|
318
|
+
for (const s of steps) {
|
|
319
|
+
if (ids.has(s.id)) problems.push({ code: "duplicate", step: s.id });
|
|
320
|
+
ids.add(s.id);
|
|
321
|
+
}
|
|
322
|
+
steps.forEach((s, i) => {
|
|
323
|
+
for (const d of stepDependencies(steps, s.id)) {
|
|
324
|
+
if (!ids.has(d)) problems.push({ code: "unknown", step: s.id, dependency: d });
|
|
325
|
+
else if (d === s.id || dependsOn(steps, d, s.id)) problems.push({ code: "cycle", step: s.id });
|
|
326
|
+
else if (steps.findIndex((x) => x.id === d) > i)
|
|
327
|
+
problems.push({ code: "order", step: s.id, dependency: d });
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
return problems;
|
|
331
|
+
}
|
|
332
|
+
function stepLevels(steps) {
|
|
333
|
+
const depth = /* @__PURE__ */ new Map();
|
|
334
|
+
for (const s of steps) {
|
|
335
|
+
const deps = stepDependencies(steps, s.id).filter((d) => depth.has(d));
|
|
336
|
+
depth.set(s.id, deps.length ? Math.max(...deps.map((d) => depth.get(d))) + 1 : 0);
|
|
337
|
+
}
|
|
338
|
+
const levels = [];
|
|
339
|
+
for (const s of steps) (levels[depth.get(s.id)] ??= []).push(s);
|
|
340
|
+
return levels.filter(Boolean);
|
|
341
|
+
}
|
|
342
|
+
var STEP_EVENTS = {
|
|
343
|
+
step_started: "running",
|
|
344
|
+
step_waiting: "waiting",
|
|
345
|
+
step_done: "done",
|
|
346
|
+
step_skipped: "skipped",
|
|
347
|
+
step_failed: "failed"
|
|
348
|
+
};
|
|
349
|
+
var str2 = (v) => typeof v === "string" && v ? v : void 0;
|
|
350
|
+
var ACTION_TYPES = ["sign", "email_draft", "tabular_review"];
|
|
351
|
+
var asAction = (v) => ACTION_TYPES.includes(v) ? v : void 0;
|
|
352
|
+
var asRecord = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : void 0;
|
|
353
|
+
var asStrings = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : void 0;
|
|
354
|
+
function waitingDocuments(state) {
|
|
355
|
+
return state?.status === "waiting" ? asStrings(state.waiting?.documents) ?? [] : [];
|
|
356
|
+
}
|
|
357
|
+
function eventWaitingDocuments(detail) {
|
|
358
|
+
return asStrings(asRecord(detail?.waiting)?.documents);
|
|
359
|
+
}
|
|
360
|
+
function waitingForDocumentsText(count) {
|
|
361
|
+
return `Waiting for ${count} ${count === 1 ? "document" : "documents"} to finish processing`;
|
|
362
|
+
}
|
|
363
|
+
function reopenedBy(detail) {
|
|
364
|
+
const to = str2(detail.to);
|
|
365
|
+
return asStrings(detail.reopened) ?? (to ? [to] : []);
|
|
366
|
+
}
|
|
367
|
+
function stepStatesFromActivity(events) {
|
|
368
|
+
const states = {};
|
|
369
|
+
for (const e of events) {
|
|
370
|
+
const detail = e.detail ?? {};
|
|
371
|
+
const step = str2(detail.step);
|
|
372
|
+
if (!step) continue;
|
|
373
|
+
if (e.kind === "step_sent_back") {
|
|
374
|
+
const to = str2(detail.to);
|
|
375
|
+
for (const id of reopenedBy(detail))
|
|
376
|
+
states[id] = id === to ? {
|
|
377
|
+
status: "pending",
|
|
378
|
+
sentBack: true,
|
|
379
|
+
hasNote: typeof detail.note_encrypted === "string"
|
|
380
|
+
} : { status: "pending" };
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
if (e.kind === "step_ready") {
|
|
384
|
+
states[step] = { ...states[step] ?? { status: "pending" }, announcedTo: str2(detail.to) };
|
|
385
|
+
continue;
|
|
386
|
+
}
|
|
387
|
+
if (e.kind === "step_progress") {
|
|
388
|
+
const before2 = states[step];
|
|
389
|
+
const waiting2 = asRecord(detail.waiting);
|
|
390
|
+
if (before2?.status === "waiting" && waiting2) states[step] = { ...before2, waiting: waiting2 };
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
const status = STEP_EVENTS[e.kind];
|
|
394
|
+
if (!status) continue;
|
|
395
|
+
const before = states[step];
|
|
396
|
+
const responseId = str2(detail.response_id) ?? before?.responseId ?? null;
|
|
397
|
+
const startedAt = status === "running" ? e.created_at : before?.startedAt;
|
|
398
|
+
const action = asAction(detail.action) ?? before?.action;
|
|
399
|
+
const documents = asStrings(detail.documents) ?? before?.documents;
|
|
400
|
+
const waiting = status === "waiting" ? asRecord(detail.waiting) : void 0;
|
|
401
|
+
const output = status === "done" ? asRecord(detail.output) : void 0;
|
|
402
|
+
const approved = Array.isArray(detail.approved) ? detail.approved.filter(asRecord) : void 0;
|
|
403
|
+
const finished2 = status === "done" || status === "skipped" || status === "failed";
|
|
404
|
+
const declinedBy = str2(detail.declined_by);
|
|
405
|
+
const afterFailure = status === "skipped" && (before?.status === "failed" || !!before?.skippedAfterFailure);
|
|
406
|
+
states[step] = {
|
|
407
|
+
status,
|
|
408
|
+
responseId,
|
|
409
|
+
error: str2(detail.error) ?? (afterFailure ? before?.error ?? null : null),
|
|
410
|
+
...afterFailure ? { skippedAfterFailure: true } : {},
|
|
411
|
+
...startedAt ? { startedAt } : {},
|
|
412
|
+
...action ? { action } : {},
|
|
413
|
+
...documents?.length ? { documents } : {},
|
|
414
|
+
...waiting ? { waiting } : {},
|
|
415
|
+
...output ? { output } : {},
|
|
416
|
+
...approved ? { approved } : {},
|
|
417
|
+
...finished2 ? { by: e.actor_ext_id ?? null } : {},
|
|
418
|
+
...finished2 && e.created_at ? { at: e.created_at } : {},
|
|
419
|
+
...declinedBy ? { declinedBy } : {}
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
return states;
|
|
423
|
+
}
|
|
424
|
+
function stepFields(step) {
|
|
425
|
+
return step.kind === "form" ? step.inputs : step.kind === "review" ? step.fields ?? [] : [];
|
|
426
|
+
}
|
|
427
|
+
var runFieldsOf = (steps) => steps.flatMap(stepFields);
|
|
428
|
+
function runFields(workflow) {
|
|
429
|
+
return [...workflow.inputs, ...workflowSteps(workflow).flatMap(stepFields)];
|
|
430
|
+
}
|
|
431
|
+
function initialRunInputs(workflow, inputs = {}) {
|
|
432
|
+
return { ...defaultInputs({ ...workflow, inputs: runFields(workflow) }), ...inputs };
|
|
433
|
+
}
|
|
434
|
+
var finished = (s) => s?.status === "done" || s?.status === "skipped";
|
|
435
|
+
function stepPhase(steps, states, id) {
|
|
436
|
+
const s = states[id];
|
|
437
|
+
if (s && s.status !== "pending") return s.status;
|
|
438
|
+
return stepDependencies(steps, id).every((d) => finished(states[d])) ? "ready" : "blocked";
|
|
439
|
+
}
|
|
440
|
+
var isRunFinished = (steps, states) => steps.length > 0 && steps.every((s) => finished(states[s.id]));
|
|
441
|
+
var isPersonStep = (step) => step.kind !== "agent" && step.kind !== "action";
|
|
442
|
+
var isPersonAction = (step) => step.kind === "action" && (step.action.type === "sign" || step.action.type === "email_draft");
|
|
443
|
+
var canAssign = (step) => isPersonStep(step) || isPersonAction(step);
|
|
444
|
+
function nextAction(steps, states, current, { needsStart = false, canRetry = false } = {}) {
|
|
445
|
+
const i = steps.findIndex((s) => s.id === current);
|
|
446
|
+
const step = steps[i];
|
|
447
|
+
if (!step) return "wait";
|
|
448
|
+
const phase = stepPhase(steps, states, step.id);
|
|
449
|
+
if (phase === "blocked") return "wait";
|
|
450
|
+
const following = steps[i + 1];
|
|
451
|
+
const independentNext = !!following && !dependsOn(steps, following.id, step.id);
|
|
452
|
+
if (phase === "done" || phase === "skipped") {
|
|
453
|
+
if (following) return "move";
|
|
454
|
+
return isRunFinished(steps, states) ? "finish" : "wait";
|
|
455
|
+
}
|
|
456
|
+
if (isPersonStep(step)) return "complete";
|
|
457
|
+
if (phase === "waiting" && step.kind === "action" && step.action.type === "email_draft")
|
|
458
|
+
return "complete";
|
|
459
|
+
if (phase === "ready" && needsStart) return "start";
|
|
460
|
+
if (phase !== "failed") return independentNext ? "move" : "wait";
|
|
461
|
+
const waitedFor = steps.slice(i + 1).some((s) => dependsOn(steps, s.id, step.id));
|
|
462
|
+
if (!waitedFor && following) return "move";
|
|
463
|
+
return canRetry ? "retry" : "wait";
|
|
464
|
+
}
|
|
465
|
+
function failedUpstream(steps, states, id) {
|
|
466
|
+
return upstreamSteps(steps, id).flatMap((s) => {
|
|
467
|
+
const state = states[s.id];
|
|
468
|
+
return state && (state.status === "failed" || state.skippedAfterFailure) ? [{ step: s, state }] : [];
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
function validateStep(step, inputs) {
|
|
472
|
+
const fields = stepFields(step);
|
|
473
|
+
if (!fields.length) return {};
|
|
474
|
+
return validateInputs(
|
|
475
|
+
{
|
|
476
|
+
id: step.id,
|
|
477
|
+
title: step.title,
|
|
478
|
+
inputs: fields},
|
|
479
|
+
inputs
|
|
480
|
+
);
|
|
481
|
+
}
|
|
482
|
+
function upstreamSteps(steps, id) {
|
|
483
|
+
return steps.filter((s) => s.id !== id && dependsOn(steps, id, s.id));
|
|
484
|
+
}
|
|
485
|
+
function sendBackTargets(steps, states, id) {
|
|
486
|
+
return upstreamSteps(steps, id).filter((s) => ["done", "skipped", "failed"].includes(states[s.id]?.status ?? "pending")).reverse();
|
|
487
|
+
}
|
|
488
|
+
var isBlankRef = (ref) => "step" in ref ? !ref.step : "input" in ref ? !ref.input : !ref.id.trim();
|
|
489
|
+
function stepConfigProblems(steps) {
|
|
490
|
+
const out = [];
|
|
491
|
+
for (const s of steps) {
|
|
492
|
+
if (s.kind === "action") {
|
|
493
|
+
const a = s.action;
|
|
494
|
+
if (a.type === "sign") {
|
|
495
|
+
if (!a.document || isBlankRef(a.document)) out.push({ step: s.id, missing: "document" });
|
|
496
|
+
if (!a.signers.length) out.push({ step: s.id, missing: "signers" });
|
|
497
|
+
} else if (a.type === "email_draft") {
|
|
498
|
+
if (!a.to.some((t) => t.trim())) out.push({ step: s.id, missing: "recipients" });
|
|
499
|
+
} else {
|
|
500
|
+
if (!a.tags.length) out.push({ step: s.id, missing: "tags" });
|
|
501
|
+
if (Array.isArray(a.documents) && !a.documents.length)
|
|
502
|
+
out.push({ step: s.id, missing: "documents" });
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
if (s.kind === "agent" && s.editDocument && isBlankRef(s.editDocument))
|
|
506
|
+
out.push({ step: s.id, missing: "document" });
|
|
507
|
+
}
|
|
508
|
+
return out;
|
|
509
|
+
}
|
|
510
|
+
function splitDocRef(ref) {
|
|
511
|
+
const m = /^(doc-[A-Za-z0-9]+)(?:@v(\d+))?$/.exec(ref);
|
|
512
|
+
return m ? { id: m[1], ...m[2] ? { version: Number(m[2]) } : {} } : { id: ref };
|
|
513
|
+
}
|
|
514
|
+
var DEFAULT_ASSIGNEE_WORDING = {
|
|
515
|
+
runOwner: "whoever started the run",
|
|
516
|
+
projectLead: "the project lead",
|
|
517
|
+
input: "the person in \u201C{field}\u201D"
|
|
518
|
+
};
|
|
519
|
+
function assigneeName(assignee, options = {}) {
|
|
520
|
+
const w = { ...DEFAULT_ASSIGNEE_WORDING, ...options.wording };
|
|
521
|
+
const name = (id) => options.nameOf?.(id) ?? id;
|
|
522
|
+
const told = options.announcedTo ? options.nameOf?.(options.announcedTo) : void 0;
|
|
523
|
+
if (told) return told;
|
|
524
|
+
if (!assignee) return void 0;
|
|
525
|
+
if ("user" in assignee) return name(assignee.user);
|
|
526
|
+
if ("input" in assignee) {
|
|
527
|
+
const value = options.inputs?.[assignee.input];
|
|
528
|
+
if (typeof value === "string" && value) return name(value);
|
|
529
|
+
const label = options.fields?.find((f) => f.name === assignee.input)?.label ?? assignee.input;
|
|
530
|
+
return w.input.replace("{field}", label);
|
|
531
|
+
}
|
|
532
|
+
if ("runOwner" in assignee) return w.runOwner;
|
|
533
|
+
return w.projectLead;
|
|
534
|
+
}
|
|
535
|
+
var asText = (value) => typeof value === "string" ? value.trim() : typeof value === "number" ? String(value) : "";
|
|
536
|
+
function fillStepInputs(templates, inputs) {
|
|
537
|
+
const out = {};
|
|
538
|
+
for (const [name, template] of Object.entries(templates ?? {})) {
|
|
539
|
+
const bare = /^\{\{\s*([a-z][a-z0-9_]*)\s*\}\}$/i.exec(template);
|
|
540
|
+
if (bare) {
|
|
541
|
+
out[name] = inputs[bare[1]] ?? "";
|
|
542
|
+
continue;
|
|
543
|
+
}
|
|
544
|
+
out[name] = fillRunText(template, inputs);
|
|
545
|
+
}
|
|
546
|
+
return out;
|
|
547
|
+
}
|
|
548
|
+
function fillRunText(template, inputs) {
|
|
549
|
+
return template.replace(/\{\{([^}]*)\}\}/g, (_, expr) => {
|
|
550
|
+
for (const ref of expr.split("||")) {
|
|
551
|
+
const text = asText(inputs[ref.trim()]);
|
|
552
|
+
if (text) return text;
|
|
553
|
+
}
|
|
554
|
+
return "";
|
|
555
|
+
}).trim();
|
|
556
|
+
}
|
|
557
|
+
function runThreadTitle(workflow, inputs) {
|
|
558
|
+
const template = workflow.run.kind === "steps" ? workflow.run.threadTitle : void 0;
|
|
559
|
+
return template && fillRunText(template, inputs) || workflow.title;
|
|
560
|
+
}
|
|
561
|
+
function reviewInstructions(step, inputs) {
|
|
562
|
+
return step.instructions && fillRunText(step.instructions, inputs) || step.title;
|
|
563
|
+
}
|
|
564
|
+
function composeStepPrompt(workflow, step, runInputs, { resolveWorkflow, compose } = {}) {
|
|
565
|
+
if (step.workflow) {
|
|
566
|
+
const target = resolveWorkflow?.(step.workflow);
|
|
567
|
+
if (!target) return "";
|
|
568
|
+
const inputs = { ...defaultInputs(target), ...fillStepInputs(step.with, runInputs) };
|
|
569
|
+
return target.run.kind === "prompt" ? composeWorkflowPrompt(target, inputs) : compose?.(target.id, inputs, runInputs) ?? "";
|
|
570
|
+
}
|
|
571
|
+
if (step.run?.kind === "prompt") {
|
|
572
|
+
return composeWorkflowPrompt(
|
|
573
|
+
{ ...workflow, inputs: runFields(workflow), run: step.run },
|
|
574
|
+
runInputs
|
|
575
|
+
);
|
|
576
|
+
}
|
|
577
|
+
return compose?.(step.id, runInputs, runInputs) ?? "";
|
|
578
|
+
}
|
|
579
|
+
function stepDocuments(steps, states, id) {
|
|
580
|
+
const step = steps.find((s) => s.id === id);
|
|
581
|
+
const state = states[id];
|
|
582
|
+
if (!step) return [];
|
|
583
|
+
const own = [
|
|
584
|
+
...state?.documents ?? [],
|
|
585
|
+
...state?.output?.doc_ext_ids ?? []
|
|
586
|
+
];
|
|
587
|
+
const refs = step.kind !== "review" ? own : state?.status === "done" && state.approved?.length ? state.approved.flatMap((e) => e.documents ?? []) : stepDependencies(steps, id).flatMap((dep) => states[dep]?.documents ?? []);
|
|
588
|
+
return [...new Set(refs)];
|
|
589
|
+
}
|
|
590
|
+
var DEFAULT_STEP_DOCUMENT_LABELS = {
|
|
591
|
+
open: "Open",
|
|
592
|
+
toApprove: "To approve",
|
|
593
|
+
approved: "Approved",
|
|
594
|
+
produced: "Drafted in this step",
|
|
595
|
+
version: "v{version}"
|
|
596
|
+
};
|
|
597
|
+
function StepDocumentCards({
|
|
598
|
+
refs,
|
|
599
|
+
heading,
|
|
600
|
+
nameOfDoc,
|
|
601
|
+
onOpen,
|
|
602
|
+
labels,
|
|
603
|
+
testId
|
|
604
|
+
}) {
|
|
605
|
+
const l = { ...DEFAULT_STEP_DOCUMENT_LABELS, ...labels };
|
|
606
|
+
if (!refs.length) return null;
|
|
607
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-1", "data-testid": testId, children: [
|
|
608
|
+
/* @__PURE__ */ jsx("p", { className: "px-1 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: heading }),
|
|
609
|
+
refs.map((ref) => {
|
|
610
|
+
const { id, version } = splitDocRef(ref);
|
|
611
|
+
return /* @__PURE__ */ jsxs(
|
|
612
|
+
"div",
|
|
613
|
+
{
|
|
614
|
+
className: "flex items-center gap-2 rounded-md border border-border bg-card px-2 py-1.5",
|
|
615
|
+
"data-testid": `${testId}-${id}`,
|
|
616
|
+
children: [
|
|
617
|
+
/* @__PURE__ */ jsx("span", { className: "wf-badge flex size-7 shrink-0 items-center justify-center rounded-md", children: /* @__PURE__ */ jsx(FileText, { className: "size-4" }) }),
|
|
618
|
+
/* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
|
|
619
|
+
/* @__PURE__ */ jsx(
|
|
620
|
+
"span",
|
|
621
|
+
{
|
|
622
|
+
className: "line-clamp-2 block break-words text-sm font-medium leading-snug",
|
|
623
|
+
title: nameOfDoc?.(id) ?? id,
|
|
624
|
+
children: nameOfDoc?.(id) ?? id
|
|
625
|
+
}
|
|
626
|
+
),
|
|
627
|
+
version && /* @__PURE__ */ jsx("span", { className: "block text-[11px] text-muted-foreground", children: l.version.replace("{version}", String(version)) })
|
|
628
|
+
] }),
|
|
629
|
+
onOpen && /* @__PURE__ */ jsx(
|
|
630
|
+
Button,
|
|
631
|
+
{
|
|
632
|
+
size: "sm",
|
|
633
|
+
variant: "outline",
|
|
634
|
+
className: "h-7 shrink-0 px-2 text-xs",
|
|
635
|
+
onClick: () => onOpen(ref),
|
|
636
|
+
"data-testid": `${testId}-${id}-open`,
|
|
637
|
+
children: l.open
|
|
638
|
+
}
|
|
639
|
+
)
|
|
640
|
+
]
|
|
641
|
+
},
|
|
642
|
+
ref
|
|
643
|
+
);
|
|
644
|
+
})
|
|
645
|
+
] });
|
|
646
|
+
}
|
|
647
|
+
var DEFAULT_STEP_RECORD_LABELS = {
|
|
648
|
+
doneBy: "Done by {name}",
|
|
649
|
+
approvedBy: "Approved by {name}",
|
|
650
|
+
someone: "someone"
|
|
651
|
+
};
|
|
652
|
+
var formatDate = (iso) => {
|
|
653
|
+
const t = iso ? Date.parse(iso) : NaN;
|
|
654
|
+
return Number.isNaN(t) ? "" : new Date(t).toLocaleString(void 0, { dateStyle: "medium", timeStyle: "short" });
|
|
655
|
+
};
|
|
656
|
+
var shownValue = (v, field, nameOf) => {
|
|
657
|
+
if (v === void 0 || v === null || v === "") return "\u2014";
|
|
658
|
+
if (typeof v === "boolean") return v ? "\u2713" : "\u2717";
|
|
659
|
+
if (field.type === "person" && typeof v === "string") return nameOf?.(v) ?? v;
|
|
660
|
+
if (field.type === "select") return field.options?.find((o) => o.value === v)?.label ?? String(v);
|
|
661
|
+
return typeof v === "object" ? JSON.stringify(v) : String(v);
|
|
662
|
+
};
|
|
663
|
+
function StepRecord({
|
|
664
|
+
step,
|
|
665
|
+
state,
|
|
666
|
+
inputs,
|
|
667
|
+
nameOf,
|
|
668
|
+
labels,
|
|
669
|
+
className,
|
|
670
|
+
testId
|
|
671
|
+
}) {
|
|
672
|
+
const l = { ...DEFAULT_STEP_RECORD_LABELS, ...labels };
|
|
673
|
+
if (state?.status !== "done") return null;
|
|
674
|
+
const who = state.by ? nameOf?.(state.by) ?? l.someone : void 0;
|
|
675
|
+
const fields = stepFields(step);
|
|
676
|
+
if (!who && !fields.length) return null;
|
|
677
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("space-y-1 px-1", className), "data-testid": testId, children: [
|
|
678
|
+
who && /* @__PURE__ */ jsxs("p", { className: "text-xs", children: [
|
|
679
|
+
(step.kind === "review" ? l.approvedBy : l.doneBy).replace("{name}", who),
|
|
680
|
+
state.at && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
|
|
681
|
+
" \xB7 ",
|
|
682
|
+
formatDate(state.at)
|
|
683
|
+
] })
|
|
684
|
+
] }),
|
|
685
|
+
fields.length > 0 && /* @__PURE__ */ jsx("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-0.5 text-xs", children: fields.map((f) => /* @__PURE__ */ jsxs("div", { className: "contents", children: [
|
|
686
|
+
/* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: f.label }),
|
|
687
|
+
/* @__PURE__ */ jsx("dd", { className: "min-w-0 break-words", "data-testid": `${testId}-field-${f.name}`, children: shownValue(inputs[f.name], f, nameOf) })
|
|
688
|
+
] }, f.name)) })
|
|
689
|
+
] });
|
|
690
|
+
}
|
|
691
|
+
function StepDocumentButton({
|
|
692
|
+
kind,
|
|
693
|
+
name,
|
|
694
|
+
onOpen,
|
|
695
|
+
showName = false,
|
|
696
|
+
label = "Open {name}",
|
|
697
|
+
testId
|
|
698
|
+
}) {
|
|
699
|
+
const text = label.replace("{name}", name);
|
|
700
|
+
return /* @__PURE__ */ jsxs(
|
|
701
|
+
"button",
|
|
702
|
+
{
|
|
703
|
+
type: "button",
|
|
704
|
+
onClick: onOpen,
|
|
705
|
+
title: text,
|
|
706
|
+
"aria-label": text,
|
|
707
|
+
className: cn(
|
|
708
|
+
`wf-kind-${kind}`,
|
|
709
|
+
showName ? "min-w-0 shrink" : "shrink-0",
|
|
710
|
+
"-ml-px flex h-8 items-center gap-1.5 rounded-r-lg border border-border bg-card px-2 text-xs font-medium shadow-sm hover:border-[hsl(var(--wf-accent)/0.55)] hover:text-[hsl(var(--wf-accent))]"
|
|
711
|
+
),
|
|
712
|
+
"data-testid": testId,
|
|
713
|
+
children: [
|
|
714
|
+
/* @__PURE__ */ jsx(FileText, { className: "wf-kind-text size-3.5 shrink-0", "aria-hidden": true }),
|
|
715
|
+
showName && /* @__PURE__ */ jsx("span", { className: "max-w-[14rem] truncate", children: name })
|
|
716
|
+
]
|
|
717
|
+
}
|
|
718
|
+
);
|
|
719
|
+
}
|
|
720
|
+
var WORKFLOW_STEP_KINDS = [
|
|
721
|
+
"form",
|
|
722
|
+
"upload",
|
|
723
|
+
"agent",
|
|
724
|
+
"review",
|
|
725
|
+
"sign",
|
|
726
|
+
"email_draft",
|
|
727
|
+
"tabular_review"
|
|
728
|
+
];
|
|
729
|
+
var stepKindOf = (step) => step.kind === "action" ? step.action.type : step.kind;
|
|
730
|
+
var STEP_KIND_ICONS = {
|
|
731
|
+
form: FileInput,
|
|
732
|
+
upload: Upload,
|
|
733
|
+
agent: Bot,
|
|
734
|
+
review: ClipboardCheck,
|
|
735
|
+
sign: PenLine,
|
|
736
|
+
email_draft: Mail,
|
|
737
|
+
tabular_review: Table2
|
|
738
|
+
};
|
|
739
|
+
var DEFAULT_STEP_KIND_LABELS = {
|
|
740
|
+
form: "Form",
|
|
741
|
+
upload: "Upload",
|
|
742
|
+
agent: "AI step",
|
|
743
|
+
review: "Approval",
|
|
744
|
+
sign: "Sign",
|
|
745
|
+
email_draft: "Email draft",
|
|
746
|
+
tabular_review: "Tabular review"
|
|
747
|
+
};
|
|
748
|
+
function useMentionAutocomplete({
|
|
749
|
+
value,
|
|
750
|
+
onValueChange,
|
|
751
|
+
candidates,
|
|
752
|
+
textareaRef
|
|
753
|
+
}) {
|
|
754
|
+
const [caret, setCaret] = useState(null);
|
|
755
|
+
const [dismissedAt, setDismissedAt] = useState(null);
|
|
756
|
+
useEffect(() => {
|
|
757
|
+
if (dismissedAt !== null && value[dismissedAt] !== "@") setDismissedAt(null);
|
|
758
|
+
}, [value, dismissedAt]);
|
|
759
|
+
const match = useMemo(() => {
|
|
760
|
+
if (caret === null) return null;
|
|
761
|
+
const query = findMentionQuery(value, Math.min(caret, value.length));
|
|
762
|
+
return query && candidates.some((candidate) => query.query === `${candidate.label} `) ? null : query;
|
|
763
|
+
}, [value, caret, candidates]);
|
|
764
|
+
const items = useMemo(
|
|
765
|
+
() => match ? filterMentionCandidates(candidates, match.query) : [],
|
|
766
|
+
[match, candidates]
|
|
767
|
+
);
|
|
768
|
+
const isOpen = !!match && items.length > 0 && dismissedAt !== match.start;
|
|
769
|
+
const readCaret = useCallback(() => {
|
|
770
|
+
const ta = textareaRef.current;
|
|
771
|
+
setCaret(ta ? ta.selectionStart : null);
|
|
772
|
+
}, [textareaRef]);
|
|
773
|
+
const pick = useCallback(
|
|
774
|
+
(candidate) => {
|
|
775
|
+
if (!match || caret === null) return;
|
|
776
|
+
const next = insertMention(value, match.start, Math.min(caret, value.length), candidate.label);
|
|
777
|
+
onValueChange(next.text);
|
|
778
|
+
setCaret(next.caret);
|
|
779
|
+
setDismissedAt(match.start);
|
|
780
|
+
requestAnimationFrame(() => {
|
|
781
|
+
const ta = textareaRef.current;
|
|
782
|
+
if (!ta) return;
|
|
783
|
+
ta.focus();
|
|
784
|
+
ta.setSelectionRange(next.caret, next.caret);
|
|
785
|
+
});
|
|
786
|
+
},
|
|
787
|
+
[match, caret, value, onValueChange, textareaRef]
|
|
788
|
+
);
|
|
789
|
+
const nav = useListKeyNav({
|
|
790
|
+
open: isOpen,
|
|
791
|
+
items,
|
|
792
|
+
onPick: pick,
|
|
793
|
+
onDismiss: () => setDismissedAt(match?.start ?? null),
|
|
794
|
+
resetKey: match?.query
|
|
795
|
+
});
|
|
796
|
+
const handleValueChange = useCallback(
|
|
797
|
+
(next) => {
|
|
798
|
+
onValueChange(next);
|
|
799
|
+
const ta = textareaRef.current;
|
|
800
|
+
setCaret(ta ? ta.selectionStart : next.length);
|
|
801
|
+
if (dismissedAt !== null && (next.length < value.length || next[dismissedAt] !== "@")) {
|
|
802
|
+
setDismissedAt(null);
|
|
803
|
+
}
|
|
804
|
+
},
|
|
805
|
+
[onValueChange, textareaRef, dismissedAt, value]
|
|
806
|
+
);
|
|
807
|
+
return {
|
|
808
|
+
isOpen,
|
|
809
|
+
items,
|
|
810
|
+
nav,
|
|
811
|
+
pick,
|
|
812
|
+
onValueChange: handleValueChange,
|
|
813
|
+
textareaProps: { onSelect: readCaret }
|
|
814
|
+
};
|
|
815
|
+
}
|
|
816
|
+
function StepBadgeMark({ phase, icon }) {
|
|
817
|
+
if (phase === "done") return icon ? /* @__PURE__ */ jsx(Fragment, { children: icon }) : /* @__PURE__ */ jsx(Check, { strokeWidth: 3 });
|
|
818
|
+
if (phase === "running") return /* @__PURE__ */ jsx(Loader2, { className: "animate-spin" });
|
|
819
|
+
if (phase === "waiting") return /* @__PURE__ */ jsx(Hourglass, {});
|
|
820
|
+
if (phase === "failed") return /* @__PURE__ */ jsx(AlertTriangle, {});
|
|
821
|
+
if (phase === "skipped") return /* @__PURE__ */ jsx(MinusCircle, {});
|
|
822
|
+
return icon ? /* @__PURE__ */ jsx(Fragment, { children: icon }) : /* @__PURE__ */ jsx("span", { className: "size-1.5 rounded-full bg-current opacity-60" });
|
|
823
|
+
}
|
|
824
|
+
var StepChip = forwardRef(function StepChip2({
|
|
825
|
+
kind,
|
|
826
|
+
phase,
|
|
827
|
+
icon,
|
|
828
|
+
label,
|
|
829
|
+
current,
|
|
830
|
+
heading,
|
|
831
|
+
labelClassName,
|
|
832
|
+
labelTestId,
|
|
833
|
+
children,
|
|
834
|
+
inert,
|
|
835
|
+
className,
|
|
836
|
+
...rest
|
|
837
|
+
}, ref) {
|
|
838
|
+
const body = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
839
|
+
/* @__PURE__ */ jsx("span", { className: "wf-badge", "aria-hidden": true, children: /* @__PURE__ */ jsx(StepBadgeMark, { phase, icon }) }),
|
|
840
|
+
current && heading ? /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-col text-left", children: [
|
|
841
|
+
/* @__PURE__ */ jsx("span", { className: "wf-kind-text truncate text-[9px] font-semibold uppercase leading-3 tracking-wider", children: heading }),
|
|
842
|
+
/* @__PURE__ */ jsx(
|
|
843
|
+
"span",
|
|
844
|
+
{
|
|
845
|
+
className: cn("wf-chip-label font-semibold", labelClassName),
|
|
846
|
+
"data-testid": labelTestId,
|
|
847
|
+
children: label
|
|
848
|
+
}
|
|
849
|
+
)
|
|
850
|
+
] }) : /* @__PURE__ */ jsx("span", { className: cn("wf-chip-label", labelClassName), "data-testid": labelTestId, children: label }),
|
|
851
|
+
children
|
|
852
|
+
] });
|
|
853
|
+
const classes = cn("wf-chip", `wf-kind-${kind}`, className);
|
|
854
|
+
if (inert)
|
|
855
|
+
return /* @__PURE__ */ jsx(
|
|
856
|
+
"span",
|
|
857
|
+
{
|
|
858
|
+
className: classes,
|
|
859
|
+
"data-phase": phase,
|
|
860
|
+
"aria-current": current ? "step" : void 0,
|
|
861
|
+
...rest,
|
|
862
|
+
children: body
|
|
863
|
+
}
|
|
864
|
+
);
|
|
865
|
+
return /* @__PURE__ */ jsx(
|
|
866
|
+
"button",
|
|
867
|
+
{
|
|
868
|
+
ref,
|
|
869
|
+
type: "button",
|
|
870
|
+
className: classes,
|
|
871
|
+
"data-phase": phase,
|
|
872
|
+
"aria-current": current ? "step" : void 0,
|
|
873
|
+
...rest,
|
|
874
|
+
children: body
|
|
875
|
+
}
|
|
876
|
+
);
|
|
877
|
+
});
|
|
878
|
+
function useElementSize(ref) {
|
|
879
|
+
const [size, setSize] = useState({ width: 0, height: 0 });
|
|
880
|
+
useLayoutEffect(() => {
|
|
881
|
+
const el = ref.current;
|
|
882
|
+
if (!el) return;
|
|
883
|
+
const measure = () => {
|
|
884
|
+
const rect = el.getBoundingClientRect();
|
|
885
|
+
setSize(
|
|
886
|
+
(prev) => prev.width === rect.width && prev.height === rect.height ? prev : { width: rect.width, height: rect.height }
|
|
887
|
+
);
|
|
888
|
+
};
|
|
889
|
+
measure();
|
|
890
|
+
window.addEventListener("resize", measure);
|
|
891
|
+
const stopObserving = observeResize(el, measure);
|
|
892
|
+
return () => {
|
|
893
|
+
window.removeEventListener("resize", measure);
|
|
894
|
+
stopObserving();
|
|
895
|
+
};
|
|
896
|
+
}, [ref]);
|
|
897
|
+
return size;
|
|
898
|
+
}
|
|
899
|
+
function rootFontSizePx() {
|
|
900
|
+
if (typeof document === "undefined") return 16;
|
|
901
|
+
const size = parseFloat(getComputedStyle(document.documentElement).fontSize);
|
|
902
|
+
return Number.isFinite(size) && size > 0 ? size : 16;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
export { DEFAULT_ASSIGNEE_WORDING, DEFAULT_STEP_DOCUMENT_LABELS, DEFAULT_STEP_KIND_LABELS, DEFAULT_STEP_RECORD_LABELS, EMPTY_WORKFLOW_SCOPE, SKILL_PROMPT_FALLBACK_PLACEHOLDER, SKILL_PROMPT_LABEL, STEP_KIND_ICONS, StepBadgeMark, StepChip, StepDocumentButton, StepDocumentCards, StepRecord, WORKFLOW_STEP_KINDS, assigneeName, buildLaunch, canAssign, composeStepPrompt, composeWorkflowPrompt, defaultInputs, dependsOn, eventWaitingDocuments, failedUpstream, fieldToFrontmatter, fillRunText, fillStepInputs, formatDate, initialRunInputs, inputsFromContext, isEmptyWorkflowScope, isPersonAction, isPersonStep, isRunFinished, isSteppedWorkflow, isWorkflowScope, nextAction, orderSteps, promptFieldName, reviewInstructions, rootFontSizePx, runFields, runFieldsOf, runThreadTitle, sendBackTargets, shownValue, skillToWorkflow, splitDocRef, stepConfigProblems, stepDependencies, stepDocuments, stepFields, stepKindOf, stepLevels, stepPhase, stepStatesFromActivity, upstreamSteps, useElementSize, useMentionAutocomplete, validateInputs, validateStep, validateWorkflowGraph, waitingDocuments, waitingForDocumentsText, workflowAccepts, workflowFromFrontmatter, workflowSteps, workflowsAccepting, workflowsForHost };
|
|
906
|
+
//# sourceMappingURL=chunk-7HAM7Y5U.js.map
|
|
907
|
+
//# sourceMappingURL=chunk-7HAM7Y5U.js.map
|