@athenaintel/react 0.56.0 → 0.57.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +75 -1
  2. package/dist/agent-runtime/src/inbound-channel.cjs +96 -0
  3. package/dist/agent-runtime/src/inbound-channel.cjs.map +1 -0
  4. package/dist/agent-runtime/src/inbound-channel.d.ts +75 -0
  5. package/dist/agent-runtime/src/inbound-channel.js +96 -0
  6. package/dist/agent-runtime/src/inbound-channel.js.map +1 -0
  7. package/dist/agent-runtime/src/index.d.ts +2 -1
  8. package/dist/agent-runtime/src/interrupts.cjs +45 -3
  9. package/dist/agent-runtime/src/interrupts.cjs.map +1 -1
  10. package/dist/agent-runtime/src/interrupts.d.ts +51 -4
  11. package/dist/agent-runtime/src/interrupts.js +46 -4
  12. package/dist/agent-runtime/src/interrupts.js.map +1 -1
  13. package/dist/agent-runtime/src/offline-status.cjs.map +1 -1
  14. package/dist/agent-runtime/src/offline-status.d.ts +25 -0
  15. package/dist/agent-runtime/src/offline-status.js.map +1 -1
  16. package/dist/agent-runtime/src/thread-handoff-flow-machine.d.ts +8 -8
  17. package/dist/agent-runtime/src/tool-metadata.cjs +8 -0
  18. package/dist/agent-runtime/src/tool-metadata.cjs.map +1 -1
  19. package/dist/agent-runtime/src/tool-metadata.js +8 -0
  20. package/dist/agent-runtime/src/tool-metadata.js.map +1 -1
  21. package/dist/auth/AthenaSSOProvider.cjs +54 -12
  22. package/dist/auth/AthenaSSOProvider.cjs.map +1 -1
  23. package/dist/auth/AthenaSSOProvider.d.ts +23 -2
  24. package/dist/auth/AthenaSSOProvider.js +54 -12
  25. package/dist/auth/AthenaSSOProvider.js.map +1 -1
  26. package/dist/auth/index.cjs +2 -0
  27. package/dist/auth/index.cjs.map +1 -1
  28. package/dist/auth/index.d.ts +1 -0
  29. package/dist/auth/index.js +2 -0
  30. package/dist/auth/index.js.map +1 -1
  31. package/dist/auth/sign-back-in.cjs +141 -0
  32. package/dist/auth/sign-back-in.cjs.map +1 -0
  33. package/dist/auth/sign-back-in.d.ts +117 -0
  34. package/dist/auth/sign-back-in.js +141 -0
  35. package/dist/auth/sign-back-in.js.map +1 -0
  36. package/dist/chat/AthenaChat.cjs +21 -3
  37. package/dist/chat/AthenaChat.cjs.map +1 -1
  38. package/dist/chat/AthenaChat.js +21 -3
  39. package/dist/chat/AthenaChat.js.map +1 -1
  40. package/dist/chat/StatewireApprovalCard.cjs +6 -2
  41. package/dist/chat/StatewireApprovalCard.cjs.map +1 -1
  42. package/dist/chat/StatewireApprovalCard.d.ts +8 -1
  43. package/dist/chat/StatewireApprovalCard.js +7 -3
  44. package/dist/chat/StatewireApprovalCard.js.map +1 -1
  45. package/dist/chat-ui/index.cjs +5 -0
  46. package/dist/chat-ui/index.cjs.map +1 -1
  47. package/dist/chat-ui/index.d.ts +1 -0
  48. package/dist/chat-ui/index.js +6 -1
  49. package/dist/chat-ui/index.js.map +1 -1
  50. package/dist/chat-ui/messages/inbound-channel-message.cjs +242 -0
  51. package/dist/chat-ui/messages/inbound-channel-message.cjs.map +1 -0
  52. package/dist/chat-ui/messages/inbound-channel-message.d.ts +53 -0
  53. package/dist/chat-ui/messages/inbound-channel-message.js +242 -0
  54. package/dist/chat-ui/messages/inbound-channel-message.js.map +1 -0
  55. package/dist/chat-ui/messages/inbound-channel-reader.cjs +184 -0
  56. package/dist/chat-ui/messages/inbound-channel-reader.cjs.map +1 -0
  57. package/dist/chat-ui/messages/inbound-channel-reader.d.ts +65 -0
  58. package/dist/chat-ui/messages/inbound-channel-reader.js +184 -0
  59. package/dist/chat-ui/messages/inbound-channel-reader.js.map +1 -0
  60. package/dist/chat-ui/messages/message-components.cjs +32 -15
  61. package/dist/chat-ui/messages/message-components.cjs.map +1 -1
  62. package/dist/chat-ui/messages/message-components.d.ts +7 -0
  63. package/dist/chat-ui/messages/message-components.js +33 -16
  64. package/dist/chat-ui/messages/message-components.js.map +1 -1
  65. package/dist/composer/sign-back-in-draft.cjs +62 -0
  66. package/dist/composer/sign-back-in-draft.cjs.map +1 -0
  67. package/dist/composer/sign-back-in-draft.d.ts +34 -0
  68. package/dist/composer/sign-back-in-draft.js +62 -0
  69. package/dist/composer/sign-back-in-draft.js.map +1 -0
  70. package/dist/diagnostics/athena-diagnostics.cjs.map +1 -1
  71. package/dist/diagnostics/athena-diagnostics.d.ts +6 -1
  72. package/dist/diagnostics/athena-diagnostics.js.map +1 -1
  73. package/dist/index.cjs +9 -0
  74. package/dist/index.cjs.map +1 -1
  75. package/dist/index.d.ts +2 -0
  76. package/dist/index.js +9 -0
  77. package/dist/index.js.map +1 -1
  78. package/dist/provider/AthenaProvider.cjs +48 -3
  79. package/dist/provider/AthenaProvider.cjs.map +1 -1
  80. package/dist/provider/AthenaProvider.js +49 -4
  81. package/dist/provider/AthenaProvider.js.map +1 -1
  82. package/dist/react/package.json.cjs +1 -1
  83. package/dist/react/package.json.js +1 -1
  84. package/dist/runtime/auth.cjs +11 -0
  85. package/dist/runtime/auth.cjs.map +1 -1
  86. package/dist/runtime/auth.d.ts +18 -1
  87. package/dist/runtime/auth.js +11 -0
  88. package/dist/runtime/auth.js.map +1 -1
  89. package/dist/styles.css +1 -1
  90. package/package.json +1 -1
@@ -34,6 +34,7 @@ import { TextShimmerLoader, ThreadRunningIndicator } from "./messages/running-in
34
34
  import { SignInCard, SignInConsent, SignInFallbackSection, SignInSecondaryButton, SignInSelect, SignInTextField } from "./auth/sign-in-card.js";
35
35
  import { RuntimeMessageCard } from "./messages/runtime-message.js";
36
36
  import { WakeMarkerCard, WakeMarkerMessage } from "./messages/wake-marker.js";
37
+ import { InboundChannelLine, InboundChannelSubject, useUserMessageCopy, withInboundMessageBody } from "./messages/inbound-channel-message.js";
37
38
  import { HandoffArrivalAfterMessage, HandoffArrivalDivider, HandoffArrivalScope } from "./messages/handoff-arrival-divider.js";
38
39
  import { AnswerLabel, AnswerLabelScope } from "./messages/answer-label.js";
39
40
  import { VoiceDelegationCard, VoiceDelegationMessage } from "./messages/voice-delegation-card.js";
@@ -83,6 +84,8 @@ export {
83
84
  HandoffCursorReveal,
84
85
  HistoryEdgeRow,
85
86
  IconButton,
87
+ InboundChannelLine,
88
+ InboundChannelSubject,
86
89
  MESSAGE_ARRIVAL_ANIMATION_CLASS,
87
90
  MarkdownText,
88
91
  MentionAuthCtx,
@@ -167,6 +170,8 @@ export {
167
170
  useReadThreadReadingCursor,
168
171
  useStatewireApprovalRequest,
169
172
  useStatewireToolOutputs,
170
- webpageMentionFingerprint
173
+ useUserMessageCopy,
174
+ webpageMentionFingerprint,
175
+ withInboundMessageBody
171
176
  };
172
177
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,242 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const react$1 = require("@assistant-ui/core/react");
5
+ const react = require("@assistant-ui/react");
6
+ const lucideReact = require("lucide-react");
7
+ const require$$0 = require("react");
8
+ const collapsible = require("../../ui/collapsible.cjs");
9
+ const inboundChannelReader = require("./inbound-channel-reader.cjs");
10
+ const inboundChannel = require("../../agent-runtime/src/inbound-channel.cjs");
11
+ const cnfast = require("cnfast");
12
+ const SlackMark = ({ className }) => /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 2447.6 2452.5", className, "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ jsxRuntime.jsxs("g", { clipRule: "evenodd", fillRule: "evenodd", children: [
13
+ /* @__PURE__ */ jsxRuntime.jsx(
14
+ "path",
15
+ {
16
+ d: "m897.4 0c-135.3.1-244.8 109.9-244.7 245.2-.1 135.3 109.5 245.1 244.8 245.2h244.8v-245.1c.1-135.3-109.5-245.1-244.9-245.3.1 0 .1 0 0 0m0 654h-652.6c-135.3.1-244.9 109.9-244.8 245.2-.2 135.3 109.4 245.1 244.7 245.3h652.7c135.3-.1 244.9-109.9 244.8-245.2.1-135.4-109.5-245.2-244.8-245.3z",
17
+ fill: "#36c5f0"
18
+ }
19
+ ),
20
+ /* @__PURE__ */ jsxRuntime.jsx(
21
+ "path",
22
+ {
23
+ d: "m2447.6 899.2c.1-135.3-109.5-245.1-244.8-245.2-135.3.1-244.9 109.9-244.8 245.2v245.3h244.8c135.3-.1 244.9-109.9 244.8-245.3zm-652.7 0v-654c.1-135.2-109.4-245-244.7-245.2-135.3.1-244.9 109.9-244.8 245.2v654c-.2 135.3 109.4 245.1 244.7 245.3 135.3-.1 244.9-109.9 244.8-245.3z",
24
+ fill: "#2eb67d"
25
+ }
26
+ ),
27
+ /* @__PURE__ */ jsxRuntime.jsx(
28
+ "path",
29
+ {
30
+ d: "m1550.1 2452.5c135.3-.1 244.9-109.9 244.8-245.2.1-135.3-109.5-245.1-244.8-245.2h-244.8v245.2c-.1 135.2 109.5 245 244.8 245.2zm0-654.1h652.7c135.3-.1 244.9-109.9 244.8-245.2.2-135.3-109.4-245.1-244.7-245.3h-652.7c-135.3.1-244.9 109.9-244.8 245.2-.1 135.4 109.4 245.2 244.7 245.3z",
31
+ fill: "#ecb22e"
32
+ }
33
+ ),
34
+ /* @__PURE__ */ jsxRuntime.jsx(
35
+ "path",
36
+ {
37
+ d: "m0 1553.2c-.1 135.3 109.5 245.1 244.8 245.2 135.3-.1 244.9-109.9 244.8-245.2v-245.2h-244.8c-135.3.1-244.9 109.9-244.8 245.2zm652.7 0v654c-.2 135.3 109.4 245.1 244.7 245.3 135.3-.1 244.9-109.9 244.8-245.2v-653.9c.2-135.3-109.4-245.1-244.7-245.3-135.4 0-244.9 109.8-244.8 245.1 0 0 0 .1 0 0",
38
+ fill: "#e01e5a"
39
+ }
40
+ )
41
+ ] }) });
42
+ const TeamsMark = ({ className }) => /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 2228.833 2073.333", className, "aria-hidden": "true", focusable: "false", children: [
43
+ /* @__PURE__ */ jsxRuntime.jsx(
44
+ "path",
45
+ {
46
+ fill: "#5059C9",
47
+ d: "M1554.637 777.5h575.713c54.391 0 98.483 44.092 98.483 98.483v524.398c0 199.901-162.051 361.952-361.952 361.952h-1.711c-199.901.028-361.975-162-362.004-361.901V828.971c0-28.427 23.044-51.471 51.471-51.471z"
48
+ }
49
+ ),
50
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { fill: "#5059C9", cx: "1943.75", cy: "440.583", r: "233.25" }),
51
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { fill: "#7B83EB", cx: "1218.083", cy: "336.917", r: "336.917" }),
52
+ /* @__PURE__ */ jsxRuntime.jsx(
53
+ "path",
54
+ {
55
+ fill: "#7B83EB",
56
+ d: "M1667.323 777.5H717.01c-53.743 1.33-96.257 45.931-95.01 99.676v598.105c-7.505 322.519 247.657 590.16 570.167 598.053 322.51-7.893 577.671-275.534 570.167-598.053V877.176c1.245-53.745-41.268-98.346-95.011-99.676z"
57
+ }
58
+ ),
59
+ /* @__PURE__ */ jsxRuntime.jsx(
60
+ "path",
61
+ {
62
+ fill: "#4B53BC",
63
+ d: "M95.01 466.5h950.312c52.473 0 95.01 42.538 95.01 95.01v950.312c0 52.473-42.538 95.01-95.01 95.01H95.01c-52.473 0-95.01-42.538-95.01-95.01V561.51c0-52.472 42.538-95.01 95.01-95.01z"
64
+ }
65
+ ),
66
+ /* @__PURE__ */ jsxRuntime.jsx("path", { fill: "#FFF", d: "M820.211 828.193H630.241v517.297H509.211V828.193H320.123V727.844h500.088z" })
67
+ ] });
68
+ const ChannelMark = ({
69
+ kind,
70
+ className
71
+ }) => {
72
+ switch (kind) {
73
+ case "slack":
74
+ return /* @__PURE__ */ jsxRuntime.jsx(SlackMark, { className });
75
+ case "teams":
76
+ return /* @__PURE__ */ jsxRuntime.jsx(TeamsMark, { className });
77
+ case "email":
78
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MailIcon, { className: cnfast.cn("text-sky-600", className), "aria-hidden": "true" });
79
+ case "sms":
80
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquareIcon, { className: cnfast.cn("text-emerald-600", className), "aria-hidden": "true" });
81
+ case "api":
82
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CodeIcon, { className: cnfast.cn("text-muted-foreground", className), "aria-hidden": "true" });
83
+ case "voice_memo":
84
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AudioLinesIcon, { className: cnfast.cn("text-violet-600", className), "aria-hidden": "true" });
85
+ default:
86
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquareIcon, { className: cnfast.cn("text-muted-foreground", className), "aria-hidden": "true" });
87
+ }
88
+ };
89
+ function firstText(parts) {
90
+ if (!Array.isArray(parts)) return "";
91
+ for (const part of parts) {
92
+ if (typeof part === "object" && part !== null && part.type === "text" && typeof part.text === "string") {
93
+ return part.text;
94
+ }
95
+ }
96
+ return "";
97
+ }
98
+ const InboundChannelFacts = ({ message }) => /* @__PURE__ */ jsxRuntime.jsxs(
99
+ "div",
100
+ {
101
+ className: "flex w-full min-w-0 flex-col gap-2 rounded-xl border border-border bg-background px-3 py-2.5 text-left text-xs",
102
+ "data-slot": "inbound-channel-facts",
103
+ children: [
104
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: "What the agent received with this message" }),
105
+ message.facts.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("dl", { className: "grid grid-cols-[auto_minmax(0,1fr)] gap-x-3 gap-y-1", children: message.facts.map((fact, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "contents", children: [
106
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { className: "whitespace-nowrap text-muted-foreground", children: fact.label }),
107
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { className: "text-foreground [overflow-wrap:anywhere]", children: fact.value })
108
+ ] }, `${fact.key}-${index}`)) }) : null,
109
+ message.quoted ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
110
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: "Earlier in the thread" }),
111
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "whitespace-pre-wrap border-border border-l-2 pl-2 text-foreground [overflow-wrap:anywhere]", children: message.quoted })
112
+ ] }) : null
113
+ ]
114
+ }
115
+ );
116
+ const InboundChannelSource = ({
117
+ message,
118
+ className
119
+ }) => {
120
+ const [open, setOpen] = require$$0.useState(false);
121
+ const origin = message.origin;
122
+ const name = origin.senderName;
123
+ const handle = origin.senderHandle;
124
+ const primary = name ?? handle ?? origin.label;
125
+ const secondary = name && handle ? handle : null;
126
+ const channelLine = [origin.label, origin.place].filter(Boolean).join(" · ");
127
+ return /* @__PURE__ */ jsxRuntime.jsxs(
128
+ collapsible.Collapsible,
129
+ {
130
+ open,
131
+ onOpenChange: setOpen,
132
+ className: cnfast.cn("flex w-full min-w-0 flex-col items-end gap-1", className),
133
+ "data-slot": "inbound-channel",
134
+ "data-channel": origin.kind,
135
+ children: [
136
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group/inbound-channel relative flex min-w-0 max-w-full justify-end", children: [
137
+ /* @__PURE__ */ jsxRuntime.jsxs(
138
+ collapsible.CollapsibleTrigger,
139
+ {
140
+ "data-testid": "inbound-channel-source",
141
+ className: "flex min-w-0 max-w-full items-center gap-1.5 rounded-md px-1.5 py-0.5 text-muted-foreground text-xs transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
142
+ children: [
143
+ /* @__PURE__ */ jsxRuntime.jsx(ChannelMark, { kind: origin.kind, className: "size-3.5 shrink-0" }),
144
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium text-foreground/80", children: primary }),
145
+ secondary ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: secondary }) : null,
146
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: `, via ${channelLine}. Show what the agent received` }),
147
+ /* @__PURE__ */ jsxRuntime.jsx(
148
+ lucideReact.ChevronDownIcon,
149
+ {
150
+ className: cnfast.cn("size-3 shrink-0 transition-transform", open && "rotate-180"),
151
+ "aria-hidden": "true"
152
+ }
153
+ )
154
+ ]
155
+ }
156
+ ),
157
+ open ? null : /* @__PURE__ */ jsxRuntime.jsxs(
158
+ "div",
159
+ {
160
+ "aria-hidden": "true",
161
+ "data-slot": "inbound-channel-card",
162
+ className: "pointer-events-none absolute top-full right-0 z-20 mt-1 flex w-max max-w-xs flex-col gap-0.5 rounded-md bg-foreground px-3 py-1.5 text-left text-background text-xs opacity-0 shadow-md transition-opacity delay-0 group-focus-within/inbound-channel:opacity-100 group-hover/inbound-channel:opacity-100 group-hover/inbound-channel:delay-300",
163
+ children: [
164
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5 font-medium", children: [
165
+ /* @__PURE__ */ jsxRuntime.jsx(ChannelMark, { kind: origin.kind, className: "size-3.5 shrink-0" }),
166
+ channelLine
167
+ ] }),
168
+ name ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: name }) : null,
169
+ handle ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-80", children: handle }) : null,
170
+ origin.subject ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-80", children: `${origin.kind === "voice_memo" ? "Memo" : "Subject"}: ${origin.subject}` }) : null
171
+ ]
172
+ }
173
+ )
174
+ ] }),
175
+ /* @__PURE__ */ jsxRuntime.jsx(collapsible.CollapsibleContent, { className: "w-full min-w-0", children: /* @__PURE__ */ jsxRuntime.jsx(InboundChannelFacts, { message }) })
176
+ ]
177
+ }
178
+ );
179
+ };
180
+ const InboundChannelLine = ({ className }) => {
181
+ const custom = react.useAuiState((s) => {
182
+ var _a;
183
+ return (_a = s.message.metadata) == null ? void 0 : _a.custom;
184
+ });
185
+ const parts = react.useAuiState((s) => s.message.parts);
186
+ const message = require$$0.useMemo(
187
+ () => inboundChannel.isInboundChannelMessage(custom) ? inboundChannelReader.readInboundChannelMessage({ custom, text: firstText(parts) }) : null,
188
+ [custom, parts]
189
+ );
190
+ return message ? /* @__PURE__ */ jsxRuntime.jsx(InboundChannelSource, { message, className }) : null;
191
+ };
192
+ const InboundChannelSubject = () => {
193
+ const subject = react.useAuiState((s) => {
194
+ var _a;
195
+ return inboundChannel.inboundEmailSubject((_a = s.message.metadata) == null ? void 0 : _a.custom);
196
+ });
197
+ if (!subject) return null;
198
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-1 font-semibold", "data-slot": "inbound-channel-subject", children: subject });
199
+ };
200
+ const wrappedTextComponents = /* @__PURE__ */ new WeakMap();
201
+ function withInboundMessageBody(Text) {
202
+ const cached = wrappedTextComponents.get(Text);
203
+ if (cached) return cached;
204
+ const InboundMessageBodyText = (props) => {
205
+ const custom = react.useAuiState((s) => {
206
+ var _a;
207
+ return (_a = s.message.metadata) == null ? void 0 : _a.custom;
208
+ });
209
+ const text = require$$0.useMemo(() => inboundChannel.inboundMessageBody({ custom, text: props.text }), [custom, props.text]);
210
+ return /* @__PURE__ */ jsxRuntime.jsx(Text, { ...props, text });
211
+ };
212
+ wrappedTextComponents.set(Text, InboundMessageBodyText);
213
+ return InboundMessageBodyText;
214
+ }
215
+ function writeClipboard(text) {
216
+ if (typeof navigator === "undefined" || !navigator.clipboard) {
217
+ return Promise.reject(new Error("Clipboard API is unavailable"));
218
+ }
219
+ return navigator.clipboard.writeText(text);
220
+ }
221
+ function useUserMessageCopy() {
222
+ const custom = react.useAuiState((s) => {
223
+ var _a;
224
+ return (_a = s.message.metadata) == null ? void 0 : _a.custom;
225
+ });
226
+ const copyToClipboard = require$$0.useCallback(
227
+ (text) => {
228
+ const words = inboundChannel.inboundMessageBody({ custom, text });
229
+ const subject = inboundChannel.inboundEmailSubject(custom);
230
+ return writeClipboard(subject ? [subject, words].filter(Boolean).join("\n\n") : words);
231
+ },
232
+ [custom]
233
+ );
234
+ return react$1.useActionBarCopy({ copyToClipboard });
235
+ }
236
+ exports.ChannelMark = ChannelMark;
237
+ exports.InboundChannelLine = InboundChannelLine;
238
+ exports.InboundChannelSource = InboundChannelSource;
239
+ exports.InboundChannelSubject = InboundChannelSubject;
240
+ exports.useUserMessageCopy = useUserMessageCopy;
241
+ exports.withInboundMessageBody = withInboundMessageBody;
242
+ //# sourceMappingURL=inbound-channel-message.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbound-channel-message.cjs","sources":["../../../src/chat-ui/messages/inbound-channel-message.tsx"],"sourcesContent":["/**\n * A user turn that came in over a channel (Slack, email, a text, Microsoft\n * Teams, the Programmatic API, a voice memo), drawn as the words that were\n * sent under a line naming the channel and the sender.\n *\n * The channel's routing block (`<inbound-message-context>`: the facts the\n * agent is told, such as Slack ids, the numbers a text went between and how a\n * reply is delivered) leaves the bubble. The line above the bubble opens it\n * as a labelled list, and hovering the line shows the channel, the place and\n * the sender in full. Every host that renders the SDK's user message gets\n * this; a host with its own user message composes it from\n * `InboundChannelLine`, `InboundChannelSubject` and `withInboundMessageBody`\n * (or `UserMessageText`). Only a message with the `inbound_channel` envelope\n * is a channel message: tags someone types show as typed.\n *\n * The hover card is CSS, not a Radix tooltip, and the glyphs are icons the\n * chat already draws: a host that splits `node_modules` into startup vendor\n * chunks (the Office pane) would otherwise load a tooltip stack at startup for\n * a line it rarely shows.\n */\nimport { useActionBarCopy } from \"@assistant-ui/core/react\";\nimport { type TextMessagePartComponent, useAuiState } from \"@assistant-ui/react\";\nimport {\n inboundEmailSubject,\n inboundMessageBody,\n isInboundChannelMessage,\n} from \"@athenaintel/agent-runtime\";\nimport { AudioLinesIcon, ChevronDownIcon, CodeIcon, MailIcon, MessageSquareIcon } from \"lucide-react\";\nimport { type FC, useCallback, useMemo, useState } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from \"../../ui/collapsible\";\nimport {\n type InboundChannelKind,\n type InboundChannelMessage,\n readInboundChannelMessage,\n} from \"./inbound-channel-reader\";\n\n/** Slack's four-colour mark. */\nconst SlackMark: FC<{ className?: string }> = ({ className }) => (\n <svg viewBox=\"0 0 2447.6 2452.5\" className={className} aria-hidden=\"true\" focusable=\"false\">\n <g clipRule=\"evenodd\" fillRule=\"evenodd\">\n <path\n d=\"m897.4 0c-135.3.1-244.8 109.9-244.7 245.2-.1 135.3 109.5 245.1 244.8 245.2h244.8v-245.1c.1-135.3-109.5-245.1-244.9-245.3.1 0 .1 0 0 0m0 654h-652.6c-135.3.1-244.9 109.9-244.8 245.2-.2 135.3 109.4 245.1 244.7 245.3h652.7c135.3-.1 244.9-109.9 244.8-245.2.1-135.4-109.5-245.2-244.8-245.3z\"\n fill=\"#36c5f0\"\n />\n <path\n d=\"m2447.6 899.2c.1-135.3-109.5-245.1-244.8-245.2-135.3.1-244.9 109.9-244.8 245.2v245.3h244.8c135.3-.1 244.9-109.9 244.8-245.3zm-652.7 0v-654c.1-135.2-109.4-245-244.7-245.2-135.3.1-244.9 109.9-244.8 245.2v654c-.2 135.3 109.4 245.1 244.7 245.3 135.3-.1 244.9-109.9 244.8-245.3z\"\n fill=\"#2eb67d\"\n />\n <path\n d=\"m1550.1 2452.5c135.3-.1 244.9-109.9 244.8-245.2.1-135.3-109.5-245.1-244.8-245.2h-244.8v245.2c-.1 135.2 109.5 245 244.8 245.2zm0-654.1h652.7c135.3-.1 244.9-109.9 244.8-245.2.2-135.3-109.4-245.1-244.7-245.3h-652.7c-135.3.1-244.9 109.9-244.8 245.2-.1 135.4 109.4 245.2 244.7 245.3z\"\n fill=\"#ecb22e\"\n />\n <path\n d=\"m0 1553.2c-.1 135.3 109.5 245.1 244.8 245.2 135.3-.1 244.9-109.9 244.8-245.2v-245.2h-244.8c-135.3.1-244.9 109.9-244.8 245.2zm652.7 0v654c-.2 135.3 109.4 245.1 244.7 245.3 135.3-.1 244.9-109.9 244.8-245.2v-653.9c.2-135.3-109.4-245.1-244.7-245.3-135.4 0-244.9 109.8-244.8 245.1 0 0 0 .1 0 0\"\n fill=\"#e01e5a\"\n />\n </g>\n </svg>\n);\n\n/** Microsoft Teams' mark: the two people and the T tile, in flat colour. */\nconst TeamsMark: FC<{ className?: string }> = ({ className }) => (\n <svg viewBox=\"0 0 2228.833 2073.333\" className={className} aria-hidden=\"true\" focusable=\"false\">\n <path\n fill=\"#5059C9\"\n d=\"M1554.637 777.5h575.713c54.391 0 98.483 44.092 98.483 98.483v524.398c0 199.901-162.051 361.952-361.952 361.952h-1.711c-199.901.028-361.975-162-362.004-361.901V828.971c0-28.427 23.044-51.471 51.471-51.471z\"\n />\n <circle fill=\"#5059C9\" cx=\"1943.75\" cy=\"440.583\" r=\"233.25\" />\n <circle fill=\"#7B83EB\" cx=\"1218.083\" cy=\"336.917\" r=\"336.917\" />\n <path\n fill=\"#7B83EB\"\n d=\"M1667.323 777.5H717.01c-53.743 1.33-96.257 45.931-95.01 99.676v598.105c-7.505 322.519 247.657 590.16 570.167 598.053 322.51-7.893 577.671-275.534 570.167-598.053V877.176c1.245-53.745-41.268-98.346-95.011-99.676z\"\n />\n <path\n fill=\"#4B53BC\"\n d=\"M95.01 466.5h950.312c52.473 0 95.01 42.538 95.01 95.01v950.312c0 52.473-42.538 95.01-95.01 95.01H95.01c-52.473 0-95.01-42.538-95.01-95.01V561.51c0-52.472 42.538-95.01 95.01-95.01z\"\n />\n <path fill=\"#FFF\" d=\"M820.211 828.193H630.241v517.297H509.211V828.193H320.123V727.844h500.088z\" />\n </svg>\n);\n\n/**\n * The channel's mark at the size `className` gives: Slack's and Teams' own\n * logos, a tinted glyph for email, texts, the API and voice memos, a speech\n * bubble for any other channel. Decorative: the line it sits on names the\n * channel.\n */\nexport const ChannelMark: FC<{ kind: InboundChannelKind; className?: string }> = ({\n kind,\n className,\n}) => {\n switch (kind) {\n case \"slack\":\n return <SlackMark className={className} />;\n case \"teams\":\n return <TeamsMark className={className} />;\n case \"email\":\n return <MailIcon className={cn(\"text-sky-600\", className)} aria-hidden=\"true\" />;\n case \"sms\":\n return <MessageSquareIcon className={cn(\"text-emerald-600\", className)} aria-hidden=\"true\" />;\n case \"api\":\n return <CodeIcon className={cn(\"text-muted-foreground\", className)} aria-hidden=\"true\" />;\n case \"voice_memo\":\n return <AudioLinesIcon className={cn(\"text-violet-600\", className)} aria-hidden=\"true\" />;\n default:\n return <MessageSquareIcon className={cn(\"text-muted-foreground\", className)} aria-hidden=\"true\" />;\n }\n};\n\n/** The first text part's words: where a channel's routing block sits. */\nfunction firstText(parts: unknown): string {\n if (!Array.isArray(parts)) return \"\";\n for (const part of parts) {\n if (\n typeof part === \"object\" &&\n part !== null &&\n (part as { type?: unknown }).type === \"text\" &&\n typeof (part as { text?: unknown }).text === \"string\"\n ) {\n return (part as { text: string }).text;\n }\n }\n return \"\";\n}\n\n/** Everything the agent read with the message, labelled; the thread a mention came in below it. */\nconst InboundChannelFacts: FC<{ message: InboundChannelMessage }> = ({ message }) => (\n <div\n className=\"flex w-full min-w-0 flex-col gap-2 rounded-xl border border-border bg-background px-3 py-2.5 text-left text-xs\"\n data-slot=\"inbound-channel-facts\"\n >\n <p className=\"text-muted-foreground\">What the agent received with this message</p>\n {message.facts.length > 0 ? (\n <dl className=\"grid grid-cols-[auto_minmax(0,1fr)] gap-x-3 gap-y-1\">\n {message.facts.map((fact, index) => (\n <div key={`${fact.key}-${index}`} className=\"contents\">\n <dt className=\"whitespace-nowrap text-muted-foreground\">{fact.label}</dt>\n <dd className=\"text-foreground [overflow-wrap:anywhere]\">{fact.value}</dd>\n </div>\n ))}\n </dl>\n ) : null}\n {message.quoted ? (\n <div className=\"flex flex-col gap-1\">\n <p className=\"text-muted-foreground\">Earlier in the thread</p>\n <p className=\"whitespace-pre-wrap border-border border-l-2 pl-2 text-foreground [overflow-wrap:anywhere]\">\n {message.quoted}\n </p>\n </div>\n ) : null}\n </div>\n);\n\n/**\n * The line above a channel message's bubble: the channel's mark, the sender's\n * name and address (an email address, a phone number), and a chevron that\n * opens what the agent received. Hovering or focusing it shows a card with\n * the channel, the place and the sender in full, while the facts are closed.\n */\nexport const InboundChannelSource: FC<{ message: InboundChannelMessage; className?: string }> = ({\n message,\n className,\n}) => {\n const [open, setOpen] = useState(false);\n const origin = message.origin;\n const name = origin.senderName;\n const handle = origin.senderHandle;\n const primary = name ?? handle ?? origin.label;\n const secondary = name && handle ? handle : null;\n const channelLine = [origin.label, origin.place].filter(Boolean).join(\" · \");\n\n return (\n <Collapsible\n open={open}\n onOpenChange={setOpen}\n className={cn(\"flex w-full min-w-0 flex-col items-end gap-1\", className)}\n data-slot=\"inbound-channel\"\n data-channel={origin.kind}\n >\n <div className=\"group/inbound-channel relative flex min-w-0 max-w-full justify-end\">\n <CollapsibleTrigger\n data-testid=\"inbound-channel-source\"\n className=\"flex min-w-0 max-w-full items-center gap-1.5 rounded-md px-1.5 py-0.5 text-muted-foreground text-xs transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <ChannelMark kind={origin.kind} className=\"size-3.5 shrink-0\" />\n <span className=\"truncate font-medium text-foreground/80\">{primary}</span>\n {secondary ? <span className=\"truncate\">{secondary}</span> : null}\n <span className=\"sr-only\">{`, via ${channelLine}. Show what the agent received`}</span>\n <ChevronDownIcon\n className={cn(\"size-3 shrink-0 transition-transform\", open && \"rotate-180\")}\n aria-hidden=\"true\"\n />\n </CollapsibleTrigger>\n {/* The hover card: what the line says, in full (the button's own text\n carries it for screen readers). Shown below the line, over the\n bubble, after a short rest, and never while the facts are open. */}\n {open ? null : (\n <div\n aria-hidden=\"true\"\n data-slot=\"inbound-channel-card\"\n className=\"pointer-events-none absolute top-full right-0 z-20 mt-1 flex w-max max-w-xs flex-col gap-0.5 rounded-md bg-foreground px-3 py-1.5 text-left text-background text-xs opacity-0 shadow-md transition-opacity delay-0 group-focus-within/inbound-channel:opacity-100 group-hover/inbound-channel:opacity-100 group-hover/inbound-channel:delay-300\"\n >\n <span className=\"flex items-center gap-1.5 font-medium\">\n <ChannelMark kind={origin.kind} className=\"size-3.5 shrink-0\" />\n {channelLine}\n </span>\n {name ? <span>{name}</span> : null}\n {handle ? <span className=\"opacity-80\">{handle}</span> : null}\n {origin.subject ? (\n <span className=\"opacity-80\">\n {`${origin.kind === \"voice_memo\" ? \"Memo\" : \"Subject\"}: ${origin.subject}`}\n </span>\n ) : null}\n </div>\n )}\n </div>\n <CollapsibleContent className=\"w-full min-w-0\">\n <InboundChannelFacts message={message} />\n </CollapsibleContent>\n </Collapsible>\n );\n};\n\n/**\n * The line above the bubble for the assistant-ui message in scope; nothing\n * for a message without the `inbound_channel` envelope. Selects the raw\n * metadata and parts (stable for a settled message) and derives in `useMemo`.\n */\nexport const InboundChannelLine: FC<{ className?: string }> = ({ className }) => {\n const custom = useAuiState((s) => s.message.metadata?.custom);\n const parts = useAuiState((s) => s.message.parts);\n const message = useMemo(\n () =>\n isInboundChannelMessage(custom)\n ? readInboundChannelMessage({ custom, text: firstText(parts) })\n : null,\n [custom, parts],\n );\n return message ? <InboundChannelSource message={message} className={className} /> : null;\n};\n\n/** An email's subject, the bubble's first line. Nothing for any other message. */\nexport const InboundChannelSubject: FC = () => {\n const subject = useAuiState((s) => inboundEmailSubject(s.message.metadata?.custom));\n if (!subject) return null;\n return (\n <div className=\"mb-1 font-semibold\" data-slot=\"inbound-channel-subject\">\n {subject}\n </div>\n );\n};\n\nconst wrappedTextComponents = new WeakMap<TextMessagePartComponent, TextMessagePartComponent>();\n\n/**\n * `Text` showing a channel message's words without the routing block the\n * agent read ahead of them. Any other text passes through unchanged, tags a\n * person typed included. Cached per component, so a host's part map keeps a\n * stable identity.\n */\nexport function withInboundMessageBody(Text: TextMessagePartComponent): TextMessagePartComponent {\n const cached = wrappedTextComponents.get(Text);\n if (cached) return cached;\n const InboundMessageBodyText: TextMessagePartComponent = (props) => {\n const custom = useAuiState((s) => s.message.metadata?.custom);\n const text = useMemo(() => inboundMessageBody({ custom, text: props.text }), [custom, props.text]);\n return <Text {...props} text={text} />;\n };\n wrappedTextComponents.set(Text, InboundMessageBodyText);\n return InboundMessageBodyText;\n}\n\n/** The clipboard write assistant-ui's own Copy makes. */\nfunction writeClipboard(text: string): Promise<void> {\n if (typeof navigator === \"undefined\" || !navigator.clipboard) {\n return Promise.reject(new Error(\"Clipboard API is unavailable\"));\n }\n return navigator.clipboard.writeText(text);\n}\n\n/**\n * Copy for a user bubble, which copies what the bubble shows: a channel\n * message's words without the routing block the agent read ahead of them\n * (`inboundMessageBody`), under an email's subject (`inboundEmailSubject`);\n * any other message's text as assistant-ui's own Copy does. While the message\n * is being edited it copies the draft, as that Copy does. `copy` writes the\n * clipboard and flashes `isCopied`; `disabled` says there is nothing to copy.\n */\nexport function useUserMessageCopy(): { copy: () => void; disabled: boolean; isCopied: boolean } {\n const custom = useAuiState((s) => s.message.metadata?.custom);\n const copyToClipboard = useCallback(\n (text: string) => {\n const words = inboundMessageBody({ custom, text });\n const subject = inboundEmailSubject(custom);\n return writeClipboard(subject ? [subject, words].filter(Boolean).join(\"\\n\\n\") : words);\n },\n [custom],\n );\n return useActionBarCopy({ copyToClipboard });\n}\n"],"names":["jsx","jsxs","MailIcon","cn","MessageSquareIcon","CodeIcon","AudioLinesIcon","useState","Collapsible","CollapsibleTrigger","ChevronDownIcon","CollapsibleContent","useAuiState","useMemo","isInboundChannelMessage","readInboundChannelMessage","inboundEmailSubject","inboundMessageBody","useCallback","useActionBarCopy"],"mappings":";;;;;;;;;;;AAsCA,MAAM,YAAwC,CAAC,EAAE,gBAC/CA,2BAAAA,IAAC,SAAI,SAAQ,qBAAoB,WAAsB,eAAY,QAAO,WAAU,SAClF,UAAAC,2BAAAA,KAAC,OAAE,UAAS,WAAU,UAAS,WAC7B,UAAA;AAAA,EAAAD,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,GAAE;AAAA,MACF,MAAK;AAAA,IAAA;AAAA,EAAA;AAAA,EAEPA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,GAAE;AAAA,MACF,MAAK;AAAA,IAAA;AAAA,EAAA;AAAA,EAEPA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,GAAE;AAAA,MACF,MAAK;AAAA,IAAA;AAAA,EAAA;AAAA,EAEPA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,GAAE;AAAA,MACF,MAAK;AAAA,IAAA;AAAA,EAAA;AACP,EAAA,CACF,EAAA,CACF;AAIF,MAAM,YAAwC,CAAC,EAAE,UAAA,MAC/CC,2BAAAA,KAAC,OAAA,EAAI,SAAQ,yBAAwB,WAAsB,eAAY,QAAO,WAAU,SACtF,UAAA;AAAA,EAAAD,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,GAAE;AAAA,IAAA;AAAA,EAAA;AAAA,EAEJA,2BAAAA,IAAC,YAAO,MAAK,WAAU,IAAG,WAAU,IAAG,WAAU,GAAE,SAAA,CAAS;AAAA,EAC5DA,2BAAAA,IAAC,YAAO,MAAK,WAAU,IAAG,YAAW,IAAG,WAAU,GAAE,UAAA,CAAU;AAAA,EAC9DA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,GAAE;AAAA,IAAA;AAAA,EAAA;AAAA,EAEJA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,GAAE;AAAA,IAAA;AAAA,EAAA;AAAA,EAEJA,2BAAAA,IAAC,QAAA,EAAK,MAAK,QAAO,GAAE,4EAAA,CAA4E;AAAA,GAClG;AASK,MAAM,cAAoE,CAAC;AAAA,EAChF;AAAA,EACA;AACF,MAAM;AACJ,UAAQ,MAAA;AAAA,IACN,KAAK;AACH,aAAOA,+BAAC,aAAU,WAAsB;AAAA,IAC1C,KAAK;AACH,aAAOA,+BAAC,aAAU,WAAsB;AAAA,IAC1C,KAAK;AACH,aAAOA,2BAAAA,IAACE,wBAAS,WAAWC,OAAAA,GAAG,gBAAgB,SAAS,GAAG,eAAY,QAAO;AAAA,IAChF,KAAK;AACH,aAAOH,2BAAAA,IAACI,iCAAkB,WAAWD,OAAAA,GAAG,oBAAoB,SAAS,GAAG,eAAY,QAAO;AAAA,IAC7F,KAAK;AACH,aAAOH,2BAAAA,IAACK,wBAAS,WAAWF,OAAAA,GAAG,yBAAyB,SAAS,GAAG,eAAY,QAAO;AAAA,IACzF,KAAK;AACH,aAAOH,2BAAAA,IAACM,8BAAe,WAAWH,OAAAA,GAAG,mBAAmB,SAAS,GAAG,eAAY,QAAO;AAAA,IACzF;AACE,aAAOH,2BAAAA,IAACI,iCAAkB,WAAWD,OAAAA,GAAG,yBAAyB,SAAS,GAAG,eAAY,QAAO;AAAA,EAAA;AAEtG;AAGA,SAAS,UAAU,OAAwB;AACzC,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO;AAClC,aAAW,QAAQ,OAAO;AACxB,QACE,OAAO,SAAS,YAChB,SAAS,QACR,KAA4B,SAAS,UACtC,OAAQ,KAA4B,SAAS,UAC7C;AACA,aAAQ,KAA0B;AAAA,IACpC;AAAA,EACF;AACA,SAAO;AACT;AAGA,MAAM,sBAA8D,CAAC,EAAE,QAAA,MACrEF,2BAAAA;AAAAA,EAAC;AAAA,EAAA;AAAA,IACC,WAAU;AAAA,IACV,aAAU;AAAA,IAEV,UAAA;AAAA,MAAAD,2BAAAA,IAAC,KAAA,EAAE,WAAU,yBAAwB,UAAA,6CAAyC;AAAA,MAC7E,QAAQ,MAAM,SAAS,IACtBA,2BAAAA,IAAC,QAAG,WAAU,uDACX,UAAA,QAAQ,MAAM,IAAI,CAAC,MAAM,UACxBC,2BAAAA,KAAC,OAAA,EAAiC,WAAU,YAC1C,UAAA;AAAA,QAAAD,2BAAAA,IAAC,MAAA,EAAG,WAAU,2CAA2C,UAAA,KAAK,OAAM;AAAA,QACpEA,2BAAAA,IAAC,MAAA,EAAG,WAAU,4CAA4C,eAAK,MAAA,CAAM;AAAA,MAAA,KAF7D,GAAG,KAAK,GAAG,IAAI,KAAK,EAG9B,CACD,GACH,IACE;AAAA,MACH,QAAQ,SACPC,gCAAC,OAAA,EAAI,WAAU,uBACb,UAAA;AAAA,QAAAD,2BAAAA,IAAC,KAAA,EAAE,WAAU,yBAAwB,UAAA,yBAAqB;AAAA,QAC1DA,2BAAAA,IAAC,KAAA,EAAE,WAAU,8FACV,kBAAQ,OAAA,CACX;AAAA,MAAA,EAAA,CACF,IACE;AAAA,IAAA;AAAA,EAAA;AACN;AASK,MAAM,uBAAmF,CAAC;AAAA,EAC/F;AAAA,EACA;AACF,MAAM;AACJ,QAAM,CAAC,MAAM,OAAO,IAAIO,WAAAA,SAAS,KAAK;AACtC,QAAM,SAAS,QAAQ;AACvB,QAAM,OAAO,OAAO;AACpB,QAAM,SAAS,OAAO;AACtB,QAAM,UAAU,QAAQ,UAAU,OAAO;AACzC,QAAM,YAAY,QAAQ,SAAS,SAAS;AAC5C,QAAM,cAAc,CAAC,OAAO,OAAO,OAAO,KAAK,EAAE,OAAO,OAAO,EAAE,KAAK,KAAK;AAE3E,SACEN,2BAAAA;AAAAA,IAACO,YAAAA;AAAAA,IAAA;AAAA,MACC;AAAA,MACA,cAAc;AAAA,MACd,WAAWL,OAAAA,GAAG,gDAAgD,SAAS;AAAA,MACvE,aAAU;AAAA,MACV,gBAAc,OAAO;AAAA,MAErB,UAAA;AAAA,QAAAF,2BAAAA,KAAC,OAAA,EAAI,WAAU,sEACb,UAAA;AAAA,UAAAA,2BAAAA;AAAAA,YAACQ,YAAAA;AAAAA,YAAA;AAAA,cACC,eAAY;AAAA,cACZ,WAAU;AAAA,cAEV,UAAA;AAAA,gBAAAT,2BAAAA,IAAC,aAAA,EAAY,MAAM,OAAO,MAAM,WAAU,qBAAoB;AAAA,gBAC9DA,2BAAAA,IAAC,QAAA,EAAK,WAAU,2CAA2C,UAAA,SAAQ;AAAA,gBAClE,YAAYA,2BAAAA,IAAC,QAAA,EAAK,WAAU,YAAY,qBAAU,IAAU;AAAA,+CAC5D,QAAA,EAAK,WAAU,WAAW,UAAA,SAAS,WAAW,kCAAiC;AAAA,gBAChFA,2BAAAA;AAAAA,kBAACU,YAAAA;AAAAA,kBAAA;AAAA,oBACC,WAAWP,OAAAA,GAAG,wCAAwC,QAAQ,YAAY;AAAA,oBAC1E,eAAY;AAAA,kBAAA;AAAA,gBAAA;AAAA,cACd;AAAA,YAAA;AAAA,UAAA;AAAA,UAKD,OAAO,OACNF,2BAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cACC,eAAY;AAAA,cACZ,aAAU;AAAA,cACV,WAAU;AAAA,cAEV,UAAA;AAAA,gBAAAA,2BAAAA,KAAC,QAAA,EAAK,WAAU,yCACd,UAAA;AAAA,kBAAAD,2BAAAA,IAAC,aAAA,EAAY,MAAM,OAAO,MAAM,WAAU,qBAAoB;AAAA,kBAC7D;AAAA,gBAAA,GACH;AAAA,gBACC,OAAOA,2BAAAA,IAAC,QAAA,EAAM,UAAA,KAAA,CAAK,IAAU;AAAA,gBAC7B,SAASA,2BAAAA,IAAC,QAAA,EAAK,WAAU,cAAc,kBAAO,IAAU;AAAA,gBACxD,OAAO,UACNA,2BAAAA,IAAC,QAAA,EAAK,WAAU,cACb,UAAA,GAAG,OAAO,SAAS,eAAe,SAAS,SAAS,KAAK,OAAO,OAAO,IAC1E,IACE;AAAA,cAAA;AAAA,YAAA;AAAA,UAAA;AAAA,QACN,GAEJ;AAAA,uCACCW,YAAAA,oBAAA,EAAmB,WAAU,kBAC5B,UAAAX,2BAAAA,IAAC,qBAAA,EAAoB,SAAkB,EAAA,CACzC;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGN;AAOO,MAAM,qBAAiD,CAAC,EAAE,gBAAgB;AAC/E,QAAM,SAASY,MAAAA,YAAY,CAAC;;AAAM,mBAAE,QAAQ,aAAV,mBAAoB;AAAA,GAAM;AAC5D,QAAM,QAAQA,MAAAA,YAAY,CAAC,MAAM,EAAE,QAAQ,KAAK;AAChD,QAAM,UAAUC,WAAAA;AAAAA,IACd,MACEC,uCAAwB,MAAM,IAC1BC,qBAAAA,0BAA0B,EAAE,QAAQ,MAAM,UAAU,KAAK,EAAA,CAAG,IAC5D;AAAA,IACN,CAAC,QAAQ,KAAK;AAAA,EAAA;AAEhB,SAAO,UAAUf,2BAAAA,IAAC,sBAAA,EAAqB,SAAkB,WAAsB,IAAK;AACtF;AAGO,MAAM,wBAA4B,MAAM;AAC7C,QAAM,UAAUY,kBAAY,CAAC,MAAA;;AAAMI,0BAAAA,qBAAoB,OAAE,QAAQ,aAAV,mBAAoB,MAAM;AAAA,GAAC;AAClF,MAAI,CAAC,QAAS,QAAO;AACrB,wCACG,OAAA,EAAI,WAAU,sBAAqB,aAAU,2BAC3C,UAAA,SACH;AAEJ;AAEA,MAAM,4CAA4B,QAAA;AAQ3B,SAAS,uBAAuB,MAA0D;AAC/F,QAAM,SAAS,sBAAsB,IAAI,IAAI;AAC7C,MAAI,OAAQ,QAAO;AACnB,QAAM,yBAAmD,CAAC,UAAU;AAClE,UAAM,SAASJ,MAAAA,YAAY,CAAC;;AAAM,qBAAE,QAAQ,aAAV,mBAAoB;AAAA,KAAM;AAC5D,UAAM,OAAOC,WAAAA,QAAQ,MAAMI,eAAAA,mBAAmB,EAAE,QAAQ,MAAM,MAAM,KAAA,CAAM,GAAG,CAAC,QAAQ,MAAM,IAAI,CAAC;AACjG,WAAOjB,2BAAAA,IAAC,MAAA,EAAM,GAAG,OAAO,KAAA,CAAY;AAAA,EACtC;AACA,wBAAsB,IAAI,MAAM,sBAAsB;AACtD,SAAO;AACT;AAGA,SAAS,eAAe,MAA6B;AACnD,MAAI,OAAO,cAAc,eAAe,CAAC,UAAU,WAAW;AAC5D,WAAO,QAAQ,OAAO,IAAI,MAAM,8BAA8B,CAAC;AAAA,EACjE;AACA,SAAO,UAAU,UAAU,UAAU,IAAI;AAC3C;AAUO,SAAS,qBAAiF;AAC/F,QAAM,SAASY,MAAAA,YAAY,CAAC;;AAAM,mBAAE,QAAQ,aAAV,mBAAoB;AAAA,GAAM;AAC5D,QAAM,kBAAkBM,WAAAA;AAAAA,IACtB,CAAC,SAAiB;AAChB,YAAM,QAAQD,eAAAA,mBAAmB,EAAE,QAAQ,MAAM;AACjD,YAAM,UAAUD,eAAAA,oBAAoB,MAAM;AAC1C,aAAO,eAAe,UAAU,CAAC,SAAS,KAAK,EAAE,OAAO,OAAO,EAAE,KAAK,MAAM,IAAI,KAAK;AAAA,IACvF;AAAA,IACA,CAAC,MAAM;AAAA,EAAA;AAET,SAAOG,QAAAA,iBAAiB,EAAE,iBAAiB;AAC7C;;;;;;;"}
@@ -0,0 +1,53 @@
1
+ import { type TextMessagePartComponent } from "@assistant-ui/react";
2
+ import { type FC } from "react";
3
+ import { type InboundChannelKind, type InboundChannelMessage } from "./inbound-channel-reader";
4
+ /**
5
+ * The channel's mark at the size `className` gives: Slack's and Teams' own
6
+ * logos, a tinted glyph for email, texts, the API and voice memos, a speech
7
+ * bubble for any other channel. Decorative: the line it sits on names the
8
+ * channel.
9
+ */
10
+ export declare const ChannelMark: FC<{
11
+ kind: InboundChannelKind;
12
+ className?: string;
13
+ }>;
14
+ /**
15
+ * The line above a channel message's bubble: the channel's mark, the sender's
16
+ * name and address (an email address, a phone number), and a chevron that
17
+ * opens what the agent received. Hovering or focusing it shows a card with
18
+ * the channel, the place and the sender in full, while the facts are closed.
19
+ */
20
+ export declare const InboundChannelSource: FC<{
21
+ message: InboundChannelMessage;
22
+ className?: string;
23
+ }>;
24
+ /**
25
+ * The line above the bubble for the assistant-ui message in scope; nothing
26
+ * for a message without the `inbound_channel` envelope. Selects the raw
27
+ * metadata and parts (stable for a settled message) and derives in `useMemo`.
28
+ */
29
+ export declare const InboundChannelLine: FC<{
30
+ className?: string;
31
+ }>;
32
+ /** An email's subject, the bubble's first line. Nothing for any other message. */
33
+ export declare const InboundChannelSubject: FC;
34
+ /**
35
+ * `Text` showing a channel message's words without the routing block the
36
+ * agent read ahead of them. Any other text passes through unchanged, tags a
37
+ * person typed included. Cached per component, so a host's part map keeps a
38
+ * stable identity.
39
+ */
40
+ export declare function withInboundMessageBody(Text: TextMessagePartComponent): TextMessagePartComponent;
41
+ /**
42
+ * Copy for a user bubble, which copies what the bubble shows: a channel
43
+ * message's words without the routing block the agent read ahead of them
44
+ * (`inboundMessageBody`), under an email's subject (`inboundEmailSubject`);
45
+ * any other message's text as assistant-ui's own Copy does. While the message
46
+ * is being edited it copies the draft, as that Copy does. `copy` writes the
47
+ * clipboard and flashes `isCopied`; `disabled` says there is nothing to copy.
48
+ */
49
+ export declare function useUserMessageCopy(): {
50
+ copy: () => void;
51
+ disabled: boolean;
52
+ isCopied: boolean;
53
+ };
@@ -0,0 +1,242 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useActionBarCopy } from "@assistant-ui/core/react";
3
+ import { useAuiState } from "@assistant-ui/react";
4
+ import { ChevronDownIcon, MessageSquareIcon, AudioLinesIcon, CodeIcon, MailIcon } from "lucide-react";
5
+ import { useMemo, useCallback, useState } from "react";
6
+ import { Collapsible, CollapsibleTrigger, CollapsibleContent } from "../../ui/collapsible.js";
7
+ import { readInboundChannelMessage } from "./inbound-channel-reader.js";
8
+ import { isInboundChannelMessage, inboundEmailSubject, inboundMessageBody } from "../../agent-runtime/src/inbound-channel.js";
9
+ import { cn } from "cnfast";
10
+ const SlackMark = ({ className }) => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 2447.6 2452.5", className, "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ jsxs("g", { clipRule: "evenodd", fillRule: "evenodd", children: [
11
+ /* @__PURE__ */ jsx(
12
+ "path",
13
+ {
14
+ d: "m897.4 0c-135.3.1-244.8 109.9-244.7 245.2-.1 135.3 109.5 245.1 244.8 245.2h244.8v-245.1c.1-135.3-109.5-245.1-244.9-245.3.1 0 .1 0 0 0m0 654h-652.6c-135.3.1-244.9 109.9-244.8 245.2-.2 135.3 109.4 245.1 244.7 245.3h652.7c135.3-.1 244.9-109.9 244.8-245.2.1-135.4-109.5-245.2-244.8-245.3z",
15
+ fill: "#36c5f0"
16
+ }
17
+ ),
18
+ /* @__PURE__ */ jsx(
19
+ "path",
20
+ {
21
+ d: "m2447.6 899.2c.1-135.3-109.5-245.1-244.8-245.2-135.3.1-244.9 109.9-244.8 245.2v245.3h244.8c135.3-.1 244.9-109.9 244.8-245.3zm-652.7 0v-654c.1-135.2-109.4-245-244.7-245.2-135.3.1-244.9 109.9-244.8 245.2v654c-.2 135.3 109.4 245.1 244.7 245.3 135.3-.1 244.9-109.9 244.8-245.3z",
22
+ fill: "#2eb67d"
23
+ }
24
+ ),
25
+ /* @__PURE__ */ jsx(
26
+ "path",
27
+ {
28
+ d: "m1550.1 2452.5c135.3-.1 244.9-109.9 244.8-245.2.1-135.3-109.5-245.1-244.8-245.2h-244.8v245.2c-.1 135.2 109.5 245 244.8 245.2zm0-654.1h652.7c135.3-.1 244.9-109.9 244.8-245.2.2-135.3-109.4-245.1-244.7-245.3h-652.7c-135.3.1-244.9 109.9-244.8 245.2-.1 135.4 109.4 245.2 244.7 245.3z",
29
+ fill: "#ecb22e"
30
+ }
31
+ ),
32
+ /* @__PURE__ */ jsx(
33
+ "path",
34
+ {
35
+ d: "m0 1553.2c-.1 135.3 109.5 245.1 244.8 245.2 135.3-.1 244.9-109.9 244.8-245.2v-245.2h-244.8c-135.3.1-244.9 109.9-244.8 245.2zm652.7 0v654c-.2 135.3 109.4 245.1 244.7 245.3 135.3-.1 244.9-109.9 244.8-245.2v-653.9c.2-135.3-109.4-245.1-244.7-245.3-135.4 0-244.9 109.8-244.8 245.1 0 0 0 .1 0 0",
36
+ fill: "#e01e5a"
37
+ }
38
+ )
39
+ ] }) });
40
+ const TeamsMark = ({ className }) => /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 2228.833 2073.333", className, "aria-hidden": "true", focusable: "false", children: [
41
+ /* @__PURE__ */ jsx(
42
+ "path",
43
+ {
44
+ fill: "#5059C9",
45
+ d: "M1554.637 777.5h575.713c54.391 0 98.483 44.092 98.483 98.483v524.398c0 199.901-162.051 361.952-361.952 361.952h-1.711c-199.901.028-361.975-162-362.004-361.901V828.971c0-28.427 23.044-51.471 51.471-51.471z"
46
+ }
47
+ ),
48
+ /* @__PURE__ */ jsx("circle", { fill: "#5059C9", cx: "1943.75", cy: "440.583", r: "233.25" }),
49
+ /* @__PURE__ */ jsx("circle", { fill: "#7B83EB", cx: "1218.083", cy: "336.917", r: "336.917" }),
50
+ /* @__PURE__ */ jsx(
51
+ "path",
52
+ {
53
+ fill: "#7B83EB",
54
+ d: "M1667.323 777.5H717.01c-53.743 1.33-96.257 45.931-95.01 99.676v598.105c-7.505 322.519 247.657 590.16 570.167 598.053 322.51-7.893 577.671-275.534 570.167-598.053V877.176c1.245-53.745-41.268-98.346-95.011-99.676z"
55
+ }
56
+ ),
57
+ /* @__PURE__ */ jsx(
58
+ "path",
59
+ {
60
+ fill: "#4B53BC",
61
+ d: "M95.01 466.5h950.312c52.473 0 95.01 42.538 95.01 95.01v950.312c0 52.473-42.538 95.01-95.01 95.01H95.01c-52.473 0-95.01-42.538-95.01-95.01V561.51c0-52.472 42.538-95.01 95.01-95.01z"
62
+ }
63
+ ),
64
+ /* @__PURE__ */ jsx("path", { fill: "#FFF", d: "M820.211 828.193H630.241v517.297H509.211V828.193H320.123V727.844h500.088z" })
65
+ ] });
66
+ const ChannelMark = ({
67
+ kind,
68
+ className
69
+ }) => {
70
+ switch (kind) {
71
+ case "slack":
72
+ return /* @__PURE__ */ jsx(SlackMark, { className });
73
+ case "teams":
74
+ return /* @__PURE__ */ jsx(TeamsMark, { className });
75
+ case "email":
76
+ return /* @__PURE__ */ jsx(MailIcon, { className: cn("text-sky-600", className), "aria-hidden": "true" });
77
+ case "sms":
78
+ return /* @__PURE__ */ jsx(MessageSquareIcon, { className: cn("text-emerald-600", className), "aria-hidden": "true" });
79
+ case "api":
80
+ return /* @__PURE__ */ jsx(CodeIcon, { className: cn("text-muted-foreground", className), "aria-hidden": "true" });
81
+ case "voice_memo":
82
+ return /* @__PURE__ */ jsx(AudioLinesIcon, { className: cn("text-violet-600", className), "aria-hidden": "true" });
83
+ default:
84
+ return /* @__PURE__ */ jsx(MessageSquareIcon, { className: cn("text-muted-foreground", className), "aria-hidden": "true" });
85
+ }
86
+ };
87
+ function firstText(parts) {
88
+ if (!Array.isArray(parts)) return "";
89
+ for (const part of parts) {
90
+ if (typeof part === "object" && part !== null && part.type === "text" && typeof part.text === "string") {
91
+ return part.text;
92
+ }
93
+ }
94
+ return "";
95
+ }
96
+ const InboundChannelFacts = ({ message }) => /* @__PURE__ */ jsxs(
97
+ "div",
98
+ {
99
+ className: "flex w-full min-w-0 flex-col gap-2 rounded-xl border border-border bg-background px-3 py-2.5 text-left text-xs",
100
+ "data-slot": "inbound-channel-facts",
101
+ children: [
102
+ /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: "What the agent received with this message" }),
103
+ message.facts.length > 0 ? /* @__PURE__ */ jsx("dl", { className: "grid grid-cols-[auto_minmax(0,1fr)] gap-x-3 gap-y-1", children: message.facts.map((fact, index) => /* @__PURE__ */ jsxs("div", { className: "contents", children: [
104
+ /* @__PURE__ */ jsx("dt", { className: "whitespace-nowrap text-muted-foreground", children: fact.label }),
105
+ /* @__PURE__ */ jsx("dd", { className: "text-foreground [overflow-wrap:anywhere]", children: fact.value })
106
+ ] }, `${fact.key}-${index}`)) }) : null,
107
+ message.quoted ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
108
+ /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: "Earlier in the thread" }),
109
+ /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap border-border border-l-2 pl-2 text-foreground [overflow-wrap:anywhere]", children: message.quoted })
110
+ ] }) : null
111
+ ]
112
+ }
113
+ );
114
+ const InboundChannelSource = ({
115
+ message,
116
+ className
117
+ }) => {
118
+ const [open, setOpen] = useState(false);
119
+ const origin = message.origin;
120
+ const name = origin.senderName;
121
+ const handle = origin.senderHandle;
122
+ const primary = name ?? handle ?? origin.label;
123
+ const secondary = name && handle ? handle : null;
124
+ const channelLine = [origin.label, origin.place].filter(Boolean).join(" · ");
125
+ return /* @__PURE__ */ jsxs(
126
+ Collapsible,
127
+ {
128
+ open,
129
+ onOpenChange: setOpen,
130
+ className: cn("flex w-full min-w-0 flex-col items-end gap-1", className),
131
+ "data-slot": "inbound-channel",
132
+ "data-channel": origin.kind,
133
+ children: [
134
+ /* @__PURE__ */ jsxs("div", { className: "group/inbound-channel relative flex min-w-0 max-w-full justify-end", children: [
135
+ /* @__PURE__ */ jsxs(
136
+ CollapsibleTrigger,
137
+ {
138
+ "data-testid": "inbound-channel-source",
139
+ className: "flex min-w-0 max-w-full items-center gap-1.5 rounded-md px-1.5 py-0.5 text-muted-foreground text-xs transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
140
+ children: [
141
+ /* @__PURE__ */ jsx(ChannelMark, { kind: origin.kind, className: "size-3.5 shrink-0" }),
142
+ /* @__PURE__ */ jsx("span", { className: "truncate font-medium text-foreground/80", children: primary }),
143
+ secondary ? /* @__PURE__ */ jsx("span", { className: "truncate", children: secondary }) : null,
144
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: `, via ${channelLine}. Show what the agent received` }),
145
+ /* @__PURE__ */ jsx(
146
+ ChevronDownIcon,
147
+ {
148
+ className: cn("size-3 shrink-0 transition-transform", open && "rotate-180"),
149
+ "aria-hidden": "true"
150
+ }
151
+ )
152
+ ]
153
+ }
154
+ ),
155
+ open ? null : /* @__PURE__ */ jsxs(
156
+ "div",
157
+ {
158
+ "aria-hidden": "true",
159
+ "data-slot": "inbound-channel-card",
160
+ className: "pointer-events-none absolute top-full right-0 z-20 mt-1 flex w-max max-w-xs flex-col gap-0.5 rounded-md bg-foreground px-3 py-1.5 text-left text-background text-xs opacity-0 shadow-md transition-opacity delay-0 group-focus-within/inbound-channel:opacity-100 group-hover/inbound-channel:opacity-100 group-hover/inbound-channel:delay-300",
161
+ children: [
162
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5 font-medium", children: [
163
+ /* @__PURE__ */ jsx(ChannelMark, { kind: origin.kind, className: "size-3.5 shrink-0" }),
164
+ channelLine
165
+ ] }),
166
+ name ? /* @__PURE__ */ jsx("span", { children: name }) : null,
167
+ handle ? /* @__PURE__ */ jsx("span", { className: "opacity-80", children: handle }) : null,
168
+ origin.subject ? /* @__PURE__ */ jsx("span", { className: "opacity-80", children: `${origin.kind === "voice_memo" ? "Memo" : "Subject"}: ${origin.subject}` }) : null
169
+ ]
170
+ }
171
+ )
172
+ ] }),
173
+ /* @__PURE__ */ jsx(CollapsibleContent, { className: "w-full min-w-0", children: /* @__PURE__ */ jsx(InboundChannelFacts, { message }) })
174
+ ]
175
+ }
176
+ );
177
+ };
178
+ const InboundChannelLine = ({ className }) => {
179
+ const custom = useAuiState((s) => {
180
+ var _a;
181
+ return (_a = s.message.metadata) == null ? void 0 : _a.custom;
182
+ });
183
+ const parts = useAuiState((s) => s.message.parts);
184
+ const message = useMemo(
185
+ () => isInboundChannelMessage(custom) ? readInboundChannelMessage({ custom, text: firstText(parts) }) : null,
186
+ [custom, parts]
187
+ );
188
+ return message ? /* @__PURE__ */ jsx(InboundChannelSource, { message, className }) : null;
189
+ };
190
+ const InboundChannelSubject = () => {
191
+ const subject = useAuiState((s) => {
192
+ var _a;
193
+ return inboundEmailSubject((_a = s.message.metadata) == null ? void 0 : _a.custom);
194
+ });
195
+ if (!subject) return null;
196
+ return /* @__PURE__ */ jsx("div", { className: "mb-1 font-semibold", "data-slot": "inbound-channel-subject", children: subject });
197
+ };
198
+ const wrappedTextComponents = /* @__PURE__ */ new WeakMap();
199
+ function withInboundMessageBody(Text) {
200
+ const cached = wrappedTextComponents.get(Text);
201
+ if (cached) return cached;
202
+ const InboundMessageBodyText = (props) => {
203
+ const custom = useAuiState((s) => {
204
+ var _a;
205
+ return (_a = s.message.metadata) == null ? void 0 : _a.custom;
206
+ });
207
+ const text = useMemo(() => inboundMessageBody({ custom, text: props.text }), [custom, props.text]);
208
+ return /* @__PURE__ */ jsx(Text, { ...props, text });
209
+ };
210
+ wrappedTextComponents.set(Text, InboundMessageBodyText);
211
+ return InboundMessageBodyText;
212
+ }
213
+ function writeClipboard(text) {
214
+ if (typeof navigator === "undefined" || !navigator.clipboard) {
215
+ return Promise.reject(new Error("Clipboard API is unavailable"));
216
+ }
217
+ return navigator.clipboard.writeText(text);
218
+ }
219
+ function useUserMessageCopy() {
220
+ const custom = useAuiState((s) => {
221
+ var _a;
222
+ return (_a = s.message.metadata) == null ? void 0 : _a.custom;
223
+ });
224
+ const copyToClipboard = useCallback(
225
+ (text) => {
226
+ const words = inboundMessageBody({ custom, text });
227
+ const subject = inboundEmailSubject(custom);
228
+ return writeClipboard(subject ? [subject, words].filter(Boolean).join("\n\n") : words);
229
+ },
230
+ [custom]
231
+ );
232
+ return useActionBarCopy({ copyToClipboard });
233
+ }
234
+ export {
235
+ ChannelMark,
236
+ InboundChannelLine,
237
+ InboundChannelSource,
238
+ InboundChannelSubject,
239
+ useUserMessageCopy,
240
+ withInboundMessageBody
241
+ };
242
+ //# sourceMappingURL=inbound-channel-message.js.map