@signalcore/ui 1.0.0-beta.2 → 1.0.0-beta.3
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/README.md +47 -21
- package/dist/AgentAbout.js +6 -2
- package/dist/AgentAbout.js.map +1 -1
- package/dist/AgentChat.d.ts +7 -1
- package/dist/AgentChat.js +154 -2
- package/dist/AgentChat.js.map +1 -1
- package/dist/AgentSpace.d.ts +12 -3
- package/dist/AgentSpace.js +53 -11
- package/dist/AgentSpace.js.map +1 -1
- package/dist/Threads.d.ts +73 -0
- package/dist/Threads.js +140 -0
- package/dist/Threads.js.map +1 -0
- package/dist/automation/marks.js +7 -3
- package/dist/automation/marks.js.map +1 -1
- package/dist/automation/messages.d.ts +4 -0
- package/dist/automation/messages.js +5 -1
- package/dist/automation/messages.js.map +1 -1
- package/dist/automation/when.js +8 -0
- package/dist/automation/when.js.map +1 -1
- package/dist/client.d.ts +14 -4
- package/dist/client.js +7 -2
- package/dist/client.js.map +1 -1
- package/dist/contract.d.ts +9 -4
- package/dist/es.d.ts +2 -0
- package/dist/es.js +22 -3
- package/dist/es.js.map +1 -1
- package/dist/frames.d.ts +7 -1
- package/dist/frames.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.js +5 -4
- package/dist/surface/Form.js +1 -1
- package/dist/types.d.ts +11 -0
- package/dist/types.js.map +1 -1
- package/dist/useConversation.d.ts +2 -0
- package/dist/useConversation.js +16 -0
- package/dist/useConversation.js.map +1 -1
- package/dist/widget.js +17 -16
- package/package.json +1 -1
- package/src/AgentAbout.tsx +4 -0
- package/src/AgentChat.tsx +203 -1
- package/src/AgentSpace.tsx +89 -13
- package/src/Threads.tsx +218 -0
- package/src/automation/marks.tsx +7 -0
- package/src/automation/messages.ts +8 -0
- package/src/automation/when.ts +4 -0
- package/src/client.ts +26 -10
- package/src/contract.ts +240 -26
- package/src/es.ts +21 -0
- package/src/frames.ts +3 -1
- package/src/index.ts +9 -1
- package/src/styles.css +191 -0
- package/src/types.ts +11 -0
- package/src/useConversation.ts +10 -0
- package/src/widget/element.tsx +13 -4
- package/src/widget/widget.css +13 -0
package/dist/AgentChat.js
CHANGED
|
@@ -2,6 +2,7 @@ import { actionWords } from "./about.js";
|
|
|
2
2
|
import { classes } from "./classes.js";
|
|
3
3
|
import { KIT_MESSAGES } from "./kit/messages.js";
|
|
4
4
|
import { KitProvider } from "./kit/context.js";
|
|
5
|
+
import { Button } from "./kit/Button.js";
|
|
5
6
|
import { actionMark } from "./marks.js";
|
|
6
7
|
import { BROWSER_MESSAGES, BrowserView } from "./BrowserView.js";
|
|
7
8
|
import { channelParts } from "./channelParts.js";
|
|
@@ -10,6 +11,8 @@ import { useReveal } from "./reveal.js";
|
|
|
10
11
|
import { useConversationFiles } from "./conversationFiles.js";
|
|
11
12
|
import "./frames.js";
|
|
12
13
|
import { AudioPlayer } from "./kit/AudioPlayer.js";
|
|
14
|
+
import { Field } from "./kit/Field.js";
|
|
15
|
+
import { Checkbox, NumberInput, TextArea, TextInput } from "./kit/Inputs.js";
|
|
13
16
|
import { FileChips, UploadChips, carriesFiles, useUploads } from "./kit/FileField.js";
|
|
14
17
|
import { stepGlyph } from "./stepGlyphs.js";
|
|
15
18
|
import { Markdown } from "./surface/Markdown.js";
|
|
@@ -54,6 +57,10 @@ const CHAT_MESSAGES = {
|
|
|
54
57
|
inputs: {},
|
|
55
58
|
allow: "Allow",
|
|
56
59
|
decline: "Decline",
|
|
60
|
+
approvals: (count) => `${count} actions need your approval`,
|
|
61
|
+
approveAll: "Approve all",
|
|
62
|
+
approveSome: (count) => `Approve ${count}`,
|
|
63
|
+
declineAll: "Decline all",
|
|
57
64
|
confirming: "Waiting for the business to confirm",
|
|
58
65
|
handedOff: "Handed to a person",
|
|
59
66
|
handover: (holder, by, name) => {
|
|
@@ -125,6 +132,7 @@ function Chat({ client, conversationId, name, messages, classNames, components,
|
|
|
125
132
|
onTool: onTool ?? (() => Promise.reject(new Error(words.noTool)))
|
|
126
133
|
});
|
|
127
134
|
const files = useConversationFiles(client, conversationId, live.messages, onOpenFile);
|
|
135
|
+
useReadAsShown(client, conversationId, live.messages.at(-1)?.id);
|
|
128
136
|
const uploads = useUploads(attachments ? files : void 0, { max: 10 });
|
|
129
137
|
const attaching = attachments && (write !== void 0 || live.awaiting === null);
|
|
130
138
|
const [over, setOver] = useState(false);
|
|
@@ -449,6 +457,7 @@ function Log({ live, name, words, classNames, components, locale, following, too
|
|
|
449
457
|
components,
|
|
450
458
|
locale,
|
|
451
459
|
onAction: live.act,
|
|
460
|
+
onActAll: live.actAll,
|
|
452
461
|
builder,
|
|
453
462
|
files,
|
|
454
463
|
who,
|
|
@@ -670,8 +679,9 @@ function DeliveryMark({ message, words, classNames }) {
|
|
|
670
679
|
* for (on a person's page, one the business allows is a quiet line instead); on a channel, where
|
|
671
680
|
* it got to.
|
|
672
681
|
*/
|
|
673
|
-
function Reply({ message, from, awaiting, current, answers, name, words, classNames, components, locale, onAction, builder, files, who, steps, onChannel }) {
|
|
682
|
+
function Reply({ message, from, awaiting, current, answers, name, words, classNames, components, locale, onAction, builder, files, who, steps, onChannel, onActAll }) {
|
|
674
683
|
const text = useReveal(message.text, from ?? message.text.length);
|
|
684
|
+
const asked = message.steps.filter((step) => step.request !== null && !(step.request.decides === "business" && who === "person"));
|
|
675
685
|
const { shown: said, typing } = onChannel ? channelParts(message, text) : {
|
|
676
686
|
shown: [text],
|
|
677
687
|
typing: false
|
|
@@ -735,9 +745,16 @@ function Reply({ message, from, awaiting, current, answers, name, words, classNa
|
|
|
735
745
|
})
|
|
736
746
|
})
|
|
737
747
|
}, step.id)),
|
|
748
|
+
asked.length > 1 && /* @__PURE__ */ jsx(Approvals, {
|
|
749
|
+
steps: asked,
|
|
750
|
+
name,
|
|
751
|
+
words,
|
|
752
|
+
classNames,
|
|
753
|
+
onActAll
|
|
754
|
+
}, asked.map((step) => step.id).join()),
|
|
738
755
|
message.steps.map((step) => {
|
|
739
756
|
const { request } = step;
|
|
740
|
-
if (request === null) return null;
|
|
757
|
+
if (request === null || asked.length > 1 && asked.some((one) => one.id === step.id)) return null;
|
|
741
758
|
if (request.decides === "business" && who === "person") return /* @__PURE__ */ jsxs("p", {
|
|
742
759
|
part: "confirming",
|
|
743
760
|
className: classes(classNames, "sc-chat__confirming"),
|
|
@@ -938,6 +955,141 @@ function Approval({ request, name, words, classNames, components, locale, onActi
|
|
|
938
955
|
});
|
|
939
956
|
}
|
|
940
957
|
/**
|
|
958
|
+
* Several actions a reply waits on the person's leave for, in one card: a box to tick for each
|
|
959
|
+
* (all ticked to begin with), what each would take under it, editable while ticked, and one
|
|
960
|
+
* button that sends a yes for each ticked (with what was changed) and a no for the rest, at once.
|
|
961
|
+
*/
|
|
962
|
+
function Approvals({ steps, name, words, classNames, onActAll }) {
|
|
963
|
+
const [chosen, setChosen] = useState(() => new Set(steps.map((step) => step.id)));
|
|
964
|
+
const [edits, setEdits] = useState({});
|
|
965
|
+
const [sent, setSent] = useState(false);
|
|
966
|
+
const inputOf = (step) => ({
|
|
967
|
+
...step.request.input,
|
|
968
|
+
...edits[step.id]
|
|
969
|
+
});
|
|
970
|
+
const send = () => {
|
|
971
|
+
setSent(true);
|
|
972
|
+
onActAll(steps.map((step) => chosen.has(step.id) ? {
|
|
973
|
+
surface: step.id,
|
|
974
|
+
name: "approve",
|
|
975
|
+
data: step.id in edits ? { input: inputOf(step) } : {},
|
|
976
|
+
label: words.allow
|
|
977
|
+
} : {
|
|
978
|
+
surface: step.id,
|
|
979
|
+
name: "decline",
|
|
980
|
+
data: {},
|
|
981
|
+
label: words.decline
|
|
982
|
+
}));
|
|
983
|
+
};
|
|
984
|
+
const label = chosen.size === steps.length ? words.approveAll : chosen.size === 0 ? words.declineAll : words.approveSome(chosen.size);
|
|
985
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
986
|
+
part: "approval",
|
|
987
|
+
className: classes(classNames, "sc-chat__request", "sc-chat__requests"),
|
|
988
|
+
children: [
|
|
989
|
+
/* @__PURE__ */ jsxs("header", { children: [/* @__PURE__ */ jsx(ShieldWarningIcon, { "aria-hidden": true }), words.approvals(steps.length)] }),
|
|
990
|
+
/* @__PURE__ */ jsx("ul", { children: steps.map((step) => {
|
|
991
|
+
const ticked = chosen.has(step.id);
|
|
992
|
+
return /* @__PURE__ */ jsxs("li", {
|
|
993
|
+
className: classes(classNames, "sc-chat__ask"),
|
|
994
|
+
children: [/* @__PURE__ */ jsx(Checkbox, {
|
|
995
|
+
value: ticked,
|
|
996
|
+
disabled: sent,
|
|
997
|
+
onChange: (on) => {
|
|
998
|
+
setChosen((last) => {
|
|
999
|
+
const next = new Set(last);
|
|
1000
|
+
if (on) next.add(step.id);
|
|
1001
|
+
else next.delete(step.id);
|
|
1002
|
+
return next;
|
|
1003
|
+
});
|
|
1004
|
+
},
|
|
1005
|
+
children: words.request(name, step.request.action)
|
|
1006
|
+
}), ticked && /* @__PURE__ */ jsx("div", {
|
|
1007
|
+
className: classes(classNames, "sc-chat__ask-fields"),
|
|
1008
|
+
children: Object.entries(inputOf(step)).map(([field, value]) => /* @__PURE__ */ jsx(InputValue, {
|
|
1009
|
+
label: words.inputs[field] ?? field,
|
|
1010
|
+
value,
|
|
1011
|
+
disabled: sent,
|
|
1012
|
+
onChange: (changed) => {
|
|
1013
|
+
setEdits((last) => ({
|
|
1014
|
+
...last,
|
|
1015
|
+
[step.id]: {
|
|
1016
|
+
...last[step.id],
|
|
1017
|
+
[field]: changed
|
|
1018
|
+
}
|
|
1019
|
+
}));
|
|
1020
|
+
}
|
|
1021
|
+
}, field))
|
|
1022
|
+
})]
|
|
1023
|
+
}, step.id);
|
|
1024
|
+
}) }),
|
|
1025
|
+
/* @__PURE__ */ jsx("footer", { children: /* @__PURE__ */ jsx(Button, {
|
|
1026
|
+
tone: "primary",
|
|
1027
|
+
disabled: sent,
|
|
1028
|
+
onClick: send,
|
|
1029
|
+
children: label
|
|
1030
|
+
}) })
|
|
1031
|
+
]
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
* One field of an action's input, editable as what it holds: words, a number, a yes or no;
|
|
1036
|
+
* anything else (a list, an object) shown as it is.
|
|
1037
|
+
*/
|
|
1038
|
+
function InputValue({ label, value, disabled, onChange }) {
|
|
1039
|
+
if (typeof value === "boolean") return /* @__PURE__ */ jsx(Checkbox, {
|
|
1040
|
+
value,
|
|
1041
|
+
disabled,
|
|
1042
|
+
onChange,
|
|
1043
|
+
children: label
|
|
1044
|
+
});
|
|
1045
|
+
return /* @__PURE__ */ jsx(Field, {
|
|
1046
|
+
label,
|
|
1047
|
+
children: (ids) => typeof value === "number" ? /* @__PURE__ */ jsx(NumberInput, {
|
|
1048
|
+
...ids,
|
|
1049
|
+
value,
|
|
1050
|
+
disabled,
|
|
1051
|
+
onChange
|
|
1052
|
+
}) : typeof value === "string" ? value.length > 80 || value.includes("\n") ? /* @__PURE__ */ jsx(TextArea, {
|
|
1053
|
+
...ids,
|
|
1054
|
+
value,
|
|
1055
|
+
disabled,
|
|
1056
|
+
onChange
|
|
1057
|
+
}) : /* @__PURE__ */ jsx(TextInput, {
|
|
1058
|
+
...ids,
|
|
1059
|
+
value,
|
|
1060
|
+
disabled,
|
|
1061
|
+
onChange
|
|
1062
|
+
}) : /* @__PURE__ */ jsx(TextInput, {
|
|
1063
|
+
...ids,
|
|
1064
|
+
value: JSON.stringify(value),
|
|
1065
|
+
disabled: true,
|
|
1066
|
+
onChange: () => void 0
|
|
1067
|
+
})
|
|
1068
|
+
});
|
|
1069
|
+
}
|
|
1070
|
+
/**
|
|
1071
|
+
* On a person's page, what came is read as the chat shows it: each newest message while the page
|
|
1072
|
+
* is in sight, and once it comes back into sight. Their threads' `unread` follows.
|
|
1073
|
+
*/
|
|
1074
|
+
function useReadAsShown(client, conversationId, newest) {
|
|
1075
|
+
useEffect(() => {
|
|
1076
|
+
if (client.who !== "person" || newest === void 0) return void 0;
|
|
1077
|
+
const read = () => {
|
|
1078
|
+
if (document.visibilityState === "hidden") return;
|
|
1079
|
+
client.conversations.read(conversationId).catch(() => void 0);
|
|
1080
|
+
};
|
|
1081
|
+
read();
|
|
1082
|
+
document.addEventListener("visibilitychange", read);
|
|
1083
|
+
return () => {
|
|
1084
|
+
document.removeEventListener("visibilitychange", read);
|
|
1085
|
+
};
|
|
1086
|
+
}, [
|
|
1087
|
+
client,
|
|
1088
|
+
conversationId,
|
|
1089
|
+
newest
|
|
1090
|
+
]);
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
941
1093
|
* Where the person writes: a box that grows a few lines with the text. Enter sends, Shift+Enter
|
|
942
1094
|
* breaks the line; nothing goes while a reply is on its way or the socket is closed, but the
|
|
943
1095
|
* person can keep writing. While the turn waits for them to act above, the box is closed and
|