@firstlovecenter/ai-chat 0.6.1 → 0.8.0
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/CHANGELOG.md +50 -0
- package/dist/drizzle/index.cjs +14 -0
- package/dist/drizzle/index.cjs.map +1 -1
- package/dist/drizzle/index.d.cts +18 -1
- package/dist/drizzle/index.d.ts +18 -1
- package/dist/drizzle/index.js +14 -0
- package/dist/drizzle/index.js.map +1 -1
- package/dist/prisma/index.cjs +6 -0
- package/dist/prisma/index.cjs.map +1 -1
- package/dist/prisma/index.d.cts +4 -1
- package/dist/prisma/index.d.ts +4 -1
- package/dist/prisma/index.js +6 -0
- package/dist/prisma/index.js.map +1 -1
- package/dist/server/index.cjs +169 -12
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +27 -3
- package/dist/server/index.d.ts +27 -3
- package/dist/server/index.js +169 -12
- package/dist/server/index.js.map +1 -1
- package/dist/{types-CQntnyDJ.d.cts → types-BnwUkqKb.d.cts} +8 -0
- package/dist/{types-CQntnyDJ.d.ts → types-BnwUkqKb.d.ts} +8 -0
- package/dist/ui/index.cjs +137 -98
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.cts +15 -2
- package/dist/ui/index.d.ts +15 -2
- package/dist/ui/index.js +137 -98
- package/dist/ui/index.js.map +1 -1
- package/package.json +1 -1
- package/prisma/chat-models.prisma +5 -0
|
@@ -152,6 +152,11 @@ type ChatMessage = {
|
|
|
152
152
|
* `rolePrompt` is the persona the assistant adopts. When non-null, it
|
|
153
153
|
* takes precedence over the host's static `rolePrompt` configureAiChat
|
|
154
154
|
* option, so admins can edit live in the settings UI.
|
|
155
|
+
*
|
|
156
|
+
* `gcpProjectId` is an admin-editable override for the GCP project that
|
|
157
|
+
* every Vertex API call targets. When non-null, it takes precedence over
|
|
158
|
+
* the host's static `VertexPort.projectId` so admins can flip projects
|
|
159
|
+
* (staging ↔ prod, multi-tenant) without redeploying.
|
|
155
160
|
*/
|
|
156
161
|
type AiSettings = {
|
|
157
162
|
toolProvider: string;
|
|
@@ -159,6 +164,7 @@ type AiSettings = {
|
|
|
159
164
|
chatInterface: string;
|
|
160
165
|
maxOutputTokens: number;
|
|
161
166
|
rolePrompt: string | null;
|
|
167
|
+
gcpProjectId: string | null;
|
|
162
168
|
updatedAt: Date | null;
|
|
163
169
|
updatedByUserId: number | null;
|
|
164
170
|
};
|
|
@@ -255,6 +261,8 @@ type AiSettingsPatch = {
|
|
|
255
261
|
maxOutputTokens?: number;
|
|
256
262
|
/** Pass `null` to clear back to the host's static fallback. */
|
|
257
263
|
rolePrompt?: string | null;
|
|
264
|
+
/** Pass `null` to clear back to the host's static VertexPort.projectId. */
|
|
265
|
+
gcpProjectId?: string | null;
|
|
258
266
|
};
|
|
259
267
|
/**
|
|
260
268
|
* The whole reason this package is ORM-agnostic. Implemented by:
|
|
@@ -152,6 +152,11 @@ type ChatMessage = {
|
|
|
152
152
|
* `rolePrompt` is the persona the assistant adopts. When non-null, it
|
|
153
153
|
* takes precedence over the host's static `rolePrompt` configureAiChat
|
|
154
154
|
* option, so admins can edit live in the settings UI.
|
|
155
|
+
*
|
|
156
|
+
* `gcpProjectId` is an admin-editable override for the GCP project that
|
|
157
|
+
* every Vertex API call targets. When non-null, it takes precedence over
|
|
158
|
+
* the host's static `VertexPort.projectId` so admins can flip projects
|
|
159
|
+
* (staging ↔ prod, multi-tenant) without redeploying.
|
|
155
160
|
*/
|
|
156
161
|
type AiSettings = {
|
|
157
162
|
toolProvider: string;
|
|
@@ -159,6 +164,7 @@ type AiSettings = {
|
|
|
159
164
|
chatInterface: string;
|
|
160
165
|
maxOutputTokens: number;
|
|
161
166
|
rolePrompt: string | null;
|
|
167
|
+
gcpProjectId: string | null;
|
|
162
168
|
updatedAt: Date | null;
|
|
163
169
|
updatedByUserId: number | null;
|
|
164
170
|
};
|
|
@@ -255,6 +261,8 @@ type AiSettingsPatch = {
|
|
|
255
261
|
maxOutputTokens?: number;
|
|
256
262
|
/** Pass `null` to clear back to the host's static fallback. */
|
|
257
263
|
rolePrompt?: string | null;
|
|
264
|
+
/** Pass `null` to clear back to the host's static VertexPort.projectId. */
|
|
265
|
+
gcpProjectId?: string | null;
|
|
258
266
|
};
|
|
259
267
|
/**
|
|
260
268
|
* The whole reason this package is ORM-agnostic. Implemented by:
|
package/dist/ui/index.cjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var React = require('react');
|
|
5
|
+
var navigation = require('next/navigation');
|
|
5
6
|
var lucideReact = require('lucide-react');
|
|
6
7
|
var radixUi = require('radix-ui');
|
|
7
8
|
var jsxRuntime = require('react/jsx-runtime');
|
|
@@ -672,10 +673,14 @@ var PROVIDER_DESCRIPTIONS = {
|
|
|
672
673
|
function AiChat({
|
|
673
674
|
userFirstName,
|
|
674
675
|
scopeLabel,
|
|
675
|
-
initialProvider
|
|
676
|
+
initialProvider,
|
|
677
|
+
initialSessionId = null
|
|
676
678
|
}) {
|
|
679
|
+
const router = navigation.useRouter();
|
|
677
680
|
const [sessions, setSessions] = React.useState([]);
|
|
678
|
-
const [activeSessionId, setActiveSessionId] = React.useState(
|
|
681
|
+
const [activeSessionId, setActiveSessionId] = React.useState(
|
|
682
|
+
initialSessionId
|
|
683
|
+
);
|
|
679
684
|
const [answers, setAnswers] = React.useState([]);
|
|
680
685
|
const [pending, setPending] = React.useState(false);
|
|
681
686
|
const [question, setQuestion] = React.useState("");
|
|
@@ -689,7 +694,6 @@ function AiChat({
|
|
|
689
694
|
const textareaRef = React.useRef(null);
|
|
690
695
|
const lastAnswerRef = React.useRef(null);
|
|
691
696
|
const prevAnswersLen = React.useRef(0);
|
|
692
|
-
const autoOpenedRef = React.useRef(false);
|
|
693
697
|
React.useLayoutEffect(() => {
|
|
694
698
|
const el = textareaRef.current;
|
|
695
699
|
if (!el) return;
|
|
@@ -705,33 +709,7 @@ function AiChat({
|
|
|
705
709
|
if (!res.ok) return;
|
|
706
710
|
const data = await res.json();
|
|
707
711
|
if (cancelled) return;
|
|
708
|
-
|
|
709
|
-
setSessions(list);
|
|
710
|
-
if (!autoOpenedRef.current && list.length > 0) {
|
|
711
|
-
autoOpenedRef.current = true;
|
|
712
|
-
const mostRecentId = list[0].id;
|
|
713
|
-
setLoadingSession(true);
|
|
714
|
-
setActiveSessionId(mostRecentId);
|
|
715
|
-
try {
|
|
716
|
-
const sres = await fetch(`/api/chat/sessions/${mostRecentId}`, {
|
|
717
|
-
cache: "no-store"
|
|
718
|
-
});
|
|
719
|
-
if (cancelled) return;
|
|
720
|
-
if (!sres.ok) {
|
|
721
|
-
setAnswers([]);
|
|
722
|
-
return;
|
|
723
|
-
}
|
|
724
|
-
const sdata = await sres.json();
|
|
725
|
-
if (cancelled) return;
|
|
726
|
-
setAnswers(messagesToAnswers(sdata.messages ?? []));
|
|
727
|
-
} catch {
|
|
728
|
-
if (!cancelled) setAnswers([]);
|
|
729
|
-
} finally {
|
|
730
|
-
if (!cancelled) setLoadingSession(false);
|
|
731
|
-
}
|
|
732
|
-
} else if (!autoOpenedRef.current) {
|
|
733
|
-
autoOpenedRef.current = true;
|
|
734
|
-
}
|
|
712
|
+
setSessions(data.sessions ?? []);
|
|
735
713
|
} catch {
|
|
736
714
|
}
|
|
737
715
|
}
|
|
@@ -740,6 +718,35 @@ function AiChat({
|
|
|
740
718
|
cancelled = true;
|
|
741
719
|
};
|
|
742
720
|
}, []);
|
|
721
|
+
React.useEffect(() => {
|
|
722
|
+
if (initialSessionId == null) {
|
|
723
|
+
setAnswers([]);
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
let cancelled = false;
|
|
727
|
+
async function load(id) {
|
|
728
|
+
setLoadingSession(true);
|
|
729
|
+
try {
|
|
730
|
+
const res = await fetch(`/api/chat/sessions/${id}`, { cache: "no-store" });
|
|
731
|
+
if (cancelled) return;
|
|
732
|
+
if (!res.ok) {
|
|
733
|
+
setAnswers([]);
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
const data = await res.json();
|
|
737
|
+
if (cancelled) return;
|
|
738
|
+
setAnswers(messagesToAnswers(data.messages ?? []));
|
|
739
|
+
} catch {
|
|
740
|
+
if (!cancelled) setAnswers([]);
|
|
741
|
+
} finally {
|
|
742
|
+
if (!cancelled) setLoadingSession(false);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
void load(initialSessionId);
|
|
746
|
+
return () => {
|
|
747
|
+
cancelled = true;
|
|
748
|
+
};
|
|
749
|
+
}, [initialSessionId]);
|
|
743
750
|
React.useEffect(() => {
|
|
744
751
|
if (answers.length > prevAnswersLen.current && lastAnswerRef.current) {
|
|
745
752
|
lastAnswerRef.current.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
@@ -755,11 +762,18 @@ function AiChat({
|
|
|
755
762
|
} catch {
|
|
756
763
|
}
|
|
757
764
|
}, []);
|
|
765
|
+
const syncUrl = React.useCallback(
|
|
766
|
+
(id) => {
|
|
767
|
+
router.push(id == null ? "/chat" : `/chat/${id}`);
|
|
768
|
+
},
|
|
769
|
+
[router]
|
|
770
|
+
);
|
|
758
771
|
const newChat = React.useCallback(() => {
|
|
759
772
|
setActiveSessionId(null);
|
|
760
773
|
setAnswers([]);
|
|
761
774
|
setQuestion("");
|
|
762
|
-
|
|
775
|
+
syncUrl(null);
|
|
776
|
+
}, [syncUrl]);
|
|
763
777
|
const changeProvider = React.useCallback(
|
|
764
778
|
async (next) => {
|
|
765
779
|
if (next === provider || providerSaving) return;
|
|
@@ -782,23 +796,27 @@ function AiChat({
|
|
|
782
796
|
},
|
|
783
797
|
[provider, providerSaving]
|
|
784
798
|
);
|
|
785
|
-
const openSession = React.useCallback(
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
799
|
+
const openSession = React.useCallback(
|
|
800
|
+
async (id) => {
|
|
801
|
+
setLoadingSession(true);
|
|
802
|
+
setActiveSessionId(id);
|
|
803
|
+
syncUrl(id);
|
|
804
|
+
try {
|
|
805
|
+
const res = await fetch(`/api/chat/sessions/${id}`, { cache: "no-store" });
|
|
806
|
+
if (!res.ok) {
|
|
807
|
+
setAnswers([]);
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
const data = await res.json();
|
|
811
|
+
setAnswers(messagesToAnswers(data.messages ?? []));
|
|
812
|
+
} catch {
|
|
791
813
|
setAnswers([]);
|
|
792
|
-
|
|
814
|
+
} finally {
|
|
815
|
+
setLoadingSession(false);
|
|
793
816
|
}
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
setAnswers([]);
|
|
798
|
-
} finally {
|
|
799
|
-
setLoadingSession(false);
|
|
800
|
-
}
|
|
801
|
-
}, []);
|
|
817
|
+
},
|
|
818
|
+
[syncUrl]
|
|
819
|
+
);
|
|
802
820
|
const persistTitle = React.useCallback(
|
|
803
821
|
async (id, title) => {
|
|
804
822
|
const trimmed = title.trim();
|
|
@@ -828,9 +846,10 @@ function AiChat({
|
|
|
828
846
|
if (activeSessionId === id) {
|
|
829
847
|
setActiveSessionId(null);
|
|
830
848
|
setAnswers([]);
|
|
849
|
+
syncUrl(null);
|
|
831
850
|
}
|
|
832
851
|
},
|
|
833
|
-
[activeSessionId]
|
|
852
|
+
[activeSessionId, syncUrl]
|
|
834
853
|
);
|
|
835
854
|
const submit = React.useCallback(
|
|
836
855
|
async (q) => {
|
|
@@ -850,6 +869,7 @@ function AiChat({
|
|
|
850
869
|
const data = await create.json();
|
|
851
870
|
sessionId = data.session.id;
|
|
852
871
|
setActiveSessionId(sessionId);
|
|
872
|
+
syncUrl(sessionId);
|
|
853
873
|
setSessions((prev) => [
|
|
854
874
|
{ id: data.session.id, title: data.session.title, updatedAt: null },
|
|
855
875
|
...prev
|
|
@@ -930,7 +950,7 @@ function AiChat({
|
|
|
930
950
|
void refreshSessions();
|
|
931
951
|
}
|
|
932
952
|
},
|
|
933
|
-
[activeSessionId, pending, refreshSessions]
|
|
953
|
+
[activeSessionId, pending, refreshSessions, syncUrl]
|
|
934
954
|
);
|
|
935
955
|
const heroVisible = answers.length === 0 && !loadingSession;
|
|
936
956
|
const greeting = React.useMemo(
|
|
@@ -1491,10 +1511,14 @@ function asDataPart(v) {
|
|
|
1491
1511
|
function VercelChat({
|
|
1492
1512
|
userFirstName,
|
|
1493
1513
|
scopeLabel,
|
|
1494
|
-
initialProvider
|
|
1514
|
+
initialProvider,
|
|
1515
|
+
initialSessionId = null
|
|
1495
1516
|
}) {
|
|
1517
|
+
const router = navigation.useRouter();
|
|
1496
1518
|
const [sessions, setSessions] = React.useState([]);
|
|
1497
|
-
const [activeSessionId, setActiveSessionId] = React.useState(
|
|
1519
|
+
const [activeSessionId, setActiveSessionId] = React.useState(
|
|
1520
|
+
initialSessionId
|
|
1521
|
+
);
|
|
1498
1522
|
const [sidebarOpen, setSidebarOpen] = React.useState(false);
|
|
1499
1523
|
const [loadingSession, setLoadingSession] = React.useState(false);
|
|
1500
1524
|
const [provider, setProvider] = React.useState(initialProvider);
|
|
@@ -1508,7 +1532,6 @@ function VercelChat({
|
|
|
1508
1532
|
const textareaRef = React.useRef(null);
|
|
1509
1533
|
const lastAnswerRef = React.useRef(null);
|
|
1510
1534
|
const prevAnswersLen = React.useRef(0);
|
|
1511
|
-
const autoOpenedRef = React.useRef(false);
|
|
1512
1535
|
const activeSessionIdRef = React.useRef(activeSessionId);
|
|
1513
1536
|
const providerRef = React.useRef(provider);
|
|
1514
1537
|
React.useEffect(() => {
|
|
@@ -1564,48 +1587,7 @@ function VercelChat({
|
|
|
1564
1587
|
if (!res.ok) return;
|
|
1565
1588
|
const json = await res.json();
|
|
1566
1589
|
if (cancelled) return;
|
|
1567
|
-
|
|
1568
|
-
setSessions(list);
|
|
1569
|
-
if (!autoOpenedRef.current && list.length > 0) {
|
|
1570
|
-
autoOpenedRef.current = true;
|
|
1571
|
-
const mostRecentId = list[0].id;
|
|
1572
|
-
setLoadingSession(true);
|
|
1573
|
-
setActiveSessionId(mostRecentId);
|
|
1574
|
-
try {
|
|
1575
|
-
const sres = await fetch(`/api/chat/sessions/${mostRecentId}`, {
|
|
1576
|
-
cache: "no-store"
|
|
1577
|
-
});
|
|
1578
|
-
if (cancelled) return;
|
|
1579
|
-
if (!sres.ok) {
|
|
1580
|
-
setMessages([]);
|
|
1581
|
-
setHydratedBlocks({});
|
|
1582
|
-
setHydratedProse({});
|
|
1583
|
-
setHydratedErrors({});
|
|
1584
|
-
return;
|
|
1585
|
-
}
|
|
1586
|
-
const sjson = await sres.json();
|
|
1587
|
-
if (cancelled) return;
|
|
1588
|
-
const { uiMessages, blocksMap, proseMap, errorsMap } = storedToUseChat(
|
|
1589
|
-
sjson.messages ?? []
|
|
1590
|
-
);
|
|
1591
|
-
setMessages(uiMessages);
|
|
1592
|
-
setHydratedBlocks(blocksMap);
|
|
1593
|
-
setHydratedProse(proseMap);
|
|
1594
|
-
setHydratedErrors(errorsMap);
|
|
1595
|
-
setStartedAt({});
|
|
1596
|
-
} catch {
|
|
1597
|
-
if (!cancelled) {
|
|
1598
|
-
setMessages([]);
|
|
1599
|
-
setHydratedBlocks({});
|
|
1600
|
-
setHydratedProse({});
|
|
1601
|
-
setHydratedErrors({});
|
|
1602
|
-
}
|
|
1603
|
-
} finally {
|
|
1604
|
-
if (!cancelled) setLoadingSession(false);
|
|
1605
|
-
}
|
|
1606
|
-
} else if (!autoOpenedRef.current) {
|
|
1607
|
-
autoOpenedRef.current = true;
|
|
1608
|
-
}
|
|
1590
|
+
setSessions(json.sessions ?? []);
|
|
1609
1591
|
} catch {
|
|
1610
1592
|
}
|
|
1611
1593
|
}
|
|
@@ -1613,7 +1595,54 @@ function VercelChat({
|
|
|
1613
1595
|
return () => {
|
|
1614
1596
|
cancelled = true;
|
|
1615
1597
|
};
|
|
1616
|
-
}, [
|
|
1598
|
+
}, []);
|
|
1599
|
+
React.useEffect(() => {
|
|
1600
|
+
if (initialSessionId == null) {
|
|
1601
|
+
setMessages([]);
|
|
1602
|
+
setHydratedBlocks({});
|
|
1603
|
+
setHydratedProse({});
|
|
1604
|
+
setHydratedErrors({});
|
|
1605
|
+
return;
|
|
1606
|
+
}
|
|
1607
|
+
let cancelled = false;
|
|
1608
|
+
async function load(id) {
|
|
1609
|
+
setLoadingSession(true);
|
|
1610
|
+
try {
|
|
1611
|
+
const res = await fetch(`/api/chat/sessions/${id}`, { cache: "no-store" });
|
|
1612
|
+
if (cancelled) return;
|
|
1613
|
+
if (!res.ok) {
|
|
1614
|
+
setMessages([]);
|
|
1615
|
+
setHydratedBlocks({});
|
|
1616
|
+
setHydratedProse({});
|
|
1617
|
+
setHydratedErrors({});
|
|
1618
|
+
return;
|
|
1619
|
+
}
|
|
1620
|
+
const json = await res.json();
|
|
1621
|
+
if (cancelled) return;
|
|
1622
|
+
const { uiMessages, blocksMap, proseMap, errorsMap } = storedToUseChat(
|
|
1623
|
+
json.messages ?? []
|
|
1624
|
+
);
|
|
1625
|
+
setMessages(uiMessages);
|
|
1626
|
+
setHydratedBlocks(blocksMap);
|
|
1627
|
+
setHydratedProse(proseMap);
|
|
1628
|
+
setHydratedErrors(errorsMap);
|
|
1629
|
+
setStartedAt({});
|
|
1630
|
+
} catch {
|
|
1631
|
+
if (!cancelled) {
|
|
1632
|
+
setMessages([]);
|
|
1633
|
+
setHydratedBlocks({});
|
|
1634
|
+
setHydratedProse({});
|
|
1635
|
+
setHydratedErrors({});
|
|
1636
|
+
}
|
|
1637
|
+
} finally {
|
|
1638
|
+
if (!cancelled) setLoadingSession(false);
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
void load(initialSessionId);
|
|
1642
|
+
return () => {
|
|
1643
|
+
cancelled = true;
|
|
1644
|
+
};
|
|
1645
|
+
}, [initialSessionId, setMessages]);
|
|
1617
1646
|
const answers = React.useMemo(() => {
|
|
1618
1647
|
const liveBlocks = [];
|
|
1619
1648
|
const liveErrors = [];
|
|
@@ -1712,6 +1741,12 @@ function VercelChat({
|
|
|
1712
1741
|
}
|
|
1713
1742
|
prevAnswersLen.current = answers.length;
|
|
1714
1743
|
}, [answers.length]);
|
|
1744
|
+
const syncUrl = React.useCallback(
|
|
1745
|
+
(id) => {
|
|
1746
|
+
router.push(id == null ? "/chat" : `/chat/${id}`);
|
|
1747
|
+
},
|
|
1748
|
+
[router]
|
|
1749
|
+
);
|
|
1715
1750
|
const newChat = React.useCallback(() => {
|
|
1716
1751
|
setActiveSessionId(null);
|
|
1717
1752
|
setMessages([]);
|
|
@@ -1720,7 +1755,8 @@ function VercelChat({
|
|
|
1720
1755
|
setHydratedErrors({});
|
|
1721
1756
|
setStartedAt({});
|
|
1722
1757
|
setInput("");
|
|
1723
|
-
|
|
1758
|
+
syncUrl(null);
|
|
1759
|
+
}, [setMessages, setInput, syncUrl]);
|
|
1724
1760
|
const changeProvider = React.useCallback(
|
|
1725
1761
|
async (next) => {
|
|
1726
1762
|
if (next === provider || providerSaving) return;
|
|
@@ -1747,6 +1783,7 @@ function VercelChat({
|
|
|
1747
1783
|
async (id) => {
|
|
1748
1784
|
setLoadingSession(true);
|
|
1749
1785
|
setActiveSessionId(id);
|
|
1786
|
+
syncUrl(id);
|
|
1750
1787
|
try {
|
|
1751
1788
|
const res = await fetch(`/api/chat/sessions/${id}`, { cache: "no-store" });
|
|
1752
1789
|
if (!res.ok) {
|
|
@@ -1774,7 +1811,7 @@ function VercelChat({
|
|
|
1774
1811
|
setLoadingSession(false);
|
|
1775
1812
|
}
|
|
1776
1813
|
},
|
|
1777
|
-
[setMessages]
|
|
1814
|
+
[setMessages, syncUrl]
|
|
1778
1815
|
);
|
|
1779
1816
|
const persistTitle = React.useCallback(
|
|
1780
1817
|
async (id, title) => {
|
|
@@ -1808,9 +1845,10 @@ function VercelChat({
|
|
|
1808
1845
|
setHydratedBlocks({});
|
|
1809
1846
|
setHydratedProse({});
|
|
1810
1847
|
setHydratedErrors({});
|
|
1848
|
+
syncUrl(null);
|
|
1811
1849
|
}
|
|
1812
1850
|
},
|
|
1813
|
-
[activeSessionId, setMessages]
|
|
1851
|
+
[activeSessionId, setMessages, syncUrl]
|
|
1814
1852
|
);
|
|
1815
1853
|
const submitForm = React.useCallback(
|
|
1816
1854
|
async (e) => {
|
|
@@ -1827,6 +1865,7 @@ function VercelChat({
|
|
|
1827
1865
|
const json = await create.json();
|
|
1828
1866
|
activeSessionIdRef.current = json.session.id;
|
|
1829
1867
|
setActiveSessionId(json.session.id);
|
|
1868
|
+
syncUrl(json.session.id);
|
|
1830
1869
|
setSessions((prev) => [
|
|
1831
1870
|
{ id: json.session.id, title: json.session.title, updatedAt: null },
|
|
1832
1871
|
...prev
|
|
@@ -1837,7 +1876,7 @@ function VercelChat({
|
|
|
1837
1876
|
}
|
|
1838
1877
|
handleSubmit(e);
|
|
1839
1878
|
},
|
|
1840
|
-
[input, status, handleSubmit]
|
|
1879
|
+
[input, status, handleSubmit, syncUrl]
|
|
1841
1880
|
);
|
|
1842
1881
|
React.useEffect(() => {
|
|
1843
1882
|
setStartedAt((prev) => {
|