@vinaverse/react-native 0.0.0-stage → 0.1.0-alpha.11

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.
Files changed (57) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +326 -2
  3. package/dist/ask.cjs +62 -0
  4. package/dist/ask.cjs.map +1 -0
  5. package/dist/ask.d.cts +38 -0
  6. package/dist/ask.d.ts +38 -0
  7. package/dist/ask.js +5 -0
  8. package/dist/ask.js.map +1 -0
  9. package/dist/chat.cjs +274 -0
  10. package/dist/chat.cjs.map +1 -0
  11. package/dist/chat.d.cts +292 -0
  12. package/dist/chat.d.ts +292 -0
  13. package/dist/chat.js +5 -0
  14. package/dist/chat.js.map +1 -0
  15. package/dist/chunk-2J2LIJLW.js +624 -0
  16. package/dist/chunk-2J2LIJLW.js.map +1 -0
  17. package/dist/chunk-4PXQ7DEY.cjs +680 -0
  18. package/dist/chunk-4PXQ7DEY.cjs.map +1 -0
  19. package/dist/chunk-6QYDPGRS.cjs +97 -0
  20. package/dist/chunk-6QYDPGRS.cjs.map +1 -0
  21. package/dist/chunk-7KPCO443.js +74 -0
  22. package/dist/chunk-7KPCO443.js.map +1 -0
  23. package/dist/chunk-EFEXTVIT.js +88 -0
  24. package/dist/chunk-EFEXTVIT.js.map +1 -0
  25. package/dist/chunk-KSHDF3MG.js +1996 -0
  26. package/dist/chunk-KSHDF3MG.js.map +1 -0
  27. package/dist/chunk-MG32E4JI.cjs +268 -0
  28. package/dist/chunk-MG32E4JI.cjs.map +1 -0
  29. package/dist/chunk-NMKJ7LIJ.cjs +76 -0
  30. package/dist/chunk-NMKJ7LIJ.cjs.map +1 -0
  31. package/dist/chunk-POJP52GE.js +261 -0
  32. package/dist/chunk-POJP52GE.js.map +1 -0
  33. package/dist/chunk-XAG2P447.cjs +2035 -0
  34. package/dist/chunk-XAG2P447.cjs.map +1 -0
  35. package/dist/context-gHCLFsJh.d.cts +212 -0
  36. package/dist/context-gHCLFsJh.d.ts +212 -0
  37. package/dist/history.cjs +673 -0
  38. package/dist/history.cjs.map +1 -0
  39. package/dist/history.d.cts +177 -0
  40. package/dist/history.d.ts +177 -0
  41. package/dist/history.js +618 -0
  42. package/dist/history.js.map +1 -0
  43. package/dist/index.cjs +304 -0
  44. package/dist/index.cjs.map +1 -0
  45. package/dist/index.d.cts +12 -0
  46. package/dist/index.d.ts +12 -0
  47. package/dist/index.js +7 -0
  48. package/dist/index.js.map +1 -0
  49. package/dist/launcher.cjs +86 -0
  50. package/dist/launcher.cjs.map +1 -0
  51. package/dist/launcher.d.cts +122 -0
  52. package/dist/launcher.d.ts +122 -0
  53. package/dist/launcher.js +5 -0
  54. package/dist/launcher.js.map +1 -0
  55. package/dist/theme-BhiEGv64.d.cts +35 -0
  56. package/dist/theme-BhiEGv64.d.ts +35 -0
  57. package/package.json +311 -3
@@ -0,0 +1,624 @@
1
+ import { Button, useChat, FailureSlot, FailureActionButton, ChatContextProvider, ChatHeader, DisclosureBar, MessageList } from './chunk-KSHDF3MG.js';
2
+ import { useTheme, useNativeLifecycle, themeProblems, ThemeProvider, useAgentSweep } from './chunk-EFEXTVIT.js';
3
+ import { useAgentRuntime, useAgentConversation, useAgentName } from '@vinaverse/react/agent';
4
+ export { AgentRuntimeProvider, forgetGreeting, greetedKey, useAgentConversation, useAgentFeatures, useAgentLauncher, useAgentName, useAgentProfile, useAgentRuntime, useAgentStatus, useAgentStatusState } from '@vinaverse/react/agent';
5
+ import { useCopy, useConversationSelector, bannedWordsIn, CopyProvider } from '@vinaverse/react';
6
+ import { useState, memo, useCallback, useMemo, useEffect, useRef } from 'react';
7
+ import { View, TextInput, Text, Platform, KeyboardAvoidingView } from 'react-native';
8
+ import { codePoints, MAX_TEXT } from '@vinaverse/client/conversation';
9
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
10
+ import { motion } from '@vinaverse/tokens';
11
+
12
+ function DefaultComposer(props) {
13
+ const { t, direction } = useCopy();
14
+ const { colors, radius, space, font, size } = useTheme();
15
+ const [text, setText] = useState("");
16
+ const length = codePoints(text);
17
+ const canSend = text.trim().length > 0 && length <= MAX_TEXT;
18
+ const send = () => {
19
+ if (!canSend) return;
20
+ props.onSend(text);
21
+ setText("");
22
+ };
23
+ return /* @__PURE__ */ jsxs(
24
+ View,
25
+ {
26
+ style: {
27
+ flexDirection: "row",
28
+ alignItems: "flex-end",
29
+ gap: space.sm,
30
+ paddingHorizontal: space.lg,
31
+ paddingVertical: space.sm,
32
+ borderTopWidth: 1,
33
+ borderTopColor: colors.divider,
34
+ backgroundColor: colors.background
35
+ },
36
+ children: [
37
+ /* @__PURE__ */ jsx(
38
+ TextInput,
39
+ {
40
+ value: text,
41
+ onChangeText: setText,
42
+ placeholder: props.placeholder,
43
+ placeholderTextColor: colors.textMuted,
44
+ accessibilityLabel: props.placeholder,
45
+ multiline: true,
46
+ maxLength: MAX_TEXT * 2,
47
+ testID: "vinaverse-composer-input",
48
+ style: {
49
+ flex: 1,
50
+ minHeight: size.touchTarget,
51
+ maxHeight: 140,
52
+ paddingHorizontal: space.md,
53
+ paddingVertical: space.sm,
54
+ borderRadius: radius.lg,
55
+ borderWidth: 1,
56
+ borderColor: colors.border,
57
+ color: colors.text,
58
+ backgroundColor: colors.surface,
59
+ fontSize: font.size.md,
60
+ textAlign: direction === "rtl" ? "right" : "left",
61
+ writingDirection: direction,
62
+ ...font.family ? { fontFamily: font.family } : {}
63
+ }
64
+ }
65
+ ),
66
+ props.responding && !text ? /* @__PURE__ */ jsx(
67
+ Button,
68
+ {
69
+ label: t("stop"),
70
+ onPress: props.onStop,
71
+ testID: "vinaverse-stop"
72
+ }
73
+ ) : /* @__PURE__ */ jsx(
74
+ Button,
75
+ {
76
+ label: t("send"),
77
+ variant: "primary",
78
+ disabled: !canSend,
79
+ onPress: send,
80
+ testID: "vinaverse-send"
81
+ }
82
+ )
83
+ ]
84
+ }
85
+ );
86
+ }
87
+ var Composer = /* @__PURE__ */ memo(function Composer2(props) {
88
+ const { store, slots } = useChat();
89
+ const { t } = useCopy();
90
+ const takeover = useConversationSelector(store, (v) => v.takeover);
91
+ const name = useConversationSelector(store, (v) => v.agent.name);
92
+ const responding = useConversationSelector(store, (v) => v.responding);
93
+ const { onError } = props;
94
+ const onSend = useCallback(
95
+ (text) => {
96
+ try {
97
+ store.send(text);
98
+ } catch (error) {
99
+ onError?.(error);
100
+ }
101
+ },
102
+ [store, onError]
103
+ );
104
+ const onStop = useCallback(() => store.cancel(), [store]);
105
+ const placeholder = takeover ? t("composerPlaceholderTakeover", {
106
+ by: takeover.by || t("staffFallbackRole")
107
+ }) : t("composerPlaceholder", { agent: name ?? t("agentFallbackName") });
108
+ const Slot = slots.Composer;
109
+ const own = { placeholder, responding, onSend, onStop };
110
+ return Slot ? /* @__PURE__ */ jsx(Slot, { ...own, Default: DefaultComposer }) : /* @__PURE__ */ jsx(DefaultComposer, { ...own });
111
+ });
112
+ var CONNECTING_DELAY = motion.bannerDelay;
113
+ var StatusBanner = /* @__PURE__ */ memo(function StatusBanner2() {
114
+ const { store, slots } = useChat();
115
+ const { t } = useCopy();
116
+ const banner = useConversationSelector(store, (v) => v.banner);
117
+ const status = useConversationSelector(store, (v) => v.status);
118
+ const conversationId = useConversationSelector(
119
+ store,
120
+ (v) => v.conversationId
121
+ );
122
+ const unavailable = useMemo(
123
+ () => ({
124
+ kind: "unavailable",
125
+ reason: status,
126
+ retry: () => store.start(),
127
+ conversationId
128
+ }),
129
+ [store, status, conversationId]
130
+ );
131
+ const [late, setLate] = useState(false);
132
+ useEffect(() => {
133
+ setLate(false);
134
+ if (banner !== "connecting") return;
135
+ const timer = setTimeout(() => setLate(true), CONNECTING_DELAY);
136
+ return () => clearTimeout(timer);
137
+ }, [banner]);
138
+ if (banner === null || banner === "connecting" && !late) return null;
139
+ if (banner === "unavailable")
140
+ return /* @__PURE__ */ jsx(
141
+ FailureSlot,
142
+ {
143
+ slot: slots.Unavailable,
144
+ state: unavailable,
145
+ Default: DefaultUnavailable
146
+ }
147
+ );
148
+ const text = {
149
+ connecting: t("bannerConnecting"),
150
+ reconnecting: t("bannerReconnecting"),
151
+ offline: t("bannerOffline"),
152
+ continued_elsewhere: t("bannerContinuedElsewhere")
153
+ }[banner];
154
+ const action = banner === "continued_elsewhere" ? /* @__PURE__ */ jsx(
155
+ Button,
156
+ {
157
+ label: t("continueHere"),
158
+ variant: "text",
159
+ onPress: () => void store.continueHere()
160
+ }
161
+ ) : banner === "offline" ? /* @__PURE__ */ jsx(
162
+ Button,
163
+ {
164
+ label: t("tryAgain"),
165
+ variant: "text",
166
+ onPress: () => store.start()
167
+ }
168
+ ) : null;
169
+ return /* @__PURE__ */ jsx(Banner, { text, children: action });
170
+ });
171
+ function DefaultUnavailable(props) {
172
+ const { t } = useCopy();
173
+ const { retry } = props.state;
174
+ return /* @__PURE__ */ jsxs(Banner, { text: t("bannerUnavailable"), children: [
175
+ retry ? /* @__PURE__ */ jsx(Button, { label: t("tryAgain"), variant: "text", onPress: retry }) : null,
176
+ /* @__PURE__ */ jsx(FailureActionButton, { state: props.state })
177
+ ] });
178
+ }
179
+ function Banner(props) {
180
+ const { colors, space, font } = useTheme();
181
+ return /* @__PURE__ */ jsxs(
182
+ View,
183
+ {
184
+ accessibilityLiveRegion: "polite",
185
+ accessibilityRole: "alert",
186
+ style: {
187
+ flexDirection: "row",
188
+ alignItems: "center",
189
+ justifyContent: "space-between",
190
+ gap: space.sm,
191
+ paddingHorizontal: space.lg,
192
+ paddingVertical: space.xs,
193
+ backgroundColor: colors.surface,
194
+ borderBottomWidth: 1,
195
+ borderBottomColor: colors.divider
196
+ },
197
+ children: [
198
+ /* @__PURE__ */ jsx(
199
+ Text,
200
+ {
201
+ style: { color: colors.text, fontSize: font.size.sm, flexShrink: 1 },
202
+ children: props.text
203
+ }
204
+ ),
205
+ props.children
206
+ ]
207
+ }
208
+ );
209
+ }
210
+ function VinaverseChatProvider(props) {
211
+ const {
212
+ conversation,
213
+ components,
214
+ agentAvatar,
215
+ timeZone,
216
+ starters,
217
+ imagePolicy
218
+ } = props;
219
+ const handlers = useRef(props);
220
+ handlers.current = props;
221
+ const slots = useStableSlots(components);
222
+ const hasAction = props.failureAction !== void 0;
223
+ const actionLabel = props.failureAction?.label;
224
+ const failureAction = useMemo(
225
+ () => hasAction ? { label: actionLabel } : null,
226
+ [hasAction, actionLabel]
227
+ );
228
+ const value = useMemo(
229
+ () => ({
230
+ store: conversation,
231
+ handlers,
232
+ slots,
233
+ agentAvatar,
234
+ timeZone,
235
+ failureAction,
236
+ starters,
237
+ imagePolicy
238
+ }),
239
+ [
240
+ conversation,
241
+ slots,
242
+ agentAvatar,
243
+ timeZone,
244
+ failureAction,
245
+ starters,
246
+ imagePolicy
247
+ ]
248
+ );
249
+ useNativeLifecycle(conversation);
250
+ useEffect(() => {
251
+ conversation.start();
252
+ }, [conversation]);
253
+ const { onWarning, theme, copy } = props;
254
+ useEffect(() => {
255
+ if (!onWarning) return;
256
+ for (const problem of themeProblems(theme))
257
+ onWarning(`Vinaverse theme: ${problem}`, { code: "theme" });
258
+ for (const key of bannedWordsIn(copy ?? {}))
259
+ onWarning(
260
+ `Vinaverse copy: "${key}" says assistant, bot or crew; the copy says agent.`,
261
+ { code: "copy" }
262
+ );
263
+ }, [onWarning, theme, copy]);
264
+ return /* @__PURE__ */ jsx(CopyProvider, { locale: props.locale, copy: props.copy, children: /* @__PURE__ */ jsx(ThemeProvider, { theme: props.theme, colorScheme: props.colorScheme, children: /* @__PURE__ */ jsx(ChatContextProvider, { value, children: props.children }) }) });
265
+ }
266
+ function VinaverseChat(props) {
267
+ return /* @__PURE__ */ jsx(VinaverseChatProvider, { ...props, children: /* @__PURE__ */ jsx(
268
+ Layout,
269
+ {
270
+ hideHeader: props.hideHeader === true,
271
+ keyboardVerticalOffset: props.keyboardVerticalOffset ?? 0,
272
+ keyboardBehavior: props.keyboardBehavior ?? (Platform.OS === "ios" ? "padding" : "none"),
273
+ style: props.style,
274
+ onError: props.onWarning,
275
+ suggestion: props.suggestion ?? null,
276
+ suggestionTestID: props.suggestionTestID ?? "vinaverse-suggestion",
277
+ footer: props.footer
278
+ }
279
+ ) });
280
+ }
281
+ function Layout(props) {
282
+ const { colors } = useTheme();
283
+ const { direction } = useCopy();
284
+ const { onError } = props;
285
+ const reportError = useMemo(
286
+ () => onError ? (e) => onError(String(e), { code: "send_failed" }) : void 0,
287
+ [onError]
288
+ );
289
+ return /* @__PURE__ */ jsxs(
290
+ KeyboardAvoidingView,
291
+ {
292
+ ...props.keyboardBehavior === "none" ? { enabled: false } : { behavior: props.keyboardBehavior },
293
+ keyboardVerticalOffset: props.keyboardVerticalOffset,
294
+ style: [
295
+ { flex: 1, backgroundColor: colors.background, direction },
296
+ props.style
297
+ ],
298
+ children: [
299
+ props.hideHeader ? null : /* @__PURE__ */ jsx(ChatHeader, {}),
300
+ /* @__PURE__ */ jsx(DisclosureBar, {}),
301
+ /* @__PURE__ */ jsx(StatusBanner, {}),
302
+ /* @__PURE__ */ jsx(View, { style: { flex: 1 }, children: /* @__PURE__ */ jsx(MessageList, {}) }),
303
+ props.suggestion ? /* @__PURE__ */ jsx(Suggestion, { chip: props.suggestion, testID: props.suggestionTestID }) : null,
304
+ /* @__PURE__ */ jsx(Composer, { ...reportError ? { onError: reportError } : {} }),
305
+ props.footer
306
+ ]
307
+ }
308
+ );
309
+ }
310
+ function Suggestion(props) {
311
+ const { store, handlers } = useChat();
312
+ const { space } = useTheme();
313
+ return /* @__PURE__ */ jsx(View, { style: { paddingHorizontal: space.lg, alignItems: "flex-start" }, children: /* @__PURE__ */ jsx(
314
+ Button,
315
+ {
316
+ label: props.chip.label,
317
+ testID: props.testID,
318
+ onPress: () => {
319
+ store.send(props.chip.message);
320
+ handlers.current?.onChip?.(props.chip);
321
+ }
322
+ }
323
+ ) });
324
+ }
325
+ function useStableSlots(slots) {
326
+ const held = useRef({});
327
+ const next = slots ?? {};
328
+ if (!sameSlots(held.current, next)) held.current = next;
329
+ return held.current;
330
+ }
331
+ function sameSlots(a, b) {
332
+ const keys = /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)]);
333
+ for (const key of keys) {
334
+ if (key === "cards") {
335
+ const ca = a.cards ?? {};
336
+ const cb = b.cards ?? {};
337
+ const kinds = /* @__PURE__ */ new Set([...Object.keys(ca), ...Object.keys(cb)]);
338
+ for (const kind of kinds) if (ca[kind] !== cb[kind]) return false;
339
+ } else if (a[key] !== b[key]) return false;
340
+ }
341
+ return true;
342
+ }
343
+ function AgentChat(props) {
344
+ const {
345
+ agentKey,
346
+ place,
347
+ entryPoint,
348
+ askAbout,
349
+ onContact,
350
+ onOpenPrivacy,
351
+ components,
352
+ agentName,
353
+ opener,
354
+ openerTestID,
355
+ ...chat
356
+ } = props;
357
+ const runtime = useAgentRuntime();
358
+ useAgentSweep(runtime);
359
+ const { conversation, state, startNew } = useAgentConversation(agentKey, {
360
+ place: place ?? null,
361
+ entryPoint: entryPoint ?? null
362
+ });
363
+ const store = conversation.store;
364
+ const spoke = useConversationSelector(
365
+ store,
366
+ (v) => v.items.some((i) => i.type === "message" && i.role === "person")
367
+ );
368
+ const { Ended, Unreachable, UnavailableScreen, Footer, ...slots } = components ?? {};
369
+ const copy = useMemo(
370
+ () => agentName ? { ...props.copy, agentFallbackName: agentName } : props.copy,
371
+ [agentName, props.copy]
372
+ );
373
+ const events = {
374
+ onOpenTarget: chat.onOpenTarget ? (target, card) => {
375
+ runtime.emit({
376
+ type: "target_opened",
377
+ key: conversation.key,
378
+ cardId: card.id,
379
+ kind: target.type
380
+ });
381
+ chat.onOpenTarget?.(target, card);
382
+ } : void 0,
383
+ onOpenLink: chat.onOpenLink ? (link, card) => {
384
+ runtime.emit({
385
+ type: "link_opened",
386
+ key: conversation.key,
387
+ cardId: card.id,
388
+ kind: card.kind
389
+ });
390
+ chat.onOpenLink?.(link, card);
391
+ } : void 0,
392
+ onChip: (chip) => {
393
+ runtime.emit({ type: "chip_tapped", key: conversation.key });
394
+ chat.onChip?.(chip);
395
+ }
396
+ };
397
+ const shared = {
398
+ ...chat,
399
+ ...events.onOpenTarget ? { onOpenTarget: events.onOpenTarget } : {},
400
+ ...events.onOpenLink ? { onOpenLink: events.onOpenLink } : {},
401
+ onChip: events.onChip,
402
+ ...copy ? { copy } : {},
403
+ ...onContact && !chat.failureAction ? { failureAction: { onPress: () => onContact() } } : {},
404
+ conversation: store,
405
+ components: slots
406
+ };
407
+ if (state.failure === "ended") {
408
+ const own = {
409
+ onStartNew: startNew,
410
+ reason: state.reason,
411
+ code: state.code,
412
+ onContact
413
+ };
414
+ return /* @__PURE__ */ jsx(VinaverseChatProvider, { ...shared, children: /* @__PURE__ */ jsx(Centered, { children: Ended ? /* @__PURE__ */ jsx(Ended, { ...own, Default: DefaultEnded }) : /* @__PURE__ */ jsx(DefaultEnded, { ...own }) }) });
415
+ }
416
+ if (state.failure === "unreachable") {
417
+ const own = {
418
+ onRetry: conversation.retry,
419
+ reason: state.reason,
420
+ onContact
421
+ };
422
+ return /* @__PURE__ */ jsx(VinaverseChatProvider, { ...shared, children: /* @__PURE__ */ jsx(Centered, { children: Unreachable ? /* @__PURE__ */ jsx(Unreachable, { ...own, Default: DefaultUnreachable }) : /* @__PURE__ */ jsx(DefaultUnreachable, { ...own }) }) });
423
+ }
424
+ if (state.failure === "unavailable") {
425
+ const own = {
426
+ reason: state.reason,
427
+ code: state.code,
428
+ onContact,
429
+ onRetry: conversation.retry
430
+ };
431
+ return /* @__PURE__ */ jsx(VinaverseChatProvider, { ...shared, children: /* @__PURE__ */ jsx(Centered, { children: UnavailableScreen ? /* @__PURE__ */ jsx(UnavailableScreen, { ...own, Default: DefaultUnavailableScreen }) : /* @__PURE__ */ jsx(DefaultUnavailableScreen, { ...own }) }) });
432
+ }
433
+ const offered = opener && !spoke ? opener : null;
434
+ return /* @__PURE__ */ jsx(
435
+ VinaverseChat,
436
+ {
437
+ ...shared,
438
+ suggestion: offered ?? (state.moved && askAbout ? { label: askAbout, message: askAbout } : null),
439
+ ...offered ? { suggestionTestID: openerTestID ?? "vinaverse-opener" } : {},
440
+ footer: Footer === null ? null : /* @__PURE__ */ jsx(
441
+ FooterFor,
442
+ {
443
+ store,
444
+ state,
445
+ rate: conversation.rate,
446
+ canRate: conversation.canRate,
447
+ Footer,
448
+ onOpenPrivacy
449
+ }
450
+ )
451
+ }
452
+ );
453
+ }
454
+ function FooterFor(props) {
455
+ const newest = useConversationSelector(props.store, newestWholeReply);
456
+ const turnId = newest && props.canRate(newest) ? newest : null;
457
+ const own = {
458
+ turnId,
459
+ rating: turnId ? props.state.ratings.get(turnId) : void 0,
460
+ onRate: (rating) => {
461
+ if (turnId) props.rate(turnId, rating);
462
+ },
463
+ onOpenPrivacy: props.onOpenPrivacy
464
+ };
465
+ const { Footer } = props;
466
+ return Footer ? /* @__PURE__ */ jsx(Footer, { ...own, Default: AgentFooter }) : /* @__PURE__ */ jsx(AgentFooter, { ...own });
467
+ }
468
+ function newestWholeReply(view) {
469
+ for (let i = view.items.length - 1; i >= 0; i--) {
470
+ const item = view.items[i];
471
+ if (item?.type !== "message" || item.role !== "agent") continue;
472
+ const whole = item.state === "sent" && !item.partial && !item.refusal && item.key.startsWith("a:");
473
+ return whole ? item.key.slice(2) : null;
474
+ }
475
+ return null;
476
+ }
477
+ function Centered(props) {
478
+ const { colors, space } = useTheme();
479
+ return /* @__PURE__ */ jsx(
480
+ View,
481
+ {
482
+ style: {
483
+ flex: 1,
484
+ alignItems: "center",
485
+ justifyContent: "center",
486
+ padding: space.xl,
487
+ backgroundColor: colors.background
488
+ },
489
+ children: props.children
490
+ }
491
+ );
492
+ }
493
+ function Notice(props) {
494
+ const { colors, space, font } = useTheme();
495
+ return /* @__PURE__ */ jsxs(
496
+ View,
497
+ {
498
+ accessibilityRole: "alert",
499
+ style: { alignItems: "center", gap: space.md },
500
+ children: [
501
+ /* @__PURE__ */ jsx(
502
+ Text,
503
+ {
504
+ style: {
505
+ color: colors.text,
506
+ fontSize: font.size.lg,
507
+ fontWeight: "600",
508
+ textAlign: "center"
509
+ },
510
+ children: props.title
511
+ }
512
+ ),
513
+ /* @__PURE__ */ jsx(
514
+ Text,
515
+ {
516
+ style: {
517
+ color: colors.textMuted,
518
+ fontSize: font.size.md,
519
+ textAlign: "center"
520
+ },
521
+ children: props.body
522
+ }
523
+ ),
524
+ props.action && props.onPress ? /* @__PURE__ */ jsx(
525
+ Button,
526
+ {
527
+ label: props.action,
528
+ variant: "primary",
529
+ onPress: props.onPress
530
+ }
531
+ ) : null
532
+ ]
533
+ }
534
+ );
535
+ }
536
+ function DefaultEnded(props) {
537
+ const { t } = useCopy();
538
+ return /* @__PURE__ */ jsx(
539
+ Notice,
540
+ {
541
+ title: t("agentEnded"),
542
+ body: t("agentEndedBody"),
543
+ action: t("agentStartOver"),
544
+ onPress: props.onStartNew
545
+ }
546
+ );
547
+ }
548
+ function DefaultUnavailableScreen(props) {
549
+ const { t } = useCopy();
550
+ const name = useAgentName(t("agentFallbackName"));
551
+ const title = t("agentOff", { agent: name });
552
+ return /* @__PURE__ */ jsx(
553
+ Notice,
554
+ {
555
+ title: title.charAt(0).toUpperCase() + title.slice(1),
556
+ body: t("agentOffBody"),
557
+ ...props.onContact ? { action: t("talkToPerson"), onPress: props.onContact } : {}
558
+ }
559
+ );
560
+ }
561
+ function DefaultUnreachable(props) {
562
+ const { t } = useCopy();
563
+ const name = useAgentName(t("agentFallbackName"));
564
+ return /* @__PURE__ */ jsx(
565
+ Notice,
566
+ {
567
+ title: t("agentUnreachable", { agent: name }),
568
+ body: t("agentUnreachableBody"),
569
+ action: t("tryAgain"),
570
+ onPress: props.onRetry
571
+ }
572
+ );
573
+ }
574
+ function AgentFooter(props) {
575
+ const { t } = useCopy();
576
+ const { colors, space, font } = useTheme();
577
+ const muted = { color: colors.textMuted, fontSize: font.size.sm };
578
+ return /* @__PURE__ */ jsxs(
579
+ View,
580
+ {
581
+ style: {
582
+ flexDirection: "row",
583
+ flexWrap: "wrap",
584
+ alignItems: "center",
585
+ gap: space.xs,
586
+ paddingHorizontal: space.lg
587
+ },
588
+ children: [
589
+ props.turnId === null ? null : props.rating ? /* @__PURE__ */ jsx(Text, { style: muted, children: t("helpfulThanks") }) : /* @__PURE__ */ jsxs(Fragment, { children: [
590
+ /* @__PURE__ */ jsx(Text, { style: muted, children: t("helpful") }),
591
+ /* @__PURE__ */ jsx(
592
+ Button,
593
+ {
594
+ label: t("helpfulYes"),
595
+ variant: "text",
596
+ onPress: () => props.onRate("up")
597
+ }
598
+ ),
599
+ /* @__PURE__ */ jsx(
600
+ Button,
601
+ {
602
+ label: t("helpfulNo"),
603
+ variant: "text",
604
+ onPress: () => props.onRate("down")
605
+ }
606
+ )
607
+ ] }),
608
+ props.onOpenPrivacy ? /* @__PURE__ */ jsx(
609
+ Button,
610
+ {
611
+ label: t("privacy"),
612
+ variant: "text",
613
+ role: "link",
614
+ onPress: props.onOpenPrivacy
615
+ }
616
+ ) : null
617
+ ]
618
+ }
619
+ );
620
+ }
621
+
622
+ export { AgentChat, AgentFooter, Composer, DefaultComposer, DefaultEnded, DefaultUnavailable, DefaultUnavailableScreen, DefaultUnreachable, StatusBanner, VinaverseChat, VinaverseChatProvider, newestWholeReply };
623
+ //# sourceMappingURL=chunk-2J2LIJLW.js.map
624
+ //# sourceMappingURL=chunk-2J2LIJLW.js.map