@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.
- package/LICENSE +202 -0
- package/README.md +326 -2
- package/dist/ask.cjs +62 -0
- package/dist/ask.cjs.map +1 -0
- package/dist/ask.d.cts +38 -0
- package/dist/ask.d.ts +38 -0
- package/dist/ask.js +5 -0
- package/dist/ask.js.map +1 -0
- package/dist/chat.cjs +274 -0
- package/dist/chat.cjs.map +1 -0
- package/dist/chat.d.cts +292 -0
- package/dist/chat.d.ts +292 -0
- package/dist/chat.js +5 -0
- package/dist/chat.js.map +1 -0
- package/dist/chunk-2J2LIJLW.js +624 -0
- package/dist/chunk-2J2LIJLW.js.map +1 -0
- package/dist/chunk-4PXQ7DEY.cjs +680 -0
- package/dist/chunk-4PXQ7DEY.cjs.map +1 -0
- package/dist/chunk-6QYDPGRS.cjs +97 -0
- package/dist/chunk-6QYDPGRS.cjs.map +1 -0
- package/dist/chunk-7KPCO443.js +74 -0
- package/dist/chunk-7KPCO443.js.map +1 -0
- package/dist/chunk-EFEXTVIT.js +88 -0
- package/dist/chunk-EFEXTVIT.js.map +1 -0
- package/dist/chunk-KSHDF3MG.js +1996 -0
- package/dist/chunk-KSHDF3MG.js.map +1 -0
- package/dist/chunk-MG32E4JI.cjs +268 -0
- package/dist/chunk-MG32E4JI.cjs.map +1 -0
- package/dist/chunk-NMKJ7LIJ.cjs +76 -0
- package/dist/chunk-NMKJ7LIJ.cjs.map +1 -0
- package/dist/chunk-POJP52GE.js +261 -0
- package/dist/chunk-POJP52GE.js.map +1 -0
- package/dist/chunk-XAG2P447.cjs +2035 -0
- package/dist/chunk-XAG2P447.cjs.map +1 -0
- package/dist/context-gHCLFsJh.d.cts +212 -0
- package/dist/context-gHCLFsJh.d.ts +212 -0
- package/dist/history.cjs +673 -0
- package/dist/history.cjs.map +1 -0
- package/dist/history.d.cts +177 -0
- package/dist/history.d.ts +177 -0
- package/dist/history.js +618 -0
- package/dist/history.js.map +1 -0
- package/dist/index.cjs +304 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +12 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/launcher.cjs +86 -0
- package/dist/launcher.cjs.map +1 -0
- package/dist/launcher.d.cts +122 -0
- package/dist/launcher.d.ts +122 -0
- package/dist/launcher.js +5 -0
- package/dist/launcher.js.map +1 -0
- package/dist/theme-BhiEGv64.d.cts +35 -0
- package/dist/theme-BhiEGv64.d.ts +35 -0
- package/package.json +311 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
http://www.apache.org/licenses/
|
|
5
|
+
|
|
6
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
8
|
+
1. Definitions.
|
|
9
|
+
|
|
10
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
13
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
+
the copyright owner that is granting the License.
|
|
15
|
+
|
|
16
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
+
other entities that control, are controlled by, or are under common
|
|
18
|
+
control with that entity. For the purposes of this definition,
|
|
19
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
+
direction or management of such entity, whether by contract or
|
|
21
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
24
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
+
exercising permissions granted by this License.
|
|
26
|
+
|
|
27
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
+
including but not limited to software source code, documentation
|
|
29
|
+
source, and configuration files.
|
|
30
|
+
|
|
31
|
+
"Object" form shall mean any form resulting from mechanical
|
|
32
|
+
transformation or translation of a Source form, including but
|
|
33
|
+
not limited to compiled object code, generated documentation,
|
|
34
|
+
and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
41
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
+
form, that is based on (or derived from) the Work and for which the
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
66
|
+
|
|
67
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
+
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
74
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
+
(except as stated in this section) patent license to make, have made,
|
|
78
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
+
where such license applies only to those patent claims licensable
|
|
80
|
+
by such Contributor that are necessarily infringed by their
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
89
|
+
|
|
90
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
+
modifications, and in Source or Object form, provided that You
|
|
93
|
+
meet the following conditions:
|
|
94
|
+
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
98
|
+
(b) You must cause any modified files to carry prominent notices
|
|
99
|
+
stating that You changed the files; and
|
|
100
|
+
|
|
101
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
+
that You distribute, all copyright, patent, trademark, and
|
|
103
|
+
attribution notices from the Source form of the Work,
|
|
104
|
+
excluding those notices that do not pertain to any part of
|
|
105
|
+
the Derivative Works; and
|
|
106
|
+
|
|
107
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding those notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
130
|
+
|
|
131
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
+
this License, without any additional terms or conditions.
|
|
135
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
+
the terms of any separate license agreement you may have executed
|
|
137
|
+
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
139
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
144
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
+
implied, including, without limitation, any warranties or conditions
|
|
149
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
152
|
+
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
179
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
+
|
|
181
|
+
To apply the Apache License to your work, attach the following
|
|
182
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
+
replaced with your own identifying information. (Don't include
|
|
184
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
+
comment syntax for the file format. We also recommend that a
|
|
186
|
+
file or class name and description of purpose be included on the
|
|
187
|
+
same "printed page" as the copyright notice for easier
|
|
188
|
+
identification within third-party archives.
|
|
189
|
+
|
|
190
|
+
Copyright [yyyy] [name of copyright owner]
|
|
191
|
+
|
|
192
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
+
you may not use this file except in compliance with the License.
|
|
194
|
+
You may obtain a copy of the License at
|
|
195
|
+
|
|
196
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
+
|
|
198
|
+
Unless required by applicable law or agreed to in writing, software
|
|
199
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
+
See the License for the specific language governing permissions and
|
|
202
|
+
limitations under the License.
|
package/README.md
CHANGED
|
@@ -1,3 +1,327 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @vinaverse/react-native
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A ready, themeable conversation with your Vinaverse agent for React Native and Expo apps. Drop it into a screen,
|
|
4
|
+
give it a conversation whose session comes from your backend, and it draws everything the realtime protocol defines:
|
|
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
|
|
7
|
+
person from your business taking over, and every way a session ends. No native module; New Architecture; FlashList 2.3.2 or later.
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { createConversation } from '@vinaverse/client/conversation';
|
|
11
|
+
import { CardCarousel, VinaverseChat } from '@vinaverse/react-native';
|
|
12
|
+
|
|
13
|
+
// Outside the screen: it connects early and survives navigation.
|
|
14
|
+
const conversation = createConversation({
|
|
15
|
+
getSession: (request) => api.vinaverseSession(request), // your backend creates it with its service key
|
|
16
|
+
locale: 'es-US',
|
|
17
|
+
deepLinkPrefixes: ['yourapp://bookings/'],
|
|
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 };
|
|
21
|
+
|
|
22
|
+
export function AgentScreen() {
|
|
23
|
+
return (
|
|
24
|
+
<VinaverseChat
|
|
25
|
+
conversation={conversation}
|
|
26
|
+
locale="es-US"
|
|
27
|
+
theme={{ light: { primary: '#7A2E8E', personBubble: '#7A2E8E' } }}
|
|
28
|
+
components={components}
|
|
29
|
+
onProposal={(card, decision) => api.decideProposal(card, decision)} // your backend, the person's token
|
|
30
|
+
onOpenLink={(link) => router.push(link)}
|
|
31
|
+
/>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Hosting the agent (the runtime)
|
|
37
|
+
|
|
38
|
+
An app that hosts the agent writes its backend once (`createAgentRuntime`, `@vinaverse/client/agent`) and draws the
|
|
39
|
+
parts; which conversation, keeping it across screens, waiting the backend out, a conversation that ended, the backend
|
|
40
|
+
out of reach, status, name, ratings and sign-out are the runtime's.
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
import { createAgentRuntime } from '@vinaverse/client/agent';
|
|
44
|
+
import { AgentChat, CardCarousel } from '@vinaverse/react-native/chat';
|
|
45
|
+
import { AgentLauncher, AgentRuntimeProvider } from '@vinaverse/react-native/launcher';
|
|
46
|
+
import { AskAboutRow } from '@vinaverse/react-native/ask';
|
|
47
|
+
import { AgentHistoryList, AgentTranscript } from '@vinaverse/react-native/history'; // the history screens
|
|
48
|
+
|
|
49
|
+
const agent = createAgentRuntime({ backend: { openSession, refreshSecret, status }, conversation: { locale } });
|
|
50
|
+
const components = { CardGroup: CardCarousel, Image: ExpoImage }; // module level: stable
|
|
51
|
+
const imagePolicy = { hosts: ['images.example.com'], aspectRatio: 1.6, Placeholder: BrandTile }; // stable too
|
|
52
|
+
|
|
53
|
+
<AgentRuntimeProvider runtime={agent}>
|
|
54
|
+
<Tabs />
|
|
55
|
+
<AgentLauncher subject={user?.id ?? null} mode={side} Mark={YourMark}
|
|
56
|
+
route={currentTab} routes={['home', 'explore']} hidden={sheetOpen} // never with the keyboard up
|
|
57
|
+
storage={preferences} onOpen={({ route, mode, entryPoint }) => openChat(route, mode, entryPoint)}
|
|
58
|
+
style={{ position: 'absolute', right: 16, bottom: tabBarHeight + 16 }} />
|
|
59
|
+
</AgentRuntimeProvider>
|
|
60
|
+
|
|
61
|
+
// The chat screen
|
|
62
|
+
<AgentChat
|
|
63
|
+
agentKey={{ subject: user?.id ?? null, mode: side, scope: businessId }}
|
|
64
|
+
place={{ screen: 'professional', entity: { type: 'professional', id } }}
|
|
65
|
+
entryPoint={entryPoint} // 'launcher', 'ask', 'deep_link': session_opened says it
|
|
66
|
+
askAbout={`Tell me about ${name}`} // offered when the session was told another place
|
|
67
|
+
starters={startersFor(screen)} // when the session brings no welcome
|
|
68
|
+
components={components}
|
|
69
|
+
onOpenTarget={(t) => router.push(routeFor(t))} // a card about a professional, a space, a booking
|
|
70
|
+
onOpenLink={openLink}
|
|
71
|
+
onContact={() => router.push('/contact')} // a person, when the agent fails or is unavailable
|
|
72
|
+
onOpenPrivacy={() => router.push('/privacy')}
|
|
73
|
+
prefetchImage={(url) => Image.prefetch(url)}
|
|
74
|
+
imagePolicy={imagePolicy}
|
|
75
|
+
/>
|
|
76
|
+
|
|
77
|
+
// On the app's own page about a professional
|
|
78
|
+
<AskAboutRow title={`Ask ${agentName} about ${name}`} onPress={({ entryPoint }) => openChat('professional', side, entryPoint)} />
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
- **Parts:** `AgentChat` draws the conversation, a conversation that ended (`components.Ended`: `onStartNew`,
|
|
82
|
+
`reason`, `code`, `onContact`), the backend out of reach (`components.Unreachable`: `onRetry`, `reason`,
|
|
83
|
+
`onContact`), no agent at all (`components.UnavailableScreen`, the whole screen: off, or the session refused;
|
|
84
|
+
`reason`, `code`, `onRetry`, `onContact`), and under the composer thumbs on the newest whole reply seen live and the
|
|
85
|
+
privacy link (`components.Footer`, `null` to hide). Each slot replaces its screen entirely, layout and words, and gets
|
|
86
|
+
the kit's part as `Default` to wrap instead; to change only the words, pass `copy`. A person to contact
|
|
87
|
+
(`onContact`) reaches every full-screen slot. `opener` is a first question as a chip the person taps (a flow that asks for itself), until they say
|
|
88
|
+
anything; nothing is ever sent in their name. So a setup flow starts when the person taps it, never on its own:
|
|
89
|
+
starting it automatically would put words in their mouth, which the kit declines by design. The opener chip's test id
|
|
90
|
+
is `vinaverse-opener` (`openerTestID` for your own); the chip asking about where the person moved is
|
|
91
|
+
`vinaverse-suggestion` (`VinaverseChat`'s `suggestionTestID`). `AgentLauncher` is a round button with
|
|
92
|
+
a greeting bubble once per person and mode (`storage`: your preferences store; `greeting`: words or words by mode,
|
|
93
|
+
read through `announce`; `storageKey` maps the record to one your app already keeps, so nobody is greeted twice),
|
|
94
|
+
your `Mark` inside, floating where `placement` says (`edge`, `bottom` above your tab bar, `inset`; `style` after it),
|
|
95
|
+
with `appearance` (a `ring`, the `shadow`, the bubble's `tail`), shown on your `routes` only, never with the keyboard
|
|
96
|
+
up (`hideWithKeyboard`; on iOS it goes as the keyboard starts to rise, on Android once it is up), stepping aside when you say (`hidden`), and only when the status offers it; its button,
|
|
97
|
+
bubble and entrance are slots (`LauncherButton`, `LauncherGreeting`, `LauncherEntrance`: a short fade and scale,
|
|
98
|
+
none with reduced motion). Its `onOpen` and the ask row's `onPress` give `entryPoint` (`launcher`, `ask`): pass it to
|
|
99
|
+
`AgentChat`'s `entryPoint` (or `deep_link`, or your own words) and `session_opened` says where the chat was opened
|
|
100
|
+
from. Every agent part asks the runtime to `sweep()` when the app comes back to the foreground. `AskAboutRow` is "ask the agent about this" on
|
|
101
|
+
your own pages, decided once as the page draws, from the status already read: it is never added under a drawn page
|
|
102
|
+
(an agent whose status arrives later shows from the next visit), and `appearance` gives it a tint (`background`) and the
|
|
103
|
+
`chevron` or none, and `testID` its test id.
|
|
104
|
+
- **Policies and adapters:** `imagePolicy` (photo hosts, frame, the stand-in for a missing photo, given the card's `title` and `kind`) applies to every card
|
|
105
|
+
and every fetch ahead; `announce` reads finished replies and the greeting your way; `onChip` hears a tapped chip.
|
|
106
|
+
Card renderers get the card read once (`read`). A listing with no rating draws `copy.ratingNone` in the rating's place (empty by default; "New", say).
|
|
107
|
+
- **History** (`@vinaverse/react-native/history` only, never `.`, so an app without a history screen ships none
|
|
108
|
+
of it): `AgentHistoryList` lists the person's past conversations, newest activity first, a page at a time as
|
|
109
|
+
they scroll (title, when, how many messages, whether it ended); a row opens (`onOpen`: show `AgentTranscript`), an
|
|
110
|
+
open one continues (`onContinue(conversation, live)`: pinned under its own key, `useAgentHistory().keyOf`, show
|
|
111
|
+
`AgentChat` with it), and deletes after the person confirms (`confirmDelete`, default the platform's alert with the
|
|
112
|
+
copy's words; a refused delete is said on the row and through `onWarning`). `AgentTranscript` reads one back, the
|
|
113
|
+
newest page first and earlier pages above (a button, and the top of the list), drawn with the chat's own bubbles and
|
|
114
|
+
cards over a read-only store, so a restored card takes nothing (no proposal confirmed, no link opened, no answer),
|
|
115
|
+
a guardrail's refusal reads as it did live ("Not answered" under the person's message) and a proposal shows the
|
|
116
|
+
outcome it had; `agentKey` + `onContinue` add "Continue", except for a conversation that `ended` (pass the row's
|
|
117
|
+
`state === 'ended'`, as the list offers Continue only for an open one). Slots: `Row`, `Empty`, `Failure`, `ListComponent` on the
|
|
118
|
+
list; `Header`, `Failure`, `ListComponent`, `MessageBubble`, `Image`, `CardGroup` and `cards` on the transcript.
|
|
119
|
+
Both show when the status offers history (`useAgentFeatures().history`); your backend serves the two routes
|
|
120
|
+
(`backendRoutes`' `list` and `read`), else they say history is not available.
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
import { AgentHistoryList, AgentTranscript } from '@vinaverse/react-native/history';
|
|
124
|
+
|
|
125
|
+
<AgentHistoryList subject={user?.id ?? null} mode={side} timeZone={tz}
|
|
126
|
+
onOpen={(c) => router.push({ pathname: `/history/${c.id}`, params: { ended: String(c.state === 'ended') } })}
|
|
127
|
+
onContinue={(c) => router.push({ pathname: '/chat', params: { mode: c.experience_mode, scope: c.business_scope_id } })} />
|
|
128
|
+
<AgentTranscript conversationId={id} ended={ended === 'true'} agentKey={{ subject: user?.id ?? null, mode: side }} onContinue={() => router.push('/chat')} />
|
|
129
|
+
```
|
|
130
|
+
- **Hooks** for your own parts: `useAgentConversation`, `useAgentStatus`, `useAgentStatusState` (`{ status, reading,
|
|
131
|
+
failed }`: "still reading" apart from "could not read"), `useAgentFeatures`, `useAgentProfile`, `useAgentName`,
|
|
132
|
+
`useAgentLauncher`, `useAgentRuntime`; `useAgentHistory`, `useAgentTranscript` (`@vinaverse/react-native/history`).
|
|
133
|
+
- **Events** for analytics through `onEvent`: sessions, ratings, chips, targets and links opened, the launcher shown,
|
|
134
|
+
opened, greeted and its greeting closed.
|
|
135
|
+
- **StrictMode, in development only:** React mounts, unmounts and mounts again, so a conversation still opening is let
|
|
136
|
+
go with the first unmount and the second mount asks your backend for another session: two `openSession` calls per
|
|
137
|
+
opening in development, one in a release build. The first request's answer is dropped, never shown.
|
|
138
|
+
|
|
139
|
+
## Install
|
|
140
|
+
|
|
141
|
+
```sh
|
|
142
|
+
npm install @vinaverse/react-native@alpha @vinaverse/client@alpha @shopify/flash-list@^2.3.2
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Alphas are published under the `alpha` tag. Keep every `@vinaverse/*` package on the same version, so your app and the
|
|
146
|
+
kit share one copy of `@vinaverse/client`.
|
|
147
|
+
|
|
148
|
+
**Import by part.** The package has an entry per part: `@vinaverse/react-native/chat` (the conversation, `AgentChat`,
|
|
149
|
+
`VinaverseChat`, cards, theme), `/launcher` (`AgentLauncher` and its parts) and `/ask` (`AskAboutRow`). The launcher and
|
|
150
|
+
the ask row each re-export the runtime bindings (`AgentRuntimeProvider`, the hooks) and the theme. The entries share
|
|
151
|
+
their modules, so two of them still mean one theme and one chat context. `@vinaverse/react-native` itself still exports
|
|
152
|
+
everything.
|
|
153
|
+
|
|
154
|
+
What it buys, honestly. Metro without tree shaking (its default) puts every module an app imports statically, anywhere,
|
|
155
|
+
into the one bundle it writes for iOS or Android. Measured on the kit alone (minified, brotli, peers excluded):
|
|
156
|
+
|
|
157
|
+
| The app imports | Ships |
|
|
158
|
+
|---|---|
|
|
159
|
+
| `@vinaverse/react-native` | 14.9 kB |
|
|
160
|
+
| `/launcher` and `/ask`, no chat screen | 2.9 kB |
|
|
161
|
+
| `/launcher`, `/ask` and `/chat` (a chat screen anywhere) | 15.1 kB |
|
|
162
|
+
|
|
163
|
+
- **The bundle** shrinks only for an app that never imports `/chat`. An app with a chat screen ships the whole kit
|
|
164
|
+
whichever way it imports it; the separate entries add about 0.1 kB.
|
|
165
|
+
- **Start-up** is where an app with a chat screen gains: a screen that imports only `/launcher` runs the kit's 2.5 kB
|
|
166
|
+
of launcher code when it loads, not all 15 kB (with `@vinaverse/react-native`, using the launcher loads every part).
|
|
167
|
+
Inline requires (`inlineRequires`) defer a module until its first use, but they do not split the kit's own entry:
|
|
168
|
+
only the per-part imports do.
|
|
169
|
+
- **Both** need the chat screen loaded lazily (`React.lazy`, or Expo Router's async routes). On iOS and Android a
|
|
170
|
+
production Metro bundle is still one file, so lazy loading defers when the chat's code runs, never whether it ships;
|
|
171
|
+
on the web, async routes put it in a bundle of its own.
|
|
172
|
+
|
|
173
|
+
Loading the chat screen lazily. On the web, Expo Router's async routes (`"asyncRoutes"` in the `expo-router` plugin's
|
|
174
|
+
options in `app.json`, e.g. `{ "web": true, "default": "development" }`) put each route's code in a bundle of its own,
|
|
175
|
+
loaded the first time it is visited. That setting makes routes async on iOS and Android in development only, so a
|
|
176
|
+
production iOS or Android build gets no deferral from it: there, `React.lazy` is what defers the chat:
|
|
177
|
+
|
|
178
|
+
```tsx
|
|
179
|
+
import { lazy, Suspense } from 'react';
|
|
180
|
+
import { AgentLauncher, AgentRuntimeProvider } from '@vinaverse/react-native/launcher'; // the tabs: 2.5 kB of the kit
|
|
181
|
+
|
|
182
|
+
// Only this file imports /chat, and only when the screen is first drawn.
|
|
183
|
+
const ChatScreen = lazy(() => import('./ChatScreen')); // ChatScreen.tsx: import { AgentChat } from '@vinaverse/react-native/chat'
|
|
184
|
+
|
|
185
|
+
export function Chat() {
|
|
186
|
+
return (
|
|
187
|
+
<Suspense fallback={null}>
|
|
188
|
+
<ChatScreen />
|
|
189
|
+
</Suspense>
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
What is lost without it: a screen that imports `/chat` statically, or anything that does, loads and runs the whole chat
|
|
195
|
+
(about 13 kB of the kit, its cards and list) when that screen's module first runs; with inline requires, when it is
|
|
196
|
+
first used. Nothing breaks either way, and the bundle is the same on iOS and Android.
|
|
197
|
+
|
|
198
|
+
**One build under Metro.** Every `@vinaverse/*` entry lists the `react-native` condition first, which React Native's
|
|
199
|
+
and Expo's Metro configs set for iOS and Android: Metro takes the CommonJS build for an `import`, a `require`, and a
|
|
200
|
+
`require` Babel writes for you (an `export const X = ImportedBinding` becomes a getter that requires), so an app holds
|
|
201
|
+
one copy of the kit and one of each React context. Before 0.1.0-alpha.8 an ES import and a require resolved to
|
|
202
|
+
different builds, and a card drawn from the second found no chat around it; a `metro.config.js` that forces the `import`
|
|
203
|
+
condition for `@vinaverse/*` is no longer needed (harmless if kept). Jest with jest-expo resolves the same CommonJS
|
|
204
|
+
build, untransformed. Web bundlers (no `react-native` condition) take the ES module build for an import: import the kit
|
|
205
|
+
with `import` statements there.
|
|
206
|
+
|
|
207
|
+
**Size on iOS and Android comes from the per-part entries, not tree shaking.** Metro takes the CommonJS build there,
|
|
208
|
+
which no tree shaking (Expo's production tree shaking included) can trim: a screen ships and runs every module of the
|
|
209
|
+
entry it imports. So import by part (`/launcher`, `/ask`, `/chat`) to keep the kit's start-up work to the parts a
|
|
210
|
+
screen draws. Tree shaking (webpack, Rollup, esbuild, Expo on the web) applies on the web only, where an import takes
|
|
211
|
+
the ES module build.
|
|
212
|
+
|
|
213
|
+
## Peer dependencies
|
|
214
|
+
|
|
215
|
+
| Package | Range | Why |
|
|
216
|
+
|---|---|---|
|
|
217
|
+
| `react` | `>=19.1` | hooks over `useSyncExternalStore` |
|
|
218
|
+
| `react-native` | `>=0.81` | the New Architecture (FlashList v2 needs it) |
|
|
219
|
+
| `@shopify/flash-list` | `>=2.3.2 <3` | the chat list: `maintainVisibleContentPosition` with `startRenderingFromBottom` and `autoscrollToBottomThreshold`; the kit is tested on 2.3.2 |
|
|
220
|
+
|
|
221
|
+
## What you can change, and what you cannot
|
|
222
|
+
|
|
223
|
+
- **Change:** colors (light and dark), font family, radii and spacing (`theme`); every string (`copy`, in en, es and
|
|
224
|
+
pt-BR built in); the header, bubbles, composer, empty state, images, the list (LegendList works) and any card kind
|
|
225
|
+
(`components`, each slot gets the default as `Default` to wrap it); or compose your own layout from the exported
|
|
226
|
+
parts inside `VinaverseChatProvider`, or your own UI on `@vinaverse/react`'s hooks.
|
|
227
|
+
- **Cannot:** remove, cover or reword the AI disclosure (the server's text, always shown under the header); remove
|
|
228
|
+
"Powered by Vinaverse" (v1); show a person from your business as the agent or the agent as a person; call the agent
|
|
229
|
+
an assistant; draw a proposal as done before your backend's outcome, or confirm one without `onProposal`. The kit
|
|
230
|
+
draws these outside every slot.
|
|
231
|
+
|
|
232
|
+
## Sessions and the app's lifecycle
|
|
233
|
+
|
|
234
|
+
- **The session comes from your backend**, never a fixed secret: `getSession(request)` when the conversation opens and
|
|
235
|
+
on the person's next action after a session ended, and `refreshSecret(sessionId)` for a fresh client secret (on a
|
|
236
|
+
refused secret, 4401, and before reopening after the background). The app never holds a service key.
|
|
237
|
+
- **Background**: the kit tells the conversation when the app goes to the background and comes back (`AppState`).
|
|
238
|
+
By default the connection stays, without pings; `createConversation({ closeInBackground: true, refreshSecret })`
|
|
239
|
+
closes it in the background and opens it again, with a fresh secret, in the foreground. Nothing typed is lost.
|
|
240
|
+
- **A session's end**: pass `expires_at` on from the session your backend created. Past it (the tenant's tool token
|
|
241
|
+
with it), the person's next message gets a new session for the same conversation from `getSession`; the old one is
|
|
242
|
+
never reopened with a fresh secret. A reconnect keeps everything drawn: the session's transcript merges by id.
|
|
243
|
+
- **Modes**: a customer and a professional each get their own conversation, `createConversationsByMode`, and the
|
|
244
|
+
screen draws `conversations.select(mode)`. Each mode keeps its own history on the device, and `getSession` gets the
|
|
245
|
+
`mode` so your backend creates the session for that mode's agent.
|
|
246
|
+
- **Language**: the agent answers in `subject.locale`, which your backend sets when it creates the session; the kit's
|
|
247
|
+
`locale` prop is only for its own words, dates and money (and is passed to `getSession` as a hint you may ignore).
|
|
248
|
+
|
|
249
|
+
## Handlers
|
|
250
|
+
|
|
251
|
+
| Prop | When |
|
|
252
|
+
|---|---|
|
|
253
|
+
| `onProposal(card, 'confirm' \| 'decline')` | the person decided a proposal: apply it with your backend and the person's token, return the outcome |
|
|
254
|
+
| `onOpenLink(link, card)` | a card's link (it already passed the deep-link rule): route by the page it names |
|
|
255
|
+
| `onCardAction(card, action)` | a card action without a link (also sent to the session) |
|
|
256
|
+
| `onPickPhoto(question, card)` | a photo question: pick, upload to your backend, return `{ upload_ref }` |
|
|
257
|
+
| `failureAction` | `{ label?, onPress(state) }`: a way out on a failed turn and on "couldn't connect" ([When the agent fails](#when-the-agent-fails)) |
|
|
258
|
+
| `onWarning(message, { code })` | warnings for your logger, `code` one of `theme` (hard to read), `copy` (says "assistant"), `send_failed`, `answer_failed`, `proposal_failed`, `photo_failed`, so you count them without the text |
|
|
259
|
+
|
|
260
|
+
## When the agent fails
|
|
261
|
+
|
|
262
|
+
Two failures need a way out for the person: a turn that failed before any reply ("Something went wrong.") and no
|
|
263
|
+
session to talk to ("Couldn't connect.", with "Try again"). Give one action for both, drawn as a button by the kit's
|
|
264
|
+
own parts, so a person is always the way out:
|
|
265
|
+
|
|
266
|
+
```tsx
|
|
267
|
+
<VinaverseChat
|
|
268
|
+
conversation={conversation}
|
|
269
|
+
failureAction={{ onPress: (state) => openSupport(state.conversationId) }} // "Talk to a person", in the person's language
|
|
270
|
+
/>
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
`label` replaces "Talk to a person" (the copy's `talkToPerson`, which `copy` can also change). Or replace either part:
|
|
274
|
+
`components.Error` (the failed turn) and `components.Unavailable` (the banner) each get the `state` and the kit's own
|
|
275
|
+
part as `Default`. With neither, the kit draws both as before.
|
|
276
|
+
|
|
277
|
+
| `state` | |
|
|
278
|
+
|---|---|
|
|
279
|
+
| `kind` | `turn_failed` or `unavailable` |
|
|
280
|
+
| `reason` | the turn's error code (`internal`, `timeout`, …), or `unavailable` / `unauthorized` |
|
|
281
|
+
| `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 |
|
|
282
|
+
| `conversationId` | the conversation, once a session named it: for your support records |
|
|
283
|
+
|
|
284
|
+
## Listings, carousels, links and the welcome
|
|
285
|
+
|
|
286
|
+
- **Professionals and spaces** draw as photo cards: the hero photo (through your `Image` slot, so `expo-image`'s cache
|
|
287
|
+
applies), the name's monogram when there is none or it fails, rating with its count, "From $45" and the next open
|
|
288
|
+
time, said as people say it ("Next: tomorrow, 10:00 AM"; `copy.today` and `copy.tomorrow`, else the date). The
|
|
289
|
+
photo frame is `imagePolicy.aspectRatio` (default 1.6); `'natural'` draws a card on its own in its photo's own
|
|
290
|
+
shape, held within `naturalAspect` (square to 2:1 by default), while a card in a carousel keeps the fixed frame.
|
|
291
|
+
- **Bookings, services and every other card** show their `status` (a booking's "Confirmed") first among the badges,
|
|
292
|
+
and a tap opens what the card is about (its `ref`) through `onOpenTarget`, as a listing does.
|
|
293
|
+
- **A carousel** for the cards a turn draws together: add the kit's `CardCarousel`. A turn's cards of one carousel
|
|
294
|
+
group join one row where the first of them is, even with another card between them. Without it they draw one under
|
|
295
|
+
another; it is opt-in so an app that does not use it does not ship it.
|
|
296
|
+
|
|
297
|
+
```tsx
|
|
298
|
+
import { CardCarousel, VinaverseChat } from '@vinaverse/react-native';
|
|
299
|
+
const components = { Image: ExpoImage, CardGroup: CardCarousel }; // module level: a stable object
|
|
300
|
+
<VinaverseChat conversation={conversation} components={components} onOpenLink={openLink} />;
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
- **Links**: when your scope keeps the agent from answering, it shows your own help, support, policy, contact or
|
|
304
|
+
feedback pages. Each opens through `onOpenLink` (an https page too: your in-app browser), a deep link only when it
|
|
305
|
+
passes your deep-link prefixes.
|
|
306
|
+
- **The welcome**: pass `welcome` on from the session your backend created; the kit greets an empty conversation with
|
|
307
|
+
it and its chips (no model call). A chip sends its message as the person's own. An `EmptyState` slot gets both.
|
|
308
|
+
|
|
309
|
+
## The keyboard
|
|
310
|
+
|
|
311
|
+
`keyboardBehavior` keeps the composer above the keyboard: `padding` on iOS by default, nothing on Android (the window
|
|
312
|
+
resizes). An edge-to-edge Android app whose window does not resize passes `padding`; an app that manages the keyboard
|
|
313
|
+
itself passes `none`. This is checked on devices in the release's stabilization phase, not by the unit tests.
|
|
314
|
+
|
|
315
|
+
## Performance and accessibility
|
|
316
|
+
|
|
317
|
+
A streamed reply re-renders only its own bubble, at most once per frame; a new message renders one row; typing renders
|
|
318
|
+
only the composer (held by render-count tests). The list is anchored at the bottom without being inverted, so screen
|
|
319
|
+
readers read it oldest first; finished replies are announced once; every control has a 44 pt target and a role;
|
|
320
|
+
right-to-left languages, large text and reduced motion are respected.
|
|
321
|
+
|
|
322
|
+
More: [docs/architecture/ui-kits.md](../../docs/architecture/ui-kits.md). An Expo example:
|
|
323
|
+
[examples/expo-chat](../../examples/expo-chat).
|
|
324
|
+
|
|
325
|
+
## License
|
|
326
|
+
|
|
327
|
+
Apache-2.0
|
package/dist/ask.cjs
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkNMKJ7LIJ_cjs = require('./chunk-NMKJ7LIJ.cjs');
|
|
4
|
+
var chunk6QYDPGRS_cjs = require('./chunk-6QYDPGRS.cjs');
|
|
5
|
+
var agent = require('@vinaverse/react/agent');
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
Object.defineProperty(exports, "AskAboutRow", {
|
|
10
|
+
enumerable: true,
|
|
11
|
+
get: function () { return chunkNMKJ7LIJ_cjs.AskAboutRow; }
|
|
12
|
+
});
|
|
13
|
+
Object.defineProperty(exports, "ThemeProvider", {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
get: function () { return chunk6QYDPGRS_cjs.ThemeProvider; }
|
|
16
|
+
});
|
|
17
|
+
Object.defineProperty(exports, "useTheme", {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
get: function () { return chunk6QYDPGRS_cjs.useTheme; }
|
|
20
|
+
});
|
|
21
|
+
Object.defineProperty(exports, "AgentRuntimeProvider", {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
get: function () { return agent.AgentRuntimeProvider; }
|
|
24
|
+
});
|
|
25
|
+
Object.defineProperty(exports, "forgetGreeting", {
|
|
26
|
+
enumerable: true,
|
|
27
|
+
get: function () { return agent.forgetGreeting; }
|
|
28
|
+
});
|
|
29
|
+
Object.defineProperty(exports, "greetedKey", {
|
|
30
|
+
enumerable: true,
|
|
31
|
+
get: function () { return agent.greetedKey; }
|
|
32
|
+
});
|
|
33
|
+
Object.defineProperty(exports, "useAgentConversation", {
|
|
34
|
+
enumerable: true,
|
|
35
|
+
get: function () { return agent.useAgentConversation; }
|
|
36
|
+
});
|
|
37
|
+
Object.defineProperty(exports, "useAgentFeatures", {
|
|
38
|
+
enumerable: true,
|
|
39
|
+
get: function () { return agent.useAgentFeatures; }
|
|
40
|
+
});
|
|
41
|
+
Object.defineProperty(exports, "useAgentLauncher", {
|
|
42
|
+
enumerable: true,
|
|
43
|
+
get: function () { return agent.useAgentLauncher; }
|
|
44
|
+
});
|
|
45
|
+
Object.defineProperty(exports, "useAgentName", {
|
|
46
|
+
enumerable: true,
|
|
47
|
+
get: function () { return agent.useAgentName; }
|
|
48
|
+
});
|
|
49
|
+
Object.defineProperty(exports, "useAgentProfile", {
|
|
50
|
+
enumerable: true,
|
|
51
|
+
get: function () { return agent.useAgentProfile; }
|
|
52
|
+
});
|
|
53
|
+
Object.defineProperty(exports, "useAgentRuntime", {
|
|
54
|
+
enumerable: true,
|
|
55
|
+
get: function () { return agent.useAgentRuntime; }
|
|
56
|
+
});
|
|
57
|
+
Object.defineProperty(exports, "useAgentStatus", {
|
|
58
|
+
enumerable: true,
|
|
59
|
+
get: function () { return agent.useAgentStatus; }
|
|
60
|
+
});
|
|
61
|
+
//# sourceMappingURL=ask.cjs.map
|
|
62
|
+
//# sourceMappingURL=ask.cjs.map
|
package/dist/ask.cjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"ask.cjs","sourcesContent":[]}
|
package/dist/ask.d.cts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export { AgentRuntimeProvider, GreetingStorage, UseAgentConversation, UseAgentLauncher, forgetGreeting, greetedKey, useAgentConversation, useAgentFeatures, useAgentLauncher, useAgentName, useAgentProfile, useAgentRuntime, useAgentStatus } from '@vinaverse/react/agent';
|
|
2
|
+
import { CopyOverrides } from '@vinaverse/react';
|
|
3
|
+
import { ComponentType, ReactNode } from 'react';
|
|
4
|
+
import { a as ThemeOverrides, C as ColorSchemeSetting } from './theme-BhiEGv64.cjs';
|
|
5
|
+
export { T as Theme, b as ThemeProvider, u as useTheme } from './theme-BhiEGv64.cjs';
|
|
6
|
+
import '@vinaverse/tokens';
|
|
7
|
+
|
|
8
|
+
/** The row's look beyond the theme. */
|
|
9
|
+
interface AskAboutRowAppearance {
|
|
10
|
+
/** A tint behind the row; default the theme's `surface`. */
|
|
11
|
+
readonly background?: string;
|
|
12
|
+
/** The chevron at the row's end. Default true. */
|
|
13
|
+
readonly chevron?: boolean;
|
|
14
|
+
}
|
|
15
|
+
interface AskAboutRowProps {
|
|
16
|
+
/** "Ask Example Agent about Riley Sample". */
|
|
17
|
+
readonly title: string;
|
|
18
|
+
readonly body?: string;
|
|
19
|
+
/** The person asks: open the chat with `entryPoint` (`ask`), so the session says where it was opened from. */
|
|
20
|
+
readonly onPress: (from: {
|
|
21
|
+
readonly entryPoint: 'ask';
|
|
22
|
+
}) => void;
|
|
23
|
+
/** The app's brand mark at the row's start; default the agent name's first letter. */
|
|
24
|
+
readonly Mark?: ComponentType<{
|
|
25
|
+
readonly size: number;
|
|
26
|
+
readonly color: string;
|
|
27
|
+
}>;
|
|
28
|
+
readonly appearance?: AskAboutRowAppearance;
|
|
29
|
+
readonly locale?: string;
|
|
30
|
+
readonly copy?: CopyOverrides;
|
|
31
|
+
readonly theme?: ThemeOverrides;
|
|
32
|
+
readonly colorScheme?: ColorSchemeSetting;
|
|
33
|
+
/** The row's test id. Default `vinaverse-ask-about`. */
|
|
34
|
+
readonly testID?: string;
|
|
35
|
+
}
|
|
36
|
+
declare function AskAboutRow(props: AskAboutRowProps): ReactNode;
|
|
37
|
+
|
|
38
|
+
export { AskAboutRow, type AskAboutRowAppearance, type AskAboutRowProps, ColorSchemeSetting, ThemeOverrides };
|