teko-chat-sdk 1.0.0 → 1.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/README.md +21 -17
- package/dist/index.cjs +116 -12
- package/dist/index.d.cts +15 -5
- package/dist/index.d.ts +15 -5
- package/dist/index.js +116 -12
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ React component library giúp các ECOM app của Teko tích hợp AI chatbot v
|
|
|
7
7
|
- **3 UI states**: `bubble` → `mini` popup → `fullscreen` split layout (35/65)
|
|
8
8
|
- **Mobile mode**: `layoutMode="mobile"` — mini popup chuyển thành bottom sheet full-width; fullscreen chuyển thành single-column với floating toggle icon + right panel bottom sheet overlay
|
|
9
9
|
- **Streaming responses**: AI response xuất hiện dần theo chunks (typewriter effect)
|
|
10
|
-
- **Pluggable transport**:
|
|
10
|
+
- **Pluggable transport**: Truyền `transportMode` tường minh (`'websocket'` / `'stream'` / `'rest'`) — mock built-in khi `chatBffUrl` rỗng
|
|
11
11
|
- **Bidirectional context**: Right-side app UI push context ngược về AI qua `ref.sendContext()`
|
|
12
12
|
- **Intent-driven UI**: BFF trả về intent → SDK tự điều phối giao diện
|
|
13
13
|
- **Quick reply**: Suggest options từ BFF hiển thị dưới dạng clickable buttons
|
|
@@ -68,10 +68,11 @@ export default function App() {
|
|
|
68
68
|
|
|
69
69
|
**Core**
|
|
70
70
|
|
|
71
|
-
| Prop
|
|
72
|
-
|
|
|
73
|
-
| `appId`
|
|
74
|
-
| `chatBffUrl`
|
|
71
|
+
| Prop | Type | Required | Mô tả |
|
|
72
|
+
| --------------- | ----------------------------------- | -------- | -------------------------------------------------------- |
|
|
73
|
+
| `appId` | `string` | ✅ | App identifier, gửi lên BFF để phân biệt context |
|
|
74
|
+
| `chatBffUrl` | `string` | ✅ | BFF endpoint. Để `""` → SDK dùng mock handler (dev only) |
|
|
75
|
+
| `transportMode` | `'websocket' \| 'stream' \| 'rest'` | ✅ | Giao thức giao tiếp với BFF. Bắt buộc truyền tường minh. |
|
|
75
76
|
|
|
76
77
|
**Business logic**
|
|
77
78
|
|
|
@@ -200,13 +201,15 @@ function CartPage({ onContextUpdate }) {
|
|
|
200
201
|
|
|
201
202
|
## BFF Protocol
|
|
202
203
|
|
|
203
|
-
|
|
204
|
+
App consumer truyền `transportMode` tường minh để chọn giao thức:
|
|
204
205
|
|
|
205
|
-
| `
|
|
206
|
-
|
|
|
207
|
-
| `
|
|
208
|
-
| `
|
|
209
|
-
| `
|
|
206
|
+
| `transportMode` | Giao thức | Ghi chú |
|
|
207
|
+
| --------------- | -------------- | --------------------------------------------------------------------- |
|
|
208
|
+
| `'websocket'` | WebSocket | Persistent connection, BFF push `TransportFrame` JSON qua `ws.send()` |
|
|
209
|
+
| `'stream'` | HTTP Streaming | POST request, BFF trả newline-delimited JSON (`application/x-ndjson`) |
|
|
210
|
+
| `'rest'` | REST JSON | POST request, BFF trả JSON một lần (không stream) |
|
|
211
|
+
|
|
212
|
+
**Mock handler:** Khi `chatBffUrl=""` hoặc không truyền, SDK tự dùng mock handler tích hợp (bất kể `transportMode`). Không cần backend — simulate streaming word-by-word.
|
|
210
213
|
|
|
211
214
|
### TransportFrame (BFF → SDK streaming format)
|
|
212
215
|
|
|
@@ -412,7 +415,7 @@ teko-chat-sdk/
|
|
|
412
415
|
│ │ ├── WebSocketTransport.ts # wss:// — persistent WS, auto-retry
|
|
413
416
|
│ │ ├── HttpStreamTransport.ts # https:// — fetch ndjson streaming
|
|
414
417
|
│ │ ├── MockTransport.ts # dev fallback — wraps mockHandler, simulates chunks
|
|
415
|
-
│ │ └── createTransport.ts # factory:
|
|
418
|
+
│ │ └── createTransport.ts # factory: chọn transport theo transportMode
|
|
416
419
|
│ ├── utils/
|
|
417
420
|
│ │ ├── mockHandler.ts # Mock BFF logic (dùng bởi MockTransport)
|
|
418
421
|
│ │ └── chatTheme.ts # ChatThemeContext, useChatTheme, hexToRgba
|
|
@@ -436,12 +439,13 @@ teko-chat-sdk/
|
|
|
436
439
|
```
|
|
437
440
|
ECOM App
|
|
438
441
|
│
|
|
439
|
-
└── <TekoChatWidget ref={chatRef} chatBffUrl="..." onIntent={...} renderRightPanel={...} />
|
|
442
|
+
└── <TekoChatWidget ref={chatRef} chatBffUrl="..." transportMode="stream" onIntent={...} renderRightPanel={...} />
|
|
440
443
|
│
|
|
441
|
-
│ createTransport(chatBffUrl)
|
|
442
|
-
│
|
|
443
|
-
│
|
|
444
|
-
│
|
|
444
|
+
│ createTransport(chatBffUrl, transportMode):
|
|
445
|
+
│ transportMode='websocket' → WebSocketTransport (persistent, streaming chunks)
|
|
446
|
+
│ transportMode='stream' → HttpStreamTransport (fetch ndjson)
|
|
447
|
+
│ transportMode='rest' → RestTransport (plain JSON, no stream)
|
|
448
|
+
│ chatBffUrl="" → MockTransport (dev, simulate streaming)
|
|
445
449
|
▼
|
|
446
450
|
BFF → LLM Core → Business Services
|
|
447
451
|
(push TransportFrame chunks: {type:'chunk'} → {type:'done'})
|
package/dist/index.cjs
CHANGED
|
@@ -1320,6 +1320,105 @@ var MockTransport = class {
|
|
|
1320
1320
|
}
|
|
1321
1321
|
};
|
|
1322
1322
|
|
|
1323
|
+
// src/transports/RestTransport.ts
|
|
1324
|
+
var TOOL_INTENT_MAP = {
|
|
1325
|
+
INTENT_VIEW_CART: {
|
|
1326
|
+
action: "show_ui",
|
|
1327
|
+
componentKey: "cart",
|
|
1328
|
+
intent: "viewCart"
|
|
1329
|
+
},
|
|
1330
|
+
INTENT_VIEW_ORDER: {
|
|
1331
|
+
action: "show_ui",
|
|
1332
|
+
componentKey: "order",
|
|
1333
|
+
intent: "viewOrder"
|
|
1334
|
+
}
|
|
1335
|
+
};
|
|
1336
|
+
var RestTransport = class {
|
|
1337
|
+
// POC default: gpt-4.1-mini — override bằng cách truyền model vào constructor nếu cần
|
|
1338
|
+
constructor(url, token, model = "gpt-4.1-mini") {
|
|
1339
|
+
this.url = url;
|
|
1340
|
+
this.token = token;
|
|
1341
|
+
this.model = model;
|
|
1342
|
+
}
|
|
1343
|
+
onChunk() {
|
|
1344
|
+
}
|
|
1345
|
+
onDone(cb) {
|
|
1346
|
+
this.doneCb = cb;
|
|
1347
|
+
}
|
|
1348
|
+
onError(cb) {
|
|
1349
|
+
this.errorCb = cb;
|
|
1350
|
+
}
|
|
1351
|
+
connect() {
|
|
1352
|
+
return Promise.resolve();
|
|
1353
|
+
}
|
|
1354
|
+
disconnect() {
|
|
1355
|
+
}
|
|
1356
|
+
async send(request) {
|
|
1357
|
+
try {
|
|
1358
|
+
const ctx = request.appContext ?? {};
|
|
1359
|
+
const metadata = {
|
|
1360
|
+
session_id: request.conversationId,
|
|
1361
|
+
...this.token && { authorization: this.token },
|
|
1362
|
+
...ctx
|
|
1363
|
+
};
|
|
1364
|
+
const body = {
|
|
1365
|
+
model: this.model,
|
|
1366
|
+
user: request.userId ?? "user",
|
|
1367
|
+
messages: [{ role: "user", content: request.message ?? "" }],
|
|
1368
|
+
metadata
|
|
1369
|
+
};
|
|
1370
|
+
const res = await fetch(this.url, {
|
|
1371
|
+
method: "POST",
|
|
1372
|
+
headers: {
|
|
1373
|
+
"Content-Type": "application/json",
|
|
1374
|
+
Accept: "application/json"
|
|
1375
|
+
},
|
|
1376
|
+
body: JSON.stringify(body)
|
|
1377
|
+
});
|
|
1378
|
+
if (!res.ok) {
|
|
1379
|
+
throw new Error(`[RestTransport] HTTP ${res.status}`);
|
|
1380
|
+
}
|
|
1381
|
+
const json = await res.json();
|
|
1382
|
+
const choice = json.choices?.[0];
|
|
1383
|
+
const content = choice?.message?.content ?? "";
|
|
1384
|
+
const toolCall = choice?.message?.tool_calls?.[0];
|
|
1385
|
+
let result;
|
|
1386
|
+
if (toolCall?.type === "function") {
|
|
1387
|
+
const mapped = TOOL_INTENT_MAP[toolCall.function.name] ?? {
|
|
1388
|
+
action: "show_ui",
|
|
1389
|
+
componentKey: toolCall.function.name.toLowerCase(),
|
|
1390
|
+
intent: toolCall.function.name
|
|
1391
|
+
};
|
|
1392
|
+
let intentPayload;
|
|
1393
|
+
try {
|
|
1394
|
+
intentPayload = JSON.parse(toolCall.function.arguments);
|
|
1395
|
+
} catch {
|
|
1396
|
+
}
|
|
1397
|
+
result = {
|
|
1398
|
+
conversationId: request.conversationId ?? json.id ?? "",
|
|
1399
|
+
message: content,
|
|
1400
|
+
intent: mapped.intent,
|
|
1401
|
+
action: mapped.action,
|
|
1402
|
+
componentKey: mapped.componentKey,
|
|
1403
|
+
intentPayload,
|
|
1404
|
+
timestamp: Date.now()
|
|
1405
|
+
};
|
|
1406
|
+
} else {
|
|
1407
|
+
result = {
|
|
1408
|
+
conversationId: request.conversationId ?? json.id ?? "",
|
|
1409
|
+
message: content,
|
|
1410
|
+
intent: "none",
|
|
1411
|
+
action: "none",
|
|
1412
|
+
timestamp: Date.now()
|
|
1413
|
+
};
|
|
1414
|
+
}
|
|
1415
|
+
this.doneCb?.(result);
|
|
1416
|
+
} catch (err) {
|
|
1417
|
+
this.errorCb?.(err);
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
};
|
|
1421
|
+
|
|
1323
1422
|
// src/transports/WebSocketTransport.ts
|
|
1324
1423
|
var MAX_RETRIES = 3;
|
|
1325
1424
|
var BASE_RETRY_DELAY_MS = 1e3;
|
|
@@ -1392,11 +1491,14 @@ var WebSocketTransport = class {
|
|
|
1392
1491
|
};
|
|
1393
1492
|
|
|
1394
1493
|
// src/transports/createTransport.ts
|
|
1395
|
-
function createTransport(bffUrl, conversationId, token) {
|
|
1494
|
+
function createTransport(bffUrl, conversationId, token, transportMode) {
|
|
1396
1495
|
if (!bffUrl) {
|
|
1397
1496
|
return new MockTransport(conversationId);
|
|
1398
1497
|
}
|
|
1399
|
-
if (
|
|
1498
|
+
if (transportMode === "rest") {
|
|
1499
|
+
return new RestTransport(bffUrl, token);
|
|
1500
|
+
}
|
|
1501
|
+
if (transportMode === "websocket") {
|
|
1400
1502
|
return new WebSocketTransport(bffUrl, token);
|
|
1401
1503
|
}
|
|
1402
1504
|
return new HttpStreamTransport(bffUrl, token);
|
|
@@ -1419,6 +1521,7 @@ var generateId = () => Math.random().toString(36).slice(2, 10);
|
|
|
1419
1521
|
var generateConversationId = () => `conv-${Date.now()}-${generateId()}`;
|
|
1420
1522
|
var useChatSession = ({
|
|
1421
1523
|
chatBffUrl,
|
|
1524
|
+
transportMode,
|
|
1422
1525
|
onIntent,
|
|
1423
1526
|
onDebugEvent,
|
|
1424
1527
|
getAppContext
|
|
@@ -1440,13 +1543,11 @@ var useChatSession = ({
|
|
|
1440
1543
|
}
|
|
1441
1544
|
setIsLoading(true);
|
|
1442
1545
|
const { userId, token } = await getTekoAuth();
|
|
1443
|
-
|
|
1444
|
-
if (
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
}
|
|
1449
|
-
}
|
|
1546
|
+
const sdkContext = {};
|
|
1547
|
+
if (token) sdkContext.authorization = token;
|
|
1548
|
+
const userAppContext = getAppContext ? await getAppContext() : {};
|
|
1549
|
+
const mergedContext = { ...sdkContext, ...userAppContext };
|
|
1550
|
+
const appContext = Object.keys(mergedContext).length > 0 ? mergedContext : void 0;
|
|
1450
1551
|
const req = {
|
|
1451
1552
|
conversationId: conversationIdRef.current,
|
|
1452
1553
|
timestamp: Date.now(),
|
|
@@ -1459,7 +1560,8 @@ var useChatSession = ({
|
|
|
1459
1560
|
const transport = createTransport(
|
|
1460
1561
|
chatBffUrl,
|
|
1461
1562
|
conversationIdRef.current,
|
|
1462
|
-
token
|
|
1563
|
+
token,
|
|
1564
|
+
transportMode
|
|
1463
1565
|
);
|
|
1464
1566
|
const streamingIdRef = { current: generateId() };
|
|
1465
1567
|
let firstChunk = true;
|
|
@@ -1502,7 +1604,7 @@ var useChatSession = ({
|
|
|
1502
1604
|
timestamp: Date.now(),
|
|
1503
1605
|
payload: { action: data.action, componentKey }
|
|
1504
1606
|
});
|
|
1505
|
-
onIntent?.(data.action, componentKey);
|
|
1607
|
+
onIntent?.(data.action, componentKey, data.intentPayload);
|
|
1506
1608
|
}
|
|
1507
1609
|
setMessages((prev) => {
|
|
1508
1610
|
const last = prev[prev.length - 1];
|
|
@@ -1561,7 +1663,7 @@ var useChatSession = ({
|
|
|
1561
1663
|
setIsLoading(false);
|
|
1562
1664
|
}
|
|
1563
1665
|
},
|
|
1564
|
-
[
|
|
1666
|
+
[getAppContext, onDebugEvent, chatBffUrl, transportMode, onIntent]
|
|
1565
1667
|
);
|
|
1566
1668
|
const contextDebounceRef = (0, import_react6.useRef)(null);
|
|
1567
1669
|
const sendMessage = (0, import_react6.useCallback)(
|
|
@@ -1635,6 +1737,7 @@ var TekoChatWidget = (0, import_react7.forwardRef)(
|
|
|
1635
1737
|
({
|
|
1636
1738
|
appId,
|
|
1637
1739
|
chatBffUrl,
|
|
1740
|
+
transportMode,
|
|
1638
1741
|
onIntent,
|
|
1639
1742
|
renderRightPanel,
|
|
1640
1743
|
renderBubble,
|
|
@@ -1674,6 +1777,7 @@ var TekoChatWidget = (0, import_react7.forwardRef)(
|
|
|
1674
1777
|
const { messages, isLoading, sendMessage, sendContext } = useChatSession({
|
|
1675
1778
|
appId,
|
|
1676
1779
|
chatBffUrl,
|
|
1780
|
+
transportMode,
|
|
1677
1781
|
onIntent: handleIntent,
|
|
1678
1782
|
onDebugEvent,
|
|
1679
1783
|
getAppContext
|
package/dist/index.d.cts
CHANGED
|
@@ -32,6 +32,8 @@ interface BFFResponseData {
|
|
|
32
32
|
options: SuggestOption[];
|
|
33
33
|
};
|
|
34
34
|
timestamp: number;
|
|
35
|
+
/** Payload từ tool_calls.arguments (parsed JSON). Populated bởi RestTransport khi BFF/LLM trả về tool_calls. */
|
|
36
|
+
intentPayload?: Record<string, unknown>;
|
|
35
37
|
}
|
|
36
38
|
interface BFFResponse {
|
|
37
39
|
code: number;
|
|
@@ -78,14 +80,22 @@ type TransportFrame = {
|
|
|
78
80
|
};
|
|
79
81
|
interface TekoChatWidgetProps {
|
|
80
82
|
appId: string;
|
|
81
|
-
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* - chuỗi rỗng hoặc không truyền → mock handler (dev only)
|
|
83
|
+
/**
|
|
84
|
+
* BFF endpoint.
|
|
85
|
+
* Để trống hoặc không truyền → SDK dùng mock handler (dev only).
|
|
85
86
|
*/
|
|
86
87
|
chatBffUrl: string;
|
|
88
|
+
/**
|
|
89
|
+
* Giao thức giao tiếp với BFF. Required.
|
|
90
|
+
* - `'websocket'` : WebSocket (ws:// hoặc wss://)
|
|
91
|
+
* - `'stream'` : HTTP ndjson streaming (http:// hoặc https://)
|
|
92
|
+
* - `'rest'` : Plain REST JSON — POST + nhận JSON một lần, không stream
|
|
93
|
+
*
|
|
94
|
+
* Khi chatBffUrl rỗng (không truyền), SDK tự dùng mock handler (dev only).
|
|
95
|
+
*/
|
|
96
|
+
transportMode: 'websocket' | 'stream' | 'rest';
|
|
87
97
|
/** Callback khi BFF trả về intent action (show_ui, navigate, ...) */
|
|
88
|
-
onIntent?: (action: string, componentKey?: string) => void;
|
|
98
|
+
onIntent?: (action: string, componentKey?: string, payload?: Record<string, unknown>) => void;
|
|
89
99
|
/** Render content cho right panel ở fullscreen state */
|
|
90
100
|
renderRightPanel?: (componentKey: string) => ReactNode;
|
|
91
101
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -32,6 +32,8 @@ interface BFFResponseData {
|
|
|
32
32
|
options: SuggestOption[];
|
|
33
33
|
};
|
|
34
34
|
timestamp: number;
|
|
35
|
+
/** Payload từ tool_calls.arguments (parsed JSON). Populated bởi RestTransport khi BFF/LLM trả về tool_calls. */
|
|
36
|
+
intentPayload?: Record<string, unknown>;
|
|
35
37
|
}
|
|
36
38
|
interface BFFResponse {
|
|
37
39
|
code: number;
|
|
@@ -78,14 +80,22 @@ type TransportFrame = {
|
|
|
78
80
|
};
|
|
79
81
|
interface TekoChatWidgetProps {
|
|
80
82
|
appId: string;
|
|
81
|
-
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* - chuỗi rỗng hoặc không truyền → mock handler (dev only)
|
|
83
|
+
/**
|
|
84
|
+
* BFF endpoint.
|
|
85
|
+
* Để trống hoặc không truyền → SDK dùng mock handler (dev only).
|
|
85
86
|
*/
|
|
86
87
|
chatBffUrl: string;
|
|
88
|
+
/**
|
|
89
|
+
* Giao thức giao tiếp với BFF. Required.
|
|
90
|
+
* - `'websocket'` : WebSocket (ws:// hoặc wss://)
|
|
91
|
+
* - `'stream'` : HTTP ndjson streaming (http:// hoặc https://)
|
|
92
|
+
* - `'rest'` : Plain REST JSON — POST + nhận JSON một lần, không stream
|
|
93
|
+
*
|
|
94
|
+
* Khi chatBffUrl rỗng (không truyền), SDK tự dùng mock handler (dev only).
|
|
95
|
+
*/
|
|
96
|
+
transportMode: 'websocket' | 'stream' | 'rest';
|
|
87
97
|
/** Callback khi BFF trả về intent action (show_ui, navigate, ...) */
|
|
88
|
-
onIntent?: (action: string, componentKey?: string) => void;
|
|
98
|
+
onIntent?: (action: string, componentKey?: string, payload?: Record<string, unknown>) => void;
|
|
89
99
|
/** Render content cho right panel ở fullscreen state */
|
|
90
100
|
renderRightPanel?: (componentKey: string) => ReactNode;
|
|
91
101
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1284,6 +1284,105 @@ var MockTransport = class {
|
|
|
1284
1284
|
}
|
|
1285
1285
|
};
|
|
1286
1286
|
|
|
1287
|
+
// src/transports/RestTransport.ts
|
|
1288
|
+
var TOOL_INTENT_MAP = {
|
|
1289
|
+
INTENT_VIEW_CART: {
|
|
1290
|
+
action: "show_ui",
|
|
1291
|
+
componentKey: "cart",
|
|
1292
|
+
intent: "viewCart"
|
|
1293
|
+
},
|
|
1294
|
+
INTENT_VIEW_ORDER: {
|
|
1295
|
+
action: "show_ui",
|
|
1296
|
+
componentKey: "order",
|
|
1297
|
+
intent: "viewOrder"
|
|
1298
|
+
}
|
|
1299
|
+
};
|
|
1300
|
+
var RestTransport = class {
|
|
1301
|
+
// POC default: gpt-4.1-mini — override bằng cách truyền model vào constructor nếu cần
|
|
1302
|
+
constructor(url, token, model = "gpt-4.1-mini") {
|
|
1303
|
+
this.url = url;
|
|
1304
|
+
this.token = token;
|
|
1305
|
+
this.model = model;
|
|
1306
|
+
}
|
|
1307
|
+
onChunk() {
|
|
1308
|
+
}
|
|
1309
|
+
onDone(cb) {
|
|
1310
|
+
this.doneCb = cb;
|
|
1311
|
+
}
|
|
1312
|
+
onError(cb) {
|
|
1313
|
+
this.errorCb = cb;
|
|
1314
|
+
}
|
|
1315
|
+
connect() {
|
|
1316
|
+
return Promise.resolve();
|
|
1317
|
+
}
|
|
1318
|
+
disconnect() {
|
|
1319
|
+
}
|
|
1320
|
+
async send(request) {
|
|
1321
|
+
try {
|
|
1322
|
+
const ctx = request.appContext ?? {};
|
|
1323
|
+
const metadata = {
|
|
1324
|
+
session_id: request.conversationId,
|
|
1325
|
+
...this.token && { authorization: this.token },
|
|
1326
|
+
...ctx
|
|
1327
|
+
};
|
|
1328
|
+
const body = {
|
|
1329
|
+
model: this.model,
|
|
1330
|
+
user: request.userId ?? "user",
|
|
1331
|
+
messages: [{ role: "user", content: request.message ?? "" }],
|
|
1332
|
+
metadata
|
|
1333
|
+
};
|
|
1334
|
+
const res = await fetch(this.url, {
|
|
1335
|
+
method: "POST",
|
|
1336
|
+
headers: {
|
|
1337
|
+
"Content-Type": "application/json",
|
|
1338
|
+
Accept: "application/json"
|
|
1339
|
+
},
|
|
1340
|
+
body: JSON.stringify(body)
|
|
1341
|
+
});
|
|
1342
|
+
if (!res.ok) {
|
|
1343
|
+
throw new Error(`[RestTransport] HTTP ${res.status}`);
|
|
1344
|
+
}
|
|
1345
|
+
const json = await res.json();
|
|
1346
|
+
const choice = json.choices?.[0];
|
|
1347
|
+
const content = choice?.message?.content ?? "";
|
|
1348
|
+
const toolCall = choice?.message?.tool_calls?.[0];
|
|
1349
|
+
let result;
|
|
1350
|
+
if (toolCall?.type === "function") {
|
|
1351
|
+
const mapped = TOOL_INTENT_MAP[toolCall.function.name] ?? {
|
|
1352
|
+
action: "show_ui",
|
|
1353
|
+
componentKey: toolCall.function.name.toLowerCase(),
|
|
1354
|
+
intent: toolCall.function.name
|
|
1355
|
+
};
|
|
1356
|
+
let intentPayload;
|
|
1357
|
+
try {
|
|
1358
|
+
intentPayload = JSON.parse(toolCall.function.arguments);
|
|
1359
|
+
} catch {
|
|
1360
|
+
}
|
|
1361
|
+
result = {
|
|
1362
|
+
conversationId: request.conversationId ?? json.id ?? "",
|
|
1363
|
+
message: content,
|
|
1364
|
+
intent: mapped.intent,
|
|
1365
|
+
action: mapped.action,
|
|
1366
|
+
componentKey: mapped.componentKey,
|
|
1367
|
+
intentPayload,
|
|
1368
|
+
timestamp: Date.now()
|
|
1369
|
+
};
|
|
1370
|
+
} else {
|
|
1371
|
+
result = {
|
|
1372
|
+
conversationId: request.conversationId ?? json.id ?? "",
|
|
1373
|
+
message: content,
|
|
1374
|
+
intent: "none",
|
|
1375
|
+
action: "none",
|
|
1376
|
+
timestamp: Date.now()
|
|
1377
|
+
};
|
|
1378
|
+
}
|
|
1379
|
+
this.doneCb?.(result);
|
|
1380
|
+
} catch (err) {
|
|
1381
|
+
this.errorCb?.(err);
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
};
|
|
1385
|
+
|
|
1287
1386
|
// src/transports/WebSocketTransport.ts
|
|
1288
1387
|
var MAX_RETRIES = 3;
|
|
1289
1388
|
var BASE_RETRY_DELAY_MS = 1e3;
|
|
@@ -1356,11 +1455,14 @@ var WebSocketTransport = class {
|
|
|
1356
1455
|
};
|
|
1357
1456
|
|
|
1358
1457
|
// src/transports/createTransport.ts
|
|
1359
|
-
function createTransport(bffUrl, conversationId, token) {
|
|
1458
|
+
function createTransport(bffUrl, conversationId, token, transportMode) {
|
|
1360
1459
|
if (!bffUrl) {
|
|
1361
1460
|
return new MockTransport(conversationId);
|
|
1362
1461
|
}
|
|
1363
|
-
if (
|
|
1462
|
+
if (transportMode === "rest") {
|
|
1463
|
+
return new RestTransport(bffUrl, token);
|
|
1464
|
+
}
|
|
1465
|
+
if (transportMode === "websocket") {
|
|
1364
1466
|
return new WebSocketTransport(bffUrl, token);
|
|
1365
1467
|
}
|
|
1366
1468
|
return new HttpStreamTransport(bffUrl, token);
|
|
@@ -1383,6 +1485,7 @@ var generateId = () => Math.random().toString(36).slice(2, 10);
|
|
|
1383
1485
|
var generateConversationId = () => `conv-${Date.now()}-${generateId()}`;
|
|
1384
1486
|
var useChatSession = ({
|
|
1385
1487
|
chatBffUrl,
|
|
1488
|
+
transportMode,
|
|
1386
1489
|
onIntent,
|
|
1387
1490
|
onDebugEvent,
|
|
1388
1491
|
getAppContext
|
|
@@ -1404,13 +1507,11 @@ var useChatSession = ({
|
|
|
1404
1507
|
}
|
|
1405
1508
|
setIsLoading(true);
|
|
1406
1509
|
const { userId, token } = await getTekoAuth();
|
|
1407
|
-
|
|
1408
|
-
if (
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
}
|
|
1413
|
-
}
|
|
1510
|
+
const sdkContext = {};
|
|
1511
|
+
if (token) sdkContext.authorization = token;
|
|
1512
|
+
const userAppContext = getAppContext ? await getAppContext() : {};
|
|
1513
|
+
const mergedContext = { ...sdkContext, ...userAppContext };
|
|
1514
|
+
const appContext = Object.keys(mergedContext).length > 0 ? mergedContext : void 0;
|
|
1414
1515
|
const req = {
|
|
1415
1516
|
conversationId: conversationIdRef.current,
|
|
1416
1517
|
timestamp: Date.now(),
|
|
@@ -1423,7 +1524,8 @@ var useChatSession = ({
|
|
|
1423
1524
|
const transport = createTransport(
|
|
1424
1525
|
chatBffUrl,
|
|
1425
1526
|
conversationIdRef.current,
|
|
1426
|
-
token
|
|
1527
|
+
token,
|
|
1528
|
+
transportMode
|
|
1427
1529
|
);
|
|
1428
1530
|
const streamingIdRef = { current: generateId() };
|
|
1429
1531
|
let firstChunk = true;
|
|
@@ -1466,7 +1568,7 @@ var useChatSession = ({
|
|
|
1466
1568
|
timestamp: Date.now(),
|
|
1467
1569
|
payload: { action: data.action, componentKey }
|
|
1468
1570
|
});
|
|
1469
|
-
onIntent?.(data.action, componentKey);
|
|
1571
|
+
onIntent?.(data.action, componentKey, data.intentPayload);
|
|
1470
1572
|
}
|
|
1471
1573
|
setMessages((prev) => {
|
|
1472
1574
|
const last = prev[prev.length - 1];
|
|
@@ -1525,7 +1627,7 @@ var useChatSession = ({
|
|
|
1525
1627
|
setIsLoading(false);
|
|
1526
1628
|
}
|
|
1527
1629
|
},
|
|
1528
|
-
[
|
|
1630
|
+
[getAppContext, onDebugEvent, chatBffUrl, transportMode, onIntent]
|
|
1529
1631
|
);
|
|
1530
1632
|
const contextDebounceRef = useRef4(null);
|
|
1531
1633
|
const sendMessage = useCallback3(
|
|
@@ -1599,6 +1701,7 @@ var TekoChatWidget = forwardRef(
|
|
|
1599
1701
|
({
|
|
1600
1702
|
appId,
|
|
1601
1703
|
chatBffUrl,
|
|
1704
|
+
transportMode,
|
|
1602
1705
|
onIntent,
|
|
1603
1706
|
renderRightPanel,
|
|
1604
1707
|
renderBubble,
|
|
@@ -1638,6 +1741,7 @@ var TekoChatWidget = forwardRef(
|
|
|
1638
1741
|
const { messages, isLoading, sendMessage, sendContext } = useChatSession({
|
|
1639
1742
|
appId,
|
|
1640
1743
|
chatBffUrl,
|
|
1744
|
+
transportMode,
|
|
1641
1745
|
onIntent: handleIntent,
|
|
1642
1746
|
onDebugEvent,
|
|
1643
1747
|
getAppContext
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "teko-chat-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "TekoChatSDK - AI chatbot SDK for Teko ECOM apps",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"main": "./dist/index.
|
|
8
|
-
"module": "./dist/index.
|
|
7
|
+
"main": "./dist/index.cjs",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
9
|
"types": "./dist/index.d.ts",
|
|
10
10
|
"exports": {
|
|
11
11
|
".": {
|
|
12
12
|
"types": "./dist/index.d.ts",
|
|
13
|
-
"import": "./dist/index.
|
|
14
|
-
"require": "./dist/index.
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"require": "./dist/index.cjs"
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
17
|
"files": [
|