@floegence/floe-webapp-core 0.27.3 → 0.27.5

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.
@@ -6,6 +6,7 @@ export interface ChatContextValue {
6
6
  isLoadingHistory: Accessor<boolean>;
7
7
  hasMoreHistory: Accessor<boolean>;
8
8
  streamingMessageId: Accessor<string | null>;
9
+ isPreparing: Accessor<boolean>;
9
10
  isWorking: Accessor<boolean>;
10
11
  config: Accessor<ChatConfig>;
11
12
  virtualListConfig: Accessor<VirtualListConfig>;
@@ -1,60 +1,79 @@
1
- import { createComponent as N } from "solid-js/web";
2
- import { createMemo as x, createEffect as _, on as O, createSignal as I, useContext as V, createContext as G, batch as H } from "solid-js";
3
- import { createStore as W, reconcile as S, produce as y } from "solid-js/store";
4
- import { deferNonBlocking as m } from "../../utils/defer.js";
5
- import { DEFAULT_VIRTUAL_LIST_CONFIG as J } from "./types.js";
6
- const L = G();
7
- function de() {
8
- const r = V(L);
9
- if (!r)
1
+ import { createComponent as X } from "solid-js/web";
2
+ import { createMemo as b, createEffect as Y, on as Z, createSignal as C, useContext as $, createContext as ee, batch as E } from "solid-js";
3
+ import { createStore as te, reconcile as v, produce as M } from "solid-js/store";
4
+ import { deferNonBlocking as p } from "../../utils/defer.js";
5
+ import { DEFAULT_VIRTUAL_LIST_CONFIG as se } from "./types.js";
6
+ const F = ee();
7
+ function Ce() {
8
+ const o = $(F);
9
+ if (!o)
10
10
  throw new Error("useChatContext must be used within a ChatProvider");
11
- return r;
11
+ return o;
12
12
  }
13
- const ge = (r) => {
14
- const k = x(() => ({
13
+ const Me = (o) => {
14
+ const S = b(() => ({
15
15
  placeholder: "Type a message...",
16
16
  allowAttachments: !0,
17
17
  maxAttachments: 10,
18
18
  maxAttachmentSize: 10485760,
19
19
  // 10MB
20
- ...r.config
21
- })), i = x(() => ({
22
- ...J,
23
- ...r.config?.virtualList
24
- })), [c, u] = W(r.initialMessages || []), U = /* @__PURE__ */ new Map();
25
- _(O(() => r.initialMessages, (e) => {
26
- e && e.length > 0 && u(S(e));
20
+ ...o.config
21
+ })), d = b(() => ({
22
+ ...se,
23
+ ...o.config?.virtualList
24
+ })), [c, u] = te(o.initialMessages || []), z = /* @__PURE__ */ new Map();
25
+ Y(Z(() => o.initialMessages, (e) => {
26
+ e && e.length > 0 && u(v(e));
27
27
  }, {
28
28
  defer: !0
29
29
  }));
30
- const [w, A] = I(!1), [T, E] = I(!0), [v, b] = I(null), g = /* @__PURE__ */ new Map(), F = x(() => v() !== null), h = (e) => {
31
- u(y((t) => {
30
+ const [A, H] = C(!1), [P, R] = C(!0), [L, x] = C(null), [B, I] = C(0);
31
+ let D = 0;
32
+ const g = /* @__PURE__ */ new Set(), h = [], f = /* @__PURE__ */ new Map(), O = (e) => {
33
+ if (!g.delete(e)) return;
34
+ const t = h.indexOf(e);
35
+ t >= 0 && h.splice(t, 1), I(g.size);
36
+ }, j = () => {
37
+ const e = ++D;
38
+ return g.add(e), h.push(e), I(g.size), e;
39
+ }, q = () => {
40
+ for (; h.length > 0; ) {
41
+ const e = h.shift();
42
+ if (e === void 0) return;
43
+ if (g.has(e)) {
44
+ g.delete(e), I(g.size);
45
+ return;
46
+ }
47
+ }
48
+ }, U = b(() => B() > 0), N = b(() => U() || L() !== null), k = (e) => {
49
+ u(M((t) => {
32
50
  t.push(e);
33
51
  }));
34
52
  }, l = (e, t) => {
35
- u(y((s) => {
36
- const o = s.findIndex((n) => n.id === e);
37
- o !== -1 && (s[o] = t(s[o]));
53
+ u(M((s) => {
54
+ const n = s.findIndex((a) => a.id === e);
55
+ n !== -1 && (s[n] = t(s[n]));
38
56
  }));
39
- }, P = (e) => {
40
- u(y((t) => {
41
- const s = t.findIndex((o) => o.id === e);
57
+ }, W = (e) => {
58
+ u(M((t) => {
59
+ const s = t.findIndex((n) => n.id === e);
42
60
  s !== -1 && t.splice(s, 1);
43
- })), g.delete(e);
44
- }, R = () => {
45
- u(S([])), g.clear();
46
- }, B = (e) => {
47
- u(S(e));
61
+ })), f.delete(e);
62
+ }, _ = () => {
63
+ u(v([])), f.clear();
64
+ }, V = (e) => {
65
+ u(v(e));
48
66
  };
49
- let M = [], C = null;
50
- const z = () => {
51
- const e = M;
52
- M = [], C = null, H(() => {
53
- e.forEach(D);
67
+ let T = [], w = null;
68
+ const G = () => {
69
+ const e = T;
70
+ T = [], w = null, E(() => {
71
+ e.forEach(Q);
54
72
  });
55
- }, D = (e) => {
73
+ }, Q = (e) => {
56
74
  switch (e.type) {
57
75
  case "message-start": {
76
+ q();
58
77
  const t = {
59
78
  id: e.messageId,
60
79
  role: "assistant",
@@ -62,20 +81,20 @@ const ge = (r) => {
62
81
  status: "streaming",
63
82
  timestamp: Date.now()
64
83
  };
65
- h(t), b(e.messageId);
84
+ k(t), x(e.messageId);
66
85
  break;
67
86
  }
68
87
  case "block-start": {
69
88
  l(e.messageId, (t) => ({
70
89
  ...t,
71
- blocks: [...t.blocks, K(e.blockType)]
90
+ blocks: [...t.blocks, ne(e.blockType)]
72
91
  }));
73
92
  break;
74
93
  }
75
94
  case "block-delta": {
76
95
  l(e.messageId, (t) => {
77
- const s = [...t.blocks], o = s[e.blockIndex];
78
- return o && "content" in o && typeof o.content == "string" && (o.content += e.delta), {
96
+ const s = [...t.blocks], n = s[e.blockIndex];
97
+ return n && "content" in n && typeof n.content == "string" && (n.content += e.delta), {
79
98
  ...t,
80
99
  blocks: s
81
100
  };
@@ -98,7 +117,7 @@ const ge = (r) => {
98
117
  l(e.messageId, (t) => ({
99
118
  ...t,
100
119
  status: "complete"
101
- })), b(null);
120
+ })), x(null);
102
121
  break;
103
122
  }
104
123
  case "error": {
@@ -106,64 +125,72 @@ const ge = (r) => {
106
125
  ...t,
107
126
  status: "error",
108
127
  error: e.error
109
- })), b(null);
128
+ })), x(null);
110
129
  break;
111
130
  }
112
131
  }
113
- }, j = {
132
+ }, J = {
114
133
  messages: () => c,
115
- coldMessages: U,
116
- isLoadingHistory: w,
117
- hasMoreHistory: T,
118
- streamingMessageId: v,
119
- isWorking: F,
120
- config: k,
121
- virtualListConfig: i,
134
+ coldMessages: z,
135
+ isLoadingHistory: A,
136
+ hasMoreHistory: P,
137
+ streamingMessageId: L,
138
+ isPreparing: U,
139
+ isWorking: N,
140
+ config: S,
141
+ virtualListConfig: d,
122
142
  sendMessage: async (e, t = []) => {
123
143
  const s = {
124
144
  id: crypto.randomUUID(),
125
145
  role: "user",
126
- blocks: Q(e, t),
146
+ blocks: oe(e, t),
127
147
  status: "sending",
128
148
  timestamp: Date.now()
129
149
  };
130
- H(() => {
131
- h(s), l(s.id, (d) => ({
132
- ...d,
150
+ E(() => {
151
+ k(s), l(s.id, (i) => ({
152
+ ...i,
133
153
  status: "complete"
134
154
  }));
135
155
  });
136
- const o = r.callbacks?.onSendMessage;
137
- if (!o) return;
138
- const n = e, a = [...t];
139
- m(() => {
140
- Promise.resolve(o(n, a, h)).catch((d) => {
141
- console.error("Failed to send message:", d);
156
+ try {
157
+ o.callbacks?.onWillSend?.(e, t);
158
+ } catch (i) {
159
+ console.error("onWillSend error:", i);
160
+ }
161
+ const n = o.callbacks?.onSendMessage;
162
+ if (!n) return;
163
+ const a = j(), r = e, m = [...t];
164
+ p(() => {
165
+ Promise.resolve().then(() => n(r, m, k)).catch((i) => {
166
+ console.error("Failed to send message:", i);
167
+ }).finally(() => {
168
+ O(a);
142
169
  });
143
170
  });
144
171
  },
145
172
  loadMoreHistory: async () => {
146
- if (w() || !T()) return;
147
- const e = r.callbacks?.onLoadMore;
148
- e && (A(!0), m(() => {
173
+ if (A() || !P()) return;
174
+ const e = o.callbacks?.onLoadMore;
175
+ e && (H(!0), p(() => {
149
176
  Promise.resolve(e()).then((t) => {
150
177
  if (t.length === 0) {
151
- E(!1);
178
+ R(!1);
152
179
  return;
153
180
  }
154
- u(y((s) => {
181
+ u(M((s) => {
155
182
  s.unshift(...t);
156
183
  }));
157
184
  }).catch((t) => {
158
185
  console.error("Failed to load history:", t);
159
186
  }).finally(() => {
160
- A(!1);
187
+ H(!1);
161
188
  });
162
189
  }));
163
190
  },
164
191
  retryMessage: (e) => {
165
- const t = r.callbacks?.onRetry;
166
- t && m(() => {
192
+ const t = o.callbacks?.onRetry;
193
+ t && p(() => {
167
194
  try {
168
195
  t(e);
169
196
  } catch (s) {
@@ -171,97 +198,97 @@ const ge = (r) => {
171
198
  }
172
199
  });
173
200
  },
174
- addMessage: h,
201
+ addMessage: k,
175
202
  updateMessage: l,
176
- deleteMessage: P,
177
- clearMessages: R,
178
- setMessages: B,
203
+ deleteMessage: W,
204
+ clearMessages: _,
205
+ setMessages: V,
179
206
  handleStreamEvent: (e) => {
180
- M.push(e), C || (C = requestAnimationFrame(z));
207
+ T.push(e), w || (w = requestAnimationFrame(G));
181
208
  },
182
209
  uploadAttachment: async (e) => {
183
- const t = r.callbacks?.onUploadAttachment;
210
+ const t = o.callbacks?.onUploadAttachment;
184
211
  return t ? await t(e) : URL.createObjectURL(e);
185
212
  },
186
213
  toggleToolCollapse: (e, t) => {
187
214
  l(e, (s) => ({
188
215
  ...s,
189
- blocks: s.blocks.map((o) => {
190
- if (o.type === "tool-call" && o.toolId === t) {
191
- const n = o.collapsed === void 0 ? !1 : !o.collapsed;
216
+ blocks: s.blocks.map((n) => {
217
+ if (n.type === "tool-call" && n.toolId === t) {
218
+ const a = n.collapsed === void 0 ? !1 : !n.collapsed;
192
219
  return {
193
- ...o,
194
- collapsed: n
220
+ ...n,
221
+ collapsed: a
195
222
  };
196
223
  }
197
- return o;
224
+ return n;
198
225
  })
199
226
  }));
200
227
  },
201
228
  approveToolCall: (e, t, s) => {
202
- l(e, (n) => ({
203
- ...n,
204
- blocks: n.blocks.map((a) => a.type !== "tool-call" || a.toolId !== t || a.requiresApproval !== !0 || a.approvalState !== "required" ? a : s ? {
205
- ...a,
229
+ l(e, (a) => ({
230
+ ...a,
231
+ blocks: a.blocks.map((r) => r.type !== "tool-call" || r.toolId !== t || r.requiresApproval !== !0 || r.approvalState !== "required" ? r : s ? {
232
+ ...r,
206
233
  approvalState: "approved",
207
234
  status: "running"
208
235
  } : {
209
- ...a,
236
+ ...r,
210
237
  approvalState: "rejected",
211
238
  status: "error",
212
- error: a.error || "Rejected by user"
239
+ error: r.error || "Rejected by user"
213
240
  })
214
241
  }));
215
- const o = r.callbacks?.onToolApproval;
216
- o && m(() => {
217
- Promise.resolve(o(e, t, s)).catch((n) => {
218
- console.error("Failed to approve tool call:", n);
242
+ const n = o.callbacks?.onToolApproval;
243
+ n && p(() => {
244
+ Promise.resolve(n(e, t, s)).catch((a) => {
245
+ console.error("Failed to approve tool call:", a);
219
246
  });
220
247
  });
221
248
  },
222
- heightCache: g,
249
+ heightCache: f,
223
250
  setMessageHeight: (e, t) => {
224
- g.set(e, t);
251
+ f.set(e, t);
225
252
  },
226
- getMessageHeight: (e) => g.get(e) || i().defaultItemHeight,
253
+ getMessageHeight: (e) => f.get(e) || d().defaultItemHeight,
227
254
  toggleChecklistItem: (e, t, s) => {
228
- let o = null;
229
- l(e, (a) => {
230
- const d = [...a.blocks], f = d[t];
231
- if (f && f.type === "checklist") {
232
- const q = f.items.map((p) => p.id === s ? (o = !p.checked, {
233
- ...p,
234
- checked: o
235
- }) : p);
236
- d[t] = {
237
- ...f,
238
- items: q
255
+ let n = null;
256
+ l(e, (r) => {
257
+ const m = [...r.blocks], i = m[t];
258
+ if (i && i.type === "checklist") {
259
+ const K = i.items.map((y) => y.id === s ? (n = !y.checked, {
260
+ ...y,
261
+ checked: n
262
+ }) : y);
263
+ m[t] = {
264
+ ...i,
265
+ items: K
239
266
  };
240
267
  }
241
268
  return {
242
- ...a,
243
- blocks: d
269
+ ...r,
270
+ blocks: m
244
271
  };
245
272
  });
246
- const n = r.callbacks?.onChecklistChange;
247
- !n || o === null || m(() => {
273
+ const a = o.callbacks?.onChecklistChange;
274
+ !a || n === null || p(() => {
248
275
  try {
249
- n(e, t, s, o);
250
- } catch (a) {
251
- console.error("Failed to handle checklist change:", a);
276
+ a(e, t, s, n);
277
+ } catch (r) {
278
+ console.error("Failed to handle checklist change:", r);
252
279
  }
253
280
  });
254
281
  }
255
282
  };
256
- return N(L.Provider, {
257
- value: j,
283
+ return X(F.Provider, {
284
+ value: J,
258
285
  get children() {
259
- return r.children;
286
+ return o.children;
260
287
  }
261
288
  });
262
289
  };
263
- function K(r) {
264
- switch (r) {
290
+ function ne(o) {
291
+ switch (o) {
265
292
  case "text":
266
293
  return {
267
294
  type: "text",
@@ -337,26 +364,26 @@ function K(r) {
337
364
  };
338
365
  }
339
366
  }
340
- function Q(r, k) {
341
- const i = [];
342
- for (const c of k)
343
- c.type === "image" ? i.push({
367
+ function oe(o, S) {
368
+ const d = [];
369
+ for (const c of S)
370
+ c.type === "image" ? d.push({
344
371
  type: "image",
345
372
  src: c.url || c.preview || "",
346
373
  alt: c.file.name
347
- }) : i.push({
374
+ }) : d.push({
348
375
  type: "file",
349
376
  name: c.file.name,
350
377
  size: c.file.size,
351
378
  mimeType: c.file.type,
352
379
  url: c.url
353
380
  });
354
- return r.trim() && i.push({
381
+ return o.trim() && d.push({
355
382
  type: "text",
356
- content: r.trim()
357
- }), i;
383
+ content: o.trim()
384
+ }), d;
358
385
  }
359
386
  export {
360
- ge as ChatProvider,
361
- de as useChatContext
387
+ Me as ChatProvider,
388
+ Ce as useChatContext
362
389
  };
@@ -159,6 +159,7 @@ export interface ChatConfig {
159
159
  maxAttachments?: number;
160
160
  }
161
161
  export interface ChatCallbacks {
162
+ onWillSend?: (content: string, attachments: Attachment[]) => void;
162
163
  onSendMessage?: (content: string, attachments: Attachment[], addMessage: (msg: Message) => void) => Promise<void>;
163
164
  onLoadMore?: () => Promise<Message[]>;
164
165
  onRetry?: (messageId: string) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floegence/floe-webapp-core",
3
- "version": "0.27.3",
3
+ "version": "0.27.5",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",