@aikaara/chat-sdk 0.1.3 → 0.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aikaara/chat-sdk",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "description": "Aikaara Chat SDK — embeddable chat widget and headless client",
6
6
  "license": "MIT",
@@ -34,9 +34,12 @@
34
34
  "preview": "vite preview",
35
35
  "prepare": "git config core.hooksPath .githooks"
36
36
  },
37
+ "dependencies": {
38
+ "mqtt": "^5.10.0"
39
+ },
37
40
  "devDependencies": {
38
41
  "typescript": "^5.7.0",
39
- "vite": "^6.0.0",
42
+ "vite": "^7.3.1",
40
43
  "vite-plugin-dts": "^4.0.0"
41
44
  }
42
45
  }
@@ -1,565 +0,0 @@
1
- var b = Object.defineProperty;
2
- var v = (a, t, e) => t in a ? b(a, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : a[t] = e;
3
- var o = (a, t, e) => v(a, typeof t != "symbol" ? t + "" : t, e);
4
- class S {
5
- constructor(t, e) {
6
- o(this, "identifier");
7
- o(this, "callbacks", {});
8
- o(this, "sendFn");
9
- this.identifier = t, this.sendFn = e;
10
- }
11
- onReceived(t) {
12
- return this.callbacks.received = t, this;
13
- }
14
- onConnected(t) {
15
- return this.callbacks.connected = t, this;
16
- }
17
- onDisconnected(t) {
18
- return this.callbacks.disconnected = t, this;
19
- }
20
- onRejected(t) {
21
- return this.callbacks.rejected = t, this;
22
- }
23
- perform(t, e = {}) {
24
- this.sendFn({ action: t, ...e });
25
- }
26
- /** @internal */
27
- _notifyReceived(t) {
28
- var e, s;
29
- (s = (e = this.callbacks).received) == null || s.call(e, t);
30
- }
31
- /** @internal */
32
- _notifyConnected() {
33
- var t, e;
34
- (e = (t = this.callbacks).connected) == null || e.call(t);
35
- }
36
- /** @internal */
37
- _notifyDisconnected() {
38
- var t, e;
39
- (e = (t = this.callbacks).disconnected) == null || e.call(t);
40
- }
41
- /** @internal */
42
- _notifyRejected() {
43
- var t, e;
44
- (e = (t = this.callbacks).rejected) == null || e.call(t);
45
- }
46
- }
47
- class f {
48
- constructor(t) {
49
- o(this, "ws", null);
50
- o(this, "url");
51
- o(this, "subscriptions", /* @__PURE__ */ new Map());
52
- o(this, "welcomePromise", null);
53
- o(this, "pendingSubscriptions", /* @__PURE__ */ new Map());
54
- this.url = t;
55
- }
56
- connect() {
57
- return new Promise((t, e) => {
58
- this.welcomePromise = { resolve: t, reject: e }, this.ws = new WebSocket(this.url), this.ws.onopen = () => {
59
- }, this.ws.onmessage = (s) => {
60
- this.handleMessage(s);
61
- }, this.ws.onerror = () => {
62
- var n;
63
- const s = new Error("WebSocket connection error");
64
- (n = this.welcomePromise) == null || n.reject(s), this.welcomePromise = null;
65
- }, this.ws.onclose = () => {
66
- this.subscriptions.forEach((s) => s._notifyDisconnected());
67
- };
68
- });
69
- }
70
- disconnect() {
71
- this.ws && (this.ws.onclose = null, this.ws.close(), this.ws = null), this.subscriptions.forEach((t) => t._notifyDisconnected()), this.subscriptions.clear();
72
- }
73
- subscribe(t) {
74
- const e = JSON.stringify(t), s = new S(e, (n) => {
75
- this.send({
76
- command: "message",
77
- identifier: e,
78
- data: JSON.stringify(n)
79
- });
80
- });
81
- return this.subscriptions.set(e, s), this.send({
82
- command: "subscribe",
83
- identifier: e
84
- }), s;
85
- }
86
- subscribeAsync(t) {
87
- const e = this.subscribe(t), s = e.identifier;
88
- return new Promise((n, i) => {
89
- this.pendingSubscriptions.set(s, {
90
- resolve: () => n(e),
91
- reject: i
92
- }), setTimeout(() => {
93
- this.pendingSubscriptions.has(s) && (this.pendingSubscriptions.delete(s), i(new Error(`Subscription timeout for ${s}`)));
94
- }, 1e4);
95
- });
96
- }
97
- unsubscribe(t) {
98
- this.send({
99
- command: "unsubscribe",
100
- identifier: t
101
- }), this.subscriptions.delete(t);
102
- }
103
- perform(t, e, s = {}) {
104
- this.send({
105
- command: "message",
106
- identifier: t,
107
- data: JSON.stringify({ action: e, ...s })
108
- });
109
- }
110
- get isConnected() {
111
- var t;
112
- return ((t = this.ws) == null ? void 0 : t.readyState) === WebSocket.OPEN;
113
- }
114
- send(t) {
115
- var e;
116
- ((e = this.ws) == null ? void 0 : e.readyState) === WebSocket.OPEN && this.ws.send(JSON.stringify(t));
117
- }
118
- handleMessage(t) {
119
- var s;
120
- let e;
121
- try {
122
- e = JSON.parse(t.data);
123
- } catch {
124
- return;
125
- }
126
- switch (e.type) {
127
- case "welcome":
128
- (s = this.welcomePromise) == null || s.resolve(), this.welcomePromise = null;
129
- break;
130
- case "ping":
131
- break;
132
- case "confirm_subscription": {
133
- const n = e.identifier, i = this.subscriptions.get(n);
134
- i == null || i._notifyConnected();
135
- const c = this.pendingSubscriptions.get(n);
136
- c && (c.resolve(), this.pendingSubscriptions.delete(n));
137
- break;
138
- }
139
- case "reject_subscription": {
140
- const n = e.identifier, i = this.subscriptions.get(n);
141
- i == null || i._notifyRejected(), this.subscriptions.delete(n);
142
- const c = this.pendingSubscriptions.get(n);
143
- c && (c.reject(new Error(`Subscription rejected: ${n}`)), this.pendingSubscriptions.delete(n));
144
- break;
145
- }
146
- case "disconnect":
147
- this.subscriptions.forEach((n) => n._notifyDisconnected());
148
- break;
149
- default: {
150
- if (e.identifier && e.message !== void 0) {
151
- const n = this.subscriptions.get(e.identifier);
152
- n == null || n._notifyReceived(e.message);
153
- }
154
- break;
155
- }
156
- }
157
- }
158
- }
159
- class _ {
160
- constructor() {
161
- o(this, "handlers", /* @__PURE__ */ new Map());
162
- }
163
- on(t, e) {
164
- return this.handlers.has(t) || this.handlers.set(t, /* @__PURE__ */ new Set()), this.handlers.get(t).add(e), () => this.off(t, e);
165
- }
166
- off(t, e) {
167
- var s;
168
- (s = this.handlers.get(t)) == null || s.delete(e);
169
- }
170
- emit(t, e) {
171
- var s;
172
- (s = this.handlers.get(t)) == null || s.forEach((n) => {
173
- try {
174
- n(e);
175
- } catch (i) {
176
- console.error(`Error in event handler for "${t}":`, i);
177
- }
178
- });
179
- }
180
- removeAllListeners() {
181
- this.handlers.clear();
182
- }
183
- }
184
- const y = 1e3, w = 10, A = 400, C = 600, O = "#6366f1", U = 12, D = "system-ui, -apple-system, sans-serif", R = "Type a message...", N = "bottom-right", P = "light", F = { x: 20, y: 20 }, p = "aikaara_conversation_id";
185
- class I extends _ {
186
- constructor(e) {
187
- super();
188
- o(this, "client");
189
- o(this, "config");
190
- o(this, "state", "disconnected");
191
- o(this, "reconnectAttempt", 0);
192
- o(this, "reconnectTimer", null);
193
- this.config = e;
194
- const s = this.buildWsUrl(e.baseUrl, e.userToken);
195
- this.client = new f(s);
196
- }
197
- async connect() {
198
- this.setState("connecting");
199
- try {
200
- await this.client.connect(), this.setState("connected"), this.reconnectAttempt = 0;
201
- } catch (e) {
202
- if (this.setState("disconnected"), this.config.reconnect !== !1)
203
- this.scheduleReconnect();
204
- else
205
- throw e;
206
- }
207
- }
208
- async disconnect() {
209
- this.clearReconnectTimer(), this.client.disconnect(), this.setState("disconnected");
210
- }
211
- subscribeToConversation(e) {
212
- return this.client.subscribeAsync({
213
- channel: "ConversationChannel",
214
- conversation_id: e
215
- });
216
- }
217
- sendMessage(e, s) {
218
- const n = JSON.stringify({
219
- channel: "ConversationChannel",
220
- conversation_id: e
221
- });
222
- this.client.perform(n, "send_message", { content: s });
223
- }
224
- sendUserEvent(e, s, n, i) {
225
- const c = JSON.stringify({
226
- channel: "ConversationChannel",
227
- conversation_id: e
228
- });
229
- this.client.perform(c, "send_user_event", {
230
- event_key: s,
231
- ...n && { value: n },
232
- ...i && { source: i }
233
- });
234
- }
235
- get connectionState() {
236
- return this.state;
237
- }
238
- setState(e) {
239
- this.state !== e && (this.state = e, this.emit("connection:state", e));
240
- }
241
- scheduleReconnect() {
242
- const e = this.config.maxReconnectAttempts ?? w;
243
- if (this.reconnectAttempt >= e) {
244
- this.emit("error", new Error("Max reconnection attempts reached"));
245
- return;
246
- }
247
- this.setState("reconnecting");
248
- const n = (this.config.reconnectInterval ?? y) * Math.pow(2, this.reconnectAttempt);
249
- this.reconnectAttempt++, this.reconnectTimer = setTimeout(async () => {
250
- try {
251
- const i = this.buildWsUrl(this.config.baseUrl, this.config.userToken);
252
- this.client = new f(i), await this.connect();
253
- } catch {
254
- }
255
- }, n);
256
- }
257
- clearReconnectTimer() {
258
- this.reconnectTimer && (clearTimeout(this.reconnectTimer), this.reconnectTimer = null);
259
- }
260
- buildWsUrl(e, s) {
261
- return `${e.replace(/^http/, "ws")}/cable?token=${s}`;
262
- }
263
- }
264
- class k {
265
- constructor(t, e, s) {
266
- o(this, "baseUrl");
267
- o(this, "apiKey");
268
- o(this, "userToken");
269
- this.baseUrl = t, this.userToken = e, this.apiKey = s;
270
- }
271
- async createConversation(t) {
272
- const e = {
273
- conversation: {
274
- ...t.extUid && { ext_uid: t.extUid },
275
- ...t.systemPromptId && { system_prompt_id: t.systemPromptId },
276
- ...t.channel && { channel: t.channel },
277
- ...t.title && { title: t.title }
278
- }
279
- };
280
- return this.request("POST", "/api/v1/conversations", e);
281
- }
282
- async getMessages(t) {
283
- return (await this.request(
284
- "GET",
285
- `/api/v1/conversations/${t}/messages`
286
- )).map(this.mapMessage);
287
- }
288
- mapMessage(t) {
289
- var e;
290
- return {
291
- id: String(t.id),
292
- conversationId: String(t.conversation_id),
293
- role: t.role,
294
- content: t.content || "",
295
- toolCalls: (e = t.tool_calls) == null ? void 0 : e.map((s) => ({
296
- id: s.id,
297
- type: s.type,
298
- function: s.function
299
- })),
300
- toolCallResults: t.tool_call_results,
301
- tokensInput: t.tokens_input,
302
- tokensOutput: t.tokens_output,
303
- metadata: t.metadata,
304
- createdAt: t.created_at,
305
- status: "complete"
306
- };
307
- }
308
- async request(t, e, s) {
309
- const n = {
310
- "Content-Type": "application/json",
311
- Accept: "application/json"
312
- };
313
- this.apiKey && (n["X-Api-Key"] = this.apiKey);
314
- const i = `${this.baseUrl}${e}`, c = { method: t, headers: n };
315
- s && (c.body = JSON.stringify(s));
316
- const l = await fetch(i, c);
317
- if (!l.ok) {
318
- const u = await l.text();
319
- let g;
320
- try {
321
- const m = JSON.parse(u);
322
- g = m.error || m.message || u;
323
- } catch {
324
- g = u;
325
- }
326
- throw new Error(`API error ${l.status}: ${g}`);
327
- }
328
- const h = await l.json();
329
- if (h && typeof h == "object" && "success" in h) {
330
- if (!h.success)
331
- throw new Error(`API error: ${h.message || "Request failed"}`);
332
- return h.data;
333
- }
334
- return h;
335
- }
336
- }
337
- class E {
338
- constructor() {
339
- o(this, "_messages", []);
340
- o(this, "optimisticCounter", 0);
341
- }
342
- get messages() {
343
- return [...this._messages];
344
- }
345
- addOptimistic(t, e, s) {
346
- const n = {
347
- id: `optimistic_${++this.optimisticCounter}`,
348
- conversationId: s,
349
- role: t,
350
- content: e,
351
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
352
- status: "sending"
353
- };
354
- return this._messages.push(n), n;
355
- }
356
- confirmOptimistic(t) {
357
- const e = this._messages.find((s) => s.id === t);
358
- e && (e.status = "sent");
359
- }
360
- addStreamingMessage(t) {
361
- const e = {
362
- id: `streaming_${Date.now()}`,
363
- conversationId: t,
364
- role: "assistant",
365
- content: "",
366
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
367
- status: "streaming"
368
- };
369
- return this._messages.push(e), e;
370
- }
371
- updateStreaming(t) {
372
- const e = this._messages.findLast((s) => s.status === "streaming");
373
- e && (e.content = t);
374
- }
375
- finalizeStreaming(t) {
376
- const e = this._messages.findLast((s) => s.status === "streaming");
377
- return e && (e.status = "complete", t && (e.tokensInput = t.tokensInput, e.tokensOutput = t.tokensOutput)), e;
378
- }
379
- addMessage(t) {
380
- this._messages.push(t);
381
- }
382
- setMessages(t) {
383
- this._messages = [...t];
384
- }
385
- clear() {
386
- this._messages = [];
387
- }
388
- }
389
- class T {
390
- constructor(t, e = !0) {
391
- o(this, "_conversationId");
392
- o(this, "persist");
393
- this.persist = e, this._conversationId = t || this.loadFromStorage();
394
- }
395
- get conversationId() {
396
- return this._conversationId;
397
- }
398
- set conversationId(t) {
399
- this._conversationId = t, this.persist && t && this.saveToStorage(t);
400
- }
401
- clear() {
402
- if (this._conversationId = null, this.persist)
403
- try {
404
- localStorage.removeItem(p);
405
- } catch {
406
- }
407
- }
408
- loadFromStorage() {
409
- if (!this.persist) return null;
410
- try {
411
- return localStorage.getItem(p);
412
- } catch {
413
- return null;
414
- }
415
- }
416
- saveToStorage(t) {
417
- try {
418
- localStorage.setItem(p, t);
419
- } catch {
420
- }
421
- }
422
- }
423
- class L extends _ {
424
- constructor(e) {
425
- super();
426
- o(this, "connection");
427
- o(this, "api");
428
- o(this, "messageStore");
429
- o(this, "conversationManager");
430
- o(this, "subscription", null);
431
- o(this, "config");
432
- this.config = e, this.connection = new I(e), this.api = new k(e.baseUrl, e.userToken, e.apiKey), this.messageStore = new E(), this.conversationManager = new T(e.conversationId), this.connection.on("connection:state", (s) => {
433
- var n, i;
434
- this.emit("connection:state", s), (i = (n = this.config).onConnectionStateChange) == null || i.call(n, s);
435
- }), this.connection.on("error", (s) => {
436
- var n, i;
437
- this.emit("error", s), (i = (n = this.config).onError) == null || i.call(n, s);
438
- });
439
- }
440
- async connect() {
441
- if (await this.connection.connect(), !this.conversationManager.conversationId) {
442
- const e = await this.api.createConversation({
443
- systemPromptId: this.config.systemPromptId,
444
- channel: this.config.channel || "widget",
445
- extUid: this.config.extUid
446
- });
447
- this.conversationManager.conversationId = String(e.id);
448
- }
449
- this.subscription = await this.connection.subscribeToConversation(
450
- this.conversationManager.conversationId
451
- ), this.subscription.onReceived((e) => {
452
- this.handleBroadcast(e);
453
- }), await this.loadHistory();
454
- }
455
- async sendMessage(e) {
456
- var i, c;
457
- const s = this.conversationManager.conversationId;
458
- if (!s)
459
- throw new Error("No active conversation");
460
- const n = this.messageStore.addOptimistic("user", e, s);
461
- this.emit("message:sent", n), (c = (i = this.config).onMessage) == null || c.call(i, n), this.connection.sendMessage(s, e);
462
- }
463
- async sendUserEvent(e, s, n) {
464
- const i = this.conversationManager.conversationId;
465
- if (!i)
466
- throw new Error("No active conversation");
467
- this.connection.sendUserEvent(i, e, s, n);
468
- }
469
- async loadHistory() {
470
- const e = this.conversationManager.conversationId;
471
- if (!e) return [];
472
- try {
473
- const s = await this.api.getMessages(e);
474
- return this.messageStore.setMessages(s), s;
475
- } catch {
476
- return [];
477
- }
478
- }
479
- get messages() {
480
- return this.messageStore.messages;
481
- }
482
- get conversationId() {
483
- return this.conversationManager.conversationId;
484
- }
485
- get isConnected() {
486
- return this.connection.connectionState === "connected";
487
- }
488
- async disconnect() {
489
- this.subscription && (this.subscription = null), await this.connection.disconnect();
490
- }
491
- handleBroadcast(e) {
492
- var n, i, c, l, h, u, g, m;
493
- const s = this.conversationManager.conversationId;
494
- switch (e.type) {
495
- case "status": {
496
- const r = e.status;
497
- this.emit("status", r), (i = (n = this.config).onStatusChange) == null || i.call(n, r), r === "processing" && this.emit("typing:start", void 0);
498
- break;
499
- }
500
- case "error": {
501
- const r = new Error(e.message || "Unknown error");
502
- this.emit("error", r), (l = (c = this.config).onError) == null || l.call(c, r);
503
- break;
504
- }
505
- case "message_start": {
506
- if (e.role === "assistant") {
507
- const r = this.messageStore.addStreamingMessage(s);
508
- this.emit("stream:start", { messageId: r.id }), this.emit("typing:start", void 0);
509
- }
510
- break;
511
- }
512
- case "message_update": {
513
- const r = e.content || "", d = e.delta || "";
514
- this.messageStore.updateStreaming(r), this.emit("stream:update", { delta: d, content: r }), (u = (h = this.config).onStreamUpdate) == null || u.call(h, d, r);
515
- break;
516
- }
517
- case "message_end": {
518
- const r = e.usage, d = this.messageStore.finalizeStreaming(
519
- r ? { tokensInput: r.tokens_input || 0, tokensOutput: r.tokens_output || 0 } : void 0
520
- );
521
- this.emit("typing:stop", void 0), d && (this.emit("stream:end", {
522
- messageId: d.id,
523
- usage: r ? { tokensInput: r.tokens_input || 0, tokensOutput: r.tokens_output || 0 } : void 0
524
- }), this.emit("message:received", d), (m = (g = this.config).onMessage) == null || m.call(g, d));
525
- break;
526
- }
527
- case "message_queued": {
528
- const r = this.messageStore.messages.findLast((d) => d.status === "sending");
529
- r && this.messageStore.confirmOptimistic(r.id);
530
- break;
531
- }
532
- case "tool_execution_start":
533
- case "tool_execution_update":
534
- case "tool_execution_end":
535
- case "agent_start":
536
- case "agent_end":
537
- case "turn_start":
538
- case "turn_end":
539
- case "auto_retry_start":
540
- case "auto_retry_end":
541
- case "cancelled":
542
- this.emit("status", e.type);
543
- break;
544
- }
545
- }
546
- }
547
- export {
548
- f as A,
549
- S as C,
550
- F as D,
551
- _ as E,
552
- E as M,
553
- L as a,
554
- k as b,
555
- I as c,
556
- T as d,
557
- R as e,
558
- U as f,
559
- D as g,
560
- C as h,
561
- A as i,
562
- N as j,
563
- O as k,
564
- P as l
565
- };
@@ -1 +0,0 @@
1
- "use strict";var E=Object.defineProperty;var T=(a,t,e)=>t in a?E(a,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):a[t]=e;var o=(a,t,e)=>T(a,typeof t!="symbol"?t+"":t,e);class b{constructor(t,e){o(this,"identifier");o(this,"callbacks",{});o(this,"sendFn");this.identifier=t,this.sendFn=e}onReceived(t){return this.callbacks.received=t,this}onConnected(t){return this.callbacks.connected=t,this}onDisconnected(t){return this.callbacks.disconnected=t,this}onRejected(t){return this.callbacks.rejected=t,this}perform(t,e={}){this.sendFn({action:t,...e})}_notifyReceived(t){var e,s;(s=(e=this.callbacks).received)==null||s.call(e,t)}_notifyConnected(){var t,e;(e=(t=this.callbacks).connected)==null||e.call(t)}_notifyDisconnected(){var t,e;(e=(t=this.callbacks).disconnected)==null||e.call(t)}_notifyRejected(){var t,e;(e=(t=this.callbacks).rejected)==null||e.call(t)}}class f{constructor(t){o(this,"ws",null);o(this,"url");o(this,"subscriptions",new Map);o(this,"welcomePromise",null);o(this,"pendingSubscriptions",new Map);this.url=t}connect(){return new Promise((t,e)=>{this.welcomePromise={resolve:t,reject:e},this.ws=new WebSocket(this.url),this.ws.onopen=()=>{},this.ws.onmessage=s=>{this.handleMessage(s)},this.ws.onerror=()=>{var n;const s=new Error("WebSocket connection error");(n=this.welcomePromise)==null||n.reject(s),this.welcomePromise=null},this.ws.onclose=()=>{this.subscriptions.forEach(s=>s._notifyDisconnected())}})}disconnect(){this.ws&&(this.ws.onclose=null,this.ws.close(),this.ws=null),this.subscriptions.forEach(t=>t._notifyDisconnected()),this.subscriptions.clear()}subscribe(t){const e=JSON.stringify(t),s=new b(e,n=>{this.send({command:"message",identifier:e,data:JSON.stringify(n)})});return this.subscriptions.set(e,s),this.send({command:"subscribe",identifier:e}),s}subscribeAsync(t){const e=this.subscribe(t),s=e.identifier;return new Promise((n,i)=>{this.pendingSubscriptions.set(s,{resolve:()=>n(e),reject:i}),setTimeout(()=>{this.pendingSubscriptions.has(s)&&(this.pendingSubscriptions.delete(s),i(new Error(`Subscription timeout for ${s}`)))},1e4)})}unsubscribe(t){this.send({command:"unsubscribe",identifier:t}),this.subscriptions.delete(t)}perform(t,e,s={}){this.send({command:"message",identifier:t,data:JSON.stringify({action:e,...s})})}get isConnected(){var t;return((t=this.ws)==null?void 0:t.readyState)===WebSocket.OPEN}send(t){var e;((e=this.ws)==null?void 0:e.readyState)===WebSocket.OPEN&&this.ws.send(JSON.stringify(t))}handleMessage(t){var s;let e;try{e=JSON.parse(t.data)}catch{return}switch(e.type){case"welcome":(s=this.welcomePromise)==null||s.resolve(),this.welcomePromise=null;break;case"ping":break;case"confirm_subscription":{const n=e.identifier,i=this.subscriptions.get(n);i==null||i._notifyConnected();const c=this.pendingSubscriptions.get(n);c&&(c.resolve(),this.pendingSubscriptions.delete(n));break}case"reject_subscription":{const n=e.identifier,i=this.subscriptions.get(n);i==null||i._notifyRejected(),this.subscriptions.delete(n);const c=this.pendingSubscriptions.get(n);c&&(c.reject(new Error(`Subscription rejected: ${n}`)),this.pendingSubscriptions.delete(n));break}case"disconnect":this.subscriptions.forEach(n=>n._notifyDisconnected());break;default:{if(e.identifier&&e.message!==void 0){const n=this.subscriptions.get(e.identifier);n==null||n._notifyReceived(e.message)}break}}}}class _{constructor(){o(this,"handlers",new Map)}on(t,e){return this.handlers.has(t)||this.handlers.set(t,new Set),this.handlers.get(t).add(e),()=>this.off(t,e)}off(t,e){var s;(s=this.handlers.get(t))==null||s.delete(e)}emit(t,e){var s;(s=this.handlers.get(t))==null||s.forEach(n=>{try{n(e)}catch(i){console.error(`Error in event handler for "${t}":`,i)}})}removeAllListeners(){this.handlers.clear()}}const I=1e3,A=10,k=400,C=600,M="#6366f1",O=12,U="system-ui, -apple-system, sans-serif",D="Type a message...",F="bottom-right",L="light",R={x:20,y:20},p="aikaara_conversation_id";class S extends _{constructor(e){super();o(this,"client");o(this,"config");o(this,"state","disconnected");o(this,"reconnectAttempt",0);o(this,"reconnectTimer",null);this.config=e;const s=this.buildWsUrl(e.baseUrl,e.userToken);this.client=new f(s)}async connect(){this.setState("connecting");try{await this.client.connect(),this.setState("connected"),this.reconnectAttempt=0}catch(e){if(this.setState("disconnected"),this.config.reconnect!==!1)this.scheduleReconnect();else throw e}}async disconnect(){this.clearReconnectTimer(),this.client.disconnect(),this.setState("disconnected")}subscribeToConversation(e){return this.client.subscribeAsync({channel:"ConversationChannel",conversation_id:e})}sendMessage(e,s){const n=JSON.stringify({channel:"ConversationChannel",conversation_id:e});this.client.perform(n,"send_message",{content:s})}sendUserEvent(e,s,n,i){const c=JSON.stringify({channel:"ConversationChannel",conversation_id:e});this.client.perform(c,"send_user_event",{event_key:s,...n&&{value:n},...i&&{source:i}})}get connectionState(){return this.state}setState(e){this.state!==e&&(this.state=e,this.emit("connection:state",e))}scheduleReconnect(){const e=this.config.maxReconnectAttempts??A;if(this.reconnectAttempt>=e){this.emit("error",new Error("Max reconnection attempts reached"));return}this.setState("reconnecting");const n=(this.config.reconnectInterval??I)*Math.pow(2,this.reconnectAttempt);this.reconnectAttempt++,this.reconnectTimer=setTimeout(async()=>{try{const i=this.buildWsUrl(this.config.baseUrl,this.config.userToken);this.client=new f(i),await this.connect()}catch{}},n)}clearReconnectTimer(){this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null)}buildWsUrl(e,s){return`${e.replace(/^http/,"ws")}/cable?token=${s}`}}class v{constructor(t,e,s){o(this,"baseUrl");o(this,"apiKey");o(this,"userToken");this.baseUrl=t,this.userToken=e,this.apiKey=s}async createConversation(t){const e={conversation:{...t.extUid&&{ext_uid:t.extUid},...t.systemPromptId&&{system_prompt_id:t.systemPromptId},...t.channel&&{channel:t.channel},...t.title&&{title:t.title}}};return this.request("POST","/api/v1/conversations",e)}async getMessages(t){return(await this.request("GET",`/api/v1/conversations/${t}/messages`)).map(this.mapMessage)}mapMessage(t){var e;return{id:String(t.id),conversationId:String(t.conversation_id),role:t.role,content:t.content||"",toolCalls:(e=t.tool_calls)==null?void 0:e.map(s=>({id:s.id,type:s.type,function:s.function})),toolCallResults:t.tool_call_results,tokensInput:t.tokens_input,tokensOutput:t.tokens_output,metadata:t.metadata,createdAt:t.created_at,status:"complete"}}async request(t,e,s){const n={"Content-Type":"application/json",Accept:"application/json"};this.apiKey&&(n["X-Api-Key"]=this.apiKey);const i=`${this.baseUrl}${e}`,c={method:t,headers:n};s&&(c.body=JSON.stringify(s));const l=await fetch(i,c);if(!l.ok){const u=await l.text();let g;try{const m=JSON.parse(u);g=m.error||m.message||u}catch{g=u}throw new Error(`API error ${l.status}: ${g}`)}const h=await l.json();if(h&&typeof h=="object"&&"success"in h){if(!h.success)throw new Error(`API error: ${h.message||"Request failed"}`);return h.data}return h}}class y{constructor(){o(this,"_messages",[]);o(this,"optimisticCounter",0)}get messages(){return[...this._messages]}addOptimistic(t,e,s){const n={id:`optimistic_${++this.optimisticCounter}`,conversationId:s,role:t,content:e,createdAt:new Date().toISOString(),status:"sending"};return this._messages.push(n),n}confirmOptimistic(t){const e=this._messages.find(s=>s.id===t);e&&(e.status="sent")}addStreamingMessage(t){const e={id:`streaming_${Date.now()}`,conversationId:t,role:"assistant",content:"",createdAt:new Date().toISOString(),status:"streaming"};return this._messages.push(e),e}updateStreaming(t){const e=this._messages.findLast(s=>s.status==="streaming");e&&(e.content=t)}finalizeStreaming(t){const e=this._messages.findLast(s=>s.status==="streaming");return e&&(e.status="complete",t&&(e.tokensInput=t.tokensInput,e.tokensOutput=t.tokensOutput)),e}addMessage(t){this._messages.push(t)}setMessages(t){this._messages=[...t]}clear(){this._messages=[]}}class w{constructor(t,e=!0){o(this,"_conversationId");o(this,"persist");this.persist=e,this._conversationId=t||this.loadFromStorage()}get conversationId(){return this._conversationId}set conversationId(t){this._conversationId=t,this.persist&&t&&this.saveToStorage(t)}clear(){if(this._conversationId=null,this.persist)try{localStorage.removeItem(p)}catch{}}loadFromStorage(){if(!this.persist)return null;try{return localStorage.getItem(p)}catch{return null}}saveToStorage(t){try{localStorage.setItem(p,t)}catch{}}}class N extends _{constructor(e){super();o(this,"connection");o(this,"api");o(this,"messageStore");o(this,"conversationManager");o(this,"subscription",null);o(this,"config");this.config=e,this.connection=new S(e),this.api=new v(e.baseUrl,e.userToken,e.apiKey),this.messageStore=new y,this.conversationManager=new w(e.conversationId),this.connection.on("connection:state",s=>{var n,i;this.emit("connection:state",s),(i=(n=this.config).onConnectionStateChange)==null||i.call(n,s)}),this.connection.on("error",s=>{var n,i;this.emit("error",s),(i=(n=this.config).onError)==null||i.call(n,s)})}async connect(){if(await this.connection.connect(),!this.conversationManager.conversationId){const e=await this.api.createConversation({systemPromptId:this.config.systemPromptId,channel:this.config.channel||"widget",extUid:this.config.extUid});this.conversationManager.conversationId=String(e.id)}this.subscription=await this.connection.subscribeToConversation(this.conversationManager.conversationId),this.subscription.onReceived(e=>{this.handleBroadcast(e)}),await this.loadHistory()}async sendMessage(e){var i,c;const s=this.conversationManager.conversationId;if(!s)throw new Error("No active conversation");const n=this.messageStore.addOptimistic("user",e,s);this.emit("message:sent",n),(c=(i=this.config).onMessage)==null||c.call(i,n),this.connection.sendMessage(s,e)}async sendUserEvent(e,s,n){const i=this.conversationManager.conversationId;if(!i)throw new Error("No active conversation");this.connection.sendUserEvent(i,e,s,n)}async loadHistory(){const e=this.conversationManager.conversationId;if(!e)return[];try{const s=await this.api.getMessages(e);return this.messageStore.setMessages(s),s}catch{return[]}}get messages(){return this.messageStore.messages}get conversationId(){return this.conversationManager.conversationId}get isConnected(){return this.connection.connectionState==="connected"}async disconnect(){this.subscription&&(this.subscription=null),await this.connection.disconnect()}handleBroadcast(e){var n,i,c,l,h,u,g,m;const s=this.conversationManager.conversationId;switch(e.type){case"status":{const r=e.status;this.emit("status",r),(i=(n=this.config).onStatusChange)==null||i.call(n,r),r==="processing"&&this.emit("typing:start",void 0);break}case"error":{const r=new Error(e.message||"Unknown error");this.emit("error",r),(l=(c=this.config).onError)==null||l.call(c,r);break}case"message_start":{if(e.role==="assistant"){const r=this.messageStore.addStreamingMessage(s);this.emit("stream:start",{messageId:r.id}),this.emit("typing:start",void 0)}break}case"message_update":{const r=e.content||"",d=e.delta||"";this.messageStore.updateStreaming(r),this.emit("stream:update",{delta:d,content:r}),(u=(h=this.config).onStreamUpdate)==null||u.call(h,d,r);break}case"message_end":{const r=e.usage,d=this.messageStore.finalizeStreaming(r?{tokensInput:r.tokens_input||0,tokensOutput:r.tokens_output||0}:void 0);this.emit("typing:stop",void 0),d&&(this.emit("stream:end",{messageId:d.id,usage:r?{tokensInput:r.tokens_input||0,tokensOutput:r.tokens_output||0}:void 0}),this.emit("message:received",d),(m=(g=this.config).onMessage)==null||m.call(g,d));break}case"message_queued":{const r=this.messageStore.messages.findLast(d=>d.status==="sending");r&&this.messageStore.confirmOptimistic(r.id);break}case"tool_execution_start":case"tool_execution_update":case"tool_execution_end":case"agent_start":case"agent_end":case"turn_start":case"turn_end":case"auto_retry_start":case"auto_retry_end":case"cancelled":this.emit("status",e.type);break}}}exports.ActionCableClient=f;exports.AikaaraChatClient=N;exports.ApiClient=v;exports.ChannelSubscription=b;exports.ConnectionManager=S;exports.ConversationManager=w;exports.DEFAULT_BORDER_RADIUS=O;exports.DEFAULT_FONT_FAMILY=U;exports.DEFAULT_OFFSET=R;exports.DEFAULT_PLACEHOLDER=D;exports.DEFAULT_POSITION=F;exports.DEFAULT_PRIMARY_COLOR=M;exports.DEFAULT_THEME=L;exports.DEFAULT_WIDGET_HEIGHT=C;exports.DEFAULT_WIDGET_WIDTH=k;exports.EventEmitter=_;exports.MessageStore=y;