@chatwidgetai/chat-widget 0.1.0 → 0.1.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.
- package/dist/ai-chat-widget.umd.js +144 -219
- package/dist/ai-chat-widget.umd.js.map +1 -1
- package/dist/api/client.d.ts +9 -0
- package/dist/api/client.d.ts.map +1 -1
- package/dist/components/ChatWidget.d.ts.map +1 -1
- package/dist/components/ChatWindow.d.ts +0 -2
- package/dist/components/ChatWindow.d.ts.map +1 -1
- package/dist/hooks/useChat.d.ts +0 -10
- package/dist/hooks/useChat.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +145 -220
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +145 -219
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/utils/actionExecutor.d.ts +0 -18
- package/dist/utils/actionExecutor.d.ts.map +0 -1
package/dist/api/client.d.ts
CHANGED
|
@@ -8,6 +8,15 @@ export interface ApiClientConfig {
|
|
|
8
8
|
apiKey: string;
|
|
9
9
|
apiUrl: string;
|
|
10
10
|
}
|
|
11
|
+
export declare class ApiError extends Error {
|
|
12
|
+
status: number;
|
|
13
|
+
details?: unknown;
|
|
14
|
+
retryAfterMs?: number;
|
|
15
|
+
constructor(message: string, status: number, options?: {
|
|
16
|
+
details?: unknown;
|
|
17
|
+
retryAfterMs?: number;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
11
20
|
export declare class WidgetApiClient {
|
|
12
21
|
private config;
|
|
13
22
|
constructor(config: ApiClientConfig);
|
package/dist/api/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAE7D,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAkB;gBAEpB,MAAM,EAAE,eAAe;IAInC;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC;IAoBlC,uBAAuB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAE7D,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,QAAS,SAAQ,KAAK;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;gBAEV,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE;CAOpG;AAwDD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAkB;gBAEpB,MAAM,EAAE,eAAe;IAInC;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC;IAoBlC,uBAAuB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,mBAAmB,EAAE,CAAA;KAAE,CAAC;IAqBhH;;OAEG;IACG,UAAU,CAAC,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAwB7G;;;OAGG;IACG,WAAW,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAwB9G;;OAEG;IACG,gBAAgB,CACpB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,EAAE,GACjB,OAAO,CAAC,GAAG,CAAC;IA2Cf;;OAEG;IACG,cAAc,CAClB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,UAAU,GAAG,UAAU,GAChC,OAAO,CAAC,IAAI,CAAC;IA4BhB;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;CAsBzC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatWidget.d.ts","sourceRoot":"","sources":["../../src/components/ChatWidget.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAA8B,MAAM,OAAO,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAGvC,OAAO,sBAAsB,CAAC;AAE9B,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,
|
|
1
|
+
{"version":3,"file":"ChatWidget.d.ts","sourceRoot":"","sources":["../../src/components/ChatWidget.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAA8B,MAAM,OAAO,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAGvC,OAAO,sBAAsB,CAAC;AAE9B,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CA8H5C,CAAC"}
|
|
@@ -11,8 +11,6 @@ export interface ChatWindowProps {
|
|
|
11
11
|
error: string | null;
|
|
12
12
|
config: WidgetConfig | null;
|
|
13
13
|
onSendMessage: (message: string) => void;
|
|
14
|
-
onApproveAction: () => void;
|
|
15
|
-
onRejectAction: () => void;
|
|
16
14
|
onClose: () => void;
|
|
17
15
|
onFeedback: (messageId: string, feedback: 'positive' | 'negative') => void;
|
|
18
16
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatWindow.d.ts","sourceRoot":"","sources":["../../src/components/ChatWindow.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAA8B,MAAM,OAAO,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAK7D,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,
|
|
1
|
+
{"version":3,"file":"ChatWindow.d.ts","sourceRoot":"","sources":["../../src/components/ChatWindow.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAA8B,MAAM,OAAO,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAK7D,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,GAAG,UAAU,KAAK,IAAI,CAAC;CAC5E;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAgIhD,CAAC"}
|
package/dist/hooks/useChat.d.ts
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* Main state management for chat functionality
|
|
4
4
|
*/
|
|
5
5
|
import { ConversationMessage, WidgetConfig } from '../types';
|
|
6
|
-
import { ClientAction } from '../utils/actionExecutor';
|
|
7
6
|
export interface UseChatOptions {
|
|
8
7
|
widgetId: string;
|
|
9
8
|
apiKey: string;
|
|
@@ -11,12 +10,6 @@ export interface UseChatOptions {
|
|
|
11
10
|
onMessage?: (message: ConversationMessage) => void;
|
|
12
11
|
onError?: (error: Error) => void;
|
|
13
12
|
}
|
|
14
|
-
export interface PendingAction {
|
|
15
|
-
action: ClientAction;
|
|
16
|
-
message: string;
|
|
17
|
-
continueToken: string;
|
|
18
|
-
messageId: string;
|
|
19
|
-
}
|
|
20
13
|
export interface UseChatReturn {
|
|
21
14
|
messages: ConversationMessage[];
|
|
22
15
|
isLoading: boolean;
|
|
@@ -24,10 +17,7 @@ export interface UseChatReturn {
|
|
|
24
17
|
error: string | null;
|
|
25
18
|
config: WidgetConfig | null;
|
|
26
19
|
conversationId: string;
|
|
27
|
-
pendingAction: PendingAction | null;
|
|
28
20
|
sendMessage: (content: string) => Promise<void>;
|
|
29
|
-
approveAction: () => Promise<void>;
|
|
30
|
-
rejectAction: () => void;
|
|
31
21
|
clearMessages: () => void;
|
|
32
22
|
submitFeedback: (messageId: string, feedback: 'positive' | 'negative') => Promise<void>;
|
|
33
23
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useChat.d.ts","sourceRoot":"","sources":["../../src/hooks/useChat.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAa,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"useChat.d.ts","sourceRoot":"","sources":["../../src/hooks/useChat.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAa,MAAM,UAAU,CAAC;AAKxE,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACnD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,GAAG,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACzF;AAkED,wBAAgB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,aAAa,CAyS9D"}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export { ChatWidget } from './components/ChatWidget';
|
|
6
6
|
export { useChat } from './hooks/useChat';
|
|
7
|
+
export { ApiError } from './api/client';
|
|
7
8
|
export type { WidgetProps, WidgetTheme, WidgetPosition, WidgetSize, WidgetAppearance, WidgetBehavior, WidgetConfig, ConversationMessage, ChatMessage, KbDocument, SourceDisplayMode, ChatState, } from './types';
|
|
8
9
|
export type { UseChatOptions, UseChatReturn, } from './hooks/useChat';
|
|
9
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAGxC,YAAY,EACV,WAAW,EACX,WAAW,EACX,cAAc,EACd,UAAU,EACV,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,mBAAmB,EACnB,WAAW,EACX,UAAU,EACV,iBAAiB,EACjB,SAAS,GACV,MAAM,SAAS,CAAC;AAEjB,YAAY,EACV,cAAc,EACd,aAAa,GACd,MAAM,iBAAiB,CAAC"}
|
package/dist/index.esm.js
CHANGED
|
@@ -5,6 +5,65 @@ import { useState, useRef, useEffect, useCallback, useMemo } from 'react';
|
|
|
5
5
|
* API Client for Widget Communication
|
|
6
6
|
* Handles all HTTP requests to the widget API
|
|
7
7
|
*/
|
|
8
|
+
class ApiError extends Error {
|
|
9
|
+
constructor(message, status, options) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = 'ApiError';
|
|
12
|
+
this.status = status;
|
|
13
|
+
this.details = options?.details;
|
|
14
|
+
this.retryAfterMs = options?.retryAfterMs;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function parseRetryAfter(headerValue) {
|
|
18
|
+
if (!headerValue)
|
|
19
|
+
return undefined;
|
|
20
|
+
const seconds = Number(headerValue);
|
|
21
|
+
if (!Number.isNaN(seconds) && seconds >= 0) {
|
|
22
|
+
return seconds * 1000;
|
|
23
|
+
}
|
|
24
|
+
const date = Date.parse(headerValue);
|
|
25
|
+
if (!Number.isNaN(date)) {
|
|
26
|
+
return Math.max(0, date - Date.now());
|
|
27
|
+
}
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
async function buildApiError(response, defaultMessage) {
|
|
31
|
+
let parsedBody = null;
|
|
32
|
+
let message = defaultMessage;
|
|
33
|
+
try {
|
|
34
|
+
const raw = await response.text();
|
|
35
|
+
if (raw) {
|
|
36
|
+
try {
|
|
37
|
+
parsedBody = JSON.parse(raw);
|
|
38
|
+
if (typeof parsedBody === 'object' && parsedBody !== null) {
|
|
39
|
+
const body = parsedBody;
|
|
40
|
+
message = typeof body.error === 'string'
|
|
41
|
+
? body.error
|
|
42
|
+
: typeof body.message === 'string'
|
|
43
|
+
? body.message
|
|
44
|
+
: defaultMessage;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
message = raw;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
message = raw;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// ignore body parsing errors
|
|
57
|
+
}
|
|
58
|
+
let retryAfterMs = parseRetryAfter(response.headers.get('retry-after'));
|
|
59
|
+
if (retryAfterMs === undefined) {
|
|
60
|
+
retryAfterMs = parseRetryAfter(response.headers.get('x-ratelimit-reset'));
|
|
61
|
+
}
|
|
62
|
+
return new ApiError(message || defaultMessage, response.status, {
|
|
63
|
+
details: parsedBody,
|
|
64
|
+
retryAfterMs,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
8
67
|
class WidgetApiClient {
|
|
9
68
|
constructor(config) {
|
|
10
69
|
this.config = config;
|
|
@@ -21,23 +80,24 @@ class WidgetApiClient {
|
|
|
21
80
|
},
|
|
22
81
|
});
|
|
23
82
|
if (!response.ok) {
|
|
24
|
-
throw
|
|
83
|
+
throw await buildApiError(response, 'Failed to fetch config');
|
|
25
84
|
}
|
|
26
85
|
const json = await response.json();
|
|
27
86
|
return json;
|
|
28
87
|
}
|
|
29
88
|
async getOrCreateConversation(conversationId) {
|
|
30
|
-
const
|
|
89
|
+
const baseUrl = `${this.config.apiUrl}/api/widget/${this.config.widgetId}/conversation`;
|
|
90
|
+
const query = conversationId ? `?conversationId=${encodeURIComponent(conversationId)}` : '';
|
|
91
|
+
const response = await fetch(`${baseUrl}${query}`, {
|
|
31
92
|
method: 'GET',
|
|
32
93
|
headers: {
|
|
33
94
|
'Authorization': `Bearer ${this.config.apiKey}`,
|
|
34
|
-
}
|
|
95
|
+
},
|
|
35
96
|
});
|
|
36
97
|
if (!response.ok) {
|
|
37
|
-
|
|
38
|
-
throw new Error(error.error || 'Failed to upload file');
|
|
98
|
+
throw await buildApiError(response, 'Failed to load conversation');
|
|
39
99
|
}
|
|
40
|
-
return
|
|
100
|
+
return response.json();
|
|
41
101
|
}
|
|
42
102
|
/**
|
|
43
103
|
* Upload a file
|
|
@@ -54,8 +114,7 @@ class WidgetApiClient {
|
|
|
54
114
|
body: formData,
|
|
55
115
|
});
|
|
56
116
|
if (!response.ok) {
|
|
57
|
-
|
|
58
|
-
throw new Error(error.error || 'Failed to upload file');
|
|
117
|
+
throw await buildApiError(response, 'Failed to upload file');
|
|
59
118
|
}
|
|
60
119
|
const result = await response.json();
|
|
61
120
|
return result.file;
|
|
@@ -78,8 +137,7 @@ class WidgetApiClient {
|
|
|
78
137
|
}),
|
|
79
138
|
});
|
|
80
139
|
if (!response.ok) {
|
|
81
|
-
|
|
82
|
-
throw new Error(error.error || 'Failed to send message');
|
|
140
|
+
throw await buildApiError(response, 'Failed to send message');
|
|
83
141
|
}
|
|
84
142
|
return response.json();
|
|
85
143
|
}
|
|
@@ -101,8 +159,7 @@ class WidgetApiClient {
|
|
|
101
159
|
}),
|
|
102
160
|
});
|
|
103
161
|
if (!response.ok) {
|
|
104
|
-
|
|
105
|
-
throw new Error(error.error || `Agent request failed with status ${response.status}`);
|
|
162
|
+
throw await buildApiError(response, `Agent request failed with status ${response.status}`);
|
|
106
163
|
}
|
|
107
164
|
const data = await response.json();
|
|
108
165
|
// Check if response indicates an error
|
|
@@ -114,7 +171,7 @@ class WidgetApiClient {
|
|
|
114
171
|
catch (error) {
|
|
115
172
|
// Enhance error messages
|
|
116
173
|
if (error instanceof TypeError && error.message.includes('fetch')) {
|
|
117
|
-
throw new
|
|
174
|
+
throw new ApiError('Network error: Unable to reach the server', 0);
|
|
118
175
|
}
|
|
119
176
|
throw error;
|
|
120
177
|
}
|
|
@@ -136,13 +193,13 @@ class WidgetApiClient {
|
|
|
136
193
|
}),
|
|
137
194
|
});
|
|
138
195
|
if (!response.ok) {
|
|
139
|
-
const
|
|
196
|
+
const apiError = await buildApiError(response, 'Failed to submit feedback');
|
|
140
197
|
console.error('Feedback submission failed:', {
|
|
141
198
|
status: response.status,
|
|
142
|
-
error:
|
|
199
|
+
error: apiError.details,
|
|
143
200
|
payload: { session_id: sessionId, message_id: messageId, feedback }
|
|
144
201
|
});
|
|
145
|
-
throw
|
|
202
|
+
throw apiError;
|
|
146
203
|
}
|
|
147
204
|
}
|
|
148
205
|
/**
|
|
@@ -250,111 +307,70 @@ function isStorageAvailable() {
|
|
|
250
307
|
}
|
|
251
308
|
|
|
252
309
|
/**
|
|
253
|
-
*
|
|
254
|
-
*
|
|
255
|
-
*/
|
|
256
|
-
/**
|
|
257
|
-
* Execute a client-side action
|
|
310
|
+
* useChat Hook
|
|
311
|
+
* Main state management for chat functionality
|
|
258
312
|
*/
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
case
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
313
|
+
function deriveErrorInfo(error) {
|
|
314
|
+
if (error instanceof ApiError) {
|
|
315
|
+
const retryAfterSeconds = typeof error.retryAfterMs === 'number'
|
|
316
|
+
? Math.max(1, Math.ceil(error.retryAfterMs / 1000))
|
|
317
|
+
: undefined;
|
|
318
|
+
const lowerMessage = (error.message || '').toLowerCase();
|
|
319
|
+
let message;
|
|
320
|
+
switch (error.status) {
|
|
321
|
+
case 429: {
|
|
322
|
+
const isPerUser = lowerMessage.includes('user');
|
|
323
|
+
const base = isPerUser
|
|
324
|
+
? 'You have reached the per-user rate limit.'
|
|
325
|
+
: 'This widget has received too many requests.';
|
|
326
|
+
if (retryAfterSeconds) {
|
|
327
|
+
message = `${base} Please wait ${retryAfterSeconds} second${retryAfterSeconds === 1 ? '' : 's'} before trying again.`;
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
message = `${base} Please wait a moment and try again.`;
|
|
331
|
+
}
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
case 401:
|
|
335
|
+
message = 'Authentication failed. Please refresh the page or verify your API key.';
|
|
336
|
+
break;
|
|
337
|
+
case 403:
|
|
338
|
+
message = 'Access to this widget is restricted. Please contact the site owner if you believe this is an error.';
|
|
339
|
+
break;
|
|
340
|
+
case 404:
|
|
341
|
+
message = 'We could not find this widget. It may have been removed.';
|
|
342
|
+
break;
|
|
271
343
|
default:
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
344
|
+
if (error.status >= 500) {
|
|
345
|
+
message = 'The server encountered an error. Please try again shortly.';
|
|
346
|
+
}
|
|
347
|
+
else if (error.status > 0) {
|
|
348
|
+
message = error.message || 'Something went wrong. Please try again.';
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
message = error.message || 'Unable to connect to the server. Please check your internet connection.';
|
|
352
|
+
}
|
|
277
353
|
}
|
|
354
|
+
return { message, retryAfterSeconds, status: error.status };
|
|
278
355
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
return {
|
|
294
|
-
}
|
|
295
|
-
try {
|
|
296
|
-
// Validate URL
|
|
297
|
-
new URL(url);
|
|
298
|
-
// Redirect
|
|
299
|
-
window.location.href = url;
|
|
300
|
-
return { success: true, result: { redirected_to: url } };
|
|
301
|
-
}
|
|
302
|
-
catch (error) {
|
|
303
|
-
return { success: false, error: 'Invalid URL' };
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
/**
|
|
307
|
-
* Show a modal
|
|
308
|
-
*/
|
|
309
|
-
function executeShowModal(params) {
|
|
310
|
-
const { title, content } = params;
|
|
311
|
-
if (!title || !content) {
|
|
312
|
-
return { success: false, error: 'Title and content are required' };
|
|
313
|
-
}
|
|
314
|
-
// Use browser's alert as a simple modal
|
|
315
|
-
// In a real implementation, you'd use a proper modal component
|
|
316
|
-
alert(`${title}\n\n${content}`);
|
|
317
|
-
return { success: true, result: { shown: true } };
|
|
318
|
-
}
|
|
319
|
-
/**
|
|
320
|
-
* Copy text to clipboard
|
|
321
|
-
*/
|
|
322
|
-
async function executeCopyToClipboard(params) {
|
|
323
|
-
const text = params.text;
|
|
324
|
-
if (!text) {
|
|
325
|
-
return { success: false, error: 'Text parameter is required' };
|
|
326
|
-
}
|
|
327
|
-
try {
|
|
328
|
-
await navigator.clipboard.writeText(text);
|
|
329
|
-
return { success: true, result: { copied: text } };
|
|
330
|
-
}
|
|
331
|
-
catch (error) {
|
|
332
|
-
return {
|
|
333
|
-
success: false,
|
|
334
|
-
error: 'Failed to copy to clipboard. Please check browser permissions.'
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
/**
|
|
339
|
-
* Open chat with a specific message
|
|
340
|
-
*/
|
|
341
|
-
function executeOpenChat(params) {
|
|
342
|
-
const message = params.message;
|
|
343
|
-
if (!message) {
|
|
344
|
-
return { success: false, error: 'Message parameter is required' };
|
|
356
|
+
if (error instanceof Error) {
|
|
357
|
+
const lower = error.message.toLowerCase();
|
|
358
|
+
if (lower.includes('network')) {
|
|
359
|
+
return { message: 'Unable to connect to the server. Please check your internet connection.' };
|
|
360
|
+
}
|
|
361
|
+
if (lower.includes('timeout')) {
|
|
362
|
+
return { message: 'The request timed out. Please try again.' };
|
|
363
|
+
}
|
|
364
|
+
if (lower.includes('unauthorized') || lower.includes('401')) {
|
|
365
|
+
return { message: 'Authentication failed. Please refresh the page or verify your API key.' };
|
|
366
|
+
}
|
|
367
|
+
if (lower.includes('internal server error') || lower.includes('500')) {
|
|
368
|
+
return { message: 'The server encountered an error. Please try again shortly.' };
|
|
369
|
+
}
|
|
370
|
+
return { message: error.message || 'Something went wrong. Please try again.' };
|
|
345
371
|
}
|
|
346
|
-
|
|
347
|
-
const event = new CustomEvent('widget:open-chat', {
|
|
348
|
-
detail: { message }
|
|
349
|
-
});
|
|
350
|
-
window.dispatchEvent(event);
|
|
351
|
-
return { success: true, result: { message } };
|
|
372
|
+
return { message: 'Something went wrong. Please try again.' };
|
|
352
373
|
}
|
|
353
|
-
|
|
354
|
-
/**
|
|
355
|
-
* useChat Hook
|
|
356
|
-
* Main state management for chat functionality
|
|
357
|
-
*/
|
|
358
374
|
function useChat(options) {
|
|
359
375
|
const { widgetId, apiKey, apiUrl, onMessage, onError, } = options;
|
|
360
376
|
const [state, setState] = useState({
|
|
@@ -366,7 +382,6 @@ function useChat(options) {
|
|
|
366
382
|
conversationId: '', // Will be set after loading conversation
|
|
367
383
|
config: null,
|
|
368
384
|
});
|
|
369
|
-
const [pendingAction, setPendingAction] = useState(null);
|
|
370
385
|
const apiClient = useRef(new WidgetApiClient({ widgetId, apiKey, apiUrl }));
|
|
371
386
|
// Load configuration and conversation on mount
|
|
372
387
|
useEffect(() => {
|
|
@@ -391,8 +406,9 @@ function useChat(options) {
|
|
|
391
406
|
}));
|
|
392
407
|
}
|
|
393
408
|
catch (error) {
|
|
394
|
-
const
|
|
395
|
-
|
|
409
|
+
const errorInfo = deriveErrorInfo(error);
|
|
410
|
+
const err = error instanceof Error ? error : new Error(errorInfo.message);
|
|
411
|
+
setState(prev => ({ ...prev, error: errorInfo.message }));
|
|
396
412
|
onError?.(err);
|
|
397
413
|
}
|
|
398
414
|
};
|
|
@@ -447,7 +463,6 @@ function useChat(options) {
|
|
|
447
463
|
}
|
|
448
464
|
// Determine if widget has actions (use agent endpoint)
|
|
449
465
|
const useAgent = state.config?.behavior.agentic || (state.config?.actions && state.config.actions.length > 0);
|
|
450
|
-
console.log(useAgent);
|
|
451
466
|
let response;
|
|
452
467
|
if (useAgent) {
|
|
453
468
|
// Use agent endpoint - returns ConversationMessage[]
|
|
@@ -516,26 +531,9 @@ function useChat(options) {
|
|
|
516
531
|
}
|
|
517
532
|
}
|
|
518
533
|
catch (error) {
|
|
519
|
-
const
|
|
520
|
-
|
|
521
|
-
let userMessage = err.message;
|
|
522
|
-
// Handle specific error types
|
|
523
|
-
if (err.message.includes('Network') || err.message.includes('fetch')) {
|
|
524
|
-
userMessage = 'Unable to connect to the server. Please check your internet connection.';
|
|
525
|
-
}
|
|
526
|
-
else if (err.message.includes('401') || err.message.includes('Unauthorized')) {
|
|
527
|
-
userMessage = 'Authentication failed. Please refresh the page.';
|
|
528
|
-
}
|
|
529
|
-
else if (err.message.includes('500') || err.message.includes('Internal Server Error')) {
|
|
530
|
-
userMessage = 'The server encountered an error. Please try again later.';
|
|
531
|
-
}
|
|
532
|
-
else if (err.message.includes('timeout')) {
|
|
533
|
-
userMessage = 'Request timed out. Please try again.';
|
|
534
|
-
}
|
|
535
|
-
// Use fallback message if configured, otherwise use error message
|
|
534
|
+
const errorInfo = deriveErrorInfo(error);
|
|
535
|
+
const err = error instanceof Error ? error : new Error(errorInfo.message);
|
|
536
536
|
const fallbackMessage = state.config?.behavior?.fallbackMessage;
|
|
537
|
-
const errorMessage = fallbackMessage || userMessage;
|
|
538
|
-
// If fallback message is configured, add it as an assistant message
|
|
539
537
|
if (fallbackMessage) {
|
|
540
538
|
const fallbackAssistantMessage = {
|
|
541
539
|
id: generateMessageId(),
|
|
@@ -551,17 +549,16 @@ function useChat(options) {
|
|
|
551
549
|
messages: [...prev.messages, fallbackAssistantMessage],
|
|
552
550
|
isLoading: false,
|
|
553
551
|
isTyping: false,
|
|
554
|
-
error:
|
|
552
|
+
error: errorInfo.message,
|
|
555
553
|
}));
|
|
556
554
|
onMessage?.(fallbackAssistantMessage);
|
|
557
555
|
}
|
|
558
556
|
else {
|
|
559
|
-
// Show error message as assistant message for better UX
|
|
560
557
|
const errorAssistantMessage = {
|
|
561
558
|
id: generateMessageId(),
|
|
562
559
|
message: {
|
|
563
560
|
type: 'ai',
|
|
564
|
-
content: `⚠️ ${
|
|
561
|
+
content: `⚠️ ${errorInfo.message}`,
|
|
565
562
|
},
|
|
566
563
|
timestamp: new Date().toISOString(),
|
|
567
564
|
sources: [],
|
|
@@ -571,7 +568,7 @@ function useChat(options) {
|
|
|
571
568
|
messages: [...prev.messages, errorAssistantMessage],
|
|
572
569
|
isLoading: false,
|
|
573
570
|
isTyping: false,
|
|
574
|
-
error:
|
|
571
|
+
error: errorInfo.message,
|
|
575
572
|
}));
|
|
576
573
|
onMessage?.(errorAssistantMessage);
|
|
577
574
|
}
|
|
@@ -609,81 +606,12 @@ function useChat(options) {
|
|
|
609
606
|
}));
|
|
610
607
|
}
|
|
611
608
|
catch (error) {
|
|
612
|
-
const
|
|
609
|
+
const errorInfo = deriveErrorInfo(error);
|
|
610
|
+
const err = error instanceof Error ? error : new Error(errorInfo.message);
|
|
611
|
+
setState(prev => ({ ...prev, error: errorInfo.message }));
|
|
613
612
|
onError?.(err);
|
|
614
613
|
}
|
|
615
614
|
}, [state.conversationId, onError]);
|
|
616
|
-
/**
|
|
617
|
-
* Approve and execute pending action
|
|
618
|
-
*/
|
|
619
|
-
const approveAction = useCallback(async () => {
|
|
620
|
-
if (!pendingAction)
|
|
621
|
-
return;
|
|
622
|
-
setState(prev => ({ ...prev, isLoading: true, isTyping: true }));
|
|
623
|
-
try {
|
|
624
|
-
// Execute the client action
|
|
625
|
-
const actionResult = await executeClientAction(pendingAction.action);
|
|
626
|
-
// Update the pending action message to show execution result
|
|
627
|
-
const executionMessage = actionResult.success
|
|
628
|
-
? `✓ Action executed successfully`
|
|
629
|
-
: `✗ Action failed: ${actionResult.error}`;
|
|
630
|
-
setState(prev => ({
|
|
631
|
-
...prev,
|
|
632
|
-
messages: prev.messages.map(msg => msg.id === pendingAction.messageId
|
|
633
|
-
? { ...msg, message: { ...msg.message, content: `${msg.message.content}\n\n${executionMessage}` } }
|
|
634
|
-
: msg),
|
|
635
|
-
}));
|
|
636
|
-
// Clear pending action
|
|
637
|
-
setPendingAction(null);
|
|
638
|
-
// TODO: Implement continueAgent in API client if actions are needed
|
|
639
|
-
// For now, just show success message
|
|
640
|
-
const assistantMessage = {
|
|
641
|
-
id: generateMessageId(),
|
|
642
|
-
message: {
|
|
643
|
-
type: 'ai',
|
|
644
|
-
content: 'Action completed successfully.',
|
|
645
|
-
},
|
|
646
|
-
timestamp: new Date().toISOString(),
|
|
647
|
-
sources: [],
|
|
648
|
-
};
|
|
649
|
-
setState(prev => ({
|
|
650
|
-
...prev,
|
|
651
|
-
messages: [...prev.messages, assistantMessage],
|
|
652
|
-
isLoading: false,
|
|
653
|
-
isTyping: false,
|
|
654
|
-
}));
|
|
655
|
-
onMessage?.(assistantMessage);
|
|
656
|
-
}
|
|
657
|
-
catch (error) {
|
|
658
|
-
const err = error instanceof Error ? error : new Error('Failed to execute action');
|
|
659
|
-
setState(prev => ({
|
|
660
|
-
...prev,
|
|
661
|
-
isLoading: false,
|
|
662
|
-
isTyping: false,
|
|
663
|
-
error: err.message,
|
|
664
|
-
messages: prev.messages.map(msg => msg.id === pendingAction.messageId
|
|
665
|
-
? { ...msg, message: { ...msg.message, content: `${msg.message.content}\n\n✗ Failed to execute action` } }
|
|
666
|
-
: msg),
|
|
667
|
-
}));
|
|
668
|
-
setPendingAction(null);
|
|
669
|
-
onError?.(err);
|
|
670
|
-
}
|
|
671
|
-
}, [pendingAction, state.conversationId, onMessage, onError]);
|
|
672
|
-
/**
|
|
673
|
-
* Reject pending action
|
|
674
|
-
*/
|
|
675
|
-
const rejectAction = useCallback(() => {
|
|
676
|
-
if (!pendingAction)
|
|
677
|
-
return;
|
|
678
|
-
// Update message to show rejection
|
|
679
|
-
setState(prev => ({
|
|
680
|
-
...prev,
|
|
681
|
-
messages: prev.messages.map(msg => msg.id === pendingAction.messageId
|
|
682
|
-
? { ...msg, message: { ...msg.message, content: `${msg.message.content}\n\n✗ Action cancelled by user` } }
|
|
683
|
-
: msg),
|
|
684
|
-
}));
|
|
685
|
-
setPendingAction(null);
|
|
686
|
-
}, [pendingAction]);
|
|
687
615
|
return {
|
|
688
616
|
messages: state.messages,
|
|
689
617
|
isLoading: state.isLoading,
|
|
@@ -691,10 +619,7 @@ function useChat(options) {
|
|
|
691
619
|
error: state.error,
|
|
692
620
|
config: state.config,
|
|
693
621
|
conversationId: state.conversationId,
|
|
694
|
-
pendingAction,
|
|
695
622
|
sendMessage,
|
|
696
|
-
approveAction,
|
|
697
|
-
rejectAction,
|
|
698
623
|
clearMessages,
|
|
699
624
|
submitFeedback,
|
|
700
625
|
};
|
|
@@ -21609,7 +21534,7 @@ styleInject(css_248z);
|
|
|
21609
21534
|
|
|
21610
21535
|
const ChatWidget = ({ widgetId, apiKey, apiUrl = window.location.origin, position = 'bottom-right', theme: themeOverride, primaryColor, onOpen, onClose, onMessage, onError, }) => {
|
|
21611
21536
|
const [isOpen, setIsOpen] = useState(false);
|
|
21612
|
-
const { messages, isLoading, isTyping, error, config, sendMessage,
|
|
21537
|
+
const { messages, isLoading, isTyping, error, config, sendMessage, submitFeedback, } = useChat({
|
|
21613
21538
|
widgetId,
|
|
21614
21539
|
apiKey,
|
|
21615
21540
|
apiUrl,
|
|
@@ -21659,11 +21584,11 @@ const ChatWidget = ({ widgetId, apiKey, apiUrl = window.location.origin, positio
|
|
|
21659
21584
|
const handleFeedback = async (messageId, feedback) => {
|
|
21660
21585
|
await submitFeedback(messageId, feedback);
|
|
21661
21586
|
};
|
|
21662
|
-
return (jsx("div", { className: `ai-chat-widget ${effectiveTheme}`, style: customStyles, children: jsx("div", { className: `ai-chat-widget-container ${effectivePosition}`, children: isOpen ? (jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, error: error, config: config, onSendMessage: sendMessage,
|
|
21587
|
+
return (jsx("div", { className: `ai-chat-widget ${effectiveTheme}`, style: customStyles, children: jsx("div", { className: `ai-chat-widget-container ${effectivePosition}`, children: isOpen ? (jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, error: error, config: config, onSendMessage: sendMessage, onClose: handleToggle, onFeedback: handleFeedback })) : (jsx("button", { className: "ai-chat-button", onClick: handleToggle, "aria-label": "Open chat", style: {
|
|
21663
21588
|
width: config?.appearance.buttonSize || 60,
|
|
21664
21589
|
height: config?.appearance.buttonSize || 60,
|
|
21665
21590
|
}, children: config?.appearance.buttonIcon ? (jsx("span", { className: "ai-chat-button-icon", children: config.appearance.buttonIcon })) : (jsx("svg", { className: "ai-chat-button-svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) })) })) }) }));
|
|
21666
21591
|
};
|
|
21667
21592
|
|
|
21668
|
-
export { ChatWidget, useChat };
|
|
21593
|
+
export { ApiError, ChatWidget, useChat };
|
|
21669
21594
|
//# sourceMappingURL=index.esm.js.map
|