@twentyfourg/chat-kit 1.0.0-beta.1
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 +21 -0
- package/README.md +222 -0
- package/dist/chat-kit.js +1914 -0
- package/dist/chat-kit.js.map +1 -0
- package/dist/components/AssistantMessage.vue.d.ts +35 -0
- package/dist/components/Chat.vue.d.ts +72 -0
- package/dist/components/CitationPopover.vue.d.ts +11 -0
- package/dist/components/FeedbackRow.vue.d.ts +11 -0
- package/dist/components/IconButton.vue.d.ts +17 -0
- package/dist/components/InputBar.vue.d.ts +16 -0
- package/dist/components/KitIcon.vue.d.ts +12 -0
- package/dist/components/MessageList.vue.d.ts +36 -0
- package/dist/components/PageImageModal.vue.d.ts +14 -0
- package/dist/components/SourceCard.vue.d.ts +21 -0
- package/dist/components/SourceList.vue.d.ts +7 -0
- package/dist/components/ThinkingAnimation.vue.d.ts +15 -0
- package/dist/components/ThinkingIndicator.vue.d.ts +13 -0
- package/dist/components/ThinkingProcess.vue.d.ts +8 -0
- package/dist/components/UserMessage.vue.d.ts +7 -0
- package/dist/composables/useAutoScroll.d.ts +36 -0
- package/dist/composables/useChatEngine.d.ts +335 -0
- package/dist/composables/useDictation.d.ts +29 -0
- package/dist/copy.d.ts +144 -0
- package/dist/index.css +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/services/anonymous-auth.d.ts +63 -0
- package/dist/services/base-camp-client.d.ts +66 -0
- package/dist/services/citations.d.ts +18 -0
- package/dist/services/entities.d.ts +29 -0
- package/dist/services/markdown.d.ts +47 -0
- package/dist/services/math.d.ts +36 -0
- package/dist/services/streaming-message.d.ts +32 -0
- package/dist/services/streaming.service.d.ts +84 -0
- package/dist/services/typewriter.d.ts +54 -0
- package/dist/testing/mock-transport.d.ts +52 -0
- package/dist/testing/setup-tests.d.ts +8 -0
- package/dist/theme.css +122 -0
- package/dist/types.d.ts +389 -0
- package/package.json +76 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 24G
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# @twentyfourg/chat-kit
|
|
2
|
+
|
|
3
|
+
A ready-made chat pane for Vue 3 apps that talk to a Base Camp agent.
|
|
4
|
+
|
|
5
|
+
The Chat component includes the input bar and message list. It handles streaming replies,
|
|
6
|
+
markdown, code blocks and tables, citations (inline popover or a list of source
|
|
7
|
+
cards), thumbs feedback, voice input, and optional math rendering.
|
|
8
|
+
Everything around the chat is yours to build.
|
|
9
|
+
|
|
10
|
+
All the text and all the colors are settings, so two apps using this can look
|
|
11
|
+
and function completely differently from one another.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
pnpm add @twentyfourg/chat-kit
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Vue 3.5 or newer is a peer dependency. Import the theme once, in your app
|
|
20
|
+
entry:
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import '@twentyfourg/chat-kit/theme.css';
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## A working chat
|
|
27
|
+
|
|
28
|
+
```vue
|
|
29
|
+
<script setup lang="ts">
|
|
30
|
+
import { BaseCampClient, Chat, useChatEngine } from '@twentyfourg/chat-kit';
|
|
31
|
+
|
|
32
|
+
const transport = new BaseCampClient({
|
|
33
|
+
baseUrl: import.meta.env.VITE_BASECAMP_API,
|
|
34
|
+
getAuthToken: () => myAuthToken,
|
|
35
|
+
deployEnv: import.meta.env.VITE_DEPLOY_ENV,
|
|
36
|
+
jobNumber: import.meta.env.VITE_JOB_NUMBER,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const engine = useChatEngine({ transport, agentId: import.meta.env.VITE_AGENT_ID });
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<template>
|
|
43
|
+
<Chat :engine="engine" />
|
|
44
|
+
</template>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
You create the engine, not the component. That way, your other components can interact with the chat from outside of the kit.
|
|
48
|
+
|
|
49
|
+
`Chat` fills the height it is given and has none of its own, so it needs
|
|
50
|
+
a parent with a real height. There is a worked example in the guide.
|
|
51
|
+
|
|
52
|
+
## Trying it without a backend
|
|
53
|
+
|
|
54
|
+
`MockTransport` answers with canned replies over the same streaming path the
|
|
55
|
+
real client uses, so you can build the whole interface before anything is
|
|
56
|
+
wired up.
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import { MockTransport, useChatEngine } from '@twentyfourg/chat-kit';
|
|
60
|
+
|
|
61
|
+
const engine = useChatEngine({
|
|
62
|
+
transport: new MockTransport({ replyTo: () => ({ text: 'Hello.' }) }),
|
|
63
|
+
agentId: 'agent-1',
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Options
|
|
68
|
+
|
|
69
|
+
There are two places to set things. How the chat behaves goes on the engine,
|
|
70
|
+
what the chat shows goes on `Chat` as a prop. Everything is optional
|
|
71
|
+
except the transport, the agent id, and the engine itself.
|
|
72
|
+
|
|
73
|
+
### Engine options
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
const engine = useChatEngine({ transport, agentId, typewriter: { speed: 1.5 } });
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
| Option | Values | Default | What it does |
|
|
80
|
+
| --- | --- | --- | --- |
|
|
81
|
+
| `typewriter` | `true`, `false`, `{ speed }` | `true` | Reveals the answer a few characters at a time instead of in raw network bursts. `speed: 2` types twice as fast, `0.5` half. |
|
|
82
|
+
| `showMath` | `true`, `false`, `{ fontsDirectory }` | `false` | Runs LaTeX parsing on the answer, so `$...$` and `$$...$$` render as formulas. See [Formulas](#formulas). |
|
|
83
|
+
| `isOutOfScope` | `(text) => boolean` | off | Decides whether a finished answer is the agent declining a question. Those replies get marked and skip the thumbs row. |
|
|
84
|
+
| `onEvent` | `(event) => void` | off | Fires on finished turns, thumbs ratings, and citation clicks. See [Analytics](#analytics). |
|
|
85
|
+
|
|
86
|
+
### Chat props
|
|
87
|
+
|
|
88
|
+
```vue
|
|
89
|
+
<Chat :engine="engine" :copy="copy" show-mic show-copy citation-type="list" />
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
| Prop | Values | Default | What it does |
|
|
93
|
+
| --- | --- | --- | --- |
|
|
94
|
+
| `engine` | the engine | required | The conversation to render. Not a setting. |
|
|
95
|
+
| `copy` | copy map | built-in defaults | Every visible string in the kit. Anything you leave out falls back to its default. |
|
|
96
|
+
| `showMic` | `true`, `false` | `false` | Shows the dictation button, in browsers that support speech recognition. |
|
|
97
|
+
| `citationType` | `'inline'`, `'list'` | `'inline'` | `'inline'` swaps the `[^N]` markers in the answer for numbered chips that open a passage popover. `'list'` drops the markers and shows source cards under the answer instead. |
|
|
98
|
+
| `thinkingVariant` | `'ring'`, `'sparkles'`, `'dots'` | `'ring'` | Which animation plays while the answer is being retrieved. |
|
|
99
|
+
| `rotateThinkingLabel` | `true`, `false` | `false` | Cycles the waiting label through `copy.status.thinkingSequence` instead of holding one line. Set that array to your own list, or to an empty array to turn the cycling off from the copy side. |
|
|
100
|
+
| `showThinking` | `true`, `false` | `false` | Shows the model's reasoning: live while you wait, folded up on the finished reply. |
|
|
101
|
+
| `autoScroll` | `'off'`, `'reply'`, `'bottom'` | `'reply'` | How far the view follows a streaming answer. `'reply'` stops once the answer's own header reaches the top, so a long answer can be read from the beginning. `'bottom'` keeps the newest line in view. `'off'` leaves the view alone. Under `'reply'` and `'bottom'`, scrolling up stops the follow until the reader comes back to the bottom. |
|
|
102
|
+
| `showCopy` | `true`, `false` | `false` | Adds a copy button under each finished answer. |
|
|
103
|
+
|
|
104
|
+
### Slots
|
|
105
|
+
|
|
106
|
+
| Slot | What it's for |
|
|
107
|
+
| --- | --- |
|
|
108
|
+
| `welcome` | Replaces the default welcome block that shows before the first message. Use it for a logo, suggested questions, whatever you want. A text-only welcome can just set `copy.welcome` and skip the slot. |
|
|
109
|
+
| `message-actions` | Scoped, gives you `{ message }`. Sits on the left of the row that holds the thumbs, on finished replies. This is where an app's own button goes, an export for example, and it comes before the kit's copy button so your actions stay together. |
|
|
110
|
+
|
|
111
|
+
### Events
|
|
112
|
+
|
|
113
|
+
`Chat` emits `rated` with the message and the rating now on it, or `null`
|
|
114
|
+
when the tap cleared it. The kit has already saved the thumb by then, so this is
|
|
115
|
+
for an app that wants to follow up with a form of its own.
|
|
116
|
+
|
|
117
|
+
```vue
|
|
118
|
+
<Chat :engine="engine" @rated="(message, value) => openFeedbackForm(message, value)" />
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Theming
|
|
122
|
+
|
|
123
|
+
The components hold no colors, fonts, or spacing of their own. They read CSS
|
|
124
|
+
custom properties, and `theme.css` gives every one of them a plain default so
|
|
125
|
+
the chat is readable in an app that has themed nothing yet.
|
|
126
|
+
|
|
127
|
+
Override them from your own stylesheet. The defaults are written to lose, so an
|
|
128
|
+
ordinary rule in your app wins wherever the import sits.
|
|
129
|
+
|
|
130
|
+
Most values point at another value rather than a color, so a rebrand is
|
|
131
|
+
usually five lines:
|
|
132
|
+
|
|
133
|
+
```css
|
|
134
|
+
:root {
|
|
135
|
+
--accent: #ffde11;
|
|
136
|
+
--accent-fg: #000;
|
|
137
|
+
--text-primary: #fff;
|
|
138
|
+
--surface-card: #1f2227;
|
|
139
|
+
--font-body: 'Roboto', sans-serif;
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
The heading, label, and interface fonts follow `--font-body` unless you set
|
|
144
|
+
them. The citation and button accents follow `--accent`. An app that already
|
|
145
|
+
defines the whole set itself can skip the import.
|
|
146
|
+
|
|
147
|
+
One thing to watch. If your own tokens live inside a CSS cascade layer, layer
|
|
148
|
+
order decides the winner before anything else does. Import `theme.css` before
|
|
149
|
+
your layered styles, or state the order yourself:
|
|
150
|
+
|
|
151
|
+
```css
|
|
152
|
+
@layer chat-kit.theme, app;
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Formulas
|
|
156
|
+
|
|
157
|
+
Answers containing `$...$` or `$$...$$` can be rendered as formulas. This is
|
|
158
|
+
off by default, because a dollar sign is also a currency symbol and prices
|
|
159
|
+
should stay prices.
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
pnpm add mathlive
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
import 'mathlive/static.css';
|
|
167
|
+
|
|
168
|
+
const engine = useChatEngine({ transport, agentId, showMath: true });
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
MathLive is an optional peer dependency. An app that leaves formulas off never
|
|
172
|
+
installs it and never downloads it.
|
|
173
|
+
|
|
174
|
+
## Analytics
|
|
175
|
+
|
|
176
|
+
The engine reports completed turns, thumbs ratings, and citation clicks through
|
|
177
|
+
one hook, and your app decides whether any of it gets recorded. The kit never
|
|
178
|
+
sends analytics itself.
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
const engine = useChatEngine({
|
|
182
|
+
transport,
|
|
183
|
+
agentId,
|
|
184
|
+
onEvent: (event) => console.log(event.type, event),
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Full guide
|
|
189
|
+
|
|
190
|
+
[GUIDE.md](./GUIDE.md) covers every prop, slot, engine option, and copy string,
|
|
191
|
+
plus the layout the chat needs around it and the things it deliberately leaves
|
|
192
|
+
to you.
|
|
193
|
+
|
|
194
|
+
## House rules
|
|
195
|
+
|
|
196
|
+
These are what keep the package usable by more than one app.
|
|
197
|
+
|
|
198
|
+
1. **Nothing about a specific app.** No client names in code, file names, CSS
|
|
199
|
+
classes, or comments. Anything app-specific arrives through props, engine
|
|
200
|
+
options, or the copy map.
|
|
201
|
+
2. **No hardcoded visible text.** Components read the `ChatCopy` map, so an app
|
|
202
|
+
can reword or translate anything.
|
|
203
|
+
3. **No raw colors or fonts.** Styles use the theme's custom properties. Every
|
|
204
|
+
property a component reads has a default in `theme.css`, and a test fails if
|
|
205
|
+
one is missing or unused.
|
|
206
|
+
4. **One set of components.** No separate mobile and desktop versions. The
|
|
207
|
+
layout responds instead.
|
|
208
|
+
5. **Small components.** Around 300 lines each.
|
|
209
|
+
6. **Props down, events up.** No reaching into a child component.
|
|
210
|
+
7. **Backend code stays in `services/`.** Components talk to composables, never
|
|
211
|
+
to a service. Swapping the backend means writing one transport.
|
|
212
|
+
|
|
213
|
+
## Working on the kit
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
pnpm test # vitest, jsdom
|
|
217
|
+
pnpm type-check
|
|
218
|
+
pnpm lint
|
|
219
|
+
pnpm build # produces dist/, which is what gets published
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Tests run against the source, so no build is needed first.
|