@twentyfourg/chat-kit 1.0.0-beta.2 → 1.0.0-beta.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 +31 -0
- package/dist/chat-kit.js +70 -40
- package/dist/chat-kit.js.map +1 -1
- package/dist/components/Chat.vue.d.ts +7 -2
- package/dist/components/InputBar.vue.d.ts +8 -2
- package/dist/index.css +1 -1
- package/dist/testing/mock-transport.d.ts +6 -0
- package/dist/theme.css +8 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -114,8 +114,21 @@ that changes once the conversation has started, say) can be a computed.
|
|
|
114
114
|
| `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. |
|
|
115
115
|
| `message-footer` | Scoped, gives you `{ message }`. Whatever your app wants under a reply, below its sources and actions: follow-up prompts, a link back to something above. Rendered for every reply, streaming included, so check `message.isStreaming` if it should wait. |
|
|
116
116
|
| `composer` | Replaces the whole composer. For a state the kit's field has no shape for, such as a locked bar with an upgrade prompt. Your content calls `engine.sendMessage` itself if it needs to send. |
|
|
117
|
+
| `send` | Scoped, gives you `{ send, canSend }`. Replaces the send button and nothing else, so the field keeps its own typing, dictation, and Enter handling. For a client whose send button is a finished asset that draws its own shape and disabled state. Not rendered while an answer streams, when the stop button has the spot. |
|
|
117
118
|
| `composer-footer` | Sits inside the composer, under the field. An option that changes how the next question is handled, a hint, a counter. |
|
|
118
119
|
|
|
120
|
+
Your own send button, keeping everything else the kit does:
|
|
121
|
+
|
|
122
|
+
```vue
|
|
123
|
+
<Chat :engine="engine">
|
|
124
|
+
<template #send="{ send, canSend }">
|
|
125
|
+
<button :disabled="!canSend" @click="send">
|
|
126
|
+
<img :src="canSend ? sendIcon : sendDisabledIcon" alt="Send" />
|
|
127
|
+
</button>
|
|
128
|
+
</template>
|
|
129
|
+
</Chat>
|
|
130
|
+
```
|
|
131
|
+
|
|
119
132
|
### Events
|
|
120
133
|
|
|
121
134
|
`Chat` emits `rated` with the message and the rating now on it, or `null`
|
|
@@ -152,6 +165,24 @@ The heading, label, and interface fonts follow `--font-body` unless you set
|
|
|
152
165
|
them. The citation and button accents follow `--accent`. An app that already
|
|
153
166
|
defines the whole set itself can skip the import.
|
|
154
167
|
|
|
168
|
+
### Room around the chat
|
|
169
|
+
|
|
170
|
+
Two properties control how much space the chat takes, separately from the rest
|
|
171
|
+
of the theme:
|
|
172
|
+
|
|
173
|
+
| Property | Default | What it does |
|
|
174
|
+
| --- | --- | --- |
|
|
175
|
+
| `--chat-inset` | `24px` | The gutter between the chat's edge and its contents. The conversation and the composer both read it, so they stay lined up with each other. |
|
|
176
|
+
| `--composer-padding` | `8px` | Space between the composer's border and the field inside it. The 40px buttons set the height, not the text, so this is added to those: the default makes a 56px composer plus its border. |
|
|
177
|
+
|
|
178
|
+
A roomier chat, for a design with space to spend:
|
|
179
|
+
|
|
180
|
+
```css
|
|
181
|
+
:root {
|
|
182
|
+
--composer-padding: 24px;
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
155
186
|
One thing to watch. If your own tokens live inside a CSS cascade layer, layer
|
|
156
187
|
order decides the winner before anything else does. Import `theme.css` before
|
|
157
188
|
your layered styles, or state the order yourself:
|
package/dist/chat-kit.js
CHANGED
|
@@ -717,7 +717,7 @@ function Qe(e) {
|
|
|
717
717
|
inputMode: i
|
|
718
718
|
});
|
|
719
719
|
o.value.push(u);
|
|
720
|
-
let
|
|
720
|
+
let m = b({
|
|
721
721
|
id: K(),
|
|
722
722
|
role: "assistant",
|
|
723
723
|
text: "",
|
|
@@ -731,64 +731,71 @@ function Qe(e) {
|
|
|
731
731
|
isReceiving: !1,
|
|
732
732
|
failed: !1
|
|
733
733
|
});
|
|
734
|
-
p.value =
|
|
735
|
-
let
|
|
736
|
-
g =
|
|
737
|
-
let
|
|
738
|
-
|
|
734
|
+
p.value = m;
|
|
735
|
+
let h = new AbortController();
|
|
736
|
+
g = h;
|
|
737
|
+
let _ = new Ke((e) => {
|
|
738
|
+
m.html = e;
|
|
739
739
|
}, 25, e.showMath);
|
|
740
|
-
function
|
|
741
|
-
s.value !== "streaming" && (s.value = "streaming",
|
|
740
|
+
function v() {
|
|
741
|
+
s.value !== "streaming" && (s.value = "streaming", m.isStreaming = !0, m.isReceiving = !0, o.value.push(m));
|
|
742
742
|
}
|
|
743
|
-
let
|
|
744
|
-
|
|
745
|
-
}, e.typewriter ?? !0),
|
|
743
|
+
let y = new Ye((e) => {
|
|
744
|
+
v(), m.text += e, _.addChunk(e);
|
|
745
|
+
}, e.typewriter ?? !0), x = null, S = null;
|
|
746
746
|
try {
|
|
747
747
|
let o = await D();
|
|
748
748
|
if (await U(await t.sendMessage(r, o, {
|
|
749
749
|
message: n,
|
|
750
750
|
stream: !0,
|
|
751
751
|
...i === "voice" && { inputMode: "dictation" }
|
|
752
|
-
}, { signal:
|
|
752
|
+
}, { signal: h.signal }), {
|
|
753
753
|
onChunk: (e) => {
|
|
754
|
-
|
|
754
|
+
y.push(e);
|
|
755
755
|
},
|
|
756
756
|
onComplete: () => {},
|
|
757
757
|
onError: (e) => {
|
|
758
|
-
|
|
758
|
+
x = e;
|
|
759
759
|
},
|
|
760
760
|
onMetadata: (e) => {
|
|
761
|
-
e.sources && (
|
|
761
|
+
e.sources && (m.sources = e.sources);
|
|
762
|
+
},
|
|
763
|
+
onRateLimit: ({ limit: e, remaining: t, resetSeconds: n }) => {
|
|
764
|
+
S = {
|
|
765
|
+
limit: e,
|
|
766
|
+
remaining: t,
|
|
767
|
+
resetAt: Number.isFinite(n) ? (/* @__PURE__ */ new Date(n * 1e3)).toISOString() : ""
|
|
768
|
+
};
|
|
762
769
|
},
|
|
763
770
|
onThinkingChunk: (e) => {
|
|
764
|
-
|
|
771
|
+
m.thinking += e;
|
|
765
772
|
}
|
|
766
773
|
}, (e, t) => {
|
|
767
|
-
if (e === "citations" && Array.isArray(t)) return
|
|
774
|
+
if (e === "citations" && Array.isArray(t)) return m.citations = t, !0;
|
|
768
775
|
let n = t ?? {};
|
|
769
|
-
return e === "message_id" && typeof n.messageId == "string" ? (u.basecampMessageId = n.messageId, !0) : e === "assistant_message_id" && typeof n.messageId == "string" ? (
|
|
770
|
-
}),
|
|
771
|
-
if (
|
|
772
|
-
|
|
776
|
+
return e === "message_id" && typeof n.messageId == "string" ? (u.basecampMessageId = n.messageId, !0) : e === "assistant_message_id" && typeof n.messageId == "string" ? (m.basecampMessageId = n.messageId, !0) : e === "used_sources" && Array.isArray(t) ? (m.sources = t, !0) : e === "token_usage" && n.thread ? (l.value = n.thread, !0) : !1;
|
|
777
|
+
}), x) throw x;
|
|
778
|
+
if (h.signal.aborted) {
|
|
779
|
+
y.flush(), await _.complete(), m.isReceiving = !1, m.isStreaming = !1;
|
|
773
780
|
return;
|
|
774
781
|
}
|
|
775
|
-
if (
|
|
776
|
-
await
|
|
782
|
+
if (m.isReceiving = !1, await y.finish(), !m.text) throw Error("The response ended without any content.");
|
|
783
|
+
await _.complete(), m.isOutOfScope = e.isOutOfScope?.(m.text) ?? !1, m.isStreaming = !1, w({
|
|
777
784
|
type: "turn",
|
|
778
785
|
query: n,
|
|
779
786
|
inputMode: i,
|
|
780
|
-
response:
|
|
781
|
-
isOutOfScope:
|
|
782
|
-
citations:
|
|
783
|
-
sources:
|
|
787
|
+
response: m.text,
|
|
788
|
+
isOutOfScope: m.isOutOfScope,
|
|
789
|
+
citations: m.citations,
|
|
790
|
+
sources: m.sources,
|
|
784
791
|
threadId: a.value,
|
|
785
792
|
userMessageId: u.basecampMessageId,
|
|
786
|
-
assistantMessageId:
|
|
793
|
+
assistantMessageId: m.basecampMessageId
|
|
787
794
|
});
|
|
788
795
|
} catch (t) {
|
|
789
|
-
|
|
796
|
+
y.flush(), t?.name !== "AbortError" && (m.text ? m.failed = !0 : c.value = t instanceof Error ? t : Error(String(t))), _.stop(), m.isReceiving = !1, m.isStreaming = !1, m.text && (m.html = await W(m.text, { showMath: e.showMath }));
|
|
790
797
|
} finally {
|
|
791
|
-
|
|
798
|
+
y.destroy(), g = null, p.value = null, s.value = "idle", S ? d.value = S : f();
|
|
792
799
|
}
|
|
793
800
|
}
|
|
794
801
|
async function A() {
|
|
@@ -1034,9 +1041,22 @@ var J = (e) => new Promise((t) => setTimeout(t, e)), et = class {
|
|
|
1034
1041
|
} });
|
|
1035
1042
|
return new Response(m, {
|
|
1036
1043
|
status: 200,
|
|
1037
|
-
headers: {
|
|
1044
|
+
headers: {
|
|
1045
|
+
"Content-Type": "text/event-stream",
|
|
1046
|
+
...this.rateLimitHeaders()
|
|
1047
|
+
}
|
|
1038
1048
|
});
|
|
1039
1049
|
}
|
|
1050
|
+
rateLimitHeaders() {
|
|
1051
|
+
let e = this.options.messageLimit;
|
|
1052
|
+
if (e === void 0) return { "X-RateLimit-Limit": "unlimited" };
|
|
1053
|
+
let t = Math.ceil(this.messageCount / 2);
|
|
1054
|
+
return {
|
|
1055
|
+
"X-RateLimit-Limit": String(e),
|
|
1056
|
+
"X-RateLimit-Remaining": String(Math.max(0, e - t)),
|
|
1057
|
+
"X-RateLimit-Reset": String(Math.floor(new Date(this.quotaResetAt).getTime() / 1e3))
|
|
1058
|
+
};
|
|
1059
|
+
}
|
|
1040
1060
|
async stopMessage() {
|
|
1041
1061
|
return {
|
|
1042
1062
|
success: !0,
|
|
@@ -1271,8 +1291,10 @@ var it = {
|
|
|
1271
1291
|
}, {
|
|
1272
1292
|
default: j(() => [l(Z, { name: "stop" })]),
|
|
1273
1293
|
_: 1
|
|
1274
|
-
}, 8, ["label"])) : (
|
|
1275
|
-
|
|
1294
|
+
}, 8, ["label"])) : w(t.$slots, "send", {
|
|
1295
|
+
send: O,
|
|
1296
|
+
canSend: x.value
|
|
1297
|
+
}, () => [l(X, {
|
|
1276
1298
|
class: "input-bar__send",
|
|
1277
1299
|
label: D(u).composer.sendLabel,
|
|
1278
1300
|
disabled: !x.value,
|
|
@@ -1283,9 +1305,9 @@ var it = {
|
|
|
1283
1305
|
size: 20
|
|
1284
1306
|
})]),
|
|
1285
1307
|
_: 1
|
|
1286
|
-
}, 8, ["label", "disabled"]))])]), w(t.$slots, "footer", {}, void 0, !0)]));
|
|
1308
|
+
}, 8, ["label", "disabled"])], !0, 3)])]), w(t.$slots, "footer", {}, void 0, !0)]));
|
|
1287
1309
|
}
|
|
1288
|
-
}), [["__scopeId", "data-v-
|
|
1310
|
+
}), [["__scopeId", "data-v-4e9c096d"]]), St = 20, Ct = 300, wt = .3, Tt = 12, Et = 8;
|
|
1289
1311
|
function Dt(e, t = {}) {
|
|
1290
1312
|
let n = S("following"), r = !1, i = 0, a = !1, o = null, s = !1, c = () => t.mode?.() ?? "reply";
|
|
1291
1313
|
function l(e) {
|
|
@@ -1728,6 +1750,7 @@ var Mt = { class: "citation-popover__source" }, Nt = ["src"], Pt = { class: "cit
|
|
|
1728
1750
|
e.message.isOutOfScope ? (v(), a("div", Nn, [l(Z, { name: "warning" }), o("span", null, E(D(d).outOfScope.label), 1)])) : i("", !0),
|
|
1729
1751
|
e.showThinking && e.message.thinking ? (v(), r(On, {
|
|
1730
1752
|
key: 1,
|
|
1753
|
+
class: "assistant-message__reasoning",
|
|
1731
1754
|
text: e.message.thinking
|
|
1732
1755
|
}, null, 8, ["text"])) : i("", !0),
|
|
1733
1756
|
o("div", Pn, [o("div", {
|
|
@@ -1769,7 +1792,7 @@ var Mt = { class: "citation-popover__source" }, Nt = ["src"], Pt = { class: "cit
|
|
|
1769
1792
|
w(n.$slots, "message-footer", { message: e.message }, void 0, !0)
|
|
1770
1793
|
]));
|
|
1771
1794
|
}
|
|
1772
|
-
}), [["__scopeId", "data-v-
|
|
1795
|
+
}), [["__scopeId", "data-v-0cff2e6c"]]), Un = { class: "thinking" }, Wn = {
|
|
1773
1796
|
key: 0,
|
|
1774
1797
|
class: "thinking__label"
|
|
1775
1798
|
}, Gn = 2e3, Kn = /*#__PURE__*/ Y(/* @__PURE__ */ u({
|
|
@@ -1893,7 +1916,7 @@ var Mt = { class: "citation-popover__source" }, Nt = ["src"], Pt = { class: "cit
|
|
|
1893
1916
|
}, E(D(u).status.retryLabel), 1)])) : i("", !0)
|
|
1894
1917
|
], 512));
|
|
1895
1918
|
}
|
|
1896
|
-
}), [["__scopeId", "data-v-
|
|
1919
|
+
}), [["__scopeId", "data-v-7817c1d9"]]), rr = { class: "chat" }, ir = /*#__PURE__*/ Y(/* @__PURE__ */ u({
|
|
1897
1920
|
__name: "Chat",
|
|
1898
1921
|
props: {
|
|
1899
1922
|
engine: {},
|
|
@@ -1957,13 +1980,20 @@ var Mt = { class: "citation-popover__source" }, Nt = ["src"], Pt = { class: "cit
|
|
|
1957
1980
|
"show-mic": e.showMic,
|
|
1958
1981
|
onSend: i,
|
|
1959
1982
|
onStop: n[1] ||= () => e.engine.stopGeneration()
|
|
1960
|
-
}, s({ _: 2 }, [t.$slots
|
|
1983
|
+
}, s({ _: 2 }, [t.$slots.send ? {
|
|
1984
|
+
name: "send",
|
|
1985
|
+
fn: j(({ send: e, canSend: n }) => [w(t.$slots, "send", {
|
|
1986
|
+
send: e,
|
|
1987
|
+
canSend: n
|
|
1988
|
+
}, void 0, !0)]),
|
|
1989
|
+
key: "0"
|
|
1990
|
+
} : void 0, t.$slots["composer-footer"] ? {
|
|
1961
1991
|
name: "footer",
|
|
1962
1992
|
fn: j(() => [w(t.$slots, "composer-footer", {}, void 0, !0)]),
|
|
1963
|
-
key: "
|
|
1993
|
+
key: "1"
|
|
1964
1994
|
} : void 0]), 1032, ["busy", "show-mic"])], !0)]));
|
|
1965
1995
|
}
|
|
1966
|
-
}), [["__scopeId", "data-v-
|
|
1996
|
+
}), [["__scopeId", "data-v-7ae994a7"]]);
|
|
1967
1997
|
//#endregion
|
|
1968
1998
|
export { H as AnonymousAuthError, ue as BaseCampClient, le as BaseCampError, ir as Chat, X as IconButton, et as MockTransport, fe as RateLimitError, Ke as StreamingMessage, Ye as Typewriter, U as consumeSSEResponse, ce as createAnonymousTokenProvider, G as decodeHtmlEntities, L as defaultChatCopy, ie as fetchAuthConfig, R as formatCopy, re as provideChatCopy, W as renderMarkdownSafe, Ve as renderMarkdownStreaming, te as resolveChatCopy, se as signInAnonymously, Se as streamSSE, Ge as stripHtmlTags, B as useChatCopy, Qe as useChatEngine };
|
|
1969
1999
|
|