@xbrain-swe/nova-chat-widget 0.1.0
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 +1857 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +225 -0
- package/dist/index.d.ts +225 -0
- package/dist/index.js +1809 -0
- package/dist/index.js.map +1 -0
- package/dist/style.css +2 -0
- package/package.json +50 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
|
|
3
|
+
type XbNovaClientAction = {
|
|
4
|
+
/** 모델이 "언제 이 tool을 부를지" 판단하는 근거 — MCP tool description과 같은 역할. */
|
|
5
|
+
description: string;
|
|
6
|
+
/** JSON Schema. 안 주면 인자 없는 tool로 노출된다. */
|
|
7
|
+
inputSchema?: Record<string, unknown>;
|
|
8
|
+
/** `awaitResult`가 false(기본, fire-and-forget)일 때만 쓴다 — 모델에게 되돌려줄 순수
|
|
9
|
+
* 텍스트 템플릿, `{필드명}`으로 이 tool의 input을 치환한다(예:
|
|
10
|
+
* `"{region} 섹션을 화면에 표시했습니다."`). 안 주면 서버 기본값("완료했습니다.")을 쓴다. */
|
|
11
|
+
resultText?: string;
|
|
12
|
+
/** true면 이건 "보여주기"가 아니라 "진짜 데이터를 조회해오는" tool이다 — `handler`가
|
|
13
|
+
* 반환한 값이 실제 tool 결과로 서버에 다시 전송되고(`POST
|
|
14
|
+
* /v1/conversations/{id}/tool-results`), AI는 그 데이터로 이어서 대화한다(LangGraph의
|
|
15
|
+
* interrupt/resume과 같은 패턴). false(기본)면 `handler`는 그냥 실행되고 끝 —
|
|
16
|
+
* 반환값은 안 쓴다. */
|
|
17
|
+
awaitResult?: boolean;
|
|
18
|
+
/** 실제로 실행할 동작 — 채팅에는 아무것도 안 그리고 이 함수만 호출된다. `payload`는 이
|
|
19
|
+
* tool 호출의 input을 그대로 되돌려준다. `awaitResult:true`면 반환값(또는 resolve된
|
|
20
|
+
* Promise)이 진짜 tool 결과 텍스트가 된다 — 비워두면 "핸들러가 결과를 반환하지
|
|
21
|
+
* 않았습니다" 에러로 처리된다. */
|
|
22
|
+
handler: (payload: unknown) => void | string | Promise<void | string>;
|
|
23
|
+
/** true면 이 tool이 실행되는 시점에 대화 시트를 닫는다(대화는 안 사라진다, 나중에
|
|
24
|
+
* 다시 열면 이어짐). `highlight_region`처럼 "페이지의 특정 부분을 보여주는" 액션에
|
|
25
|
+
* 필요하다 — 모바일에서는 시트가 화면 대부분(위 7rem 제외)을 덮어서, 시트를 안 닫으면
|
|
26
|
+
* 스크롤·하이라이트가 그 밑에 가려 사용자 눈에 전혀 안 보인다. */
|
|
27
|
+
dismissSheet?: boolean;
|
|
28
|
+
/** 주면 이 tool 호출을 채팅 말풍선 자리에 직접 그린다(안 주면 기존처럼 아무것도 안
|
|
29
|
+
* 그리고 `handler`만 조용히 실행된다). "상담신청 버튼을 대화 안에 띄워줘"처럼, 결과가
|
|
30
|
+
* 텍스트가 아니라 실제 페이지 UI(버튼·팝업 트리거 등)여야 하는 client action을 위한
|
|
31
|
+
* 자리다. `payload`는 이 tool 호출의 input을 그대로 받는다 — 서버에는 안 보낸다(순수
|
|
32
|
+
* 렌더링용이라 `handler`처럼 서버 스펙 동기화 대상이 아니다). */
|
|
33
|
+
render?: (payload: unknown) => React.ReactNode;
|
|
34
|
+
};
|
|
35
|
+
type XbNovaClientActions = Record<string, XbNovaClientAction>;
|
|
36
|
+
|
|
37
|
+
type FactValue = unknown | (() => unknown);
|
|
38
|
+
/** 위젯 아바타·pill 배경 그라디언트에 쓰는 두 색상 — 기본값은 SDK 자체 톤(인디고→바이올렛)
|
|
39
|
+
* 이고, 소비자가 `<XbNovaProvider theme={{accentFrom, accentTo}}>`로 자기 브랜드 컬러를
|
|
40
|
+
* 넘기면 그걸 쓴다("카통령 브랜드 컬러를 따르게 해달라" — 파랑/보라가 사이트 톤과 안
|
|
41
|
+
* 어울린다는 피드백). CSS 커스텀 프로퍼티(`--xbnova-accent-1/2`)로 shadow host에 실려
|
|
42
|
+
* shadow DOM 안까지 상속된다(styles.css의 `.xbnova-glow-bg`, chat.tsx의 아바타 배지 참고). */
|
|
43
|
+
type XbNovaTheme = {
|
|
44
|
+
accentFrom: string;
|
|
45
|
+
accentTo: string;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
declare function XbNovaProvider({ apiKey, botId, appId, screen, apiBaseUrl, clientActions, theme, children, }: {
|
|
49
|
+
apiKey: string;
|
|
50
|
+
botId: string;
|
|
51
|
+
appId: string;
|
|
52
|
+
screen?: string;
|
|
53
|
+
apiBaseUrl?: string;
|
|
54
|
+
/** 이 페이지가 AI에게 내어줄 client action tool — 이름별로 설명·스키마·실행 함수를
|
|
55
|
+
* 등록한다("SDK 초기화 시점에 등록"). 스펙은 App 레벨 레지스트리로 자동 동기화되고
|
|
56
|
+
* (`XbNovaClientActionSync`), 콘솔의 tool 목록에 반영된다. 핸들러는 여기서만 산다. */
|
|
57
|
+
clientActions?: XbNovaClientActions;
|
|
58
|
+
/** 위젯 아바타·pill 배경에 쓰는 브랜드 컬러(그라디언트 시작/끝). 안 주면 SDK 기본
|
|
59
|
+
* 톤(인디고→바이올렛)을 쓴다 — 소비자 사이트 톤에 안 맞으면 여기서 자기 브랜드 컬러로
|
|
60
|
+
* 바꾸면 된다(예: `{accentFrom: "#BD1B21", accentTo: "#6B1317"}`). */
|
|
61
|
+
theme?: Partial<XbNovaTheme>;
|
|
62
|
+
children: React.ReactNode;
|
|
63
|
+
}): react.JSX.Element;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* AI SDK UI Message Stream v1 파서. `nova/web/lib/chat-stream.ts`에서 그대로 옮겼다 — 이미
|
|
67
|
+
* 콘솔에서 검증된 로직이라 새로 설계하지 않는다.
|
|
68
|
+
*
|
|
69
|
+
* `ai` 패키지에 의존하지 않는다 — 고객사 번들에 peer 버전 충돌을 만들지 않기 위해서다.
|
|
70
|
+
*/
|
|
71
|
+
type ViewKind = "product_list" | "product_detail" | "metric" | "choices" | "form" | "verdict";
|
|
72
|
+
type ToolPart = {
|
|
73
|
+
kind: "tool";
|
|
74
|
+
toolCallId: string;
|
|
75
|
+
toolName: string;
|
|
76
|
+
state: "input" | "output" | "error";
|
|
77
|
+
input?: unknown;
|
|
78
|
+
output?: unknown;
|
|
79
|
+
/** 위젯은 tool 이름이 아니라 이 값으로 렌더러를 고른다. */
|
|
80
|
+
view?: ViewKind | null;
|
|
81
|
+
};
|
|
82
|
+
type TextPart = {
|
|
83
|
+
kind: "text";
|
|
84
|
+
id: string;
|
|
85
|
+
text: string;
|
|
86
|
+
};
|
|
87
|
+
type MessagePart = TextPart | ToolPart;
|
|
88
|
+
type ChatMessage = {
|
|
89
|
+
role: "user" | "assistant";
|
|
90
|
+
parts: MessagePart[];
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
type ProductItem = {
|
|
94
|
+
id: string;
|
|
95
|
+
title: string;
|
|
96
|
+
subtitle?: string;
|
|
97
|
+
price?: {
|
|
98
|
+
amount: number | null;
|
|
99
|
+
currency: string;
|
|
100
|
+
};
|
|
101
|
+
imageUrl?: string | null;
|
|
102
|
+
badges?: string[];
|
|
103
|
+
attributes?: {
|
|
104
|
+
label: string;
|
|
105
|
+
value: string;
|
|
106
|
+
}[];
|
|
107
|
+
href?: string | null;
|
|
108
|
+
description?: string | null;
|
|
109
|
+
};
|
|
110
|
+
type VerdictAction = {
|
|
111
|
+
label: string;
|
|
112
|
+
/** primary(기본, 채운 버튼) | ghost(테두리만) — 기획서 4.2의 [상담신청]/[성능점검 보기] 처럼 하나는 강조, 나머지는 보조로 두고 싶을 때 쓴다. */
|
|
113
|
+
kind?: "primary" | "ghost";
|
|
114
|
+
/** 카통령 등 소비자 쪽 동작을 가리키는 자유 문자열 — SDK는 뜻을 모른다, `onVerdictAction`으로 그대로 넘긴다. */
|
|
115
|
+
action: string;
|
|
116
|
+
};
|
|
117
|
+
type VerdictOutput = {
|
|
118
|
+
/** 카드 상단 라벨 — 기본 "조건부 검토". */
|
|
119
|
+
headline?: string;
|
|
120
|
+
conclusion: string;
|
|
121
|
+
evidence: string;
|
|
122
|
+
/** 데이터로 답할 수 없는 것 — 기획서 4.2 ③: 비워두지 말고 최소 1개 이상 밝히도록 유도한다. */
|
|
123
|
+
unknowns?: string[];
|
|
124
|
+
actions?: VerdictAction[];
|
|
125
|
+
};
|
|
126
|
+
type ViewRenderer = (props: {
|
|
127
|
+
output: unknown;
|
|
128
|
+
onVerdictAction?: (action: string) => void;
|
|
129
|
+
}) => React.ReactNode;
|
|
130
|
+
type ViewRendererMap = Partial<Record<ViewKind, ViewRenderer>>;
|
|
131
|
+
|
|
132
|
+
declare function XbNovaChat({ viewRenderers, botId, barStyle, panelStyle, backdropStyle, defaultOpen, idleText, onVerdictAction, }: {
|
|
133
|
+
/** 특정 view만 자체 컴포넌트로 덮어쓰고 싶을 때 — 지정 안 한 view는 기본 렌더러를 쓴다. */
|
|
134
|
+
viewRenderers?: ViewRendererMap;
|
|
135
|
+
/** Provider의 기본 봇 대신 다른 봇과 고정적으로 대화하고 싶을 때. 힌트를 눌러 열면
|
|
136
|
+
* 그 힌트의 handoff 봇이 이 값보다 우선한다. */
|
|
137
|
+
botId?: string;
|
|
138
|
+
/** 닫힌 상태(기본/힌트 바)의 z-index·하단 offset — 이 사이트의 CTA 위에 오도록. SDK
|
|
139
|
+
* 기본값 위에 준 속성만 덮어쓴다(전체 교체 아님) — 보통 `zIndex`·`bottom` 정도만 주면
|
|
140
|
+
* 된다. 반드시 인라인 style이다(Tailwind 클래스 문자열은 안 먹는다, 위 파일 설명 참고).
|
|
141
|
+
* 예: `{ bottom: "76px", zIndex: 45 }`. */
|
|
142
|
+
barStyle?: React.CSSProperties;
|
|
143
|
+
/** 열린 상태(대화 시트/패널)의 z-index·offset. 마찬가지로 기본값 위에 병합된다. */
|
|
144
|
+
panelStyle?: React.CSSProperties;
|
|
145
|
+
/** 모바일 바텀시트 뒤 딤 배경의 z-index. `panelStyle`보다 살짝 낮게 둬야 한다. */
|
|
146
|
+
backdropStyle?: React.CSSProperties;
|
|
147
|
+
/** true면 처음부터 시트가 열려 있다. */
|
|
148
|
+
defaultOpen?: boolean;
|
|
149
|
+
/** 기본(idle) 상태 바 문구. */
|
|
150
|
+
idleText?: string;
|
|
151
|
+
/** 판단 카드의 행동 버튼을 눌렀을 때 — 실제 동작(상담신청 폼 열기, 섹션 스크롤 등)은
|
|
152
|
+
* 소비자가 정한다. SDK는 버튼에 적힌 `action` 문자열을 그대로 넘겨줄 뿐 뜻을 모른다. */
|
|
153
|
+
onVerdictAction?: (action: string) => void;
|
|
154
|
+
}): react.JSX.Element | null;
|
|
155
|
+
|
|
156
|
+
type XbNovaOnboarding = {
|
|
157
|
+
conversation_id: string;
|
|
158
|
+
greeting: string;
|
|
159
|
+
quick_replies: string[];
|
|
160
|
+
branding: {
|
|
161
|
+
title?: string;
|
|
162
|
+
};
|
|
163
|
+
};
|
|
164
|
+
type UseXbNovaChatResult = {
|
|
165
|
+
onboarding: XbNovaOnboarding | null;
|
|
166
|
+
messages: ChatMessage[];
|
|
167
|
+
busy: boolean;
|
|
168
|
+
error: string | null;
|
|
169
|
+
send: (text: string) => Promise<void>;
|
|
170
|
+
};
|
|
171
|
+
/** `botId`를 넘기면 Provider의 기본 봇 대신 그 봇으로 새 대화를 연다 — 넛지 handoff가 쓴다.
|
|
172
|
+
* `nudgeNodeId`를 넘기면 이 대화가 그 넛지에서 시작됐다고 서버에 표시한다 — 넛지 전환
|
|
173
|
+
* 퍼널(노출→클릭→첫질문→전환)의 마지막 단계가 이 값이 채워진 대화 수를 센다.
|
|
174
|
+
* `onDismissSheet`는 `dismissSheet: true`인 client action이 실행될 때 호출된다 —
|
|
175
|
+
* `<XbNovaChat>`이 시트를 닫는 함수를 넘겨준다(모바일에서 시트가 페이지 대부분을 덮어서,
|
|
176
|
+
* 안 닫으면 그 밑에서 일어나는 일이 안 보인다). */
|
|
177
|
+
declare function useXbNovaChat(options?: {
|
|
178
|
+
botId?: string;
|
|
179
|
+
nudgeNodeId?: string;
|
|
180
|
+
onDismissSheet?: () => void;
|
|
181
|
+
}): UseXbNovaChatResult;
|
|
182
|
+
|
|
183
|
+
/** ref형 — 감싸는 엘리먼트를 늘리기 싫을 때. `<div ref={useXbNovaTrack("price", data)}>`. */
|
|
184
|
+
declare function useXbNovaTrack<T extends HTMLElement = HTMLElement>(region: string, data?: FactValue, label?: string): (node: T | null) => void;
|
|
185
|
+
/** 선언형 — 감싸기만 하면 됨. `<XbNovaTrack region="price" data={{...}}>...</XbNovaTrack>`. */
|
|
186
|
+
declare function XbNovaTrack({ region, data, label, className, children, }: {
|
|
187
|
+
region: string;
|
|
188
|
+
data?: FactValue;
|
|
189
|
+
/** 사람이 읽는 이름 — 넛지 힌트·대화 오프닝 문구에 쓴다(예: "보증 정보"). */
|
|
190
|
+
label?: string;
|
|
191
|
+
className?: string;
|
|
192
|
+
children: React.ReactNode;
|
|
193
|
+
}): react.JSX.Element;
|
|
194
|
+
|
|
195
|
+
/** 커스텀 값 하나를 조건에서 쓸 수 있게 등록한다. 값 또는 함수(pull) 둘 다 된다. */
|
|
196
|
+
declare function useXbNovaFact(key: string, value: FactValue): void;
|
|
197
|
+
/** 필드가 여러 개인 객체 하나를 한 번에 등록한다 — 매물 데이터처럼. `useXbNovaFact`를
|
|
198
|
+
* 필드마다 반복하는 것과 같다. */
|
|
199
|
+
declare function useXbNovaFacts(values: Record<string, FactValue>): void;
|
|
200
|
+
/** 방문자 식별자 — 없으면 SDK가 즉시 만들어 localStorage에 고정한 뒤 그 값을 반환한다. */
|
|
201
|
+
declare function useXbNovaVisitor(): string;
|
|
202
|
+
/** 선언형 — 서버 컴포넌트 트리에서 훅을 못 쓸 때. `<XbNovaFact id="xbnova_summary" value="..." />`. */
|
|
203
|
+
declare function XbNovaFact({ id, value }: {
|
|
204
|
+
id: string;
|
|
205
|
+
value: FactValue;
|
|
206
|
+
}): null;
|
|
207
|
+
/** 선언형 — `useXbNovaFacts`의 컴포넌트 버전. */
|
|
208
|
+
declare function XbNovaFacts({ values }: {
|
|
209
|
+
values: Record<string, FactValue>;
|
|
210
|
+
}): null;
|
|
211
|
+
|
|
212
|
+
/** 이벤트 트리거를 발동시킨다 — 폴링을 기다리지 않고 그 즉시 평가한다. */
|
|
213
|
+
declare function trackXbNovaEvent(eventName: string): void;
|
|
214
|
+
|
|
215
|
+
/** 공개 API — 고객사가 설정 화면(F6)에서 동행 바/힌트를 끄고 켤 수 있게 노출한다. */
|
|
216
|
+
declare function useXbNovaSettings(): {
|
|
217
|
+
hintsEnabled: boolean;
|
|
218
|
+
disableHints: () => void;
|
|
219
|
+
enableHints: () => void;
|
|
220
|
+
barHidden: boolean;
|
|
221
|
+
hideBar: () => void;
|
|
222
|
+
showBar: () => void;
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
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 XbNovaClientActions, XbNovaFact, XbNovaFacts, type XbNovaOnboarding, XbNovaProvider, type XbNovaTheme, XbNovaTrack, trackXbNovaEvent, useXbNovaChat, useXbNovaFact, useXbNovaFacts, useXbNovaSettings, useXbNovaTrack, useXbNovaVisitor };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
|
|
3
|
+
type XbNovaClientAction = {
|
|
4
|
+
/** 모델이 "언제 이 tool을 부를지" 판단하는 근거 — MCP tool description과 같은 역할. */
|
|
5
|
+
description: string;
|
|
6
|
+
/** JSON Schema. 안 주면 인자 없는 tool로 노출된다. */
|
|
7
|
+
inputSchema?: Record<string, unknown>;
|
|
8
|
+
/** `awaitResult`가 false(기본, fire-and-forget)일 때만 쓴다 — 모델에게 되돌려줄 순수
|
|
9
|
+
* 텍스트 템플릿, `{필드명}`으로 이 tool의 input을 치환한다(예:
|
|
10
|
+
* `"{region} 섹션을 화면에 표시했습니다."`). 안 주면 서버 기본값("완료했습니다.")을 쓴다. */
|
|
11
|
+
resultText?: string;
|
|
12
|
+
/** true면 이건 "보여주기"가 아니라 "진짜 데이터를 조회해오는" tool이다 — `handler`가
|
|
13
|
+
* 반환한 값이 실제 tool 결과로 서버에 다시 전송되고(`POST
|
|
14
|
+
* /v1/conversations/{id}/tool-results`), AI는 그 데이터로 이어서 대화한다(LangGraph의
|
|
15
|
+
* interrupt/resume과 같은 패턴). false(기본)면 `handler`는 그냥 실행되고 끝 —
|
|
16
|
+
* 반환값은 안 쓴다. */
|
|
17
|
+
awaitResult?: boolean;
|
|
18
|
+
/** 실제로 실행할 동작 — 채팅에는 아무것도 안 그리고 이 함수만 호출된다. `payload`는 이
|
|
19
|
+
* tool 호출의 input을 그대로 되돌려준다. `awaitResult:true`면 반환값(또는 resolve된
|
|
20
|
+
* Promise)이 진짜 tool 결과 텍스트가 된다 — 비워두면 "핸들러가 결과를 반환하지
|
|
21
|
+
* 않았습니다" 에러로 처리된다. */
|
|
22
|
+
handler: (payload: unknown) => void | string | Promise<void | string>;
|
|
23
|
+
/** true면 이 tool이 실행되는 시점에 대화 시트를 닫는다(대화는 안 사라진다, 나중에
|
|
24
|
+
* 다시 열면 이어짐). `highlight_region`처럼 "페이지의 특정 부분을 보여주는" 액션에
|
|
25
|
+
* 필요하다 — 모바일에서는 시트가 화면 대부분(위 7rem 제외)을 덮어서, 시트를 안 닫으면
|
|
26
|
+
* 스크롤·하이라이트가 그 밑에 가려 사용자 눈에 전혀 안 보인다. */
|
|
27
|
+
dismissSheet?: boolean;
|
|
28
|
+
/** 주면 이 tool 호출을 채팅 말풍선 자리에 직접 그린다(안 주면 기존처럼 아무것도 안
|
|
29
|
+
* 그리고 `handler`만 조용히 실행된다). "상담신청 버튼을 대화 안에 띄워줘"처럼, 결과가
|
|
30
|
+
* 텍스트가 아니라 실제 페이지 UI(버튼·팝업 트리거 등)여야 하는 client action을 위한
|
|
31
|
+
* 자리다. `payload`는 이 tool 호출의 input을 그대로 받는다 — 서버에는 안 보낸다(순수
|
|
32
|
+
* 렌더링용이라 `handler`처럼 서버 스펙 동기화 대상이 아니다). */
|
|
33
|
+
render?: (payload: unknown) => React.ReactNode;
|
|
34
|
+
};
|
|
35
|
+
type XbNovaClientActions = Record<string, XbNovaClientAction>;
|
|
36
|
+
|
|
37
|
+
type FactValue = unknown | (() => unknown);
|
|
38
|
+
/** 위젯 아바타·pill 배경 그라디언트에 쓰는 두 색상 — 기본값은 SDK 자체 톤(인디고→바이올렛)
|
|
39
|
+
* 이고, 소비자가 `<XbNovaProvider theme={{accentFrom, accentTo}}>`로 자기 브랜드 컬러를
|
|
40
|
+
* 넘기면 그걸 쓴다("카통령 브랜드 컬러를 따르게 해달라" — 파랑/보라가 사이트 톤과 안
|
|
41
|
+
* 어울린다는 피드백). CSS 커스텀 프로퍼티(`--xbnova-accent-1/2`)로 shadow host에 실려
|
|
42
|
+
* shadow DOM 안까지 상속된다(styles.css의 `.xbnova-glow-bg`, chat.tsx의 아바타 배지 참고). */
|
|
43
|
+
type XbNovaTheme = {
|
|
44
|
+
accentFrom: string;
|
|
45
|
+
accentTo: string;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
declare function XbNovaProvider({ apiKey, botId, appId, screen, apiBaseUrl, clientActions, theme, children, }: {
|
|
49
|
+
apiKey: string;
|
|
50
|
+
botId: string;
|
|
51
|
+
appId: string;
|
|
52
|
+
screen?: string;
|
|
53
|
+
apiBaseUrl?: string;
|
|
54
|
+
/** 이 페이지가 AI에게 내어줄 client action tool — 이름별로 설명·스키마·실행 함수를
|
|
55
|
+
* 등록한다("SDK 초기화 시점에 등록"). 스펙은 App 레벨 레지스트리로 자동 동기화되고
|
|
56
|
+
* (`XbNovaClientActionSync`), 콘솔의 tool 목록에 반영된다. 핸들러는 여기서만 산다. */
|
|
57
|
+
clientActions?: XbNovaClientActions;
|
|
58
|
+
/** 위젯 아바타·pill 배경에 쓰는 브랜드 컬러(그라디언트 시작/끝). 안 주면 SDK 기본
|
|
59
|
+
* 톤(인디고→바이올렛)을 쓴다 — 소비자 사이트 톤에 안 맞으면 여기서 자기 브랜드 컬러로
|
|
60
|
+
* 바꾸면 된다(예: `{accentFrom: "#BD1B21", accentTo: "#6B1317"}`). */
|
|
61
|
+
theme?: Partial<XbNovaTheme>;
|
|
62
|
+
children: React.ReactNode;
|
|
63
|
+
}): react.JSX.Element;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* AI SDK UI Message Stream v1 파서. `nova/web/lib/chat-stream.ts`에서 그대로 옮겼다 — 이미
|
|
67
|
+
* 콘솔에서 검증된 로직이라 새로 설계하지 않는다.
|
|
68
|
+
*
|
|
69
|
+
* `ai` 패키지에 의존하지 않는다 — 고객사 번들에 peer 버전 충돌을 만들지 않기 위해서다.
|
|
70
|
+
*/
|
|
71
|
+
type ViewKind = "product_list" | "product_detail" | "metric" | "choices" | "form" | "verdict";
|
|
72
|
+
type ToolPart = {
|
|
73
|
+
kind: "tool";
|
|
74
|
+
toolCallId: string;
|
|
75
|
+
toolName: string;
|
|
76
|
+
state: "input" | "output" | "error";
|
|
77
|
+
input?: unknown;
|
|
78
|
+
output?: unknown;
|
|
79
|
+
/** 위젯은 tool 이름이 아니라 이 값으로 렌더러를 고른다. */
|
|
80
|
+
view?: ViewKind | null;
|
|
81
|
+
};
|
|
82
|
+
type TextPart = {
|
|
83
|
+
kind: "text";
|
|
84
|
+
id: string;
|
|
85
|
+
text: string;
|
|
86
|
+
};
|
|
87
|
+
type MessagePart = TextPart | ToolPart;
|
|
88
|
+
type ChatMessage = {
|
|
89
|
+
role: "user" | "assistant";
|
|
90
|
+
parts: MessagePart[];
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
type ProductItem = {
|
|
94
|
+
id: string;
|
|
95
|
+
title: string;
|
|
96
|
+
subtitle?: string;
|
|
97
|
+
price?: {
|
|
98
|
+
amount: number | null;
|
|
99
|
+
currency: string;
|
|
100
|
+
};
|
|
101
|
+
imageUrl?: string | null;
|
|
102
|
+
badges?: string[];
|
|
103
|
+
attributes?: {
|
|
104
|
+
label: string;
|
|
105
|
+
value: string;
|
|
106
|
+
}[];
|
|
107
|
+
href?: string | null;
|
|
108
|
+
description?: string | null;
|
|
109
|
+
};
|
|
110
|
+
type VerdictAction = {
|
|
111
|
+
label: string;
|
|
112
|
+
/** primary(기본, 채운 버튼) | ghost(테두리만) — 기획서 4.2의 [상담신청]/[성능점검 보기] 처럼 하나는 강조, 나머지는 보조로 두고 싶을 때 쓴다. */
|
|
113
|
+
kind?: "primary" | "ghost";
|
|
114
|
+
/** 카통령 등 소비자 쪽 동작을 가리키는 자유 문자열 — SDK는 뜻을 모른다, `onVerdictAction`으로 그대로 넘긴다. */
|
|
115
|
+
action: string;
|
|
116
|
+
};
|
|
117
|
+
type VerdictOutput = {
|
|
118
|
+
/** 카드 상단 라벨 — 기본 "조건부 검토". */
|
|
119
|
+
headline?: string;
|
|
120
|
+
conclusion: string;
|
|
121
|
+
evidence: string;
|
|
122
|
+
/** 데이터로 답할 수 없는 것 — 기획서 4.2 ③: 비워두지 말고 최소 1개 이상 밝히도록 유도한다. */
|
|
123
|
+
unknowns?: string[];
|
|
124
|
+
actions?: VerdictAction[];
|
|
125
|
+
};
|
|
126
|
+
type ViewRenderer = (props: {
|
|
127
|
+
output: unknown;
|
|
128
|
+
onVerdictAction?: (action: string) => void;
|
|
129
|
+
}) => React.ReactNode;
|
|
130
|
+
type ViewRendererMap = Partial<Record<ViewKind, ViewRenderer>>;
|
|
131
|
+
|
|
132
|
+
declare function XbNovaChat({ viewRenderers, botId, barStyle, panelStyle, backdropStyle, defaultOpen, idleText, onVerdictAction, }: {
|
|
133
|
+
/** 특정 view만 자체 컴포넌트로 덮어쓰고 싶을 때 — 지정 안 한 view는 기본 렌더러를 쓴다. */
|
|
134
|
+
viewRenderers?: ViewRendererMap;
|
|
135
|
+
/** Provider의 기본 봇 대신 다른 봇과 고정적으로 대화하고 싶을 때. 힌트를 눌러 열면
|
|
136
|
+
* 그 힌트의 handoff 봇이 이 값보다 우선한다. */
|
|
137
|
+
botId?: string;
|
|
138
|
+
/** 닫힌 상태(기본/힌트 바)의 z-index·하단 offset — 이 사이트의 CTA 위에 오도록. SDK
|
|
139
|
+
* 기본값 위에 준 속성만 덮어쓴다(전체 교체 아님) — 보통 `zIndex`·`bottom` 정도만 주면
|
|
140
|
+
* 된다. 반드시 인라인 style이다(Tailwind 클래스 문자열은 안 먹는다, 위 파일 설명 참고).
|
|
141
|
+
* 예: `{ bottom: "76px", zIndex: 45 }`. */
|
|
142
|
+
barStyle?: React.CSSProperties;
|
|
143
|
+
/** 열린 상태(대화 시트/패널)의 z-index·offset. 마찬가지로 기본값 위에 병합된다. */
|
|
144
|
+
panelStyle?: React.CSSProperties;
|
|
145
|
+
/** 모바일 바텀시트 뒤 딤 배경의 z-index. `panelStyle`보다 살짝 낮게 둬야 한다. */
|
|
146
|
+
backdropStyle?: React.CSSProperties;
|
|
147
|
+
/** true면 처음부터 시트가 열려 있다. */
|
|
148
|
+
defaultOpen?: boolean;
|
|
149
|
+
/** 기본(idle) 상태 바 문구. */
|
|
150
|
+
idleText?: string;
|
|
151
|
+
/** 판단 카드의 행동 버튼을 눌렀을 때 — 실제 동작(상담신청 폼 열기, 섹션 스크롤 등)은
|
|
152
|
+
* 소비자가 정한다. SDK는 버튼에 적힌 `action` 문자열을 그대로 넘겨줄 뿐 뜻을 모른다. */
|
|
153
|
+
onVerdictAction?: (action: string) => void;
|
|
154
|
+
}): react.JSX.Element | null;
|
|
155
|
+
|
|
156
|
+
type XbNovaOnboarding = {
|
|
157
|
+
conversation_id: string;
|
|
158
|
+
greeting: string;
|
|
159
|
+
quick_replies: string[];
|
|
160
|
+
branding: {
|
|
161
|
+
title?: string;
|
|
162
|
+
};
|
|
163
|
+
};
|
|
164
|
+
type UseXbNovaChatResult = {
|
|
165
|
+
onboarding: XbNovaOnboarding | null;
|
|
166
|
+
messages: ChatMessage[];
|
|
167
|
+
busy: boolean;
|
|
168
|
+
error: string | null;
|
|
169
|
+
send: (text: string) => Promise<void>;
|
|
170
|
+
};
|
|
171
|
+
/** `botId`를 넘기면 Provider의 기본 봇 대신 그 봇으로 새 대화를 연다 — 넛지 handoff가 쓴다.
|
|
172
|
+
* `nudgeNodeId`를 넘기면 이 대화가 그 넛지에서 시작됐다고 서버에 표시한다 — 넛지 전환
|
|
173
|
+
* 퍼널(노출→클릭→첫질문→전환)의 마지막 단계가 이 값이 채워진 대화 수를 센다.
|
|
174
|
+
* `onDismissSheet`는 `dismissSheet: true`인 client action이 실행될 때 호출된다 —
|
|
175
|
+
* `<XbNovaChat>`이 시트를 닫는 함수를 넘겨준다(모바일에서 시트가 페이지 대부분을 덮어서,
|
|
176
|
+
* 안 닫으면 그 밑에서 일어나는 일이 안 보인다). */
|
|
177
|
+
declare function useXbNovaChat(options?: {
|
|
178
|
+
botId?: string;
|
|
179
|
+
nudgeNodeId?: string;
|
|
180
|
+
onDismissSheet?: () => void;
|
|
181
|
+
}): UseXbNovaChatResult;
|
|
182
|
+
|
|
183
|
+
/** ref형 — 감싸는 엘리먼트를 늘리기 싫을 때. `<div ref={useXbNovaTrack("price", data)}>`. */
|
|
184
|
+
declare function useXbNovaTrack<T extends HTMLElement = HTMLElement>(region: string, data?: FactValue, label?: string): (node: T | null) => void;
|
|
185
|
+
/** 선언형 — 감싸기만 하면 됨. `<XbNovaTrack region="price" data={{...}}>...</XbNovaTrack>`. */
|
|
186
|
+
declare function XbNovaTrack({ region, data, label, className, children, }: {
|
|
187
|
+
region: string;
|
|
188
|
+
data?: FactValue;
|
|
189
|
+
/** 사람이 읽는 이름 — 넛지 힌트·대화 오프닝 문구에 쓴다(예: "보증 정보"). */
|
|
190
|
+
label?: string;
|
|
191
|
+
className?: string;
|
|
192
|
+
children: React.ReactNode;
|
|
193
|
+
}): react.JSX.Element;
|
|
194
|
+
|
|
195
|
+
/** 커스텀 값 하나를 조건에서 쓸 수 있게 등록한다. 값 또는 함수(pull) 둘 다 된다. */
|
|
196
|
+
declare function useXbNovaFact(key: string, value: FactValue): void;
|
|
197
|
+
/** 필드가 여러 개인 객체 하나를 한 번에 등록한다 — 매물 데이터처럼. `useXbNovaFact`를
|
|
198
|
+
* 필드마다 반복하는 것과 같다. */
|
|
199
|
+
declare function useXbNovaFacts(values: Record<string, FactValue>): void;
|
|
200
|
+
/** 방문자 식별자 — 없으면 SDK가 즉시 만들어 localStorage에 고정한 뒤 그 값을 반환한다. */
|
|
201
|
+
declare function useXbNovaVisitor(): string;
|
|
202
|
+
/** 선언형 — 서버 컴포넌트 트리에서 훅을 못 쓸 때. `<XbNovaFact id="xbnova_summary" value="..." />`. */
|
|
203
|
+
declare function XbNovaFact({ id, value }: {
|
|
204
|
+
id: string;
|
|
205
|
+
value: FactValue;
|
|
206
|
+
}): null;
|
|
207
|
+
/** 선언형 — `useXbNovaFacts`의 컴포넌트 버전. */
|
|
208
|
+
declare function XbNovaFacts({ values }: {
|
|
209
|
+
values: Record<string, FactValue>;
|
|
210
|
+
}): null;
|
|
211
|
+
|
|
212
|
+
/** 이벤트 트리거를 발동시킨다 — 폴링을 기다리지 않고 그 즉시 평가한다. */
|
|
213
|
+
declare function trackXbNovaEvent(eventName: string): void;
|
|
214
|
+
|
|
215
|
+
/** 공개 API — 고객사가 설정 화면(F6)에서 동행 바/힌트를 끄고 켤 수 있게 노출한다. */
|
|
216
|
+
declare function useXbNovaSettings(): {
|
|
217
|
+
hintsEnabled: boolean;
|
|
218
|
+
disableHints: () => void;
|
|
219
|
+
enableHints: () => void;
|
|
220
|
+
barHidden: boolean;
|
|
221
|
+
hideBar: () => void;
|
|
222
|
+
showBar: () => void;
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
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 XbNovaClientActions, XbNovaFact, XbNovaFacts, type XbNovaOnboarding, XbNovaProvider, type XbNovaTheme, XbNovaTrack, trackXbNovaEvent, useXbNovaChat, useXbNovaFact, useXbNovaFacts, useXbNovaSettings, useXbNovaTrack, useXbNovaVisitor };
|