@xbrain-swe/nova-chat-widget 0.1.10 → 0.1.11
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 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.js +35 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -80,6 +80,12 @@ type XbNovaClientAction = {
|
|
|
80
80
|
type XbNovaClientActions = Record<string, XbNovaClientAction>;
|
|
81
81
|
|
|
82
82
|
type FactValue = unknown | (() => unknown);
|
|
83
|
+
/** `useXbNovaContext`로 호스트가 AI에게 알려주는 상품·화면 부가 설명 한 건. 내용은 전부
|
|
84
|
+
* 호스트 자율이다 — 가입 됨/안됨 같은 판단도 호스트가 `description`에 문장으로 쓴다. */
|
|
85
|
+
type XbNovaContextEntry = {
|
|
86
|
+
title: string;
|
|
87
|
+
description: string;
|
|
88
|
+
};
|
|
83
89
|
/** 위젯 아바타·pill 배경 그라디언트에 쓰는 두 색상 — 기본값은 SDK 자체 톤(인디고→바이올렛)
|
|
84
90
|
* 이고, 소비자가 `<XbNovaProvider theme={{accentFrom, accentTo}}>`로 자기 브랜드 컬러를
|
|
85
91
|
* 넘기면 그걸 쓴다("카통령 브랜드 컬러를 따르게 해달라" — 파랑/보라가 사이트 톤과 안
|
|
@@ -158,6 +164,10 @@ type UseXbNovaChatResult = {
|
|
|
158
164
|
declare function useXbNovaChat(options?: {
|
|
159
165
|
botId?: string;
|
|
160
166
|
nudgeNodeId?: string;
|
|
167
|
+
/** 위젯이 첫 말풍선으로 보여준 문구(넛지 문구). 첫 메시지를 보낼 때 서버에 같이 보내 AI가
|
|
168
|
+
* "방금 이런 말을 건넸다"는 걸 알게 한다 — 없으면 봇 인사말을 쓴다. 서버가 설정과 일치하는지
|
|
169
|
+
* 검증해서 맞는 것만 이력에 저장한다. */
|
|
170
|
+
openingMessage?: string;
|
|
161
171
|
onDismissSheet?: () => void;
|
|
162
172
|
onFeedback?: (e: XbNovaFeedbackEvent) => void;
|
|
163
173
|
}): UseXbNovaChatResult;
|
|
@@ -249,6 +259,11 @@ declare function useXbNovaFact(key: string, value: FactValue): void;
|
|
|
249
259
|
/** 필드가 여러 개인 객체 하나를 한 번에 등록한다 — 매물 데이터처럼. `useXbNovaFact`를
|
|
250
260
|
* 필드마다 반복하는 것과 같다. */
|
|
251
261
|
declare function useXbNovaFacts(values: Record<string, FactValue>): void;
|
|
262
|
+
/** AI에게 알려줄 상품·화면 부가 설명을 등록한다. 넛지 조건용인 facts와 달리 **챗 요청의
|
|
263
|
+
* `context`로 전송**되어 답변의 근거가 된다. 내용(가입 가능 여부 같은 판단 포함)은 호스트가
|
|
264
|
+
* `description`에 문장으로 쓴다 — SDK는 형식 검증과 전달만 한다. 배열 또는 함수(pull) 둘 다
|
|
265
|
+
* 된다. 컴포넌트가 언마운트되면 자동으로 빠진다. */
|
|
266
|
+
declare function useXbNovaContext(entries: XbNovaContextEntry[] | (() => XbNovaContextEntry[])): void;
|
|
252
267
|
/** 방문자 식별자 — 없으면 SDK가 즉시 만들어 localStorage에 고정한 뒤 그 값을 반환한다. */
|
|
253
268
|
declare function useXbNovaVisitor(): string;
|
|
254
269
|
/** 선언형 — 서버 컴포넌트 트리에서 훅을 못 쓸 때. `<XbNovaFact id="xbnova_summary" value="..." />`. */
|
|
@@ -274,4 +289,4 @@ declare function useXbNovaSettings(): {
|
|
|
274
289
|
showBar: () => void;
|
|
275
290
|
};
|
|
276
291
|
|
|
277
|
-
export { type ChatMessage, type FactValue, type MessagePart, type ProductItem, type TextPart, type ToolPart, type UseXbNovaChatResult, type VerdictAction, type VerdictOutput, type ViewKind, type ViewRenderer, type ViewRendererMap, XbNovaChat, type XbNovaClientAction, type XbNovaClientActionResult, type XbNovaClientActions, XbNovaFact, XbNovaFacts, type XbNovaFeedbackEvent, type XbNovaFeedbackRating, type XbNovaFeedbackReason, type XbNovaOnboarding, XbNovaProvider, type XbNovaTheme, XbNovaTrack, trackXbNovaEvent, useXbNovaChat, useXbNovaFact, useXbNovaFacts, useXbNovaSettings, useXbNovaTrack, useXbNovaVisitor };
|
|
292
|
+
export { type ChatMessage, type FactValue, type MessagePart, type ProductItem, type TextPart, type ToolPart, type UseXbNovaChatResult, type VerdictAction, type VerdictOutput, type ViewKind, type ViewRenderer, type ViewRendererMap, XbNovaChat, type XbNovaClientAction, type XbNovaClientActionResult, type XbNovaClientActions, type XbNovaContextEntry, XbNovaFact, XbNovaFacts, type XbNovaFeedbackEvent, type XbNovaFeedbackRating, type XbNovaFeedbackReason, type XbNovaOnboarding, XbNovaProvider, type XbNovaTheme, XbNovaTrack, trackXbNovaEvent, useXbNovaChat, useXbNovaContext, useXbNovaFact, useXbNovaFacts, useXbNovaSettings, useXbNovaTrack, useXbNovaVisitor };
|
package/dist/index.d.ts
CHANGED
|
@@ -80,6 +80,12 @@ type XbNovaClientAction = {
|
|
|
80
80
|
type XbNovaClientActions = Record<string, XbNovaClientAction>;
|
|
81
81
|
|
|
82
82
|
type FactValue = unknown | (() => unknown);
|
|
83
|
+
/** `useXbNovaContext`로 호스트가 AI에게 알려주는 상품·화면 부가 설명 한 건. 내용은 전부
|
|
84
|
+
* 호스트 자율이다 — 가입 됨/안됨 같은 판단도 호스트가 `description`에 문장으로 쓴다. */
|
|
85
|
+
type XbNovaContextEntry = {
|
|
86
|
+
title: string;
|
|
87
|
+
description: string;
|
|
88
|
+
};
|
|
83
89
|
/** 위젯 아바타·pill 배경 그라디언트에 쓰는 두 색상 — 기본값은 SDK 자체 톤(인디고→바이올렛)
|
|
84
90
|
* 이고, 소비자가 `<XbNovaProvider theme={{accentFrom, accentTo}}>`로 자기 브랜드 컬러를
|
|
85
91
|
* 넘기면 그걸 쓴다("카통령 브랜드 컬러를 따르게 해달라" — 파랑/보라가 사이트 톤과 안
|
|
@@ -158,6 +164,10 @@ type UseXbNovaChatResult = {
|
|
|
158
164
|
declare function useXbNovaChat(options?: {
|
|
159
165
|
botId?: string;
|
|
160
166
|
nudgeNodeId?: string;
|
|
167
|
+
/** 위젯이 첫 말풍선으로 보여준 문구(넛지 문구). 첫 메시지를 보낼 때 서버에 같이 보내 AI가
|
|
168
|
+
* "방금 이런 말을 건넸다"는 걸 알게 한다 — 없으면 봇 인사말을 쓴다. 서버가 설정과 일치하는지
|
|
169
|
+
* 검증해서 맞는 것만 이력에 저장한다. */
|
|
170
|
+
openingMessage?: string;
|
|
161
171
|
onDismissSheet?: () => void;
|
|
162
172
|
onFeedback?: (e: XbNovaFeedbackEvent) => void;
|
|
163
173
|
}): UseXbNovaChatResult;
|
|
@@ -249,6 +259,11 @@ declare function useXbNovaFact(key: string, value: FactValue): void;
|
|
|
249
259
|
/** 필드가 여러 개인 객체 하나를 한 번에 등록한다 — 매물 데이터처럼. `useXbNovaFact`를
|
|
250
260
|
* 필드마다 반복하는 것과 같다. */
|
|
251
261
|
declare function useXbNovaFacts(values: Record<string, FactValue>): void;
|
|
262
|
+
/** AI에게 알려줄 상품·화면 부가 설명을 등록한다. 넛지 조건용인 facts와 달리 **챗 요청의
|
|
263
|
+
* `context`로 전송**되어 답변의 근거가 된다. 내용(가입 가능 여부 같은 판단 포함)은 호스트가
|
|
264
|
+
* `description`에 문장으로 쓴다 — SDK는 형식 검증과 전달만 한다. 배열 또는 함수(pull) 둘 다
|
|
265
|
+
* 된다. 컴포넌트가 언마운트되면 자동으로 빠진다. */
|
|
266
|
+
declare function useXbNovaContext(entries: XbNovaContextEntry[] | (() => XbNovaContextEntry[])): void;
|
|
252
267
|
/** 방문자 식별자 — 없으면 SDK가 즉시 만들어 localStorage에 고정한 뒤 그 값을 반환한다. */
|
|
253
268
|
declare function useXbNovaVisitor(): string;
|
|
254
269
|
/** 선언형 — 서버 컴포넌트 트리에서 훅을 못 쓸 때. `<XbNovaFact id="xbnova_summary" value="..." />`. */
|
|
@@ -274,4 +289,4 @@ declare function useXbNovaSettings(): {
|
|
|
274
289
|
showBar: () => void;
|
|
275
290
|
};
|
|
276
291
|
|
|
277
|
-
export { type ChatMessage, type FactValue, type MessagePart, type ProductItem, type TextPart, type ToolPart, type UseXbNovaChatResult, type VerdictAction, type VerdictOutput, type ViewKind, type ViewRenderer, type ViewRendererMap, XbNovaChat, type XbNovaClientAction, type XbNovaClientActionResult, type XbNovaClientActions, XbNovaFact, XbNovaFacts, type XbNovaFeedbackEvent, type XbNovaFeedbackRating, type XbNovaFeedbackReason, type XbNovaOnboarding, XbNovaProvider, type XbNovaTheme, XbNovaTrack, trackXbNovaEvent, useXbNovaChat, useXbNovaFact, useXbNovaFacts, useXbNovaSettings, useXbNovaTrack, useXbNovaVisitor };
|
|
292
|
+
export { type ChatMessage, type FactValue, type MessagePart, type ProductItem, type TextPart, type ToolPart, type UseXbNovaChatResult, type VerdictAction, type VerdictOutput, type ViewKind, type ViewRenderer, type ViewRendererMap, XbNovaChat, type XbNovaClientAction, type XbNovaClientActionResult, type XbNovaClientActions, type XbNovaContextEntry, XbNovaFact, XbNovaFacts, type XbNovaFeedbackEvent, type XbNovaFeedbackRating, type XbNovaFeedbackReason, type XbNovaOnboarding, XbNovaProvider, type XbNovaTheme, XbNovaTrack, trackXbNovaEvent, useXbNovaChat, useXbNovaContext, useXbNovaFact, useXbNovaFacts, useXbNovaSettings, useXbNovaTrack, useXbNovaVisitor };
|
package/dist/index.js
CHANGED
|
@@ -40,6 +40,17 @@ function resolveVisitorId() {
|
|
|
40
40
|
function resolveFactValue(value) {
|
|
41
41
|
return typeof value === "function" ? value() : value;
|
|
42
42
|
}
|
|
43
|
+
function collectContextEntries(registry) {
|
|
44
|
+
const out = [];
|
|
45
|
+
for (const source of registry.values()) {
|
|
46
|
+
const entries = typeof source === "function" ? source() : source;
|
|
47
|
+
if (!Array.isArray(entries)) continue;
|
|
48
|
+
for (const e of entries) {
|
|
49
|
+
if (e && typeof e.title === "string" && typeof e.description === "string") out.push(e);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
43
54
|
function InternalProvider({
|
|
44
55
|
auth,
|
|
45
56
|
clientActionHandlers,
|
|
@@ -48,6 +59,7 @@ function InternalProvider({
|
|
|
48
59
|
}) {
|
|
49
60
|
const trackRegistry = useRef(/* @__PURE__ */ new Map()).current;
|
|
50
61
|
const factsRegistry = useRef(/* @__PURE__ */ new Map()).current;
|
|
62
|
+
const contextRegistry = useRef(/* @__PURE__ */ new Map()).current;
|
|
51
63
|
const emptyHandlers = useRef(/* @__PURE__ */ new Map()).current;
|
|
52
64
|
const visitorIdRef = useRef(null);
|
|
53
65
|
if (visitorIdRef.current === null) {
|
|
@@ -58,11 +70,12 @@ function InternalProvider({
|
|
|
58
70
|
auth,
|
|
59
71
|
trackRegistry,
|
|
60
72
|
factsRegistry,
|
|
73
|
+
contextRegistry,
|
|
61
74
|
clientActionHandlers: clientActionHandlers ?? emptyHandlers,
|
|
62
75
|
visitorId: visitorIdRef.current,
|
|
63
76
|
theme
|
|
64
77
|
}),
|
|
65
|
-
[auth, trackRegistry, factsRegistry, clientActionHandlers, emptyHandlers, theme]
|
|
78
|
+
[auth, trackRegistry, factsRegistry, contextRegistry, clientActionHandlers, emptyHandlers, theme]
|
|
66
79
|
);
|
|
67
80
|
return /* @__PURE__ */ jsx(InternalContext.Provider, { value, children });
|
|
68
81
|
}
|
|
@@ -1089,7 +1102,7 @@ async function resumeToolResult(apiBaseUrl, apiKey, body, handlers) {
|
|
|
1089
1102
|
// src/use-chat.ts
|
|
1090
1103
|
var DEFAULT_CLIENT_ACTION_TIMEOUT_MS = 15e3;
|
|
1091
1104
|
function useXbNovaChat(options) {
|
|
1092
|
-
const { auth, trackRegistry, clientActionHandlers, visitorId } = useXbNovaInternal();
|
|
1105
|
+
const { auth, trackRegistry, contextRegistry, clientActionHandlers, visitorId } = useXbNovaInternal();
|
|
1093
1106
|
const botId = options?.botId ?? auth.botId;
|
|
1094
1107
|
const nudgeNodeId = options?.nudgeNodeId;
|
|
1095
1108
|
const { apiKey, apiBaseUrl } = auth;
|
|
@@ -1241,7 +1254,9 @@ function useXbNovaChat(options) {
|
|
|
1241
1254
|
return next;
|
|
1242
1255
|
});
|
|
1243
1256
|
const focused = getFocusedTrackEntry(trackRegistry);
|
|
1244
|
-
const
|
|
1257
|
+
const notes = collectContextEntries(contextRegistry);
|
|
1258
|
+
const screen = focused ? { region: focused.region, data: resolveFactValue(focused.data) } : {};
|
|
1259
|
+
const context = focused || notes.length ? { ...screen, ...notes.length ? { notes } : {} } : void 0;
|
|
1245
1260
|
try {
|
|
1246
1261
|
await streamChat(
|
|
1247
1262
|
apiBaseUrl,
|
|
@@ -1251,7 +1266,8 @@ function useXbNovaChat(options) {
|
|
|
1251
1266
|
message: trimmed,
|
|
1252
1267
|
conversation_id: onboarding?.conversation_id ?? null,
|
|
1253
1268
|
context,
|
|
1254
|
-
nudge_node_id: nudgeNodeId ?? null
|
|
1269
|
+
nudge_node_id: nudgeNodeId ?? null,
|
|
1270
|
+
opening_message: messages.length === 0 ? (options?.openingMessage ?? onboarding?.greeting) || null : null
|
|
1255
1271
|
},
|
|
1256
1272
|
{ onPart: replaceLast, onMessageId: setLastAssistantId, onError: setError }
|
|
1257
1273
|
);
|
|
@@ -1550,6 +1566,7 @@ function XbNovaChat({
|
|
|
1550
1566
|
onFeedback,
|
|
1551
1567
|
botId: activeBotId ?? botId,
|
|
1552
1568
|
nudgeNodeId: activeNudgeNodeId,
|
|
1569
|
+
openingMessage: openingLine ?? void 0,
|
|
1553
1570
|
onDismissSheet: () => setOpen(false)
|
|
1554
1571
|
});
|
|
1555
1572
|
const effectiveBotId = activeBotId ?? botId;
|
|
@@ -2124,7 +2141,7 @@ function AnswerActionsFrame({
|
|
|
2124
2141
|
}
|
|
2125
2142
|
|
|
2126
2143
|
// src/facts.ts
|
|
2127
|
-
import { useEffect as useEffect9, useRef as useRef9 } from "react";
|
|
2144
|
+
import { useEffect as useEffect9, useId, useRef as useRef9 } from "react";
|
|
2128
2145
|
function useXbNovaFact(key, value) {
|
|
2129
2146
|
const { factsRegistry } = useXbNovaInternal();
|
|
2130
2147
|
useEffect9(() => {
|
|
@@ -2153,6 +2170,18 @@ function useXbNovaFacts(values) {
|
|
|
2153
2170
|
};
|
|
2154
2171
|
}, [factsRegistry]);
|
|
2155
2172
|
}
|
|
2173
|
+
function useXbNovaContext(entries) {
|
|
2174
|
+
const { contextRegistry } = useXbNovaInternal();
|
|
2175
|
+
const id = useId();
|
|
2176
|
+
useEffect9(() => {
|
|
2177
|
+
contextRegistry.set(id, entries);
|
|
2178
|
+
});
|
|
2179
|
+
useEffect9(() => {
|
|
2180
|
+
return () => {
|
|
2181
|
+
contextRegistry.delete(id);
|
|
2182
|
+
};
|
|
2183
|
+
}, [id, contextRegistry]);
|
|
2184
|
+
}
|
|
2156
2185
|
function useXbNovaVisitor() {
|
|
2157
2186
|
const { visitorId } = useXbNovaInternal();
|
|
2158
2187
|
return visitorId;
|
|
@@ -2173,6 +2202,7 @@ export {
|
|
|
2173
2202
|
XbNovaTrack,
|
|
2174
2203
|
trackXbNovaEvent,
|
|
2175
2204
|
useXbNovaChat,
|
|
2205
|
+
useXbNovaContext,
|
|
2176
2206
|
useXbNovaFact,
|
|
2177
2207
|
useXbNovaFacts,
|
|
2178
2208
|
useXbNovaSettings,
|