@xbrain-swe/nova-chat-widget 0.3.0-dev.16 → 0.3.0-dev.17
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/index.cjs +35 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +35 -35
- package/dist/index.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -171,7 +171,8 @@ type UseXbNovaChatResult = {
|
|
|
171
171
|
messages: ChatMessage[];
|
|
172
172
|
busy: boolean;
|
|
173
173
|
error: string | null;
|
|
174
|
-
|
|
174
|
+
/** `nudgeOpening`은 대화 중 넛지를 눌러 띄운 질문이다. 답을 보낼 때 그 앞에 AI 발화로 남긴다. */
|
|
175
|
+
send: (text: string, nudgeOpening?: string | null) => Promise<void>;
|
|
175
176
|
/** client action 핸들러가 돌려준 정규화 결과(tool_call_id별). 채팅 화면이 view 렌더러로 그린다. */
|
|
176
177
|
clientResults: ClientResults;
|
|
177
178
|
/** messageId → 현재 평가. 평가 안 한 메시지는 키가 없다. */
|
package/dist/index.d.ts
CHANGED
|
@@ -171,7 +171,8 @@ type UseXbNovaChatResult = {
|
|
|
171
171
|
messages: ChatMessage[];
|
|
172
172
|
busy: boolean;
|
|
173
173
|
error: string | null;
|
|
174
|
-
|
|
174
|
+
/** `nudgeOpening`은 대화 중 넛지를 눌러 띄운 질문이다. 답을 보낼 때 그 앞에 AI 발화로 남긴다. */
|
|
175
|
+
send: (text: string, nudgeOpening?: string | null) => Promise<void>;
|
|
175
176
|
/** client action 핸들러가 돌려준 정규화 결과(tool_call_id별). 채팅 화면이 view 렌더러로 그린다. */
|
|
176
177
|
clientResults: ClientResults;
|
|
177
178
|
/** messageId → 현재 평가. 평가 안 한 메시지는 키가 없다. */
|
package/dist/index.js
CHANGED
|
@@ -73,7 +73,7 @@ function InternalProvider({
|
|
|
73
73
|
const sendEvent = useCallback((event, properties = {}) => {
|
|
74
74
|
const { auth: a, visitorId: v, sessionId: sid } = latestRef.current;
|
|
75
75
|
if (!v) return;
|
|
76
|
-
const { conversation_id: conversationId, ...rest } = properties;
|
|
76
|
+
const { conversation_id: conversationId, occurred_at: occurredAt, ...rest } = properties;
|
|
77
77
|
fetch(`${a.apiBaseUrl}/v1/events`, {
|
|
78
78
|
method: "POST",
|
|
79
79
|
keepalive: true,
|
|
@@ -84,18 +84,20 @@ function InternalProvider({
|
|
|
84
84
|
visitor_id: v,
|
|
85
85
|
session_id: sid,
|
|
86
86
|
conversation_id: conversationId ?? null,
|
|
87
|
+
occurred_at: occurredAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
87
88
|
properties: { screen: a.screen, ...rest }
|
|
88
89
|
})
|
|
89
90
|
}).catch(() => {
|
|
90
91
|
});
|
|
91
92
|
}, []);
|
|
92
93
|
const widgetViewSentRef = useRef(false);
|
|
94
|
+
const mountedAtRef = useRef((/* @__PURE__ */ new Date()).toISOString());
|
|
93
95
|
useEffect(() => {
|
|
94
96
|
if (widgetViewSentRef.current) return;
|
|
95
97
|
const send = () => {
|
|
96
98
|
if (widgetViewSentRef.current) return;
|
|
97
99
|
widgetViewSentRef.current = true;
|
|
98
|
-
sendEvent("widget_view");
|
|
100
|
+
sendEvent("widget_view", { occurred_at: mountedAtRef.current });
|
|
99
101
|
};
|
|
100
102
|
if (sessionId) {
|
|
101
103
|
send();
|
|
@@ -1185,7 +1187,6 @@ function useXbNovaChat(options) {
|
|
|
1185
1187
|
const [resumed, setResumed] = useState3(false);
|
|
1186
1188
|
const [sentOpening, setSentOpening] = useState3(null);
|
|
1187
1189
|
const conversationIdRef = useRef7(null);
|
|
1188
|
-
const pendingOpeningRef = useRef7(null);
|
|
1189
1190
|
const messagesRef = useRef7(messages);
|
|
1190
1191
|
messagesRef.current = messages;
|
|
1191
1192
|
const [busy, setBusy] = useState3(false);
|
|
@@ -1208,7 +1209,6 @@ function useXbNovaChat(options) {
|
|
|
1208
1209
|
setFeedbackState({});
|
|
1209
1210
|
dispatchedClientActionsRef.current = /* @__PURE__ */ new Set();
|
|
1210
1211
|
conversationIdRef.current = null;
|
|
1211
|
-
pendingOpeningRef.current = null;
|
|
1212
1212
|
fetch(`${apiBaseUrl}/v1/conversations`, {
|
|
1213
1213
|
method: "POST",
|
|
1214
1214
|
headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` },
|
|
@@ -1241,16 +1241,6 @@ function useXbNovaChat(options) {
|
|
|
1241
1241
|
cancelled = true;
|
|
1242
1242
|
};
|
|
1243
1243
|
}, [apiBaseUrl, apiKey, botId, userKey, threadKey]);
|
|
1244
|
-
const openingMessage = options?.openingMessage;
|
|
1245
|
-
useEffect8(() => {
|
|
1246
|
-
if (!onboarding || !nudgeNodeId || !openingMessage) return;
|
|
1247
|
-
if (messagesRef.current.length === 0) return;
|
|
1248
|
-
setMessages((prev) => [
|
|
1249
|
-
...prev,
|
|
1250
|
-
{ role: "assistant", parts: [{ kind: "text", id: `nudge:${nudgeNodeId}:${prev.length}`, text: openingMessage }] }
|
|
1251
|
-
]);
|
|
1252
|
-
pendingOpeningRef.current = openingMessage;
|
|
1253
|
-
}, [onboarding, nudgeNodeId, openingMessage]);
|
|
1254
1244
|
const appendToLastAssistant = (existingParts, newParts) => setMessages((prev) => {
|
|
1255
1245
|
const next = [...prev];
|
|
1256
1246
|
next[next.length - 1] = { ...next[next.length - 1], role: "assistant", parts: [...existingParts, ...newParts] };
|
|
@@ -1369,7 +1359,7 @@ function useXbNovaChat(options) {
|
|
|
1369
1359
|
void runClientAction(spec, part, last.parts);
|
|
1370
1360
|
}
|
|
1371
1361
|
}, [messages, clientActionHandlers, onboarding, apiBaseUrl, apiKey, botId]);
|
|
1372
|
-
async function send(text) {
|
|
1362
|
+
async function send(text, nudgeOpening) {
|
|
1373
1363
|
const trimmed = text.trim();
|
|
1374
1364
|
if (!trimmed || busy) return;
|
|
1375
1365
|
sendEvent("message_send", {
|
|
@@ -1379,8 +1369,10 @@ function useXbNovaChat(options) {
|
|
|
1379
1369
|
});
|
|
1380
1370
|
setError(null);
|
|
1381
1371
|
setBusy(true);
|
|
1372
|
+
const resumedOpening = messages.length > 0 && nudgeOpening ? nudgeOpening : null;
|
|
1382
1373
|
setMessages((prev) => [
|
|
1383
1374
|
...prev,
|
|
1375
|
+
...resumedOpening ? [{ role: "assistant", parts: [{ kind: "text", id: `nudge:${prev.length}`, text: resumedOpening }] }] : [],
|
|
1384
1376
|
{ role: "user", parts: [{ kind: "text", id: "u", text: trimmed }] },
|
|
1385
1377
|
{ role: "assistant", parts: [] }
|
|
1386
1378
|
]);
|
|
@@ -1393,14 +1385,13 @@ function useXbNovaChat(options) {
|
|
|
1393
1385
|
const notes = collectContextEntries(contextRegistry);
|
|
1394
1386
|
const screen = focused ? { region: focused.region, data: resolveFactValue(focused.data) } : {};
|
|
1395
1387
|
const context = focused || notes.length ? { ...screen, ...notes.length ? { notes } : {} } : void 0;
|
|
1396
|
-
let
|
|
1388
|
+
let openingMessage;
|
|
1397
1389
|
if (messages.length === 0) {
|
|
1398
|
-
|
|
1399
|
-
setSentOpening(
|
|
1390
|
+
openingMessage = (options?.openingMessage ?? onboarding?.greeting) || null;
|
|
1391
|
+
setSentOpening(openingMessage);
|
|
1400
1392
|
} else {
|
|
1401
|
-
|
|
1393
|
+
openingMessage = resumedOpening;
|
|
1402
1394
|
}
|
|
1403
|
-
pendingOpeningRef.current = null;
|
|
1404
1395
|
try {
|
|
1405
1396
|
await streamChat(
|
|
1406
1397
|
apiBaseUrl,
|
|
@@ -1411,7 +1402,7 @@ function useXbNovaChat(options) {
|
|
|
1411
1402
|
conversation_id: conversationIdRef.current,
|
|
1412
1403
|
context,
|
|
1413
1404
|
nudge_node_id: nudgeNodeId ?? null,
|
|
1414
|
-
opening_message:
|
|
1405
|
+
opening_message: openingMessage,
|
|
1415
1406
|
visitor_id: userKey || null,
|
|
1416
1407
|
thread_key: threadKey ?? null,
|
|
1417
1408
|
session_id: sessionId
|
|
@@ -1431,7 +1422,7 @@ function useXbNovaChat(options) {
|
|
|
1431
1422
|
setBusy(false);
|
|
1432
1423
|
}
|
|
1433
1424
|
}
|
|
1434
|
-
const opening = resumed ? null : sentOpening
|
|
1425
|
+
const opening = resumed ? null : messages.length > 0 ? sentOpening : options?.openingMessage ?? onboarding?.greeting ?? null;
|
|
1435
1426
|
return {
|
|
1436
1427
|
onboarding,
|
|
1437
1428
|
opening,
|
|
@@ -1731,6 +1722,7 @@ function XbNovaChat({
|
|
|
1731
1722
|
const [activeBotId, setActiveBotId] = useState4(void 0);
|
|
1732
1723
|
const [activeNudgeNodeId, setActiveNudgeNodeId] = useState4(void 0);
|
|
1733
1724
|
const [nudgeQuickReplies, setNudgeQuickReplies] = useState4([]);
|
|
1725
|
+
const [nudgePrompt, setNudgePrompt] = useState4(null);
|
|
1734
1726
|
const [openingLine, setOpeningLine] = useState4(null);
|
|
1735
1727
|
const [showDisclosure, setShowDisclosure] = useState4(false);
|
|
1736
1728
|
const [input, setInput] = useState4("");
|
|
@@ -1800,9 +1792,11 @@ function XbNovaChat({
|
|
|
1800
1792
|
setOpeningLine(consumed.text);
|
|
1801
1793
|
setActiveNudgeNodeId(consumed.messageNodeId);
|
|
1802
1794
|
setNudgeQuickReplies(consumed.quickReplies);
|
|
1795
|
+
setNudgePrompt(consumed.text);
|
|
1803
1796
|
sendEvent("nudge_open", { nudge_node_id: consumed.messageNodeId, bot_id: consumed.botId });
|
|
1804
1797
|
} else {
|
|
1805
1798
|
setNudgeQuickReplies([]);
|
|
1799
|
+
setNudgePrompt(null);
|
|
1806
1800
|
setActiveNudgeNodeId(void 0);
|
|
1807
1801
|
const focused = getFocusedTrackEntry(trackRegistry);
|
|
1808
1802
|
setOpeningLine(
|
|
@@ -2024,19 +2018,24 @@ function XbNovaChat({
|
|
|
2024
2018
|
/* @__PURE__ */ jsx7("div", { ref: bottomRef })
|
|
2025
2019
|
] }),
|
|
2026
2020
|
(() => {
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
{
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2021
|
+
const prompt = messages.length > 0 ? nudgePrompt : null;
|
|
2022
|
+
if (prompt || nudgeQuickReplies.length > 0) {
|
|
2023
|
+
return /* @__PURE__ */ jsxs3("div", { className: "space-y-2 border-t border-neutral-200 px-3.5 py-2.5 dark:border-neutral-700", children: [
|
|
2024
|
+
prompt ? /* @__PURE__ */ jsx7("div", { className: "text-sm font-medium", children: /* @__PURE__ */ jsx7(AssistantMarkdown, { text: prompt }) }) : null,
|
|
2025
|
+
nudgeQuickReplies.length > 0 ? /* @__PURE__ */ jsx7("div", { className: "flex flex-wrap gap-1.5", children: nudgeQuickReplies.map((q) => /* @__PURE__ */ jsx7(
|
|
2026
|
+
"button",
|
|
2027
|
+
{
|
|
2028
|
+
onClick: () => {
|
|
2029
|
+
setNudgeQuickReplies([]);
|
|
2030
|
+
setNudgePrompt(null);
|
|
2031
|
+
send(q, prompt);
|
|
2032
|
+
},
|
|
2033
|
+
className: "xbnova-chip rounded-full border px-2.5 py-1 text-[11px] font-semibold transition",
|
|
2034
|
+
children: q
|
|
2034
2035
|
},
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
q
|
|
2039
|
-
)) });
|
|
2036
|
+
q
|
|
2037
|
+
)) }) : null
|
|
2038
|
+
] });
|
|
2040
2039
|
}
|
|
2041
2040
|
const quickReplies = onboarding?.quick_replies ?? [];
|
|
2042
2041
|
if (messages.length !== 0 || quickReplies.length === 0) return null;
|
|
@@ -2056,7 +2055,8 @@ function XbNovaChat({
|
|
|
2056
2055
|
onSubmit: (e) => {
|
|
2057
2056
|
e.preventDefault();
|
|
2058
2057
|
setNudgeQuickReplies([]);
|
|
2059
|
-
|
|
2058
|
+
setNudgePrompt(null);
|
|
2059
|
+
send(input, messages.length > 0 ? nudgePrompt : null);
|
|
2060
2060
|
setInput("");
|
|
2061
2061
|
},
|
|
2062
2062
|
className: "flex items-center gap-2 border-t border-neutral-200 px-3 py-2.5 dark:border-neutral-700",
|