@aikaara/chat-sdk 0.1.3 → 0.1.4

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