@aikaara/chat-sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,557 @@
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", F = "light", L = { x: 20, y: 20 }, m = "aikaara_conversation_id";
185
+ class k 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 I {
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.systemPromptId && { system_prompt_id: t.systemPromptId },
275
+ ...t.channel && { channel: t.channel },
276
+ ...t.title && { title: t.title }
277
+ }
278
+ };
279
+ return this.request("POST", "/api/v1/conversations", e);
280
+ }
281
+ async getMessages(t) {
282
+ return (await this.request(
283
+ "GET",
284
+ `/api/v1/conversations/${t}/messages`
285
+ )).map(this.mapMessage);
286
+ }
287
+ mapMessage(t) {
288
+ var e;
289
+ return {
290
+ id: String(t.id),
291
+ conversationId: String(t.conversation_id),
292
+ role: t.role,
293
+ content: t.content || "",
294
+ toolCalls: (e = t.tool_calls) == null ? void 0 : e.map((s) => ({
295
+ id: s.id,
296
+ type: s.type,
297
+ function: s.function
298
+ })),
299
+ toolCallResults: t.tool_call_results,
300
+ tokensInput: t.tokens_input,
301
+ tokensOutput: t.tokens_output,
302
+ metadata: t.metadata,
303
+ createdAt: t.created_at,
304
+ status: "complete"
305
+ };
306
+ }
307
+ async request(t, e, s) {
308
+ const n = {
309
+ "Content-Type": "application/json",
310
+ Accept: "application/json"
311
+ };
312
+ this.apiKey && (n["X-Api-Key"] = this.apiKey);
313
+ const i = `${this.baseUrl}${e}`, c = { method: t, headers: n };
314
+ s && (c.body = JSON.stringify(s));
315
+ const d = await fetch(i, c);
316
+ if (!d.ok) {
317
+ const l = await d.text();
318
+ let u;
319
+ try {
320
+ const g = JSON.parse(l);
321
+ u = g.error || g.message || l;
322
+ } catch {
323
+ u = l;
324
+ }
325
+ throw new Error(`API error ${d.status}: ${u}`);
326
+ }
327
+ return d.json();
328
+ }
329
+ }
330
+ class E {
331
+ constructor() {
332
+ o(this, "_messages", []);
333
+ o(this, "optimisticCounter", 0);
334
+ }
335
+ get messages() {
336
+ return [...this._messages];
337
+ }
338
+ addOptimistic(t, e, s) {
339
+ const n = {
340
+ id: `optimistic_${++this.optimisticCounter}`,
341
+ conversationId: s,
342
+ role: t,
343
+ content: e,
344
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
345
+ status: "sending"
346
+ };
347
+ return this._messages.push(n), n;
348
+ }
349
+ confirmOptimistic(t) {
350
+ const e = this._messages.find((s) => s.id === t);
351
+ e && (e.status = "sent");
352
+ }
353
+ addStreamingMessage(t) {
354
+ const e = {
355
+ id: `streaming_${Date.now()}`,
356
+ conversationId: t,
357
+ role: "assistant",
358
+ content: "",
359
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
360
+ status: "streaming"
361
+ };
362
+ return this._messages.push(e), e;
363
+ }
364
+ updateStreaming(t) {
365
+ const e = this._messages.findLast((s) => s.status === "streaming");
366
+ e && (e.content = t);
367
+ }
368
+ finalizeStreaming(t) {
369
+ const e = this._messages.findLast((s) => s.status === "streaming");
370
+ return e && (e.status = "complete", t && (e.tokensInput = t.tokensInput, e.tokensOutput = t.tokensOutput)), e;
371
+ }
372
+ addMessage(t) {
373
+ this._messages.push(t);
374
+ }
375
+ setMessages(t) {
376
+ this._messages = [...t];
377
+ }
378
+ clear() {
379
+ this._messages = [];
380
+ }
381
+ }
382
+ class T {
383
+ constructor(t, e = !0) {
384
+ o(this, "_conversationId");
385
+ o(this, "persist");
386
+ this.persist = e, this._conversationId = t || this.loadFromStorage();
387
+ }
388
+ get conversationId() {
389
+ return this._conversationId;
390
+ }
391
+ set conversationId(t) {
392
+ this._conversationId = t, this.persist && t && this.saveToStorage(t);
393
+ }
394
+ clear() {
395
+ if (this._conversationId = null, this.persist)
396
+ try {
397
+ localStorage.removeItem(m);
398
+ } catch {
399
+ }
400
+ }
401
+ loadFromStorage() {
402
+ if (!this.persist) return null;
403
+ try {
404
+ return localStorage.getItem(m);
405
+ } catch {
406
+ return null;
407
+ }
408
+ }
409
+ saveToStorage(t) {
410
+ try {
411
+ localStorage.setItem(m, t);
412
+ } catch {
413
+ }
414
+ }
415
+ }
416
+ class P extends _ {
417
+ constructor(e) {
418
+ super();
419
+ o(this, "connection");
420
+ o(this, "api");
421
+ o(this, "messageStore");
422
+ o(this, "conversationManager");
423
+ o(this, "subscription", null);
424
+ o(this, "config");
425
+ this.config = e, this.connection = new k(e), this.api = new I(e.baseUrl, e.userToken, e.apiKey), this.messageStore = new E(), this.conversationManager = new T(e.conversationId), this.connection.on("connection:state", (s) => {
426
+ var n, i;
427
+ this.emit("connection:state", s), (i = (n = this.config).onConnectionStateChange) == null || i.call(n, s);
428
+ }), this.connection.on("error", (s) => {
429
+ var n, i;
430
+ this.emit("error", s), (i = (n = this.config).onError) == null || i.call(n, s);
431
+ });
432
+ }
433
+ async connect() {
434
+ if (await this.connection.connect(), !this.conversationManager.conversationId) {
435
+ const e = await this.api.createConversation({
436
+ systemPromptId: this.config.systemPromptId,
437
+ channel: this.config.channel || "widget"
438
+ });
439
+ this.conversationManager.conversationId = String(e.id);
440
+ }
441
+ this.subscription = await this.connection.subscribeToConversation(
442
+ this.conversationManager.conversationId
443
+ ), this.subscription.onReceived((e) => {
444
+ this.handleBroadcast(e);
445
+ }), await this.loadHistory();
446
+ }
447
+ async sendMessage(e) {
448
+ var i, c;
449
+ const s = this.conversationManager.conversationId;
450
+ if (!s)
451
+ throw new Error("No active conversation");
452
+ const n = this.messageStore.addOptimistic("user", e, s);
453
+ this.emit("message:sent", n), (c = (i = this.config).onMessage) == null || c.call(i, n), this.connection.sendMessage(s, e);
454
+ }
455
+ async sendUserEvent(e, s, n) {
456
+ const i = this.conversationManager.conversationId;
457
+ if (!i)
458
+ throw new Error("No active conversation");
459
+ this.connection.sendUserEvent(i, e, s, n);
460
+ }
461
+ async loadHistory() {
462
+ const e = this.conversationManager.conversationId;
463
+ if (!e) return [];
464
+ try {
465
+ const s = await this.api.getMessages(e);
466
+ return this.messageStore.setMessages(s), s;
467
+ } catch {
468
+ return [];
469
+ }
470
+ }
471
+ get messages() {
472
+ return this.messageStore.messages;
473
+ }
474
+ get conversationId() {
475
+ return this.conversationManager.conversationId;
476
+ }
477
+ get isConnected() {
478
+ return this.connection.connectionState === "connected";
479
+ }
480
+ async disconnect() {
481
+ this.subscription && (this.subscription = null), await this.connection.disconnect();
482
+ }
483
+ handleBroadcast(e) {
484
+ var n, i, c, d, l, u, g, p;
485
+ const s = this.conversationManager.conversationId;
486
+ switch (e.type) {
487
+ case "status": {
488
+ const r = e.status;
489
+ this.emit("status", r), (i = (n = this.config).onStatusChange) == null || i.call(n, r), r === "processing" && this.emit("typing:start", void 0);
490
+ break;
491
+ }
492
+ case "error": {
493
+ const r = new Error(e.message || "Unknown error");
494
+ this.emit("error", r), (d = (c = this.config).onError) == null || d.call(c, r);
495
+ break;
496
+ }
497
+ case "message_start": {
498
+ if (e.role === "assistant") {
499
+ const r = this.messageStore.addStreamingMessage(s);
500
+ this.emit("stream:start", { messageId: r.id }), this.emit("typing:start", void 0);
501
+ }
502
+ break;
503
+ }
504
+ case "message_update": {
505
+ const r = e.content || "", h = e.delta || "";
506
+ this.messageStore.updateStreaming(r), this.emit("stream:update", { delta: h, content: r }), (u = (l = this.config).onStreamUpdate) == null || u.call(l, h, r);
507
+ break;
508
+ }
509
+ case "message_end": {
510
+ const r = e.usage, h = this.messageStore.finalizeStreaming(
511
+ r ? { tokensInput: r.tokens_input || 0, tokensOutput: r.tokens_output || 0 } : void 0
512
+ );
513
+ this.emit("typing:stop", void 0), h && (this.emit("stream:end", {
514
+ messageId: h.id,
515
+ usage: r ? { tokensInput: r.tokens_input || 0, tokensOutput: r.tokens_output || 0 } : void 0
516
+ }), this.emit("message:received", h), (p = (g = this.config).onMessage) == null || p.call(g, h));
517
+ break;
518
+ }
519
+ case "message_queued": {
520
+ const r = this.messageStore.messages.findLast((h) => h.status === "sending");
521
+ r && this.messageStore.confirmOptimistic(r.id);
522
+ break;
523
+ }
524
+ case "tool_execution_start":
525
+ case "tool_execution_update":
526
+ case "tool_execution_end":
527
+ case "agent_start":
528
+ case "agent_end":
529
+ case "turn_start":
530
+ case "turn_end":
531
+ case "auto_retry_start":
532
+ case "auto_retry_end":
533
+ case "cancelled":
534
+ this.emit("status", e.type);
535
+ break;
536
+ }
537
+ }
538
+ }
539
+ export {
540
+ f as A,
541
+ S as C,
542
+ L as D,
543
+ _ as E,
544
+ E as M,
545
+ P as a,
546
+ I as b,
547
+ k as c,
548
+ T as d,
549
+ R as e,
550
+ U as f,
551
+ D as g,
552
+ C as h,
553
+ A as i,
554
+ N as j,
555
+ O as k,
556
+ F as l
557
+ };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./headless-CjIUiswe.cjs");exports.ActionCableClient=e.ActionCableClient;exports.AikaaraChatClient=e.AikaaraChatClient;exports.ApiClient=e.ApiClient;exports.ChannelSubscription=e.ChannelSubscription;exports.ConnectionManager=e.ConnectionManager;exports.ConversationManager=e.ConversationManager;exports.EventEmitter=e.EventEmitter;exports.MessageStore=e.MessageStore;