@vinaverse/react-native 0.1.0-alpha.2 → 0.1.0-alpha.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.
package/README.md CHANGED
@@ -2,12 +2,13 @@
2
2
 
3
3
  A ready, themeable conversation with your Vinaverse agent for React Native and Expo apps. Drop it into a screen,
4
4
  give it a conversation whose session comes from your backend, and it draws everything the realtime protocol defines:
5
- streaming replies, cards (people, services, bookings, questions, proposals, next steps), held and unsent messages, a
5
+ streaming replies, cards (photo cards for people and places, services, bookings, questions, proposals, next steps,
6
+ your own help pages), held and unsent messages, a
6
7
  person from your business taking over, and every way a session ends. No native module; New Architecture; FlashList 2.3.2 or later.
7
8
 
8
9
  ```tsx
9
10
  import { createConversation } from '@vinaverse/client/conversation';
10
- import { VinaverseChat } from '@vinaverse/react-native';
11
+ import { CardCarousel, VinaverseChat } from '@vinaverse/react-native';
11
12
 
12
13
  // Outside the screen: it connects early and survives navigation.
13
14
  const conversation = createConversation({
@@ -15,6 +16,8 @@ const conversation = createConversation({
15
16
  locale: 'es-US',
16
17
  deepLinkPrefixes: ['yourapp://bookings/'],
17
18
  });
19
+ // Opt-in: a turn's listing cards in one swipeable row (without it they stack). Module level: a stable object.
20
+ const components = { CardGroup: CardCarousel };
18
21
 
19
22
  export function AgentScreen() {
20
23
  return (
@@ -22,6 +25,7 @@ export function AgentScreen() {
22
25
  conversation={conversation}
23
26
  locale="es-US"
24
27
  theme={{ light: { primary: '#7A2E8E', personBubble: '#7A2E8E' } }}
28
+ components={components}
25
29
  onProposal={(card, decision) => api.decideProposal(card, decision)} // your backend, the person's token
26
30
  onOpenLink={(link) => router.push(link)}
27
31
  />
@@ -65,6 +69,12 @@ kit share one copy of `@vinaverse/client`.
65
69
  - **Background**: the kit tells the conversation when the app goes to the background and comes back (`AppState`).
66
70
  By default the connection stays, without pings; `createConversation({ closeInBackground: true, refreshSecret })`
67
71
  closes it in the background and opens it again, with a fresh secret, in the foreground. Nothing typed is lost.
72
+ - **A session's end**: pass `expires_at` on from the session your backend created. Past it (the tenant's tool token
73
+ with it), the person's next message gets a new session for the same conversation from `getSession`; the old one is
74
+ never reopened with a fresh secret. A reconnect keeps everything drawn: the session's transcript merges by id.
75
+ - **Modes**: a customer and a professional each get their own conversation, `createConversationsByMode`, and the
76
+ screen draws `conversations.select(mode)`. Each mode keeps its own history on the device, and `getSession` gets the
77
+ `mode` so your backend creates the session for that mode's agent.
68
78
  - **Language**: the agent answers in `subject.locale`, which your backend sets when it creates the session; the kit's
69
79
  `locale` prop is only for its own words, dates and money (and is passed to `getSession` as a hint you may ignore).
70
80
 
@@ -76,8 +86,53 @@ kit share one copy of `@vinaverse/client`.
76
86
  | `onOpenLink(link, card)` | a card's link (it already passed the deep-link rule): route by the page it names |
77
87
  | `onCardAction(card, action)` | a card action without a link (also sent to the session) |
78
88
  | `onPickPhoto(question, card)` | a photo question: pick, upload to your backend, return `{ upload_ref }` |
89
+ | `failureAction` | `{ label?, onPress(state) }`: a way out on a failed turn and on "couldn't connect" ([When the agent fails](#when-the-agent-fails)) |
79
90
  | `onWarning(message)` | development warnings: a hard-to-read theme, copy that says "assistant" |
80
91
 
92
+ ## When the agent fails
93
+
94
+ Two failures need a way out for the person: a turn that failed before any reply ("Something went wrong.") and no
95
+ session to talk to ("Couldn't connect.", with "Try again"). Give one action for both, drawn as a button by the kit's
96
+ own parts, so a person is always the way out:
97
+
98
+ ```tsx
99
+ <VinaverseChat
100
+ conversation={conversation}
101
+ failureAction={{ onPress: (state) => openSupport(state.conversationId) }} // "Talk to a person", in the person's language
102
+ />
103
+ ```
104
+
105
+ `label` replaces "Talk to a person" (the copy's `talkToPerson`, which `copy` can also change). Or replace either part:
106
+ `components.Error` (the failed turn) and `components.Unavailable` (the banner) each get the `state` and the kit's own
107
+ part as `Default`. With neither, the kit draws both as before.
108
+
109
+ | `state` | |
110
+ |---|---|
111
+ | `kind` | `turn_failed` or `unavailable` |
112
+ | `reason` | the turn's error code (`internal`, `timeout`, …), or `unavailable` / `unauthorized` |
113
+ | `retry` | try again, when it can be: the person's text once more, for a turn the server allows to retry (once); a new session for `unavailable`. Undefined otherwise |
114
+ | `conversationId` | the conversation, once a session named it: for your support records |
115
+
116
+ ## Listings, carousels, links and the welcome
117
+
118
+ - **Professionals and spaces** draw as photo cards: the hero photo (through your `Image` slot, so `expo-image`'s cache
119
+ applies), the name's monogram when there is none or it fails, rating with its count, "From $45" and the next open
120
+ time.
121
+ - **A carousel** for the cards a turn draws together: add the kit's `CardCarousel`. Without it they draw one under
122
+ another; it is opt-in so an app that does not use it does not ship it.
123
+
124
+ ```tsx
125
+ import { CardCarousel, VinaverseChat } from '@vinaverse/react-native';
126
+ const components = { Image: ExpoImage, CardGroup: CardCarousel }; // module level: a stable object
127
+ <VinaverseChat conversation={conversation} components={components} onOpenLink={openLink} />;
128
+ ```
129
+
130
+ - **Links**: when your scope keeps the agent from answering, it shows your own help, support, policy, contact or
131
+ feedback pages. Each opens through `onOpenLink` (an https page too: your in-app browser), a deep link only when it
132
+ passes your deep-link prefixes.
133
+ - **The welcome**: pass `welcome` on from the session your backend created; the kit greets an empty conversation with
134
+ it and its chips (no model call). A chip sends its message as the person's own. An `EmptyState` slot gets both.
135
+
81
136
  ## The keyboard
82
137
 
83
138
  `keyboardBehavior` keeps the composer above the keyboard: `padding` on iOS by default, nothing on Android (the window