@arbidocs/blocks 0.4.141 → 0.4.143
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/agents/index.cjs +440 -436
- package/dist/agents/index.js +12 -8
- package/dist/chat/index.cjs +139 -138
- package/dist/chat/index.js +4 -3
- package/dist/{chunk-S24XEVPS.cjs → chunk-464YPRAE.cjs} +33 -2
- package/dist/chunk-464YPRAE.cjs.map +1 -0
- package/dist/{chunk-7YLJHTDC.cjs → chunk-5A2QQAF5.cjs} +11 -11
- package/dist/{chunk-7YLJHTDC.cjs.map → chunk-5A2QQAF5.cjs.map} +1 -1
- package/dist/{chunk-ON3TKY5Y.js → chunk-5YHEHEJT.js} +242 -4
- package/dist/chunk-5YHEHEJT.js.map +1 -0
- package/dist/chunk-76L6LOP3.cjs +308 -0
- package/dist/chunk-76L6LOP3.cjs.map +1 -0
- package/dist/chunk-AHDJXIUB.cjs +25 -0
- package/dist/chunk-AHDJXIUB.cjs.map +1 -0
- package/dist/chunk-AOSUHWIL.js +98 -0
- package/dist/chunk-AOSUHWIL.js.map +1 -0
- package/dist/{chunk-YFF3GTJQ.js → chunk-C44TDH54.js} +14 -1613
- package/dist/chunk-C44TDH54.js.map +1 -0
- package/dist/{chunk-GFRQG36Y.cjs → chunk-COCGRJLA.cjs} +213 -57
- package/dist/chunk-COCGRJLA.cjs.map +1 -0
- package/dist/chunk-CQCC7LE7.js +210 -0
- package/dist/chunk-CQCC7LE7.js.map +1 -0
- package/dist/{chunk-UGCKUXRV.js → chunk-CSI2B2H5.js} +3 -3
- package/dist/{chunk-UGCKUXRV.js.map → chunk-CSI2B2H5.js.map} +1 -1
- package/dist/{chunk-R26BK7YL.cjs → chunk-DTROMMDX.cjs} +4 -4
- package/dist/{chunk-R26BK7YL.cjs.map → chunk-DTROMMDX.cjs.map} +1 -1
- package/dist/{chunk-65THHQVB.cjs → chunk-ECW2R2KF.cjs} +27 -27
- package/dist/{chunk-65THHQVB.cjs.map → chunk-ECW2R2KF.cjs.map} +1 -1
- package/dist/{chunk-RI6DZA5X.js → chunk-EF4ZLKRM.js} +3 -3
- package/dist/{chunk-RI6DZA5X.js.map → chunk-EF4ZLKRM.js.map} +1 -1
- package/dist/{chunk-WS5EX7DN.cjs → chunk-EYKISBDO.cjs} +5 -5
- package/dist/{chunk-WS5EX7DN.cjs.map → chunk-EYKISBDO.cjs.map} +1 -1
- package/dist/chunk-FJETR2AS.js +561 -0
- package/dist/chunk-FJETR2AS.js.map +1 -0
- package/dist/{chunk-JO3EMZ4X.js → chunk-GWSGIZQ5.js} +3 -3
- package/dist/{chunk-JO3EMZ4X.js.map → chunk-GWSGIZQ5.js.map} +1 -1
- package/dist/{chunk-O6W6RW3B.js → chunk-H4D7WKDY.js} +207 -54
- package/dist/chunk-H4D7WKDY.js.map +1 -0
- package/dist/{chunk-OAQEUTNJ.cjs → chunk-HAOKT4LC.cjs} +5 -5
- package/dist/{chunk-OAQEUTNJ.cjs.map → chunk-HAOKT4LC.cjs.map} +1 -1
- package/dist/{chunk-YWY2KIX2.js → chunk-IJST4EBM.js} +13 -9
- package/dist/chunk-IJST4EBM.js.map +1 -0
- package/dist/{chunk-3RJN2VTL.js → chunk-IXWJGOM2.js} +3 -3
- package/dist/{chunk-3RJN2VTL.js.map → chunk-IXWJGOM2.js.map} +1 -1
- package/dist/{chunk-CYNF5PZI.js → chunk-J5CWKFSC.js} +3 -3
- package/dist/{chunk-CYNF5PZI.js.map → chunk-J5CWKFSC.js.map} +1 -1
- package/dist/{chunk-OWCEQKAR.cjs → chunk-JSTKEZBS.cjs} +21 -318
- package/dist/chunk-JSTKEZBS.cjs.map +1 -0
- package/dist/{chunk-TP6PLDNM.cjs → chunk-KMZWKSKO.cjs} +8 -8
- package/dist/{chunk-TP6PLDNM.cjs.map → chunk-KMZWKSKO.cjs.map} +1 -1
- package/dist/{chunk-C4WSHRR6.cjs → chunk-KPZZ5FHE.cjs} +32 -12
- package/dist/chunk-KPZZ5FHE.cjs.map +1 -0
- package/dist/{chunk-CKCBBYTA.js → chunk-KSHKTOY2.js} +5 -205
- package/dist/chunk-KSHKTOY2.js.map +1 -0
- package/dist/chunk-LJJJ6CYH.cjs +62 -0
- package/dist/chunk-LJJJ6CYH.cjs.map +1 -0
- package/dist/chunk-LPYEUD2D.cjs +1627 -0
- package/dist/chunk-LPYEUD2D.cjs.map +1 -0
- package/dist/chunk-MHFF5N65.cjs +101 -0
- package/dist/chunk-MHFF5N65.cjs.map +1 -0
- package/dist/{chunk-GYAUJ4KT.js → chunk-MTSKK3BN.js} +32 -3
- package/dist/chunk-MTSKK3BN.js.map +1 -0
- package/dist/chunk-NHZK64TQ.js +75 -0
- package/dist/chunk-NHZK64TQ.js.map +1 -0
- package/dist/{chunk-BPBSSMRB.js → chunk-NRFAWUVD.js} +3 -3
- package/dist/{chunk-BPBSSMRB.js.map → chunk-NRFAWUVD.js.map} +1 -1
- package/dist/chunk-NWNVWO6L.cjs +80 -0
- package/dist/chunk-NWNVWO6L.cjs.map +1 -0
- package/dist/{chunk-CQ4MFKFC.cjs → chunk-O2GW5IY6.cjs} +90 -86
- package/dist/chunk-O2GW5IY6.cjs.map +1 -0
- package/dist/{chunk-3BFGL2JL.cjs → chunk-ODRHHWHY.cjs} +4 -4
- package/dist/{chunk-3BFGL2JL.cjs.map → chunk-ODRHHWHY.cjs.map} +1 -1
- package/dist/{chunk-Y3KA6X7B.js → chunk-OVR3XMYL.js} +4 -4
- package/dist/{chunk-Y3KA6X7B.js.map → chunk-OVR3XMYL.js.map} +1 -1
- package/dist/{chunk-Y5KTM3V5.js → chunk-PDKM27DF.js} +17 -295
- package/dist/chunk-PDKM27DF.js.map +1 -0
- package/dist/{chunk-OAL3B2ZU.cjs → chunk-PLJ7PHWU.cjs} +5 -5
- package/dist/{chunk-OAL3B2ZU.cjs.map → chunk-PLJ7PHWU.cjs.map} +1 -1
- package/dist/{chunk-2UUNSHDI.cjs → chunk-RB7GX2VT.cjs} +59 -1682
- package/dist/chunk-RB7GX2VT.cjs.map +1 -0
- package/dist/chunk-RFIBUWLF.cjs +232 -0
- package/dist/chunk-RFIBUWLF.cjs.map +1 -0
- package/dist/chunk-RLWIUUQ5.js +23 -0
- package/dist/chunk-RLWIUUQ5.js.map +1 -0
- package/dist/{chunk-MIDXCYZB.cjs → chunk-RQ2Y7USX.cjs} +15 -235
- package/dist/chunk-RQ2Y7USX.cjs.map +1 -0
- package/dist/chunk-SV65E4QW.js +58 -0
- package/dist/chunk-SV65E4QW.js.map +1 -0
- package/dist/{chunk-LYUO3E6V.js → chunk-SZOFGU7W.js} +3 -3
- package/dist/{chunk-LYUO3E6V.js.map → chunk-SZOFGU7W.js.map} +1 -1
- package/dist/chunk-T5B7FM7S.js +1602 -0
- package/dist/chunk-T5B7FM7S.js.map +1 -0
- package/dist/{chunk-YNIBUKV5.js → chunk-TBEVGWY3.js} +32 -14
- package/dist/chunk-TBEVGWY3.js.map +1 -0
- package/dist/{chunk-MJCCBMM5.cjs → chunk-TC3RQNEX.cjs} +6 -80
- package/dist/chunk-TC3RQNEX.cjs.map +1 -0
- package/dist/chunk-TZGBRLPK.js +288 -0
- package/dist/chunk-TZGBRLPK.js.map +1 -0
- package/dist/chunk-U6YVZDOV.cjs +574 -0
- package/dist/chunk-U6YVZDOV.cjs.map +1 -0
- package/dist/{chunk-QIMVTGKS.cjs → chunk-U73KPFYH.cjs} +255 -2
- package/dist/chunk-U73KPFYH.cjs.map +1 -0
- package/dist/{chunk-HFGXA5CL.cjs → chunk-UTTTJSQU.cjs} +4 -4
- package/dist/{chunk-HFGXA5CL.cjs.map → chunk-UTTTJSQU.cjs.map} +1 -1
- package/dist/{chunk-DLBUFHLY.js → chunk-VTTZZ4FN.js} +4 -74
- package/dist/chunk-VTTZZ4FN.js.map +1 -0
- package/dist/{chunk-5FTIHRZH.cjs → chunk-XVUOMWMD.cjs} +4 -4
- package/dist/{chunk-5FTIHRZH.cjs.map → chunk-XVUOMWMD.cjs.map} +1 -1
- package/dist/{chunk-3ZYOASAX.js → chunk-Y4ATWQGV.js} +3 -3
- package/dist/{chunk-3ZYOASAX.js.map → chunk-Y4ATWQGV.js.map} +1 -1
- package/dist/{chunk-444XKG46.js → chunk-YKQ2DPIP.js} +3 -3
- package/dist/{chunk-444XKG46.js.map → chunk-YKQ2DPIP.js.map} +1 -1
- package/dist/{chunk-HEMU73OP.cjs → chunk-YSHIC4NJ.cjs} +4 -4
- package/dist/{chunk-HEMU73OP.cjs.map → chunk-YSHIC4NJ.cjs.map} +1 -1
- package/dist/{chunk-5BXEYYH6.js → chunk-ZM26YEOT.js} +3 -3
- package/dist/{chunk-5BXEYYH6.js.map → chunk-ZM26YEOT.js.map} +1 -1
- package/dist/citations/index.cjs +12 -12
- package/dist/citations/index.js +3 -3
- package/dist/connect/docx.cjs +36 -7
- package/dist/connect/docx.cjs.map +1 -1
- package/dist/connect/docx.d.ts +9 -2
- package/dist/connect/docx.js +30 -6
- package/dist/connect/docx.js.map +1 -1
- package/dist/connect/index.cjs +805 -630
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/index.d.ts +2 -0
- package/dist/connect/index.js +639 -509
- package/dist/connect/index.js.map +1 -1
- package/dist/connection/ConnectedSettings.d.ts +3 -2
- package/dist/connection/docx/ConnectedNativeDocxComparison.d.ts +5 -0
- package/dist/connection/docx/ConnectedNativeDocxEditor.d.ts +16 -0
- package/dist/connection/{ConnectedStreamedWordArtifact.d.ts → docx/ConnectedStreamedWordArtifact.d.ts} +1 -1
- package/dist/connection/docx/support.d.ts +27 -0
- package/dist/connection/docx/useConnectedDocxReferences.d.ts +2 -0
- package/dist/connection/docx/useConnectedHouseTemplate.d.ts +2 -0
- package/dist/connection/settings-page/ConnectedAccountSettings.d.ts +35 -0
- package/dist/connection/settings-page/ConnectedMailSettings.d.ts +13 -0
- package/dist/connection/settings-page/ConnectedPremiumModels.d.ts +1 -0
- package/dist/connection/settings-page/ConnectedPrivacySettings.d.ts +12 -0
- package/dist/connection/settings-page/ConnectedSettingsPage.d.ts +29 -0
- package/dist/connection/settings-page/SessionStatusIcon.d.ts +7 -0
- package/dist/connection/settings-page/index.d.ts +6 -0
- package/dist/docx/index.cjs +17 -63
- package/dist/docx/index.cjs.map +1 -1
- package/dist/docx/index.d.ts +1 -0
- package/dist/docx/index.js +2 -64
- package/dist/docx/index.js.map +1 -1
- package/dist/docx/template/candidates.d.ts +16 -0
- package/dist/facts/index.cjs +4 -4
- package/dist/facts/index.js +3 -3
- package/dist/files/index.cjs +3 -3
- package/dist/files/index.js +2 -2
- package/dist/home/index.cjs +20 -20
- package/dist/home/index.js +4 -4
- package/dist/index.cjs +793 -755
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +25 -19
- package/dist/index.js.map +1 -1
- package/dist/lib/deep-link.d.ts +46 -0
- package/dist/lib/sidebar-mode.d.ts +1 -3
- package/dist/lib/use-close-on-escape.d.ts +6 -0
- package/dist/provider/BlocksProvider.d.ts +5 -1
- package/dist/provider/settings-section.d.ts +9 -0
- package/dist/retrieval/index.cjs +4 -4
- package/dist/retrieval/index.js +2 -2
- package/dist/settings/AppearanceSettings.d.ts +18 -0
- package/dist/settings/ServerConnectionControls.d.ts +16 -0
- package/dist/settings/SettingsPage.d.ts +31 -0
- package/dist/settings/index.cjs +189 -251
- package/dist/settings/index.cjs.map +1 -1
- package/dist/settings/index.d.ts +3 -1
- package/dist/settings/index.js +89 -200
- package/dist/settings/index.js.map +1 -1
- package/dist/shell/ShellSidebar.d.ts +37 -0
- package/dist/shell/Sidebar.d.ts +6 -6
- package/dist/shell/index.cjs +63 -50
- package/dist/shell/index.d.ts +4 -1
- package/dist/shell/index.js +5 -4
- package/dist/shell/types.d.ts +18 -0
- package/dist/shell/use-sidebar-controller.d.ts +59 -0
- package/dist/site/index.cjs +74 -73
- package/dist/site/index.js +3 -2
- package/dist/studio/index.cjs +80 -78
- package/dist/studio/index.cjs.map +1 -1
- package/dist/studio/index.js +10 -8
- package/dist/studio/index.js.map +1 -1
- package/dist/workflow-canvas/index.cjs +64 -60
- package/dist/workflow-canvas/index.cjs.map +1 -1
- package/dist/workflow-canvas/index.js +12 -8
- package/dist/workflow-canvas/index.js.map +1 -1
- package/dist/workspaces/index.cjs +3 -3
- package/dist/workspaces/index.js +2 -2
- package/node_modules/@arbidocs/coedit/package.json +1 -1
- package/package.json +4 -4
- package/dist/chunk-2UUNSHDI.cjs.map +0 -1
- package/dist/chunk-4TR5QCCX.cjs +0 -43
- package/dist/chunk-4TR5QCCX.cjs.map +0 -1
- package/dist/chunk-7NDW4KF4.cjs +0 -112
- package/dist/chunk-7NDW4KF4.cjs.map +0 -1
- package/dist/chunk-C4WSHRR6.cjs.map +0 -1
- package/dist/chunk-CKCBBYTA.js.map +0 -1
- package/dist/chunk-CQ4MFKFC.cjs.map +0 -1
- package/dist/chunk-DLBUFHLY.js.map +0 -1
- package/dist/chunk-ETXYVO6E.js +0 -109
- package/dist/chunk-ETXYVO6E.js.map +0 -1
- package/dist/chunk-GFRQG36Y.cjs.map +0 -1
- package/dist/chunk-GYAUJ4KT.js.map +0 -1
- package/dist/chunk-MCKOZACC.js +0 -41
- package/dist/chunk-MCKOZACC.js.map +0 -1
- package/dist/chunk-MIDXCYZB.cjs.map +0 -1
- package/dist/chunk-MJCCBMM5.cjs.map +0 -1
- package/dist/chunk-O6W6RW3B.js.map +0 -1
- package/dist/chunk-ON3TKY5Y.js.map +0 -1
- package/dist/chunk-OWCEQKAR.cjs.map +0 -1
- package/dist/chunk-QIMVTGKS.cjs.map +0 -1
- package/dist/chunk-S24XEVPS.cjs.map +0 -1
- package/dist/chunk-Y5KTM3V5.js.map +0 -1
- package/dist/chunk-YFF3GTJQ.js.map +0 -1
- package/dist/chunk-YNIBUKV5.js.map +0 -1
- package/dist/chunk-YWY2KIX2.js.map +0 -1
- package/dist/connection/ConnectedNativeDocxEditor.d.ts +0 -6
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var chunk32HW2Q33_cjs = require('./chunk-32HW2Q33.cjs');
|
|
5
|
+
|
|
6
|
+
// src/agents/workflows/types.ts
|
|
7
|
+
var EMPTY_WORKFLOW_SCOPE = { folders: [], labels: [] };
|
|
8
|
+
|
|
9
|
+
// src/agents/workflows/workflow.ts
|
|
10
|
+
var isWorkflowScope = (value) => typeof value === "object" && value !== null && Array.isArray(value.folders) && Array.isArray(value.labels);
|
|
11
|
+
var isEmptyWorkflowScope = (scope) => scope.folders.length === 0 && scope.labels.length === 0 && !scope.documents?.length;
|
|
12
|
+
var isFileField = (field) => field.type === "scope" || field.type === "documents";
|
|
13
|
+
function emptyValue(field) {
|
|
14
|
+
switch (field.type) {
|
|
15
|
+
case "boolean":
|
|
16
|
+
return false;
|
|
17
|
+
case "scope":
|
|
18
|
+
return { folders: [], labels: [] };
|
|
19
|
+
case "documents":
|
|
20
|
+
return { folders: [], labels: [], documents: [] };
|
|
21
|
+
default:
|
|
22
|
+
return "";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function defaultInputs(workflow) {
|
|
26
|
+
const inputs = {};
|
|
27
|
+
for (const field of workflow.inputs) {
|
|
28
|
+
const d = field.default;
|
|
29
|
+
inputs[field.name] = d === void 0 ? emptyValue(field) : isWorkflowScope(d) ? { ...d } : d;
|
|
30
|
+
}
|
|
31
|
+
return inputs;
|
|
32
|
+
}
|
|
33
|
+
function validateInputs(workflow, inputs) {
|
|
34
|
+
const errors = {};
|
|
35
|
+
for (const field of workflow.inputs) {
|
|
36
|
+
const value = inputs[field.name];
|
|
37
|
+
if (field.type === "number") {
|
|
38
|
+
const blank = value === "" || value === void 0;
|
|
39
|
+
if (blank) {
|
|
40
|
+
if (field.required) errors[field.name] = "required";
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const n = Number(value);
|
|
44
|
+
if (Number.isNaN(n)) errors[field.name] = "number";
|
|
45
|
+
else if (field.min !== void 0 && n < field.min) errors[field.name] = "min";
|
|
46
|
+
else if (field.max !== void 0 && n > field.max) errors[field.name] = "max";
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (!field.required) continue;
|
|
50
|
+
if (field.type === "documents") {
|
|
51
|
+
if (!isWorkflowScope(value) || !value.documents?.length) errors[field.name] = "required";
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (field.type === "boolean" || field.type === "scope") continue;
|
|
55
|
+
if (typeof value !== "string" || value.trim() === "") errors[field.name] = "required";
|
|
56
|
+
}
|
|
57
|
+
return errors;
|
|
58
|
+
}
|
|
59
|
+
function promptFieldName(workflow) {
|
|
60
|
+
return workflow.inputs.find((f) => !f.advanced && (f.type === "text" || f.type === "longtext"))?.name;
|
|
61
|
+
}
|
|
62
|
+
var quoteList = (names) => {
|
|
63
|
+
const quoted = names.map((n) => `"${n}"`);
|
|
64
|
+
return quoted.length <= 1 ? quoted[0] ?? "" : `${quoted.slice(0, -1).join(", ")} and ${quoted[quoted.length - 1]}`;
|
|
65
|
+
};
|
|
66
|
+
function fragment(field, value, ctx) {
|
|
67
|
+
switch (field.type) {
|
|
68
|
+
case "documents": {
|
|
69
|
+
const ids = isWorkflowScope(value) ? value.documents ?? [] : [];
|
|
70
|
+
const names = ids.flatMap((id) => {
|
|
71
|
+
const title = ctx?.documentTitles?.[id];
|
|
72
|
+
return title ? [title] : [];
|
|
73
|
+
});
|
|
74
|
+
return quoteList(names);
|
|
75
|
+
}
|
|
76
|
+
case "boolean":
|
|
77
|
+
return value ? field.trueText ?? "yes" : field.falseText ?? "no";
|
|
78
|
+
case "select": {
|
|
79
|
+
const option = field.options?.find((o) => o.value === value);
|
|
80
|
+
return option ? option.text ?? option.label : String(value ?? "");
|
|
81
|
+
}
|
|
82
|
+
case "scope":
|
|
83
|
+
return "";
|
|
84
|
+
default:
|
|
85
|
+
return typeof value === "string" ? value.trim() : String(value ?? "");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function composeWorkflowPrompt(workflow, inputs, ctx) {
|
|
89
|
+
if (workflow.run.kind !== "prompt") return "";
|
|
90
|
+
const byName = new Map(workflow.inputs.map((f) => [f.name, f]));
|
|
91
|
+
const template = workflow.run.promptTemplate;
|
|
92
|
+
let out = "";
|
|
93
|
+
let last = 0;
|
|
94
|
+
const append = (text, isValue) => {
|
|
95
|
+
let t = text;
|
|
96
|
+
if (!isValue) {
|
|
97
|
+
t = t.replace(/[ \t]{2,}/g, " ");
|
|
98
|
+
if (/[ \t]$/.test(out)) t = t.replace(/^[ \t]+/, "");
|
|
99
|
+
}
|
|
100
|
+
out += t;
|
|
101
|
+
};
|
|
102
|
+
for (const m of template.matchAll(/\{\{\s*([a-z][a-z0-9_]*)\s*\}\}/gi)) {
|
|
103
|
+
append(template.slice(last, m.index), false);
|
|
104
|
+
const field = byName.get(m[1]);
|
|
105
|
+
append(field ? fragment(field, inputs[m[1]], ctx) : "", true);
|
|
106
|
+
last = m.index + m[0].length;
|
|
107
|
+
}
|
|
108
|
+
append(template.slice(last), false);
|
|
109
|
+
return out.trim();
|
|
110
|
+
}
|
|
111
|
+
function buildLaunch(workflow, inputs, agentId) {
|
|
112
|
+
const scopeField = workflow.inputs.find(isFileField);
|
|
113
|
+
const raw = scopeField ? inputs[scopeField.name] : void 0;
|
|
114
|
+
const scope = isWorkflowScope(raw) ? raw : { ...EMPTY_WORKFLOW_SCOPE };
|
|
115
|
+
return { workflow, inputs, scope, agentId: agentId || workflow.defaultAgentId || void 0 };
|
|
116
|
+
}
|
|
117
|
+
function workflowAccepts(workflow) {
|
|
118
|
+
const kinds = /* @__PURE__ */ new Set();
|
|
119
|
+
for (const field of workflow.inputs) if (field.context) kinds.add(field.context);
|
|
120
|
+
return [...kinds];
|
|
121
|
+
}
|
|
122
|
+
function workflowsAccepting(workflows, supplied) {
|
|
123
|
+
return workflows.filter((w) => workflowAccepts(w).some((k) => supplied.includes(k)));
|
|
124
|
+
}
|
|
125
|
+
function workflowsForHost(workflows, host) {
|
|
126
|
+
return workflows.filter((w) => !w.host || w.host === host);
|
|
127
|
+
}
|
|
128
|
+
function inputsFromContext(workflow, context) {
|
|
129
|
+
const inputs = {};
|
|
130
|
+
for (const field of workflow.inputs) {
|
|
131
|
+
if (!field.context) continue;
|
|
132
|
+
if (field.context === "selection") {
|
|
133
|
+
if (context.selection) inputs[field.name] = context.selection;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const ids = field.context === "image" ? context.image ? [context.image] : [] : context.documents;
|
|
137
|
+
if (ids?.length && isFileField(field)) {
|
|
138
|
+
inputs[field.name] = { folders: [], labels: [], documents: ids.slice(0, field.max ?? 1) };
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return inputs;
|
|
142
|
+
}
|
|
143
|
+
var SKILL_PROMPT_LABEL = "What should it work on?";
|
|
144
|
+
var SKILL_PROMPT_FALLBACK_PLACEHOLDER = "Describe what you want";
|
|
145
|
+
var plainHint = (hint) => hint.replace(/^[<[]\s*|\s*[>\]]$/g, "").trim();
|
|
146
|
+
function skillToWorkflow(skill) {
|
|
147
|
+
const hint = plainHint((skill.arg_hint ?? "").trim());
|
|
148
|
+
const inputs = [
|
|
149
|
+
{
|
|
150
|
+
name: "args",
|
|
151
|
+
type: "longtext",
|
|
152
|
+
label: SKILL_PROMPT_LABEL,
|
|
153
|
+
placeholder: hint || SKILL_PROMPT_FALLBACK_PLACEHOLDER,
|
|
154
|
+
required: true
|
|
155
|
+
}
|
|
156
|
+
];
|
|
157
|
+
return {
|
|
158
|
+
id: skill.slug,
|
|
159
|
+
skill: skill.slug,
|
|
160
|
+
title: skill.name || skill.slug,
|
|
161
|
+
description: skill.description ?? "",
|
|
162
|
+
inputs,
|
|
163
|
+
run: { kind: "prompt", promptTemplate: `/${skill.slug} {{args}}` },
|
|
164
|
+
landing: "chat",
|
|
165
|
+
schedulable: true
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
function skillTitle(name) {
|
|
169
|
+
if (!/^[a-z0-9]+(?:[-_][a-z0-9]+)*$/.test(name)) return name;
|
|
170
|
+
const words = name.replace(/[-_]+/g, " ");
|
|
171
|
+
return words.charAt(0).toUpperCase() + words.slice(1);
|
|
172
|
+
}
|
|
173
|
+
function mergeSkillWorkflows(host, listings) {
|
|
174
|
+
const hostIds = new Set(host.map((w) => w.id));
|
|
175
|
+
const skills = listings.filter((s) => !(s.visibility === "builtin" && hostIds.has(s.slug))).map((s) => ({
|
|
176
|
+
...skillToWorkflow({
|
|
177
|
+
name: skillTitle(s.name || s.slug),
|
|
178
|
+
slug: s.slug,
|
|
179
|
+
description: s.description ?? void 0,
|
|
180
|
+
arg_hint: s.arg_hint ?? void 0
|
|
181
|
+
}),
|
|
182
|
+
icon: "skill"
|
|
183
|
+
})).sort((a, b) => a.id.localeCompare(b.id));
|
|
184
|
+
const shadowed = new Set(skills.map((w) => w.id));
|
|
185
|
+
return { host: host.filter((w) => !shadowed.has(w.id)), skills };
|
|
186
|
+
}
|
|
187
|
+
var FIELD_TYPES = [
|
|
188
|
+
"text",
|
|
189
|
+
"longtext",
|
|
190
|
+
"boolean",
|
|
191
|
+
"select",
|
|
192
|
+
"number",
|
|
193
|
+
"date",
|
|
194
|
+
"scope",
|
|
195
|
+
"documents"
|
|
196
|
+
];
|
|
197
|
+
var str = (v) => typeof v === "string" ? v : void 0;
|
|
198
|
+
var num = (v) => typeof v === "number" ? v : void 0;
|
|
199
|
+
var bool = (v) => typeof v === "boolean" ? v : void 0;
|
|
200
|
+
function fieldFromFrontmatter(raw) {
|
|
201
|
+
if (typeof raw !== "object" || raw === null) return null;
|
|
202
|
+
const r = raw;
|
|
203
|
+
const name = str(r.name);
|
|
204
|
+
const type = FIELD_TYPES.find((t) => t === r.type);
|
|
205
|
+
if (!name || !/^[a-z][a-z0-9_]*$/.test(name) || !type) return null;
|
|
206
|
+
const options = Array.isArray(r.options) ? r.options.flatMap((o) => {
|
|
207
|
+
const ro = o;
|
|
208
|
+
const value = str(ro?.value);
|
|
209
|
+
const label = str(ro?.label);
|
|
210
|
+
return value && label ? [
|
|
211
|
+
{
|
|
212
|
+
value,
|
|
213
|
+
label,
|
|
214
|
+
description: str(ro.description),
|
|
215
|
+
text: str(ro.text),
|
|
216
|
+
icon: str(ro.icon),
|
|
217
|
+
tone: chunk32HW2Q33_cjs.isTone(ro.tone) ? ro.tone : void 0
|
|
218
|
+
}
|
|
219
|
+
] : [];
|
|
220
|
+
}) : void 0;
|
|
221
|
+
return {
|
|
222
|
+
name,
|
|
223
|
+
type,
|
|
224
|
+
label: str(r.label) ?? name,
|
|
225
|
+
description: str(r.description),
|
|
226
|
+
placeholder: str(r.placeholder),
|
|
227
|
+
required: bool(r.required),
|
|
228
|
+
default: r.default,
|
|
229
|
+
options,
|
|
230
|
+
min: num(r.min),
|
|
231
|
+
max: num(r.max),
|
|
232
|
+
trueText: str(r.true_text),
|
|
233
|
+
falseText: str(r.false_text),
|
|
234
|
+
advanced: bool(r.advanced),
|
|
235
|
+
accept: r.accept === "image" ? "image" : void 0,
|
|
236
|
+
context: r.context === "documents" || r.context === "selection" || r.context === "image" ? r.context : void 0,
|
|
237
|
+
by: Array.isArray(r.by) ? r.by.filter((b) => b === "folders" || b === "labels") : void 0
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
function workflowFromFrontmatter(id, frontmatter, body) {
|
|
241
|
+
const inputs = Array.isArray(frontmatter.inputs) ? frontmatter.inputs.flatMap((f) => {
|
|
242
|
+
const field = fieldFromFrontmatter(f);
|
|
243
|
+
return field ? [field] : [];
|
|
244
|
+
}) : [];
|
|
245
|
+
return {
|
|
246
|
+
id,
|
|
247
|
+
title: str(frontmatter.name) ?? id,
|
|
248
|
+
description: str(frontmatter.description) ?? "",
|
|
249
|
+
icon: str(frontmatter.icon),
|
|
250
|
+
inputs,
|
|
251
|
+
run: { kind: "prompt", promptTemplate: body.trim() },
|
|
252
|
+
landing: frontmatter.landing === "files" ? "files" : "chat",
|
|
253
|
+
requiresFiles: bool(frontmatter.requires_files),
|
|
254
|
+
schedulable: bool(frontmatter.schedulable) ?? true
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
function fieldToFrontmatter(field) {
|
|
258
|
+
return compact({
|
|
259
|
+
name: field.name,
|
|
260
|
+
type: field.type,
|
|
261
|
+
label: field.label,
|
|
262
|
+
description: field.description,
|
|
263
|
+
placeholder: field.placeholder,
|
|
264
|
+
required: field.required,
|
|
265
|
+
default: field.default,
|
|
266
|
+
options: field.options?.map(
|
|
267
|
+
(o) => compact({
|
|
268
|
+
value: o.value,
|
|
269
|
+
label: o.label,
|
|
270
|
+
description: o.description,
|
|
271
|
+
text: o.text,
|
|
272
|
+
icon: o.icon,
|
|
273
|
+
tone: o.tone
|
|
274
|
+
})
|
|
275
|
+
),
|
|
276
|
+
min: field.min,
|
|
277
|
+
max: field.max,
|
|
278
|
+
true_text: field.trueText,
|
|
279
|
+
false_text: field.falseText,
|
|
280
|
+
advanced: field.advanced,
|
|
281
|
+
by: field.by,
|
|
282
|
+
accept: field.accept,
|
|
283
|
+
context: field.context
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
var compact = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
|
|
287
|
+
|
|
288
|
+
exports.EMPTY_WORKFLOW_SCOPE = EMPTY_WORKFLOW_SCOPE;
|
|
289
|
+
exports.SKILL_PROMPT_FALLBACK_PLACEHOLDER = SKILL_PROMPT_FALLBACK_PLACEHOLDER;
|
|
290
|
+
exports.SKILL_PROMPT_LABEL = SKILL_PROMPT_LABEL;
|
|
291
|
+
exports.buildLaunch = buildLaunch;
|
|
292
|
+
exports.composeWorkflowPrompt = composeWorkflowPrompt;
|
|
293
|
+
exports.defaultInputs = defaultInputs;
|
|
294
|
+
exports.fieldToFrontmatter = fieldToFrontmatter;
|
|
295
|
+
exports.inputsFromContext = inputsFromContext;
|
|
296
|
+
exports.isEmptyWorkflowScope = isEmptyWorkflowScope;
|
|
297
|
+
exports.isWorkflowScope = isWorkflowScope;
|
|
298
|
+
exports.mergeSkillWorkflows = mergeSkillWorkflows;
|
|
299
|
+
exports.promptFieldName = promptFieldName;
|
|
300
|
+
exports.skillTitle = skillTitle;
|
|
301
|
+
exports.skillToWorkflow = skillToWorkflow;
|
|
302
|
+
exports.validateInputs = validateInputs;
|
|
303
|
+
exports.workflowAccepts = workflowAccepts;
|
|
304
|
+
exports.workflowFromFrontmatter = workflowFromFrontmatter;
|
|
305
|
+
exports.workflowsAccepting = workflowsAccepting;
|
|
306
|
+
exports.workflowsForHost = workflowsForHost;
|
|
307
|
+
//# sourceMappingURL=chunk-76L6LOP3.cjs.map
|
|
308
|
+
//# sourceMappingURL=chunk-76L6LOP3.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/agents/workflows/types.ts","../src/agents/workflows/workflow.ts"],"names":["isTone"],"mappings":"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","file":"chunk-76L6LOP3.cjs","sourcesContent":["/**\n * The one workflow model: a skill with a declared input schema. Everything launchable (a quick\n * action, a slash skill, a task body, an agent's job) is a `WorkflowDefinition`.\n *\n * The shape maps 1:1 onto future SKILL.md frontmatter (`inputs:` etc., snake_case on disk; see\n * `workflowFromFrontmatter`), so the backend can adopt it without a UI change. Blocks hold no\n * domain wording: titles, labels and prompt text are data supplied by the host.\n */\n\nimport type { Tone } from '../../components/tones'\n\nexport type WorkflowFieldType =\n | 'text'\n | 'longtext'\n | 'boolean'\n | 'select'\n | 'number'\n | 'date'\n | 'scope'\n | 'documents'\n /** A workspace member (`usr-…` / `agt-…`): what a step's assignee or a signer can name. */\n | 'person'\n\n/**\n * What a launching surface can hand a workflow without asking the user: the files it is looking at\n * (`documents`), the text the user selected (`selection`), or the image on screen (`image`, a file\n * id). A field binds to one with `context`; a surface offers a workflow when it can supply one of\n * the kinds the workflow declares (`workflowAccepts`).\n */\nexport type WorkflowContextKind = 'documents' | 'selection' | 'image'\n\n/** Where the user ends up after launching. `current-chat` sends into the chat already on screen. */\nexport type WorkflowLanding = 'chat' | 'current-chat' | 'files'\n\n/** Which files a run is limited to. Empty folders and labels = every file. */\nexport interface WorkflowScope {\n /** Folder paths; `''` is the unfiled bucket. */\n folders: string[]\n /** Label (tag) ids. */\n labels: string[]\n /** Exactly these files (ids). When present it wins over folders and labels: a `documents` field or a context launch. */\n documents?: string[]\n}\n\nexport const EMPTY_WORKFLOW_SCOPE: WorkflowScope = { folders: [], labels: [] }\n\nexport type WorkflowInputValue = string | number | boolean | WorkflowScope\n\nexport interface WorkflowFieldOption {\n value: string\n label: string\n description?: string\n /** Prompt fragment substituted for `{{name}}` when chosen (falls back to the label). */\n text?: string\n /** Key into the host's icon map. */\n icon?: string\n /**\n * Colours the option's choice tile (e.g. a risk rating: low `success`, medium `warning`, high\n * `danger`), chosen or not. The label always shows, so the tone is never the only cue.\n */\n tone?: Tone\n}\n\nexport interface WorkflowField {\n /** Key in `inputs`; also the `{{placeholder}}` in the prompt template. */\n name: string\n type: WorkflowFieldType\n label: string\n description?: string\n placeholder?: string\n required?: boolean\n default?: WorkflowInputValue\n /** `select` only. */\n options?: WorkflowFieldOption[]\n /** `number` only. */\n min?: number\n max?: number\n /** `boolean`: prompt fragments substituted for `{{name}}`. */\n trueText?: string\n falseText?: string\n /** Fold behind a disclosure: advanced wording the common run does not need. */\n advanced?: boolean\n /** `scope` only: which dimensions are offered. Default both. */\n by?: Array<'folders' | 'labels'>\n /** `documents` only: what kind of file is offered; `max` is how many may be picked (default 1). */\n accept?: 'image'\n /** Prefilled by a launching surface that supplies this kind of context (see `WorkflowContextKind`). */\n context?: WorkflowContextKind\n}\n\nexport type WorkflowRun =\n /** Compose a message from `promptTemplate` and send it. */\n | { kind: 'prompt'; promptTemplate: string }\n /** The host performs it (bound by workflow id), e.g. create a label then generate. */\n | { kind: 'operation' }\n /**\n * A guided run of named steps that form a graph. A run is a work thread on the server: the\n * thread's plan carries the steps (`toPlanSteps`), its activity log records each step's progress,\n * and the work runner starts each agent step as a turn in the thread. A person does the form,\n * upload and review steps (`useWorkflowThread` / `WorkflowRunner`). Not schedulable from a single\n * form: a workflow (automation) carries the steps and its trigger (`WorkflowBuilder`).\n */\n | {\n kind: 'steps'\n /** The run thread's title, a template over the run's inputs; defaults to the workflow's. */\n threadTitle?: string\n /** In dependency order: a step only waits for steps listed before it (`orderSteps`). */\n steps: WorkflowStep[]\n completion?: WorkflowCompletion\n /** Where each step sits on the builder's canvas, by step id. */\n layout?: Record<string, { x: number; y: number }>\n }\n\n/* ------------------------------- steps ------------------------------- */\n\n/**\n * When a step's signal is raised, tested against the step's outcome once it is done (a skipped or\n * failed step never signals): a form field equals a value (case-insensitive text), the agent's\n * answer contains a phrase or matches a regex, or a review is approved. Absent = whenever it is done.\n */\nexport type WorkflowSignalWhen =\n | { field: string; equals: string | number | boolean }\n | { contains: string }\n | { matches: string }\n | { approved: true }\n\n/**\n * A named signal a step raises when it is done and its condition holds. Another workflow starts on\n * it (\"When a step signals\") as its own thread linked to this one, so the if/then between\n * workflows lives in the link and each workflow stays short.\n */\nexport interface WorkflowSignal {\n /** A slug (`[a-z0-9][a-z0-9_.-]*`), e.g. `risk-high`: what a linked workflow listens for. */\n name: string\n when?: WorkflowSignalWhen\n}\n\ninterface WorkflowStepBase {\n /** Unique within the workflow (`[a-z][a-z0-9_-]*`): the thread's progress is keyed by it. */\n id: string\n /** The step's name: the stepper and the thread's top bar show it. */\n title: string\n /** One line under the step's heading. */\n description?: string\n /** Key into the host's icon map. */\n icon?: string\n /**\n * The host commits this step before the run moves on (`commit[id]`), e.g. creates the record\n * later steps work in. Once committed the step's inputs are locked.\n */\n commit?: boolean\n /** Primary button text while on this step (until it is committed); defaults to \"Continue\". */\n nextLabel?: string\n /**\n * The steps this one waits for. Absent: the step before it in the list, so a plain list is a\n * sequence. `[]`: it starts with the run. A step waiting for several waits for them all.\n */\n after?: string[]\n /** Signals the step raises when it is done and their condition holds. */\n signals?: WorkflowSignal[]\n /**\n * Who the step is for (a person step, or a signature or email step): they are told when it is\n * ready, and only they (or the run's owner) can do it. Absent: whoever is on the run.\n */\n assignee?: WorkflowAssignee\n /** A person step left this many hours is announced again (once). */\n remindAfterHours?: number\n}\n\n/**\n * Who a step is for: a named member (`usr-…` / `agt-…`), whoever started the run, the person a\n * form's `person` field names (`input`: its name), or the project's lead.\n */\nexport type WorkflowAssignee =\n { user: string } | { runOwner: true } | { input: string } | { projectLead: true }\n\n/**\n * A document a step works on, named by where it comes from: what an earlier step produced or was\n * given (an upload's files, an agent's draft, a signed copy, an edited version), what a run input\n * names (a document pick), or one document by id (`doc-…`, optionally `@v<n>`).\n */\nexport type WorkflowDocumentRef = { step: string } | { input: string } | { id: string }\n\n/** Ask people to e-sign a document. The step waits until every signer has signed. */\nexport interface WorkflowSignAction {\n type: 'sign'\n document?: WorkflowDocumentRef\n signers: WorkflowAssignee[]\n /** Shown to the signers. */\n message?: string\n /** Unsigned this long after it starts, the step fails. */\n expiresAfterHours?: number\n}\n\n/**\n * Prepare an email in native mail, never sent by itself: its person sends it, and the step is done\n * when they say so (or send it). Every text is a template over the run (`{{field}}`,\n * `{{step.answer}}`).\n */\nexport interface WorkflowEmailDraftAction {\n type: 'email_draft'\n to: string[]\n cc?: string[]\n subject: string\n body: string\n attachments?: WorkflowDocumentRef[]\n}\n\n/** Run review columns (labels with instructions) over documents, then open the grid. */\nexport interface WorkflowTabularReviewAction {\n type: 'tabular_review'\n /** Label (tag) ids: the columns. */\n tags: string[]\n /** Every file the run's uploads took, every document of the workspace, or these documents. */\n documents: 'run_uploads' | 'workspace' | WorkflowDocumentRef[]\n /** Fill cells that already have a value again. */\n overwrite?: boolean\n}\n\nexport type WorkflowAction =\n WorkflowSignAction | WorkflowEmailDraftAction | WorkflowTabularReviewAction\nexport type WorkflowActionType = WorkflowAction['type']\n\n/** Ask for inputs. Every step's fields share the run's one input namespace (`{{name}}`). */\nexport interface WorkflowFormStep extends WorkflowStepBase {\n kind: 'form'\n inputs: WorkflowField[]\n}\n\n/** Add files to the run's workspace. Skippable unless `required`. */\nexport interface WorkflowUploadStep extends WorkflowStepBase {\n kind: 'upload'\n required?: boolean\n /** `accept` of the file picker, e.g. `.pdf,.docx`. */\n accept?: string\n /** Small muted line under the drop target. */\n hint?: string\n}\n\n/**\n * A turn the assistant takes in the run's thread. It runs a skill or another workflow\n * (`workflow`, its inputs filled from `with`) or its own `run`. It continues the thread's main\n * line, so it sees everything before it; a `branch` step runs off the main line instead and\n * delivers only its result back to it.\n */\nexport interface WorkflowAgentStep extends WorkflowStepBase {\n kind: 'agent'\n /** Id of the skill or workflow this step runs; its inputs come from `with`. */\n workflow?: string\n /**\n * The named workflow's inputs, each a template over the run's inputs: `{{client}}`, with\n * `{{a || b}}` falling back to `b` when `a` is blank. A bare `{{name}}` passes the value as is.\n */\n with?: Record<string, string>\n /** Used when no `workflow` is named. `operation`: the host composes the prompt (`compose`). */\n run?: Extract<WorkflowRun, { kind: 'prompt' } | { kind: 'operation' }>\n /** What the step shows: the answer (default) or the drafted document. */\n output?: 'answer' | 'artifact'\n /** Runs off the thread's main line and delivers only its result to it. */\n branch?: boolean\n /**\n * Edit this Word document with tracked changes (the instruction says what to change); the\n * edited copy is its next version, to accept or reject change by change. Main line only.\n */\n editDocument?: WorkflowDocumentRef\n}\n\n/** A person's review or approval: whoever completes it on the thread approves it. */\nexport interface WorkflowReviewStep extends WorkflowStepBase {\n kind: 'review'\n /** What to review, a template over the run's inputs. */\n instructions?: string\n /** What the approver fills in when approving (e.g. a rating): they join the run's inputs. */\n fields?: WorkflowField[]\n}\n\n/**\n * A step that uses a platform feature rather than producing text: an e-signature, an email draft\n * or a tabular review. It starts by itself; a signature and an email then wait for their people.\n */\nexport interface WorkflowActionStep extends WorkflowStepBase {\n kind: 'action'\n action: WorkflowAction\n}\n\nexport type WorkflowStep =\n | WorkflowFormStep\n | WorkflowUploadStep\n | WorkflowAgentStep\n | WorkflowReviewStep\n | WorkflowActionStep\n\n/** The finish screen of a stepped run. */\nexport interface WorkflowCompletion {\n title: string\n description?: string\n icon?: string\n}\n\n/**\n * Where a step of a run is, as the thread records it: not reached yet (`pending`), `running`,\n * `waiting` (an action step waiting on its signers or on its email being sent), `done`,\n * `skipped`, or `failed` (it can be retried or skipped).\n */\nexport type WorkflowStepStatus = 'pending' | 'running' | 'waiting' | 'done' | 'skipped' | 'failed'\n\n/** What a waiting step waits on (ids only), as its latest event says. */\nexport interface WorkflowActionWaiting {\n /** An agent step: the documents to finish processing before its turn starts. */\n documents?: string[]\n /** A signature: the document and version to sign, who signs, who has signed. */\n doc_ext_id?: string\n version?: number\n signers?: string[]\n signed?: string[]\n expires_at?: string\n /** An email: the draft in native mail and whose mailbox it is in. */\n draft_id?: string\n mailbox?: string\n [key: string]: unknown\n}\n\n/** What a review recorded it approved: each step it waited for, as it stood then. */\nexport interface WorkflowApprovalEvidence {\n step: string\n status: string\n /** That step's answer (a message in the thread). */\n response_id?: string\n /** The document versions it had (`doc-…@v<n>`). */\n documents?: string[]\n output?: Record<string, unknown>\n}\n\nexport interface WorkflowStepState {\n status: WorkflowStepStatus\n /** The step's answer in the thread (an agent step), or the result a branch delivered. */\n responseId?: string | null\n /** The answer's text, once read. */\n text?: string\n error?: string | null\n /**\n * Skipped while it stood failed (`error` keeps why it failed): what waits for it goes on\n * without its result.\n */\n skippedAfterFailure?: boolean\n /** When it started running (ISO), for the elapsed time while it runs. */\n startedAt?: string\n /** An action step's type, once it has started. */\n action?: WorkflowActionType\n /** What a `waiting` step waits on (an action step's people, an agent step's documents). */\n waiting?: WorkflowActionWaiting\n /** What a done action step produced (ids: the signed version, the draft, the reviewed labels). */\n output?: Record<string, unknown>\n /** The document versions the step produced or was given (`doc-…@v<n>`). */\n documents?: string[]\n /** Reopened by a send-back to this step and not touched since (`hasNote`: with a note). */\n sentBack?: boolean\n hasNote?: boolean\n /** Who was told the step is ready (`usr-…` / `agt-…`), since it last changed. */\n announcedTo?: string | null\n /** Who finished it (completed, approved, skipped, declined). */\n by?: string | null\n /** When it finished (ISO). */\n at?: string\n /** A review: what it approved. */\n approved?: WorkflowApprovalEvidence[]\n /** A declined signature: who declined. */\n declinedBy?: string\n}\n\nexport interface WorkflowDefinition {\n /** Execute a document operation directly, without creating a chat. */\n documentAction?: 'annotate_documents' | 'email_documents'\n\n /** The skill slug. */\n id: string\n title: string\n /** One line: the tile text and the task picker's hint. */\n description: string\n /** Longer explanation shown in the dialog header; defaults to `description`. */\n details?: string\n /** Key into the host's icon map. */\n icon?: string\n /** Primary button text; defaults to the dialog's generic \"Start\". */\n startLabel?: string\n /** Shipped with the app/deployment (pinned, not deletable, forkable into the user's own skills). */\n builtin?: boolean\n /** Backed by a server skill (its slug): a task runs it as a skill rather than as a prompt. */\n skill?: string\n inputs: WorkflowField[]\n run: WorkflowRun\n /** Where the user ends up after launching by default; a launch may override it. */\n landing: WorkflowLanding\n /** A model this run asks for (a run option the host applies, e.g. a stronger one for summaries). */\n model?: string\n /** Only offered by this host (e.g. `'word'`); absent = offered everywhere. */\n host?: string\n /** Needs workspace files to make sense: the dialog offers the host's add-files slot when none. */\n requiresFiles?: boolean\n /** Default agent; absent = the user's own assistant. */\n defaultAgentId?: string\n /** A free-form entry (\"my own instruction\", \"remind me\"), not a named skill: it does not name the dialog. */\n generic?: boolean\n /** Can be the body of a task (unattended). `action` workflows are not. */\n schedulable?: boolean\n /** Run options the form offers (all shown by default). */\n options?: { agent?: boolean }\n}\n\n/** What `onLaunch` receives. The host performs the launch (chat, scoping, send). */\nexport interface WorkflowLaunch {\n workflow: WorkflowDefinition\n inputs: Record<string, WorkflowInputValue>\n /** The first `scope` field's value, hoisted: the host scopes documents with it. */\n scope: WorkflowScope\n /** `undefined` = the user's own assistant, in this chat. */\n agentId?: string\n /** Overrides `workflow.landing` for this launch (the empty chat sends in place). */\n landing?: WorkflowLanding\n}\n\nexport type OnWorkflowLaunch = (launch: WorkflowLaunch) => void | Promise<void>\n\nexport type WorkflowInputs = Record<string, WorkflowInputValue>\n\n/** Validation problem of one field: the dialog maps the code to a label. */\nexport type WorkflowFieldError = 'required' | 'min' | 'max' | 'number'\nexport type WorkflowErrors = Record<string, WorkflowFieldError>\n","import { isTone } from '../../components/tones'\nimport {\n EMPTY_WORKFLOW_SCOPE,\n type WorkflowDefinition,\n type WorkflowErrors,\n type WorkflowField,\n type WorkflowFieldOption,\n type WorkflowContextKind,\n type WorkflowFieldType,\n type WorkflowInputs,\n type WorkflowInputValue,\n type WorkflowLaunch,\n type WorkflowScope,\n} from './types'\n\nexport const isWorkflowScope = (value: unknown): value is WorkflowScope =>\n typeof value === 'object' &&\n value !== null &&\n Array.isArray((value as WorkflowScope).folders) &&\n Array.isArray((value as WorkflowScope).labels)\n\nexport const isEmptyWorkflowScope = (scope: WorkflowScope): boolean =>\n scope.folders.length === 0 && scope.labels.length === 0 && !scope.documents?.length\n\n/** A field that selects files: a folder/label scope or an explicit pick. */\nconst isFileField = (field: WorkflowField): boolean =>\n field.type === 'scope' || field.type === 'documents'\n\nfunction emptyValue(field: WorkflowField): WorkflowInputValue {\n switch (field.type) {\n case 'boolean':\n return false\n case 'scope':\n return { folders: [], labels: [] }\n case 'documents':\n return { folders: [], labels: [], documents: [] }\n default:\n return ''\n }\n}\n\n/** The inputs a fresh form starts with: each field's default, else an empty value of its type. */\nexport function defaultInputs(workflow: WorkflowDefinition): WorkflowInputs {\n const inputs: WorkflowInputs = {}\n for (const field of workflow.inputs) {\n const d = field.default\n inputs[field.name] =\n d === undefined\n ? emptyValue(field)\n : isWorkflowScope(d)\n ? { ...d }\n : (d as WorkflowInputValue)\n }\n return inputs\n}\n\n/** Required-field and range problems, keyed by field name. Empty object = launchable. */\nexport function validateInputs(\n workflow: WorkflowDefinition,\n inputs: WorkflowInputs\n): WorkflowErrors {\n const errors: WorkflowErrors = {}\n for (const field of workflow.inputs) {\n const value = inputs[field.name]\n if (field.type === 'number') {\n const blank = value === '' || value === undefined\n if (blank) {\n if (field.required) errors[field.name] = 'required'\n continue\n }\n const n = Number(value)\n if (Number.isNaN(n)) errors[field.name] = 'number'\n else if (field.min !== undefined && n < field.min) errors[field.name] = 'min'\n else if (field.max !== undefined && n > field.max) errors[field.name] = 'max'\n continue\n }\n if (!field.required) continue\n if (field.type === 'documents') {\n if (!isWorkflowScope(value) || !value.documents?.length) errors[field.name] = 'required'\n continue\n }\n if (field.type === 'boolean' || field.type === 'scope') continue\n if (typeof value !== 'string' || value.trim() === '') errors[field.name] = 'required'\n }\n return errors\n}\n\n/**\n * The field that holds what the user asks for: the first common (not folded away) free-text field.\n * Text typed after a slash pre-fills it; the form puts the cursor in it when it comes first.\n */\nexport function promptFieldName(workflow: WorkflowDefinition): string | undefined {\n return workflow.inputs.find((f) => !f.advanced && (f.type === 'text' || f.type === 'longtext'))\n ?.name\n}\n\n/** What the host knows that the inputs alone do not: file ids resolved to names for the wording. */\nexport interface WorkflowComposeContext {\n documentTitles?: Record<string, string>\n}\n\nconst quoteList = (names: string[]): string => {\n const quoted = names.map((n) => `\"${n}\"`)\n return quoted.length <= 1\n ? (quoted[0] ?? '')\n : `${quoted.slice(0, -1).join(', ')} and ${quoted[quoted.length - 1]}`\n}\n\nfunction fragment(\n field: WorkflowField,\n value: WorkflowInputValue | undefined,\n ctx: WorkflowComposeContext | undefined\n): string {\n switch (field.type) {\n case 'documents': {\n // The quoted file name(s): \"the document <name>\" reads the same whichever file was picked.\n const ids = isWorkflowScope(value) ? (value.documents ?? []) : []\n const names = ids.flatMap((id) => {\n const title = ctx?.documentTitles?.[id]\n return title ? [title] : []\n })\n return quoteList(names)\n }\n case 'boolean':\n return value ? (field.trueText ?? 'yes') : (field.falseText ?? 'no')\n case 'select': {\n const option = field.options?.find((o) => o.value === value)\n return option ? (option.text ?? option.label) : String(value ?? '')\n }\n case 'scope':\n // The scope decides WHICH files the run is given; naming it in the wording only churns it.\n return ''\n default:\n return typeof value === 'string' ? value.trim() : String(value ?? '')\n }\n}\n\n/**\n * The single place a prompt string is composed from (workflow, inputs): `{{name}}` placeholders in\n * the template are replaced by each field's text. Whitespace left by empty fragments is tidied.\n */\nexport function composeWorkflowPrompt(\n workflow: WorkflowDefinition,\n inputs: WorkflowInputs,\n ctx?: WorkflowComposeContext\n): string {\n if (workflow.run.kind !== 'prompt') return ''\n const byName = new Map(workflow.inputs.map((f) => [f.name, f]))\n const template = workflow.run.promptTemplate\n // Whitespace left by empty fragments is tidied in the template's own text only: what the user\n // typed or selected (tabs, runs of spaces) reaches the prompt exactly as it was.\n let out = ''\n let last = 0\n const append = (text: string, isValue: boolean) => {\n let t = text\n if (!isValue) {\n t = t.replace(/[ \\t]{2,}/g, ' ')\n if (/[ \\t]$/.test(out)) t = t.replace(/^[ \\t]+/, '')\n }\n out += t\n }\n for (const m of template.matchAll(/\\{\\{\\s*([a-z][a-z0-9_]*)\\s*\\}\\}/gi)) {\n append(template.slice(last, m.index), false)\n const field = byName.get(m[1])\n append(field ? fragment(field, inputs[m[1]], ctx) : '', true)\n last = m.index + m[0].length\n }\n append(template.slice(last), false)\n return out.trim()\n}\n\n/** Assemble the launch the host receives: inputs, the hoisted scope and the chosen agent. */\nexport function buildLaunch(\n workflow: WorkflowDefinition,\n inputs: WorkflowInputs,\n agentId?: string\n): WorkflowLaunch {\n const scopeField = workflow.inputs.find(isFileField)\n const raw = scopeField ? inputs[scopeField.name] : undefined\n const scope = isWorkflowScope(raw) ? raw : { ...EMPTY_WORKFLOW_SCOPE }\n return { workflow, inputs, scope, agentId: agentId || workflow.defaultAgentId || undefined }\n}\n\n/* --------------------------- context launch --------------------------- */\n\n/** What a surface hands a workflow: the files in view, the selected text, the image on screen. */\nexport interface WorkflowContext {\n documents?: string[]\n selection?: string\n /** A file id. */\n image?: string\n}\n\n/** The kinds of context a workflow declares it can be started from. */\nexport function workflowAccepts(workflow: WorkflowDefinition): WorkflowContextKind[] {\n const kinds = new Set<WorkflowContextKind>()\n for (const field of workflow.inputs) if (field.context) kinds.add(field.context)\n return [...kinds]\n}\n\n/** Workflows a surface can offer: those that accept at least one kind of context it supplies. */\nexport function workflowsAccepting(\n workflows: WorkflowDefinition[],\n supplied: WorkflowContextKind[]\n): WorkflowDefinition[] {\n return workflows.filter((w) => workflowAccepts(w).some((k) => supplied.includes(k)))\n}\n\n/** Workflows a host offers: its own plus every one that is not tied to another host. */\nexport function workflowsForHost(\n workflows: WorkflowDefinition[],\n host: string\n): WorkflowDefinition[] {\n return workflows.filter((w) => !w.host || w.host === host)\n}\n\n/**\n * The inputs a context pre-fills: each field bound to a kind the surface supplied. Fields it does\n * not supply are left to the form's defaults, so the dialog still asks for them.\n */\nexport function inputsFromContext(\n workflow: WorkflowDefinition,\n context: WorkflowContext\n): WorkflowInputs {\n const inputs: WorkflowInputs = {}\n for (const field of workflow.inputs) {\n if (!field.context) continue\n if (field.context === 'selection') {\n if (context.selection) inputs[field.name] = context.selection\n continue\n }\n const ids =\n field.context === 'image' ? (context.image ? [context.image] : []) : context.documents\n if (ids?.length && isFileField(field)) {\n inputs[field.name] = { folders: [], labels: [], documents: ids.slice(0, field.max ?? 1) }\n }\n }\n return inputs\n}\n\n/* ------------------------------ skills ------------------------------- */\n\n/** The slice of a skill listing row the model needs (`SkillSummaryResponse`). */\nexport interface SkillLike {\n name: string\n slug: string\n description?: string\n arg_hint?: string\n}\n\n/** The prompt field's label when a skill brings none of its own. */\nexport const SKILL_PROMPT_LABEL = 'What should it work on?'\nexport const SKILL_PROMPT_FALLBACK_PLACEHOLDER = 'Describe what you want'\n\n/** `<prompt>` / `[topic]` becomes `prompt` / `topic`: a hint reads as a placeholder, not syntax. */\nconst plainHint = (hint: string): string => hint.replace(/^[<[]\\s*|\\s*[>\\]]$/g, '').trim()\n\n/**\n * A skill is run WITH a prompt, so it always gets a one-field form: a required free-text field\n * (`args`) whose placeholder is the skill's `arg_hint` (brackets removed). Starting one with\n * nothing is never offered; text typed after the slash pre-fills the field.\n */\nexport function skillToWorkflow(skill: SkillLike): WorkflowDefinition {\n const hint = plainHint((skill.arg_hint ?? '').trim())\n const inputs: WorkflowField[] = [\n {\n name: 'args',\n type: 'longtext',\n label: SKILL_PROMPT_LABEL,\n placeholder: hint || SKILL_PROMPT_FALLBACK_PLACEHOLDER,\n required: true,\n },\n ]\n return {\n id: skill.slug,\n skill: skill.slug,\n title: skill.name || skill.slug,\n description: skill.description ?? '',\n inputs,\n run: { kind: 'prompt', promptTemplate: `/${skill.slug} {{args}}` },\n landing: 'chat',\n schedulable: true,\n }\n}\n\n/** A skill named like its slug (\"deep-research\") reads as a title (\"Deep research\"); a written name is kept. */\nexport function skillTitle(name: string): string {\n if (!/^[a-z0-9]+(?:[-_][a-z0-9]+)*$/.test(name)) return name\n const words = name.replace(/[-_]+/g, ' ')\n return words.charAt(0).toUpperCase() + words.slice(1)\n}\n\n/** A skill as the skills list returns it (`GET /v1/assistant/skills`). */\nexport interface SkillListing extends Omit<SkillLike, 'arg_hint' | 'description'> {\n description?: string | null\n arg_hint?: string | null\n /** `builtin` ships with ARBI; `mine` and `global` are documents someone uploaded. */\n visibility?: string | null\n}\n\n/**\n * The host's own workflows together with the skills the user can run, as one list of workflows:\n * `host` (in its order) and `skills` (by slug, each a one-field form, icon `skill`). An uploaded skill with a\n * host workflow's id replaces it (your own copy is used instead of the original); a built-in skill\n * the host already offers keeps the host's richer form, so nothing is listed twice.\n */\nexport function mergeSkillWorkflows(\n host: WorkflowDefinition[],\n listings: SkillListing[]\n): { host: WorkflowDefinition[]; skills: WorkflowDefinition[] } {\n const hostIds = new Set(host.map((w) => w.id))\n const skills = listings\n .filter((s) => !(s.visibility === 'builtin' && hostIds.has(s.slug)))\n .map((s) => ({\n ...skillToWorkflow({\n name: skillTitle(s.name || s.slug),\n slug: s.slug,\n description: s.description ?? undefined,\n arg_hint: s.arg_hint ?? undefined,\n }),\n icon: 'skill',\n }))\n .sort((a, b) => a.id.localeCompare(b.id))\n const shadowed = new Set(skills.map((w) => w.id))\n return { host: host.filter((w) => !shadowed.has(w.id)), skills }\n}\n\nconst FIELD_TYPES: WorkflowFieldType[] = [\n 'text',\n 'longtext',\n 'boolean',\n 'select',\n 'number',\n 'date',\n 'scope',\n 'documents',\n]\n\nconst str = (v: unknown): string | undefined => (typeof v === 'string' ? v : undefined)\nconst num = (v: unknown): number | undefined => (typeof v === 'number' ? v : undefined)\nconst bool = (v: unknown): boolean | undefined => (typeof v === 'boolean' ? v : undefined)\n\nfunction fieldFromFrontmatter(raw: unknown): WorkflowField | null {\n if (typeof raw !== 'object' || raw === null) return null\n const r = raw as Record<string, unknown>\n const name = str(r.name)\n const type = FIELD_TYPES.find((t) => t === r.type)\n if (!name || !/^[a-z][a-z0-9_]*$/.test(name) || !type) return null\n const options = Array.isArray(r.options)\n ? r.options.flatMap((o): WorkflowFieldOption[] => {\n const ro = o as Record<string, unknown>\n const value = str(ro?.value)\n const label = str(ro?.label)\n return value && label\n ? [\n {\n value,\n label,\n description: str(ro.description),\n text: str(ro.text),\n icon: str(ro.icon),\n tone: isTone(ro.tone) ? ro.tone : undefined,\n },\n ]\n : []\n })\n : undefined\n return {\n name,\n type,\n label: str(r.label) ?? name,\n description: str(r.description),\n placeholder: str(r.placeholder),\n required: bool(r.required),\n default: r.default as WorkflowInputValue | undefined,\n options,\n min: num(r.min),\n max: num(r.max),\n trueText: str(r.true_text),\n falseText: str(r.false_text),\n advanced: bool(r.advanced),\n accept: r.accept === 'image' ? 'image' : undefined,\n context:\n r.context === 'documents' || r.context === 'selection' || r.context === 'image'\n ? r.context\n : undefined,\n by: Array.isArray(r.by)\n ? (r.by.filter((b) => b === 'folders' || b === 'labels') as Array<'folders' | 'labels'>)\n : undefined,\n }\n}\n\n/**\n * Build a workflow from parsed SKILL.md frontmatter (snake_case keys) and its body (the prompt\n * template). The inverse of what the backend will publish; seeded workflows use the same shape.\n */\nexport function workflowFromFrontmatter(\n id: string,\n frontmatter: Record<string, unknown>,\n body: string\n): WorkflowDefinition {\n const inputs = Array.isArray(frontmatter.inputs)\n ? frontmatter.inputs.flatMap((f) => {\n const field = fieldFromFrontmatter(f)\n return field ? [field] : []\n })\n : []\n return {\n id,\n title: str(frontmatter.name) ?? id,\n description: str(frontmatter.description) ?? '',\n icon: str(frontmatter.icon),\n inputs,\n run: { kind: 'prompt', promptTemplate: body.trim() },\n landing: frontmatter.landing === 'files' ? 'files' : 'chat',\n requiresFiles: bool(frontmatter.requires_files),\n schedulable: bool(frontmatter.schedulable) ?? true,\n }\n}\n\n/** snake_case keys of the on-disk form of a field (what `workflowFromFrontmatter` reads). */\nexport function fieldToFrontmatter(field: WorkflowField): Record<string, unknown> {\n return compact({\n name: field.name,\n type: field.type,\n label: field.label,\n description: field.description,\n placeholder: field.placeholder,\n required: field.required,\n default: field.default,\n options: field.options?.map((o) =>\n compact({\n value: o.value,\n label: o.label,\n description: o.description,\n text: o.text,\n icon: o.icon,\n tone: o.tone,\n })\n ),\n min: field.min,\n max: field.max,\n true_text: field.trueText,\n false_text: field.falseText,\n advanced: field.advanced,\n by: field.by,\n accept: field.accept,\n context: field.context,\n })\n}\n\nconst compact = (o: Record<string, unknown>): Record<string, unknown> =>\n Object.fromEntries(Object.entries(o).filter(([, v]) => v !== undefined))\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var react = require('react');
|
|
5
|
+
|
|
6
|
+
// src/lib/useControllableState.ts
|
|
7
|
+
function useControllableState(value, defaultValue, onChange) {
|
|
8
|
+
const [inner, setInner] = react.useState(defaultValue);
|
|
9
|
+
const isControlled = value !== void 0;
|
|
10
|
+
const current = isControlled ? value : inner;
|
|
11
|
+
const onChangeRef = react.useRef(onChange);
|
|
12
|
+
onChangeRef.current = onChange;
|
|
13
|
+
const set = react.useCallback(
|
|
14
|
+
(next) => {
|
|
15
|
+
if (!isControlled) setInner(next);
|
|
16
|
+
onChangeRef.current?.(next);
|
|
17
|
+
},
|
|
18
|
+
[isControlled]
|
|
19
|
+
);
|
|
20
|
+
return [current, set];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
exports.useControllableState = useControllableState;
|
|
24
|
+
//# sourceMappingURL=chunk-AHDJXIUB.cjs.map
|
|
25
|
+
//# sourceMappingURL=chunk-AHDJXIUB.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/useControllableState.ts"],"names":["useState","useRef","useCallback"],"mappings":";;;;;AAMO,SAAS,oBAAA,CACd,KAAA,EACA,YAAA,EACA,QAAA,EACwB;AACxB,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,eAAY,YAAY,CAAA;AAClD,EAAA,MAAM,eAAe,KAAA,KAAU,MAAA;AAC/B,EAAA,MAAM,OAAA,GAAU,eAAe,KAAA,GAAQ,KAAA;AACvC,EAAA,MAAM,WAAA,GAAcC,aAAO,QAAQ,CAAA;AACnC,EAAA,WAAA,CAAY,OAAA,GAAU,QAAA;AACtB,EAAA,MAAM,GAAA,GAAMC,iBAAA;AAAA,IACV,CAAC,IAAA,KAAY;AACX,MAAA,IAAI,CAAC,YAAA,EAAc,QAAA,CAAS,IAAI,CAAA;AAChC,MAAA,WAAA,CAAY,UAAU,IAAI,CAAA;AAAA,IAC5B,CAAA;AAAA,IACA,CAAC,YAAY;AAAA,GACf;AACA,EAAA,OAAO,CAAC,SAAS,GAAG,CAAA;AACtB","file":"chunk-AHDJXIUB.cjs","sourcesContent":["import { useCallback, useRef, useState } from 'react'\n\n/**\n * State that is controlled when `value` is passed and uncontrolled (seeded by `defaultValue`)\n * otherwise. `onChange` fires in both modes.\n */\nexport function useControllableState<T>(\n value: T | undefined,\n defaultValue: T,\n onChange?: (next: T) => void\n): [T, (next: T) => void] {\n const [inner, setInner] = useState<T>(defaultValue)\n const isControlled = value !== undefined\n const current = isControlled ? value : inner\n const onChangeRef = useRef(onChange)\n onChangeRef.current = onChange\n const set = useCallback(\n (next: T) => {\n if (!isControlled) setInner(next)\n onChangeRef.current?.(next)\n },\n [isControlled]\n )\n return [current, set]\n}\n"]}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { NativeDocxEditor } from './chunk-2FL7QJKJ.js';
|
|
3
|
+
import { useRef, useState, useEffect } from 'react';
|
|
4
|
+
import { parseVersionRef } from '@arbidocs/react/artifacts';
|
|
5
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
function redlineQuery(baseId, revisedId) {
|
|
8
|
+
const base = parseVersionRef(baseId);
|
|
9
|
+
const revised = parseVersionRef(revisedId);
|
|
10
|
+
const query = new URLSearchParams({ base_ext_id: base.docId, revised_ext_id: revised.docId });
|
|
11
|
+
if (base.version) query.set("base_version", String(base.version));
|
|
12
|
+
if (revised.version) query.set("revised_version", String(revised.version));
|
|
13
|
+
return query;
|
|
14
|
+
}
|
|
15
|
+
function NativeDocxComparison({
|
|
16
|
+
adapter,
|
|
17
|
+
baseId,
|
|
18
|
+
revisedId,
|
|
19
|
+
title,
|
|
20
|
+
onCompared
|
|
21
|
+
}) {
|
|
22
|
+
const host = useRef({ adapter, onCompared });
|
|
23
|
+
host.current = { adapter, onCompared };
|
|
24
|
+
const [documentId, setDocumentId] = useState("");
|
|
25
|
+
const [error, setError] = useState("");
|
|
26
|
+
const [attempt, setAttempt] = useState(0);
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
let cancelled = false;
|
|
29
|
+
setDocumentId("");
|
|
30
|
+
setError("");
|
|
31
|
+
void host.current.adapter.request(`/redline?${redlineQuery(baseId, revisedId)}`, { method: "POST" }).then((response) => response.json()).then((result) => {
|
|
32
|
+
if (!result.document_ext_id) throw new Error("Comparison did not return a Word document.");
|
|
33
|
+
if (!cancelled) {
|
|
34
|
+
setDocumentId(result.document_ext_id);
|
|
35
|
+
void Promise.resolve(host.current.onCompared?.(result.document_ext_id)).catch(() => {
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}).catch((error2) => {
|
|
39
|
+
if (!cancelled) setError(error2 instanceof Error ? error2.message : String(error2));
|
|
40
|
+
});
|
|
41
|
+
return () => {
|
|
42
|
+
cancelled = true;
|
|
43
|
+
};
|
|
44
|
+
}, [baseId, revisedId, attempt]);
|
|
45
|
+
if (error)
|
|
46
|
+
return /* @__PURE__ */ jsxs("div", { className: "native-docx-error", role: "alert", children: [
|
|
47
|
+
/* @__PURE__ */ jsx("p", { children: error }),
|
|
48
|
+
/* @__PURE__ */ jsx("button", { onClick: () => setAttempt((value) => value + 1), children: "Retry comparison" })
|
|
49
|
+
] });
|
|
50
|
+
if (!documentId)
|
|
51
|
+
return /* @__PURE__ */ jsx("div", { className: "native-docx-error", role: "status", children: "Comparing Word documents\u2026" });
|
|
52
|
+
return /* @__PURE__ */ jsx(
|
|
53
|
+
NativeDocxEditor,
|
|
54
|
+
{
|
|
55
|
+
adapter,
|
|
56
|
+
documentId,
|
|
57
|
+
title: `${title.replace(/\.[^.]+$/, "")} (redline).docx`
|
|
58
|
+
},
|
|
59
|
+
documentId
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
function StreamedWordArtifact({
|
|
63
|
+
adapter,
|
|
64
|
+
content,
|
|
65
|
+
title,
|
|
66
|
+
busy,
|
|
67
|
+
error,
|
|
68
|
+
documentId,
|
|
69
|
+
onSaved
|
|
70
|
+
}) {
|
|
71
|
+
if (!busy && documentId) {
|
|
72
|
+
return /* @__PURE__ */ jsx(
|
|
73
|
+
NativeDocxEditor,
|
|
74
|
+
{
|
|
75
|
+
adapter,
|
|
76
|
+
documentId,
|
|
77
|
+
title,
|
|
78
|
+
onSaved
|
|
79
|
+
},
|
|
80
|
+
documentId
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
return /* @__PURE__ */ jsx(
|
|
84
|
+
NativeDocxEditor,
|
|
85
|
+
{
|
|
86
|
+
adapter,
|
|
87
|
+
documentId: "stream-preview",
|
|
88
|
+
title,
|
|
89
|
+
draftContent: "",
|
|
90
|
+
stream: { content, busy, error }
|
|
91
|
+
},
|
|
92
|
+
"stream-preview"
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export { NativeDocxComparison, StreamedWordArtifact };
|
|
97
|
+
//# sourceMappingURL=chunk-AOSUHWIL.js.map
|
|
98
|
+
//# sourceMappingURL=chunk-AOSUHWIL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/docx/NativeDocxComparison.tsx","../src/docx/StreamedWordArtifact.tsx"],"names":["error","jsx"],"mappings":"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","file":"chunk-AOSUHWIL.js","sourcesContent":["import { useEffect, useRef, useState } from 'react'\nimport { parseVersionRef } from '@arbidocs/react/artifacts'\nimport { NativeDocxEditor, type NativeDocxAdapter } from './NativeDocxEditor'\n\nexport interface NativeDocxComparisonProps {\n adapter: NativeDocxAdapter\n baseId: string\n revisedId: string\n title: string\n onCompared?: (documentId: string) => void | Promise<void>\n}\n\n/** A `doc-…@v{n}` side names an older version: the endpoint takes its document and version apart. */\nfunction redlineQuery(baseId: string, revisedId: string): URLSearchParams {\n const base = parseVersionRef(baseId)\n const revised = parseVersionRef(revisedId)\n const query = new URLSearchParams({ base_ext_id: base.docId, revised_ext_id: revised.docId })\n if (base.version) query.set('base_version', String(base.version))\n if (revised.version) query.set('revised_version', String(revised.version))\n return query\n}\n\n/** Word comparison through the host's authenticated transport and LibreOffice service. */\nexport function NativeDocxComparison({\n adapter,\n baseId,\n revisedId,\n title,\n onCompared,\n}: NativeDocxComparisonProps) {\n const host = useRef({ adapter, onCompared })\n host.current = { adapter, onCompared }\n const [documentId, setDocumentId] = useState('')\n const [error, setError] = useState('')\n const [attempt, setAttempt] = useState(0)\n useEffect(() => {\n let cancelled = false\n setDocumentId('')\n setError('')\n void host.current.adapter\n .request(`/redline?${redlineQuery(baseId, revisedId)}`, { method: 'POST' })\n .then((response) => response.json())\n .then((result: { document_ext_id: string }) => {\n if (!result.document_ext_id) throw new Error('Comparison did not return a Word document.')\n if (!cancelled) {\n setDocumentId(result.document_ext_id)\n void Promise.resolve(host.current.onCompared?.(result.document_ext_id)).catch(() => {})\n }\n })\n .catch((error) => {\n if (!cancelled) setError(error instanceof Error ? error.message : String(error))\n })\n return () => {\n cancelled = true\n }\n }, [baseId, revisedId, attempt])\n if (error)\n return (\n <div className=\"native-docx-error\" role=\"alert\">\n <p>{error}</p>\n <button onClick={() => setAttempt((value) => value + 1)}>Retry comparison</button>\n </div>\n )\n if (!documentId)\n return (\n <div className=\"native-docx-error\" role=\"status\">\n Comparing Word documents…\n </div>\n )\n return (\n <NativeDocxEditor\n key={documentId}\n adapter={adapter}\n documentId={documentId}\n title={`${title.replace(/\\.[^.]+$/, '')} (redline).docx`}\n />\n )\n}\n","import { NativeDocxEditor, type NativeDocxAdapter } from './NativeDocxEditor'\n\nexport interface StreamedWordArtifactProps {\n adapter: NativeDocxAdapter\n /** Streamed Markdown, shown as a read-only preview while the draft is generated. */\n content: string\n title: string\n busy: boolean\n error?: string | null\n /** The DOCX draft the server stored for this generation (`doc-…`), once known. */\n documentId?: string\n onSaved?: (documentId: string) => void\n}\n\n/**\n * One drafting surface for an AI document draft. The server stores every draft as DOCX, so\n * this component never creates a document: it previews the streamed Markdown until generation\n * ends and the stored DOCX is known, then opens that DOCX in the live collaborative editor.\n */\nexport function StreamedWordArtifact({\n adapter,\n content,\n title,\n busy,\n error,\n documentId,\n onSaved,\n}: StreamedWordArtifactProps) {\n if (!busy && documentId) {\n return (\n <NativeDocxEditor\n key={documentId}\n adapter={adapter}\n documentId={documentId}\n title={title}\n onSaved={onSaved}\n />\n )\n }\n return (\n <NativeDocxEditor\n key=\"stream-preview\"\n adapter={adapter}\n documentId=\"stream-preview\"\n title={title}\n draftContent=\"\"\n stream={{ content, busy, error }}\n />\n )\n}\n"]}
|