@usecrow/client 0.1.42 → 0.1.44

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,788 @@
1
+ class I {
2
+ constructor() {
3
+ this.state = {
4
+ token: null,
5
+ metadata: {},
6
+ isVerified: !1
7
+ }, this.listeners = /* @__PURE__ */ new Set();
8
+ }
9
+ /**
10
+ * Identify the current user with a JWT token
11
+ */
12
+ identify(e) {
13
+ const { token: t, ...s } = e;
14
+ this.state = {
15
+ token: t,
16
+ metadata: s,
17
+ isVerified: !1
18
+ // Will be set when server confirms
19
+ }, this.notify(), console.log("[Crow] User identified");
20
+ }
21
+ /**
22
+ * Update verification status (called when server confirms)
23
+ */
24
+ setVerified(e) {
25
+ this.state = { ...this.state, isVerified: e }, this.notify();
26
+ }
27
+ /**
28
+ * Reset user identity (call on logout)
29
+ */
30
+ reset() {
31
+ this.state = {
32
+ token: null,
33
+ metadata: {},
34
+ isVerified: !1
35
+ }, this.notify(), console.log("[Crow] User reset");
36
+ }
37
+ /**
38
+ * Get current identity token
39
+ */
40
+ getToken() {
41
+ return this.state.token;
42
+ }
43
+ /**
44
+ * Get current identity state
45
+ */
46
+ getState() {
47
+ return { ...this.state };
48
+ }
49
+ /**
50
+ * Check if user is identified
51
+ */
52
+ isIdentified() {
53
+ return this.state.token !== null;
54
+ }
55
+ /**
56
+ * Check if user is verified
57
+ */
58
+ isVerified() {
59
+ return this.state.isVerified;
60
+ }
61
+ /**
62
+ * Subscribe to identity changes
63
+ */
64
+ subscribe(e) {
65
+ return this.listeners.add(e), () => this.listeners.delete(e);
66
+ }
67
+ notify() {
68
+ const e = this.getState();
69
+ for (const t of this.listeners)
70
+ t(e);
71
+ }
72
+ }
73
+ class C {
74
+ constructor() {
75
+ this.handlers = {};
76
+ }
77
+ /**
78
+ * Register client-side tool handlers
79
+ */
80
+ register(e) {
81
+ for (const [t, s] of Object.entries(e))
82
+ typeof s == "function" ? (this.handlers[t] = s, console.log(`[Crow] Registered client tool: ${t}`)) : console.warn(`[Crow] Skipping ${t}: handler is not a function`);
83
+ }
84
+ /**
85
+ * Unregister a tool handler
86
+ */
87
+ unregister(e) {
88
+ delete this.handlers[e], console.log(`[Crow] Unregistered client tool: ${e}`);
89
+ }
90
+ /**
91
+ * Check if a tool is registered
92
+ */
93
+ has(e) {
94
+ return e in this.handlers;
95
+ }
96
+ /**
97
+ * Get all registered tool names
98
+ */
99
+ getRegisteredTools() {
100
+ return Object.keys(this.handlers);
101
+ }
102
+ /**
103
+ * Execute a client-side tool
104
+ */
105
+ async execute(e, t) {
106
+ const s = this.handlers[e];
107
+ if (!s)
108
+ return console.warn(`[Crow] No handler registered for tool: ${e}`), {
109
+ status: "error",
110
+ error: `No handler registered for tool: ${e}`
111
+ };
112
+ try {
113
+ console.log(`[Crow] Executing client tool: ${e}`, t);
114
+ const r = await s(t);
115
+ return console.log(`[Crow] Tool ${e} completed:`, r), r;
116
+ } catch (r) {
117
+ const i = r instanceof Error ? r.message : String(r);
118
+ return console.error(`[Crow] Tool ${e} failed:`, r), {
119
+ status: "error",
120
+ error: i
121
+ };
122
+ }
123
+ }
124
+ }
125
+ const b = "crow_conv_";
126
+ class S {
127
+ constructor(e, t, s) {
128
+ this.currentId = null, this.productId = e, this.apiUrl = t, this.storage = s, this.currentId = this.loadFromStorage();
129
+ }
130
+ /**
131
+ * Get storage key for this product
132
+ */
133
+ getStorageKey() {
134
+ return `${b}${this.productId}`;
135
+ }
136
+ /**
137
+ * Load conversation ID from storage
138
+ */
139
+ loadFromStorage() {
140
+ try {
141
+ return this.storage.getItem(this.getStorageKey());
142
+ } catch {
143
+ return null;
144
+ }
145
+ }
146
+ /**
147
+ * Save conversation ID to storage
148
+ */
149
+ saveToStorage(e) {
150
+ try {
151
+ this.storage.setItem(this.getStorageKey(), e);
152
+ } catch {
153
+ }
154
+ }
155
+ /**
156
+ * Clear conversation ID from storage
157
+ */
158
+ clearStorage() {
159
+ try {
160
+ this.storage.removeItem(this.getStorageKey());
161
+ } catch {
162
+ }
163
+ }
164
+ /**
165
+ * Get current conversation ID
166
+ */
167
+ getCurrentId() {
168
+ return this.currentId;
169
+ }
170
+ /**
171
+ * Set current conversation ID
172
+ */
173
+ setCurrentId(e) {
174
+ this.currentId = e, e ? this.saveToStorage(e) : this.clearStorage();
175
+ }
176
+ /**
177
+ * Check if there's a restored conversation
178
+ */
179
+ hasRestoredConversation() {
180
+ return this.currentId !== null;
181
+ }
182
+ /**
183
+ * Clear current conversation (start new)
184
+ */
185
+ clear() {
186
+ this.currentId = null, this.clearStorage();
187
+ }
188
+ /**
189
+ * Fetch list of conversations for verified user
190
+ */
191
+ async getConversations(e) {
192
+ try {
193
+ const t = await fetch(
194
+ `${this.apiUrl}/api/chat/conversations?product_id=${this.productId}&identity_token=${encodeURIComponent(e)}`
195
+ );
196
+ if (!t.ok)
197
+ throw new Error(`HTTP error: ${t.status}`);
198
+ return (await t.json()).conversations || [];
199
+ } catch (t) {
200
+ return console.error("[Crow] Failed to load conversations:", t), [];
201
+ }
202
+ }
203
+ /**
204
+ * Load conversation history for verified user
205
+ */
206
+ async loadHistory(e, t) {
207
+ try {
208
+ const s = await fetch(
209
+ `${this.apiUrl}/api/chat/conversations/${e}/history?product_id=${this.productId}&identity_token=${encodeURIComponent(t)}`
210
+ );
211
+ if (!s.ok)
212
+ throw new Error(`HTTP error: ${s.status}`);
213
+ const r = await s.json();
214
+ return this.parseHistoryMessages(r.messages || []);
215
+ } catch (s) {
216
+ return console.error("[Crow] Failed to load conversation history:", s), [];
217
+ }
218
+ }
219
+ /**
220
+ * Load conversation history for anonymous user
221
+ */
222
+ async loadAnonymousHistory(e) {
223
+ try {
224
+ const t = await fetch(
225
+ `${this.apiUrl}/api/chat/conversations/${e}/history/anonymous?product_id=${this.productId}`
226
+ );
227
+ if (!t.ok)
228
+ throw new Error(`HTTP error: ${t.status}`);
229
+ const s = await t.json();
230
+ return this.parseHistoryMessages(s.messages || []);
231
+ } catch (t) {
232
+ return console.error("[Crow] Failed to load anonymous conversation history:", t), [];
233
+ }
234
+ }
235
+ /**
236
+ * Parse history messages from API format
237
+ */
238
+ parseHistoryMessages(e) {
239
+ return e.filter((t) => t.role !== "tool" && !t.content.startsWith("[Client Tool Result:")).map((t, s) => ({
240
+ id: `history-${s}`,
241
+ content: this.parseContent(t.content),
242
+ role: t.role === "assistant" ? "assistant" : "user",
243
+ timestamp: /* @__PURE__ */ new Date()
244
+ }));
245
+ }
246
+ /**
247
+ * Parse structured content (with thinking/text blocks) and extract just text
248
+ */
249
+ parseContent(e) {
250
+ try {
251
+ const t = JSON.parse(e);
252
+ if (Array.isArray(t)) {
253
+ const s = t.find(
254
+ (r) => r.type === "text"
255
+ );
256
+ return (s == null ? void 0 : s.text) || e;
257
+ }
258
+ } catch {
259
+ }
260
+ if (e.includes("'type': 'text'")) {
261
+ const t = e.match(
262
+ /\{'text':\s*'((?:[^'\\]|\\.)*)'\s*,\s*'type':\s*'text'/
263
+ );
264
+ if (t)
265
+ return t[1].replace(/\\n/g, `
266
+ `).replace(/\\'/g, "'");
267
+ }
268
+ return e;
269
+ }
270
+ }
271
+ function M(o) {
272
+ if (o === "[DONE]")
273
+ return { type: "done" };
274
+ try {
275
+ const e = JSON.parse(o);
276
+ switch (e.type) {
277
+ case "verification_status":
278
+ return {
279
+ type: "verification_status",
280
+ isVerified: e.is_verified === !0
281
+ };
282
+ case "conversation_id":
283
+ return {
284
+ type: "conversation_id",
285
+ conversationId: e.conversation_id
286
+ };
287
+ case "thinking":
288
+ return e.status === "complete" ? { type: "thinking_complete" } : null;
289
+ case "thinking_token":
290
+ return {
291
+ type: "thinking",
292
+ content: e.content || ""
293
+ };
294
+ case "content":
295
+ return {
296
+ type: "content",
297
+ text: e.content || "",
298
+ accumulated: ""
299
+ // Will be set by caller
300
+ };
301
+ case "citations":
302
+ return {
303
+ type: "citations",
304
+ citations: e.citations
305
+ };
306
+ case "error":
307
+ return {
308
+ type: "error",
309
+ message: e.message || "Unknown error"
310
+ };
311
+ case "tool_call_start":
312
+ return {
313
+ type: "tool_call_start",
314
+ toolName: e.tool_name,
315
+ displayName: e.display_name || void 0,
316
+ arguments: e.arguments || {}
317
+ };
318
+ case "tool_call_complete":
319
+ return {
320
+ type: "tool_call_complete",
321
+ toolName: e.tool_name,
322
+ displayName: e.display_name || void 0,
323
+ success: e.success
324
+ };
325
+ case "client_tool_call":
326
+ return {
327
+ type: "client_tool_call",
328
+ toolName: e.tool_name,
329
+ displayName: e.display_name || void 0,
330
+ arguments: e.arguments || {}
331
+ };
332
+ case "tool_consent_required":
333
+ return {
334
+ type: "tool_consent_required",
335
+ toolName: e.tool_name,
336
+ displayName: e.display_name || void 0,
337
+ arguments: e.arguments || {}
338
+ };
339
+ case "workflow_started":
340
+ return {
341
+ type: "workflow_started",
342
+ name: e.name,
343
+ todos: e.todos
344
+ };
345
+ case "todo_updated":
346
+ return {
347
+ type: "workflow_todo_updated",
348
+ todoId: e.id,
349
+ status: e.status
350
+ };
351
+ case "workflow_ended":
352
+ return { type: "workflow_ended" };
353
+ case "workflow_complete_prompt":
354
+ return { type: "workflow_complete_prompt" };
355
+ default:
356
+ return null;
357
+ }
358
+ } catch {
359
+ return console.error("[Crow] Failed to parse SSE data:", o), null;
360
+ }
361
+ }
362
+ function* T(o) {
363
+ const e = o.split(`
364
+ `);
365
+ for (const t of e)
366
+ t.startsWith("data: ") && (yield t.slice(6).trim());
367
+ }
368
+ async function* $(o, e) {
369
+ var i;
370
+ const t = (i = o.body) == null ? void 0 : i.getReader();
371
+ if (!t)
372
+ throw new Error("Response body is not readable");
373
+ const s = new TextDecoder();
374
+ let r = "";
375
+ try {
376
+ for (; ; ) {
377
+ if (e != null && e.aborted) {
378
+ t.cancel();
379
+ return;
380
+ }
381
+ const { done: l, value: d } = await t.read();
382
+ if (l) break;
383
+ const h = s.decode(d);
384
+ for (const u of T(h)) {
385
+ const c = M(u);
386
+ if (c && (c.type === "content" ? (r += c.text, yield { ...c, accumulated: r }) : yield c, c.type === "done"))
387
+ return;
388
+ }
389
+ }
390
+ } finally {
391
+ t.releaseLock();
392
+ }
393
+ }
394
+ const E = typeof window < "u" && typeof document < "u";
395
+ async function L() {
396
+ var o;
397
+ try {
398
+ const e = document.title, t = window.location.href, s = window.location.pathname, r = (((o = document.body) == null ? void 0 : o.innerText) || "").slice(0, 2e3).trim();
399
+ return {
400
+ status: "success",
401
+ data: {
402
+ title: e,
403
+ url: t,
404
+ pathname: s,
405
+ visibleText: r
406
+ }
407
+ };
408
+ } catch (e) {
409
+ return {
410
+ status: "error",
411
+ error: e instanceof Error ? e.message : "Failed to read screen"
412
+ };
413
+ }
414
+ }
415
+ const _ = E ? { whatsOnScreen: L } : {}, w = Object.keys(_);
416
+ function x() {
417
+ try {
418
+ const o = "__crow_test__";
419
+ return localStorage.setItem(o, "1"), localStorage.removeItem(o), {
420
+ getItem: (e) => localStorage.getItem(e),
421
+ setItem: (e, t) => localStorage.setItem(e, t),
422
+ removeItem: (e) => localStorage.removeItem(e)
423
+ };
424
+ } catch {
425
+ return k();
426
+ }
427
+ }
428
+ function k() {
429
+ const o = /* @__PURE__ */ new Map();
430
+ return {
431
+ getItem: (e) => o.get(e) ?? null,
432
+ setItem: (e, t) => o.set(e, t),
433
+ removeItem: (e) => o.delete(e)
434
+ };
435
+ }
436
+ const U = "https://api.usecrow.org", R = "claude-sonnet-4-20250514", v = typeof window < "u" && typeof document < "u";
437
+ function N(o) {
438
+ return o.storage ? o.storage : v ? x() : k();
439
+ }
440
+ function O(o) {
441
+ return o.streamReader ? o.streamReader : $;
442
+ }
443
+ class A {
444
+ constructor(e) {
445
+ this.context = {}, this.abortController = null, this.callbacks = {}, this._messages = [], this.messageListeners = /* @__PURE__ */ new Set(), this._isLoading = !1, this.loadingListeners = /* @__PURE__ */ new Set(), this.config = {
446
+ productId: e.productId,
447
+ apiUrl: e.apiUrl || U,
448
+ model: e.model || R,
449
+ subdomain: e.subdomain
450
+ };
451
+ const t = N(e);
452
+ this.readStream = O(e), this.identity = new I(), this.tools = new C(), this.conversations = new S(
453
+ this.config.productId,
454
+ this.config.apiUrl,
455
+ t
456
+ ), (e.enableBrowserTools ?? (v && w.length > 0)) && (this.tools.register(_), console.log("[Crow] Default tools registered:", w.join(", "))), this.identity.subscribe((r) => {
457
+ var i, l;
458
+ (l = (i = this.callbacks).onVerificationStatus) == null || l.call(i, r.isVerified);
459
+ });
460
+ }
461
+ // ============================================================================
462
+ // Configuration
463
+ // ============================================================================
464
+ /**
465
+ * Get current product ID
466
+ */
467
+ get productId() {
468
+ return this.config.productId;
469
+ }
470
+ /**
471
+ * Get current API URL
472
+ */
473
+ get apiUrl() {
474
+ return this.config.apiUrl;
475
+ }
476
+ /**
477
+ * Get/set current model
478
+ */
479
+ get model() {
480
+ return this.config.model;
481
+ }
482
+ set model(e) {
483
+ this.config.model = e;
484
+ }
485
+ // ============================================================================
486
+ // Event Callbacks
487
+ // ============================================================================
488
+ /**
489
+ * Register event callbacks
490
+ */
491
+ on(e) {
492
+ this.callbacks = { ...this.callbacks, ...e };
493
+ }
494
+ // ============================================================================
495
+ // Identity
496
+ // ============================================================================
497
+ /**
498
+ * Identify the current user with a JWT token
499
+ */
500
+ identify(e) {
501
+ this.identity.identify(e);
502
+ }
503
+ /**
504
+ * Reset user identity (call on logout)
505
+ */
506
+ resetUser() {
507
+ this.identity.reset(), this.clearMessages();
508
+ }
509
+ /**
510
+ * Check if user is identified
511
+ */
512
+ isIdentified() {
513
+ return this.identity.isIdentified();
514
+ }
515
+ /**
516
+ * Check if user is verified by server
517
+ */
518
+ isVerified() {
519
+ return this.identity.isVerified();
520
+ }
521
+ // ============================================================================
522
+ // Tools
523
+ // ============================================================================
524
+ /**
525
+ * Register client-side tool handlers
526
+ */
527
+ registerTools(e) {
528
+ this.tools.register(e);
529
+ }
530
+ /**
531
+ * Unregister a tool handler
532
+ */
533
+ unregisterTool(e) {
534
+ this.tools.unregister(e);
535
+ }
536
+ /**
537
+ * Get list of registered tool names
538
+ */
539
+ getRegisteredTools() {
540
+ return this.tools.getRegisteredTools();
541
+ }
542
+ // ============================================================================
543
+ // Context
544
+ // ============================================================================
545
+ /**
546
+ * Set context data to be sent with messages
547
+ */
548
+ setContext(e) {
549
+ this.context = { ...this.context, ...e };
550
+ }
551
+ /**
552
+ * Clear context data
553
+ */
554
+ clearContext() {
555
+ this.context = {};
556
+ }
557
+ // ============================================================================
558
+ // Messages
559
+ // ============================================================================
560
+ /**
561
+ * Get current messages
562
+ */
563
+ get messages() {
564
+ return [...this._messages];
565
+ }
566
+ /**
567
+ * Check if currently loading/streaming
568
+ */
569
+ get isLoading() {
570
+ return this._isLoading;
571
+ }
572
+ /**
573
+ * Subscribe to message changes
574
+ */
575
+ onMessages(e) {
576
+ return this.messageListeners.add(e), () => this.messageListeners.delete(e);
577
+ }
578
+ /**
579
+ * Subscribe to loading state changes
580
+ */
581
+ onLoading(e) {
582
+ return this.loadingListeners.add(e), () => this.loadingListeners.delete(e);
583
+ }
584
+ /**
585
+ * Clear all messages and start new conversation
586
+ */
587
+ clearMessages() {
588
+ this._messages = [], this.conversations.clear(), this.notifyMessages();
589
+ }
590
+ /**
591
+ * Load messages from history
592
+ */
593
+ loadMessages(e) {
594
+ this._messages = e, this.notifyMessages();
595
+ }
596
+ notifyMessages() {
597
+ const e = this.messages;
598
+ for (const t of this.messageListeners)
599
+ t(e);
600
+ }
601
+ setLoading(e) {
602
+ this._isLoading = e;
603
+ for (const t of this.loadingListeners)
604
+ t(e);
605
+ }
606
+ addMessage(e) {
607
+ var t, s;
608
+ this._messages = [...this._messages, e], this.notifyMessages(), (s = (t = this.callbacks).onMessage) == null || s.call(t, e);
609
+ }
610
+ updateMessage(e, t) {
611
+ var s, r;
612
+ this._messages = this._messages.map(
613
+ (i) => i.id === e ? { ...i, ...t } : i
614
+ ), this.notifyMessages(), (r = (s = this.callbacks).onMessageUpdate) == null || r.call(s, e, t);
615
+ }
616
+ generateMessageId(e) {
617
+ return `${e}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
618
+ }
619
+ // ============================================================================
620
+ // Conversations
621
+ // ============================================================================
622
+ /**
623
+ * Get current conversation ID
624
+ */
625
+ get conversationId() {
626
+ return this.conversations.getCurrentId();
627
+ }
628
+ /**
629
+ * Set current conversation ID
630
+ */
631
+ set conversationId(e) {
632
+ this.conversations.setCurrentId(e);
633
+ }
634
+ /**
635
+ * Get list of conversations for verified user
636
+ */
637
+ async getConversations() {
638
+ const e = this.identity.getToken();
639
+ return e ? this.conversations.getConversations(e) : (console.warn("[Crow] Cannot get conversations: user not identified"), []);
640
+ }
641
+ /**
642
+ * Load conversation history
643
+ */
644
+ async loadHistory(e) {
645
+ const t = this.identity.getToken();
646
+ return t ? this.conversations.loadHistory(e, t) : this.conversations.loadAnonymousHistory(e);
647
+ }
648
+ /**
649
+ * Switch to a different conversation
650
+ */
651
+ async switchConversation(e) {
652
+ const t = await this.loadHistory(e);
653
+ this.conversations.setCurrentId(e), this.loadMessages(t);
654
+ }
655
+ // ============================================================================
656
+ // Messaging
657
+ // ============================================================================
658
+ /**
659
+ * Send a message and receive streaming response
660
+ * Returns an async generator of stream events
661
+ */
662
+ async *sendMessage(e) {
663
+ var l, d, h, u, c, g, f, m, p, y;
664
+ if (!e.trim())
665
+ return;
666
+ const t = this.generateMessageId("user");
667
+ this.addMessage({
668
+ id: t,
669
+ content: e,
670
+ role: "user",
671
+ timestamp: /* @__PURE__ */ new Date()
672
+ });
673
+ const s = this.generateMessageId("assistant");
674
+ this.addMessage({
675
+ id: s,
676
+ content: "",
677
+ role: "assistant",
678
+ timestamp: /* @__PURE__ */ new Date()
679
+ }), this.setLoading(!0), this.abortController = new AbortController();
680
+ let r = "", i = "";
681
+ try {
682
+ const a = await fetch(`${this.config.apiUrl}/api/chat/message`, {
683
+ method: "POST",
684
+ headers: { "Content-Type": "application/json" },
685
+ body: JSON.stringify({
686
+ product_id: this.config.productId,
687
+ message: e,
688
+ conversation_id: this.conversations.getCurrentId(),
689
+ identity_token: this.identity.getToken(),
690
+ model: this.config.model,
691
+ subdomain: this.config.subdomain,
692
+ context: Object.keys(this.context).length > 0 ? this.context : void 0
693
+ }),
694
+ signal: this.abortController.signal
695
+ });
696
+ if (!a.ok)
697
+ throw new Error(`HTTP error: ${a.status}`);
698
+ for await (const n of this.readStream(a, this.abortController.signal)) {
699
+ switch (n.type) {
700
+ case "content":
701
+ r = n.accumulated, this.updateMessage(s, { content: r });
702
+ break;
703
+ case "thinking":
704
+ i += n.content, this.updateMessage(s, { thinking: i });
705
+ break;
706
+ case "thinking_complete":
707
+ this.updateMessage(s, { thinkingComplete: !0 });
708
+ break;
709
+ case "citations":
710
+ this.updateMessage(s, { citations: n.citations });
711
+ break;
712
+ case "verification_status":
713
+ this.identity.setVerified(n.isVerified);
714
+ break;
715
+ case "conversation_id":
716
+ this.conversations.setCurrentId(n.conversationId);
717
+ break;
718
+ case "client_tool_call":
719
+ await this.tools.execute(n.toolName, n.arguments), (d = (l = this.callbacks).onToolCall) == null || d.call(l, n);
720
+ break;
721
+ case "tool_call_start":
722
+ case "tool_call_complete":
723
+ (u = (h = this.callbacks).onToolCall) == null || u.call(h, n);
724
+ break;
725
+ case "workflow_started":
726
+ case "workflow_todo_updated":
727
+ case "workflow_ended":
728
+ case "workflow_complete_prompt":
729
+ (g = (c = this.callbacks).onWorkflow) == null || g.call(c, n);
730
+ break;
731
+ case "error":
732
+ this.updateMessage(s, { content: n.message }), (m = (f = this.callbacks).onError) == null || m.call(f, new Error(n.message));
733
+ break;
734
+ }
735
+ yield n;
736
+ }
737
+ } catch (a) {
738
+ if (a instanceof Error && a.name === "AbortError") {
739
+ r ? this.updateMessage(s, { content: r }) : (this._messages = this._messages.filter((n) => n.id !== s), this.notifyMessages());
740
+ return;
741
+ }
742
+ console.error("[Crow] Error:", a), this.updateMessage(s, {
743
+ content: "Sorry, I encountered an error. Please try again."
744
+ }), (y = (p = this.callbacks).onError) == null || y.call(p, a instanceof Error ? a : new Error(String(a)));
745
+ } finally {
746
+ this.setLoading(!1), this.abortController = null;
747
+ }
748
+ }
749
+ /**
750
+ * Send a message and wait for complete response (non-streaming)
751
+ */
752
+ async send(e) {
753
+ let t = null;
754
+ for await (const r of this.sendMessage(e))
755
+ if (r.type === "done")
756
+ break;
757
+ const s = this.messages;
758
+ return s.length > 0 && (t = s[s.length - 1], t.role === "assistant") ? t : null;
759
+ }
760
+ /**
761
+ * Stop current generation
762
+ */
763
+ stop() {
764
+ this.abortController && (this.abortController.abort(), this.setLoading(!1));
765
+ }
766
+ // ============================================================================
767
+ // Cleanup
768
+ // ============================================================================
769
+ /**
770
+ * Destroy the client and clean up resources
771
+ */
772
+ destroy() {
773
+ this.stop(), this.messageListeners.clear(), this.loadingListeners.clear();
774
+ }
775
+ }
776
+ export {
777
+ S as ConversationManager,
778
+ A as CrowClient,
779
+ _ as DEFAULT_TOOLS,
780
+ w as DEFAULT_TOOL_NAMES,
781
+ I as IdentityManager,
782
+ C as ToolManager,
783
+ x as createLocalStorageAdapter,
784
+ k as createMemoryStorageAdapter,
785
+ T as parseSSEChunk,
786
+ M as parseSSEData,
787
+ $ as streamResponse
788
+ };