@orbe-agro/client-core 5.6.259 → 5.6.261
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/dist/@ecme/assets/styles/app.css +23 -3
- package/dist/@ecme/assets/styles/tailwind/index.css +25 -3
- package/dist/@ecme/components/layouts/PostLoginLayout/PostLoginLayout.js +2 -1
- package/dist/@ecme/components/layouts/PostLoginLayout/PostLoginLayout.js.map +1 -1
- package/dist/@ecme/components/template/Footer.js +1 -1
- package/dist/@ecme/components/template/OrbeAiWidget/OrbeAiChatDrawer.js +121 -0
- package/dist/@ecme/components/template/OrbeAiWidget/OrbeAiChatDrawer.js.map +1 -0
- package/dist/@ecme/components/template/OrbeAiWidget/OrbeAiWidget.js +47 -18
- package/dist/@ecme/components/template/OrbeAiWidget/OrbeAiWidget.js.map +1 -1
- package/dist/@ecme/components/template/OrbeAiWidget/useResizablePanel.js +45 -31
- package/dist/@ecme/components/template/OrbeAiWidget/useResizablePanel.js.map +1 -1
- package/dist/@ecme/components/ui/Dropdown/DropdownMenu.js +5 -1
- package/dist/@ecme/components/ui/Dropdown/DropdownMenu.js.map +1 -1
- package/dist/@ecme/index.js +4 -1
- package/dist/@ecme/services/AiService.js +22 -0
- package/dist/@ecme/services/AiService.js.map +1 -1
- package/dist/@ecme/services/index.js +4 -1
- package/dist/@ecme/views/concepts/ai/Chat/components/ChatHistory.js +9 -23
- package/dist/@ecme/views/concepts/ai/Chat/components/ChatHistory.js.map +1 -1
- package/dist/@ecme/views/concepts/ai/Chat/components/ChatHistoryItem.js +6 -16
- package/dist/@ecme/views/concepts/ai/Chat/components/ChatHistoryItem.js.map +1 -1
- package/dist/@ecme/views/concepts/ai/Chat/components/ChatHistoryRenameDialog.js +10 -7
- package/dist/@ecme/views/concepts/ai/Chat/components/ChatHistoryRenameDialog.js.map +1 -1
- package/dist/@ecme/views/concepts/ai/Chat/components/ChatView.js +6 -4
- package/dist/@ecme/views/concepts/ai/Chat/components/ChatView.js.map +1 -1
- package/dist/@ecme/views/concepts/ai/Chat/hooks/useChatConversations.js +83 -0
- package/dist/@ecme/views/concepts/ai/Chat/hooks/useChatConversations.js.map +1 -0
- package/dist/@ecme/views/concepts/ai/Chat/hooks/useChatSend.js +3 -2
- package/dist/@ecme/views/concepts/ai/Chat/hooks/useChatSend.js.map +1 -1
- package/dist/@ecme/views/concepts/ai/Chat/hooks/useConversationMessages.js +37 -0
- package/dist/@ecme/views/concepts/ai/Chat/hooks/useConversationMessages.js.map +1 -0
- package/dist/@ecme/views/concepts/ai/Chat/store/generativeChatStore.js +25 -1
- package/dist/@ecme/views/concepts/ai/Chat/store/generativeChatStore.js.map +1 -1
- package/dist/@ecme/views/concepts/ai/Chat/utils.js +16 -1
- package/dist/@ecme/views/concepts/ai/Chat/utils.js.map +1 -1
- package/dist/@types/@ecme/components/layouts/PostLoginLayout/PostLoginLayout.d.ts.map +1 -1
- package/dist/@types/@ecme/components/template/OrbeAiWidget/OrbeAiChatDrawer.d.ts +14 -0
- package/dist/@types/@ecme/components/template/OrbeAiWidget/OrbeAiChatDrawer.d.ts.map +1 -0
- package/dist/@types/@ecme/components/template/OrbeAiWidget/OrbeAiWidget.d.ts.map +1 -1
- package/dist/@types/@ecme/components/template/OrbeAiWidget/useResizablePanel.d.ts +12 -5
- package/dist/@types/@ecme/components/template/OrbeAiWidget/useResizablePanel.d.ts.map +1 -1
- package/dist/@types/@ecme/components/ui/Dropdown/DropdownMenu.d.ts +2 -0
- package/dist/@types/@ecme/components/ui/Dropdown/DropdownMenu.d.ts.map +1 -1
- package/dist/@types/@ecme/services/AiService.d.ts +5 -0
- package/dist/@types/@ecme/services/AiService.d.ts.map +1 -1
- package/dist/@types/@ecme/views/concepts/ai/Chat/components/ChatHistory.d.ts +3 -1
- package/dist/@types/@ecme/views/concepts/ai/Chat/components/ChatHistory.d.ts.map +1 -1
- package/dist/@types/@ecme/views/concepts/ai/Chat/components/ChatHistoryItem.d.ts +1 -1
- package/dist/@types/@ecme/views/concepts/ai/Chat/components/ChatHistoryItem.d.ts.map +1 -1
- package/dist/@types/@ecme/views/concepts/ai/Chat/components/ChatHistoryRenameDialog.d.ts +5 -1
- package/dist/@types/@ecme/views/concepts/ai/Chat/components/ChatHistoryRenameDialog.d.ts.map +1 -1
- package/dist/@types/@ecme/views/concepts/ai/Chat/components/ChatView.d.ts +8 -1
- package/dist/@types/@ecme/views/concepts/ai/Chat/components/ChatView.d.ts.map +1 -1
- package/dist/@types/@ecme/views/concepts/ai/Chat/hooks/useChatConversations.d.ts +12 -0
- package/dist/@types/@ecme/views/concepts/ai/Chat/hooks/useChatConversations.d.ts.map +1 -0
- package/dist/@types/@ecme/views/concepts/ai/Chat/hooks/useChatSend.d.ts.map +1 -1
- package/dist/@types/@ecme/views/concepts/ai/Chat/hooks/useConversationMessages.d.ts +12 -0
- package/dist/@types/@ecme/views/concepts/ai/Chat/hooks/useConversationMessages.d.ts.map +1 -0
- package/dist/@types/@ecme/views/concepts/ai/Chat/store/generativeChatStore.d.ts +4 -0
- package/dist/@types/@ecme/views/concepts/ai/Chat/store/generativeChatStore.d.ts.map +1 -1
- package/dist/@types/@ecme/views/concepts/ai/Chat/types.d.ts +24 -0
- package/dist/@types/@ecme/views/concepts/ai/Chat/types.d.ts.map +1 -1
- package/dist/@types/@ecme/views/concepts/ai/Chat/utils.d.ts +13 -0
- package/dist/@types/@ecme/views/concepts/ai/Chat/utils.d.ts.map +1 -1
- package/dist/@types/base/configs/endpoints.config/endpoints.navigation.d.ts +8 -0
- package/dist/@types/base/configs/endpoints.config/endpoints.navigation.d.ts.map +1 -1
- package/dist/@types/base/configs/endpoints.config/transportadora/contratoFrete.d.ts +8 -0
- package/dist/@types/base/configs/endpoints.config/transportadora/contratoFrete.d.ts.map +1 -1
- package/dist/@types/base/services/modules/transportadora/ContratoFrete/ContratoFreteService.d.ts +2 -0
- package/dist/@types/base/services/modules/transportadora/ContratoFrete/ContratoFreteService.d.ts.map +1 -1
- package/dist/base/assets/styles/init.css +23 -4
- package/dist/base/configs/endpoints.config/transportadora/contratoFrete.js +3 -1
- package/dist/base/configs/endpoints.config/transportadora/contratoFrete.js.map +1 -1
- package/dist/base/index.js +3 -1
- package/dist/base/services/index.js +3 -1
- package/dist/base/services/modules/index.js +3 -1
- package/dist/base/services/modules/transportadora/ContratoFrete/ContratoFreteService.js +14 -0
- package/dist/base/services/modules/transportadora/ContratoFrete/ContratoFreteService.js.map +1 -1
- package/dist/base/services/modules/transportadora/index.js +3 -1
- package/lib/@ecme/components/layouts/PostLoginLayout/PostLoginLayout.tsx +4 -1
- package/lib/@ecme/components/template/OrbeAiWidget/OrbeAiChatDrawer.tsx +140 -0
- package/lib/@ecme/components/template/OrbeAiWidget/OrbeAiWidget.tsx +48 -16
- package/lib/@ecme/components/template/OrbeAiWidget/useResizablePanel.ts +72 -37
- package/lib/@ecme/components/ui/Dropdown/DropdownMenu.tsx +7 -1
- package/lib/@ecme/services/AiService.ts +24 -0
- package/lib/@ecme/views/concepts/ai/Chat/components/ChatHistory.tsx +11 -27
- package/lib/@ecme/views/concepts/ai/Chat/components/ChatHistoryItem.tsx +7 -13
- package/lib/@ecme/views/concepts/ai/Chat/components/ChatHistoryRenameDialog.tsx +17 -8
- package/lib/@ecme/views/concepts/ai/Chat/components/ChatView.tsx +17 -4
- package/lib/@ecme/views/concepts/ai/Chat/hooks/useChatConversations.tsx +128 -0
- package/lib/@ecme/views/concepts/ai/Chat/hooks/useChatSend.ts +3 -2
- package/lib/@ecme/views/concepts/ai/Chat/hooks/useConversationMessages.ts +68 -0
- package/lib/@ecme/views/concepts/ai/Chat/store/generativeChatStore.ts +44 -1
- package/lib/@ecme/views/concepts/ai/Chat/types.ts +28 -0
- package/lib/@ecme/views/concepts/ai/Chat/utils.ts +33 -0
- package/lib/base/configs/endpoints.config/transportadora/contratoFrete.ts +2 -0
- package/lib/base/services/modules/transportadora/ContratoFrete/ContratoFreteService.ts +14 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatView.js","sources":["../../../../../../../lib/@ecme/views/concepts/ai/Chat/components/ChatView.tsx"],"sourcesContent":["import { useRef, useEffect, useMemo } from 'react'\nimport Card from '@/components/ui/Card'\nimport ChatBox from '@/components/view/ChatBox'\nimport ChatLandingView from './ChatLandingView'\nimport ChatMobileNav from './ChatMobileNav'\nimport ChatCustomContent from './ChatCustomContent'\nimport ChatCustomAction from './ChatCustomAction'\nimport AiThinkingIndicator from './AiThinkingIndicator'\nimport AiErrorMessage from './AiErrorMessage'\nimport ToolCallChip from './ToolCallChip'\nimport ApprovalCard from './ApprovalCard'\nimport DataRequestCard from './DataRequestCard'\nimport { usGenerativeChatStore } from '../store/generativeChatStore'\nimport useChatSend from '../hooks/useChatSend'\nimport type { Conversation } from '../types'\nimport type { ScrollBarRef } from '@/components/ui/ScrollBar'\n\n/**\n * O balao de fala do agente, desenhado aqui em vez de vir do ChatBox.\n *\n * O `botBubbleClass` abaixo zera o balao que o Message desenharia, para os chips\n * de ferramenta e o card de aprovacao ficarem FORA dele — antes tudo dividia a\n * mesma caixa cinza e as ferramentas eram lidas como uma segunda mensagem.\n * Usado tambem pelo indicador de \"pensando\", que passa pelo mesmo balao zerado.\n *\n * Repete `prose text-sm` do balao original de proposito: o reset de margem do\n * @tailwindcss/typography e `.prose > :first-child`, filho DIRETO. Sem o `prose`\n * aqui, o markdown ficaria um nivel abaixo do container e o primeiro paragrafo\n * voltaria a ter margem, inflando todos os baloes.\n */\nconst BALAO_AGENTE =\n 'prose rounded-xl bg-gray-100 px-5 py-2.5 text-sm text-gray-900 dark:bg-gray-700 dark:text-gray-100'\n\nconst ChatView = () => {\n const scrollRef = useRef<ScrollBarRef>(null)\n const { selectedConversation, chatHistory, isTyping, disabledChatFresh } =\n usGenerativeChatStore()\n const { handleSend, handleApproval, handleDataSubmit } = useChatSend()\n\n const scrollToBottom = () => {\n if (scrollRef.current?.getScrollElement) {\n const scrollElement = scrollRef.current.getScrollElement()\n if (scrollElement) {\n scrollElement.scrollTop = scrollElement.scrollHeight\n }\n }\n }\n\n useEffect(() => {\n scrollToBottom()\n }, [selectedConversation, chatHistory])\n\n const messageList = useMemo(() => {\n const chat = chatHistory.find(\n (chat) => chat.id === selectedConversation,\n )\n return chat?.conversation || []\n }, [selectedConversation, chatHistory])\n\n const handleInputChange = async ({\n value,\n }: {\n value: string\n attachments?: File[]\n }) => {\n await handleSend(value)\n }\n\n const handleFinish = (id: string) => {\n disabledChatFresh(id)\n scrollToBottom()\n }\n\n return (\n <Card className=\"flex-1 h-full\" bodyClass=\"h-full\">\n <ChatMobileNav />\n <ChatBox\n ref={scrollRef}\n messageList={messageList}\n placeholder=\"Pergunte algo sobre o Orbe Agro…\"\n showMessageList={Boolean(selectedConversation)}\n showAvatar={false}\n avatarGap={false}\n myBubbleClass=\"bg-primary text-white\"\n botBubbleClass=\"bg-transparent dark:bg-transparent p-0 rounded-none\"\n errorBubbleClass=\"bg-red-50 dark:bg-red-500/10 border border-red-200 dark:border-red-500/20\"\n renderTyping={() => (\n <div className={BALAO_AGENTE}>\n <AiThinkingIndicator />\n </div>\n )}\n containerClass=\"h-[calc(100%-30px)] xl:h-full\"\n messageListClass=\"h-[calc(100%-100px)] xl:h-[calc(100%-70px)]\"\n typing={\n isTyping\n ? {\n id: 'ai',\n name: 'Chat AI',\n avatarImageUrl: '/img/thumbs/ai.jpg',\n }\n : false\n }\n customRenderer={(message) => {\n if (message.isError) {\n return <AiErrorMessage />\n }\n\n if (message.sender.id === 'ai') {\n // As ferramentas e as pausas chegam pelo streaming e\n // vivem no Conversation; o tipo do ChatBox nao os conhece.\n const { tools, pendingApproval, pendingInput } =\n message as Conversation\n // Enquanto as ferramentas rodam o conteudo ainda e '':\n // sem esta guarda sobraria um balao cinza vazio.\n const temTexto = Boolean(\n (message.content as string)?.trim(),\n )\n\n return (\n <div className=\"flex flex-col items-start gap-1.5\">\n {tools?.map((tool) => (\n <ToolCallChip key={tool.id} tool={tool} />\n ))}\n {temTexto && (\n <div className={BALAO_AGENTE}>\n <ChatCustomContent\n content={message.content as string}\n triggerTyping={\n message.fresh\n ? message.fresh\n : false\n }\n onFinish={() =>\n handleFinish(message.id)\n }\n />\n </div>\n )}\n {pendingInput && (\n <DataRequestCard\n input={pendingInput}\n onSubmit={(dados) =>\n handleDataSubmit(\n selectedConversation,\n message.id,\n dados,\n )\n }\n />\n )}\n {pendingApproval && (\n <ApprovalCard\n approval={pendingApproval}\n onDecide={(aprovado) =>\n handleApproval(\n selectedConversation,\n message.id,\n aprovado,\n )\n }\n />\n )}\n </div>\n )\n }\n\n return message.content\n }}\n customAction={(message) => {\n if (message.sender.id === 'ai' && !message.isError) {\n return (\n <ChatCustomAction\n content={message.content as string}\n />\n )\n }\n\n return null\n }}\n onInputChange={handleInputChange}\n >\n {!selectedConversation && (\n <div className=\"flex-1 min-h-0 overflow-y-auto\">\n <ChatLandingView />\n </div>\n )}\n </ChatBox>\n </Card>\n )\n}\n\nexport default ChatView\n"],"names":["chat"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ChatView.js","sources":["../../../../../../../lib/@ecme/views/concepts/ai/Chat/components/ChatView.tsx"],"sourcesContent":["import { useRef, useEffect, useMemo } from 'react'\nimport Card from '@/components/ui/Card'\nimport ChatBox from '@/components/view/ChatBox'\nimport ChatLandingView from './ChatLandingView'\nimport ChatMobileNav from './ChatMobileNav'\nimport ChatCustomContent from './ChatCustomContent'\nimport ChatCustomAction from './ChatCustomAction'\nimport AiThinkingIndicator from './AiThinkingIndicator'\nimport AiErrorMessage from './AiErrorMessage'\nimport ToolCallChip from './ToolCallChip'\nimport ApprovalCard from './ApprovalCard'\nimport DataRequestCard from './DataRequestCard'\nimport { usGenerativeChatStore } from '../store/generativeChatStore'\nimport useChatSend from '../hooks/useChatSend'\nimport useConversationMessages from '../hooks/useConversationMessages'\nimport type { Conversation } from '../types'\nimport type { ScrollBarRef } from '@/components/ui/ScrollBar'\n\n/**\n * O balao de fala do agente, desenhado aqui em vez de vir do ChatBox.\n *\n * O `botBubbleClass` abaixo zera o balao que o Message desenharia, para os chips\n * de ferramenta e o card de aprovacao ficarem FORA dele — antes tudo dividia a\n * mesma caixa cinza e as ferramentas eram lidas como uma segunda mensagem.\n * Usado tambem pelo indicador de \"pensando\", que passa pelo mesmo balao zerado.\n *\n * Repete `prose text-sm` do balao original de proposito: o reset de margem do\n * @tailwindcss/typography e `.prose > :first-child`, filho DIRETO. Sem o `prose`\n * aqui, o markdown ficaria um nivel abaixo do container e o primeiro paragrafo\n * voltaria a ter margem, inflando todos os baloes.\n */\nconst BALAO_AGENTE =\n 'prose rounded-xl bg-gray-100 px-5 py-2.5 text-sm text-gray-900 dark:bg-gray-700 dark:text-gray-100'\n\ntype ChatViewProps = {\n /**\n * Mostra o drawer de histórico do ChatMobileNav abaixo de xl. O widget\n * flutuante desliga, porque tem o próprio drawer dentro do painel.\n */\n showMobileNav?: boolean\n}\n\nconst ChatView = ({ showMobileNav = true }: ChatViewProps) => {\n const scrollRef = useRef<ScrollBarRef>(null)\n const { selectedConversation, chatHistory, isTyping, disabledChatFresh } =\n usGenerativeChatStore()\n const { handleSend, handleApproval, handleDataSubmit } = useChatSend()\n // Conversa aberta da lista: as mensagens vêm do backend na primeira vez.\n const { carregando } = useConversationMessages()\n\n const scrollToBottom = () => {\n if (scrollRef.current?.getScrollElement) {\n const scrollElement = scrollRef.current.getScrollElement()\n if (scrollElement) {\n scrollElement.scrollTop = scrollElement.scrollHeight\n }\n }\n }\n\n useEffect(() => {\n scrollToBottom()\n }, [selectedConversation, chatHistory])\n\n const messageList = useMemo(() => {\n const chat = chatHistory.find(\n (chat) => chat.id === selectedConversation,\n )\n return chat?.conversation || []\n }, [selectedConversation, chatHistory])\n\n const handleInputChange = async ({\n value,\n }: {\n value: string\n attachments?: File[]\n }) => {\n await handleSend(value)\n }\n\n const handleFinish = (id: string) => {\n disabledChatFresh(id)\n scrollToBottom()\n }\n\n return (\n <Card className=\"flex-1 h-full\" bodyClass=\"h-full\">\n {showMobileNav && <ChatMobileNav />}\n <ChatBox\n ref={scrollRef}\n messageList={messageList}\n placeholder=\"Pergunte algo sobre o Orbe Agro…\"\n showMessageList={Boolean(selectedConversation)}\n showAvatar={false}\n avatarGap={false}\n myBubbleClass=\"bg-primary text-white\"\n botBubbleClass=\"bg-transparent dark:bg-transparent p-0 rounded-none\"\n errorBubbleClass=\"bg-red-50 dark:bg-red-500/10 border border-red-200 dark:border-red-500/20\"\n renderTyping={() => (\n <div className={BALAO_AGENTE}>\n <AiThinkingIndicator />\n </div>\n )}\n containerClass={\n showMobileNav ? 'h-[calc(100%-30px)] xl:h-full' : 'h-full'\n }\n messageListClass=\"h-[calc(100%-100px)] xl:h-[calc(100%-70px)]\"\n typing={\n isTyping || carregando\n ? {\n id: 'ai',\n name: 'Chat AI',\n avatarImageUrl: '/img/thumbs/ai.jpg',\n }\n : false\n }\n customRenderer={(message) => {\n if (message.isError) {\n return <AiErrorMessage />\n }\n\n if (message.sender.id === 'ai') {\n // As ferramentas e as pausas chegam pelo streaming e\n // vivem no Conversation; o tipo do ChatBox nao os conhece.\n const { tools, pendingApproval, pendingInput } =\n message as Conversation\n // Enquanto as ferramentas rodam o conteudo ainda e '':\n // sem esta guarda sobraria um balao cinza vazio.\n const temTexto = Boolean(\n (message.content as string)?.trim(),\n )\n\n return (\n <div className=\"flex flex-col items-start gap-1.5\">\n {tools?.map((tool) => (\n <ToolCallChip key={tool.id} tool={tool} />\n ))}\n {temTexto && (\n <div className={BALAO_AGENTE}>\n <ChatCustomContent\n content={message.content as string}\n triggerTyping={\n message.fresh\n ? message.fresh\n : false\n }\n onFinish={() =>\n handleFinish(message.id)\n }\n />\n </div>\n )}\n {pendingInput && (\n <DataRequestCard\n input={pendingInput}\n onSubmit={(dados) =>\n handleDataSubmit(\n selectedConversation,\n message.id,\n dados,\n )\n }\n />\n )}\n {pendingApproval && (\n <ApprovalCard\n approval={pendingApproval}\n onDecide={(aprovado) =>\n handleApproval(\n selectedConversation,\n message.id,\n aprovado,\n )\n }\n />\n )}\n </div>\n )\n }\n\n return message.content\n }}\n customAction={(message) => {\n if (message.sender.id === 'ai' && !message.isError) {\n return (\n <ChatCustomAction\n content={message.content as string}\n />\n )\n }\n\n return null\n }}\n onInputChange={handleInputChange}\n >\n {!selectedConversation && (\n <div className=\"flex-1 min-h-0 overflow-y-auto\">\n <ChatLandingView />\n </div>\n )}\n </ChatBox>\n </Card>\n )\n}\n\nexport default ChatView\n"],"names":["chat"],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import useSWR from "swr";
|
|
3
|
+
import "../../../../../components/ui/Notification/index.js";
|
|
4
|
+
import "../../../../../components/ui/toast/index.js";
|
|
5
|
+
import { apiGetConversations, apiDeleteConversation, apiRenameConversation } from "../../../../../services/AiService.js";
|
|
6
|
+
import { useSessionUser } from "../../../../../store/authStore.js";
|
|
7
|
+
import { usGenerativeChatStore } from "../store/generativeChatStore.js";
|
|
8
|
+
import { resumoParaHistorico } from "../utils.js";
|
|
9
|
+
import toast from "../../../../../components/ui/toast/toast.js";
|
|
10
|
+
import Notification from "../../../../../components/ui/Notification/Notification.js";
|
|
11
|
+
const avisarFalha = (mensagem) => {
|
|
12
|
+
toast.push(
|
|
13
|
+
/* @__PURE__ */ jsx(Notification, { type: "danger", duration: 3e3, children: mensagem }),
|
|
14
|
+
{ placement: "top-center" }
|
|
15
|
+
);
|
|
16
|
+
};
|
|
17
|
+
const useChatConversations = () => {
|
|
18
|
+
const {
|
|
19
|
+
setChatHistory,
|
|
20
|
+
setChatHistoryName,
|
|
21
|
+
setSelectedConversation
|
|
22
|
+
} = usGenerativeChatStore();
|
|
23
|
+
const userId = useSessionUser((state) => state.user.userId);
|
|
24
|
+
const signedIn = useSessionUser((state) => state.session.signedIn);
|
|
25
|
+
useSWR(
|
|
26
|
+
signedIn && userId ? ["/ai/chat/conversations", userId] : null,
|
|
27
|
+
// O dono viaja junto com a resposta para o `onSuccess` conferir.
|
|
28
|
+
async ([, dono]) => ({
|
|
29
|
+
dono,
|
|
30
|
+
resumos: await apiGetConversations()
|
|
31
|
+
}),
|
|
32
|
+
{
|
|
33
|
+
revalidateOnFocus: false,
|
|
34
|
+
revalidateOnReconnect: false,
|
|
35
|
+
onSuccess: ({ dono, resumos }) => {
|
|
36
|
+
if (dono !== useSessionUser.getState().user.userId) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const atual = usGenerativeChatStore.getState().chatHistory;
|
|
40
|
+
setChatHistory(mesclar(atual, resumos));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
const remover = async (id) => {
|
|
45
|
+
const { chatHistory, selectedConversation } = usGenerativeChatStore.getState();
|
|
46
|
+
setChatHistory(chatHistory.filter((item) => item.id !== id));
|
|
47
|
+
if (selectedConversation === id) {
|
|
48
|
+
setSelectedConversation("");
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
await apiDeleteConversation(id);
|
|
52
|
+
} catch {
|
|
53
|
+
setChatHistory(chatHistory);
|
|
54
|
+
avisarFalha("Não foi possível excluir a conversa.");
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const renomear = async (id, title) => {
|
|
58
|
+
const anterior = usGenerativeChatStore.getState().chatHistory.find((item) => item.id === id)?.title;
|
|
59
|
+
setChatHistoryName({ id, title });
|
|
60
|
+
try {
|
|
61
|
+
await apiRenameConversation(id, title);
|
|
62
|
+
} catch {
|
|
63
|
+
if (anterior !== void 0) {
|
|
64
|
+
setChatHistoryName({ id, title: anterior });
|
|
65
|
+
}
|
|
66
|
+
avisarFalha("Não foi possível renomear a conversa.");
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
return { remover, renomear };
|
|
70
|
+
};
|
|
71
|
+
function mesclar(atual, resumos) {
|
|
72
|
+
const noStore = new Map(atual.map((chat) => [chat.id, chat]));
|
|
73
|
+
const doBackend = new Set(resumos.map((resumo) => resumo.id));
|
|
74
|
+
const soNaTela = atual.filter((chat) => !doBackend.has(chat.id));
|
|
75
|
+
const daLista = resumos.map(
|
|
76
|
+
(resumo) => noStore.get(resumo.id) ?? resumoParaHistorico(resumo)
|
|
77
|
+
);
|
|
78
|
+
return [...soNaTela, ...daLista];
|
|
79
|
+
}
|
|
80
|
+
export {
|
|
81
|
+
useChatConversations as default
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=useChatConversations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useChatConversations.js","sources":["../../../../../../../lib/@ecme/views/concepts/ai/Chat/hooks/useChatConversations.tsx"],"sourcesContent":["import useSWR from 'swr'\nimport Notification from '@/components/ui/Notification'\nimport toast from '@/components/ui/toast'\nimport {\n apiDeleteConversation,\n apiGetConversations,\n apiRenameConversation,\n} from '@/services/AiService'\nimport { useSessionUser } from '@/store/authStore'\nimport { usGenerativeChatStore } from '../store/generativeChatStore'\nimport { resumoParaHistorico } from '../utils'\nimport type { ChatHistories, GetConversationsResponse } from '../types'\n\nconst avisarFalha = (mensagem: string) => {\n toast.push(\n <Notification type=\"danger\" duration={3000}>\n {mensagem}\n </Notification>,\n { placement: 'top-center' },\n )\n}\n\n/**\n * A lista de conversas do usuário, persistida no backend, e as ações sobre ela.\n *\n * Renomear e excluir são otimistas: a tela muda na hora e volta ao estado\n * anterior se o backend recusar.\n */\nconst useChatConversations = () => {\n const {\n setChatHistory,\n setChatHistoryName,\n setSelectedConversation,\n } = usGenerativeChatStore()\n\n const userId = useSessionUser((state) => state.user.userId)\n const signedIn = useSessionUser((state) => state.session.signedIn)\n\n // O usuário faz parte da chave: cada um tem o próprio cache, e o de quem\n // saiu nunca é servido a quem entrou. Sem sessão, não busca nada.\n //\n // Sem `revalidateIfStale: false` de propósito: cada vez que a lista monta,\n // ela confere o backend. Com ele, o SWR servia o cache antigo, não chamava\n // o `onSuccess`, e a lista só aparecia depois de um F5.\n useSWR(\n signedIn && userId ? ['/ai/chat/conversations', userId] : null,\n // O dono viaja junto com a resposta para o `onSuccess` conferir.\n async ([, dono]: [string, string]) => ({\n dono,\n resumos: await apiGetConversations<GetConversationsResponse>(),\n }),\n {\n revalidateOnFocus: false,\n revalidateOnReconnect: false,\n onSuccess: ({ dono, resumos }) => {\n // Resposta atrasada de quem já saiu: descarta, senão a lista\n // de um usuário cairia na tela do outro.\n if (dono !== useSessionUser.getState().user.userId) {\n return\n }\n // Lido na hora, e não da closure: a resposta pode chegar\n // depois de o usuário já ter começado uma conversa.\n const atual = usGenerativeChatStore.getState().chatHistory\n setChatHistory(mesclar(atual, resumos))\n },\n },\n )\n\n const remover = async (id: string) => {\n const { chatHistory, selectedConversation } =\n usGenerativeChatStore.getState()\n\n setChatHistory(chatHistory.filter((item) => item.id !== id))\n if (selectedConversation === id) {\n setSelectedConversation('')\n }\n\n try {\n await apiDeleteConversation(id)\n } catch {\n setChatHistory(chatHistory)\n avisarFalha('Não foi possível excluir a conversa.')\n }\n }\n\n const renomear = async (id: string, title: string) => {\n const anterior = usGenerativeChatStore\n .getState()\n .chatHistory.find((item) => item.id === id)?.title\n\n setChatHistoryName({ id, title })\n\n try {\n await apiRenameConversation(id, title)\n } catch {\n if (anterior !== undefined) {\n setChatHistoryName({ id, title: anterior })\n }\n avisarFalha('Não foi possível renomear a conversa.')\n }\n }\n\n return { remover, renomear }\n}\n\n/**\n * Junta a lista do backend com o que já está na tela.\n *\n * - Conversa que já existe no store fica como está: pode ter mensagens\n * carregadas ou um stream em andamento.\n * - Conversa criada nesta sessão e que o backend ainda não conhece não pode\n * sumir: ela aparece primeiro, como ao ser criada.\n */\nfunction mesclar(\n atual: ChatHistories,\n resumos: GetConversationsResponse,\n): ChatHistories {\n const noStore = new Map(atual.map((chat) => [chat.id, chat]))\n const doBackend = new Set(resumos.map((resumo) => resumo.id))\n\n const soNaTela = atual.filter((chat) => !doBackend.has(chat.id))\n const daLista = resumos.map(\n (resumo) => noStore.get(resumo.id) ?? resumoParaHistorico(resumo),\n )\n return [...soNaTela, ...daLista]\n}\n\nexport default useChatConversations\n"],"names":[],"mappings":";;;;;;;;;;AAaA,MAAM,cAAc,CAAC,aAAqB;AACtC,QAAM;AAAA,wBACD,cAAA,EAAa,MAAK,UAAS,UAAU,KACjC,UAAA,UACL;AAAA,IACA,EAAE,WAAW,aAAA;AAAA,EAAa;AAElC;AAQA,MAAM,uBAAuB,MAAM;AAC/B,QAAM;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IACA,sBAAA;AAEJ,QAAM,SAAS,eAAe,CAAC,UAAU,MAAM,KAAK,MAAM;AAC1D,QAAM,WAAW,eAAe,CAAC,UAAU,MAAM,QAAQ,QAAQ;AAQjE;AAAA,IACI,YAAY,SAAS,CAAC,0BAA0B,MAAM,IAAI;AAAA;AAAA,IAE1D,OAAO,CAAA,EAAG,IAAI,OAAyB;AAAA,MACnC;AAAA,MACA,SAAS,MAAM,oBAAA;AAAA,IAA8C;AAAA,IAEjE;AAAA,MACI,mBAAmB;AAAA,MACnB,uBAAuB;AAAA,MACvB,WAAW,CAAC,EAAE,MAAM,cAAc;AAG9B,YAAI,SAAS,eAAe,SAAA,EAAW,KAAK,QAAQ;AAChD;AAAA,QACJ;AAGA,cAAM,QAAQ,sBAAsB,SAAA,EAAW;AAC/C,uBAAe,QAAQ,OAAO,OAAO,CAAC;AAAA,MAC1C;AAAA,IAAA;AAAA,EACJ;AAGJ,QAAM,UAAU,OAAO,OAAe;AAClC,UAAM,EAAE,aAAa,yBACjB,sBAAsB,SAAA;AAE1B,mBAAe,YAAY,OAAO,CAAC,SAAS,KAAK,OAAO,EAAE,CAAC;AAC3D,QAAI,yBAAyB,IAAI;AAC7B,8BAAwB,EAAE;AAAA,IAC9B;AAEA,QAAI;AACA,YAAM,sBAAsB,EAAE;AAAA,IAClC,QAAQ;AACJ,qBAAe,WAAW;AAC1B,kBAAY,sCAAsC;AAAA,IACtD;AAAA,EACJ;AAEA,QAAM,WAAW,OAAO,IAAY,UAAkB;AAClD,UAAM,WAAW,sBACZ,SAAA,EACA,YAAY,KAAK,CAAC,SAAS,KAAK,OAAO,EAAE,GAAG;AAEjD,uBAAmB,EAAE,IAAI,OAAO;AAEhC,QAAI;AACA,YAAM,sBAAsB,IAAI,KAAK;AAAA,IACzC,QAAQ;AACJ,UAAI,aAAa,QAAW;AACxB,2BAAmB,EAAE,IAAI,OAAO,SAAA,CAAU;AAAA,MAC9C;AACA,kBAAY,uCAAuC;AAAA,IACvD;AAAA,EACJ;AAEA,SAAO,EAAE,SAAS,SAAA;AACtB;AAUA,SAAS,QACL,OACA,SACa;AACb,QAAM,UAAU,IAAI,IAAI,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;AAC5D,QAAM,YAAY,IAAI,IAAI,QAAQ,IAAI,CAAC,WAAW,OAAO,EAAE,CAAC;AAE5D,QAAM,WAAW,MAAM,OAAO,CAAC,SAAS,CAAC,UAAU,IAAI,KAAK,EAAE,CAAC;AAC/D,QAAM,UAAU,QAAQ;AAAA,IACpB,CAAC,WAAW,QAAQ,IAAI,OAAO,EAAE,KAAK,oBAAoB,MAAM;AAAA,EAAA;AAEpE,SAAO,CAAC,GAAG,UAAU,GAAG,OAAO;AACnC;"}
|
|
@@ -3,6 +3,7 @@ import { streamChat, resumeChat } from "../../../../../services/AiService.js";
|
|
|
3
3
|
import "../../../../../auth/index.js";
|
|
4
4
|
import dayjs from "dayjs";
|
|
5
5
|
import uniqueId from "lodash/uniqueId";
|
|
6
|
+
import { novoIdDeConversa } from "../utils.js";
|
|
6
7
|
import useAuth from "../../../../../auth/useAuth.js";
|
|
7
8
|
const AI_ERROR_MESSAGE = "Desculpe, estou com um pequeno problema de comunicação e não consigo te atender no momento. Tente novamente em instantes.";
|
|
8
9
|
const useChatSend = () => {
|
|
@@ -140,14 +141,14 @@ const useChatSend = () => {
|
|
|
140
141
|
creteMyMessage(selectedConversation, prompt);
|
|
141
142
|
await sendMessage(selectedConversation, prompt);
|
|
142
143
|
} else {
|
|
143
|
-
const newId =
|
|
144
|
+
const newId = novoIdDeConversa();
|
|
144
145
|
pushChatHistory({
|
|
145
146
|
id: newId,
|
|
146
147
|
title: prompt,
|
|
147
148
|
lastConversation: "",
|
|
148
149
|
createdTime: dayjs().unix(),
|
|
149
150
|
updatedTime: dayjs().unix(),
|
|
150
|
-
enable:
|
|
151
|
+
enable: true
|
|
151
152
|
});
|
|
152
153
|
creteMyMessage(newId, prompt);
|
|
153
154
|
await createConversation(newId, prompt);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useChatSend.js","sources":["../../../../../../../lib/@ecme/views/concepts/ai/Chat/hooks/useChatSend.ts"],"sourcesContent":["import { usGenerativeChatStore } from '../store/generativeChatStore'\nimport { resumeChat, streamChat } from '@/services/AiService'\nimport { useAuth } from '@/auth'\nimport dayjs from 'dayjs'\nimport uniqueId from 'lodash/uniqueId'\nimport type { ChatEvent, Conversation, ToolCall } from '../types'\n\n/** Resposta genérica exibida no chat quando a comunicação com a IA falha. */\nconst AI_ERROR_MESSAGE =\n 'Desculpe, estou com um pequeno problema de comunicação e não consigo te atender no momento. Tente novamente em instantes.'\n\nconst useChatSend = () => {\n const { user } = useAuth()\n const {\n selectedConversation,\n setSelectedConversation,\n pushChatHistory,\n pushConversation,\n updateConversation,\n setIsTyping,\n } = usGenerativeChatStore()\n\n const creteMyMessage = (id: string, prompt: string) => {\n pushConversation(id, {\n id: uniqueId('ai-conversation-'),\n sender: {\n id: user.userId ?? 'me',\n name: user.userName ?? 'Você',\n avatarImageUrl: user.avatar ?? undefined,\n },\n content: prompt,\n timestamp: dayjs().toDate(),\n type: 'regular',\n isMyMessage: true,\n })\n }\n\n /**\n * Cria a mensagem da IA vazia e devolve o id, para o streaming preenchê-la.\n *\n * `fresh: false` é obrigatório: `fresh` liga a animação de máquina de\n * escrever do ChatCustomContent, que reinicia do zero a cada mudança de\n * conteúdo — com streaming, o texto ficaria piscando e voltando ao início.\n * A animação agora vem do servidor.\n */\n const createAiMessage = (\n chatId: string,\n options?: Partial<Conversation>,\n ) => {\n const messageId = uniqueId('ai-conversation-')\n pushConversation(chatId, {\n id: messageId,\n sender: {\n id: 'ai',\n name: 'Chat AI',\n avatarImageUrl: '/img/thumbs/ai.jpg',\n },\n content: '',\n timestamp: dayjs().toDate(),\n type: 'regular',\n isMyMessage: false,\n fresh: false,\n ...options,\n })\n return messageId\n }\n\n /**\n * Consome um stream escrevendo numa mensagem que já existe.\n *\n * Compartilhado pelo envio e pela retomada de aprovação: quando o usuário\n * aprova, a resposta continua na MESMA mensagem, então o acumulador de\n * texto e de ferramentas precisa partir do que já está lá.\n */\n const consumirStream = async (\n chatId: string,\n messageId: string,\n executar: (onEvent: (evento: ChatEvent) => void) => Promise<void>,\n inicial: { texto: string; tools: ToolCall[] },\n ) => {\n // Acumulados localmente: o store guarda o resultado, mas ler de volta a\n // cada token para concatenar seria uma corrida com o próprio set().\n let texto = inicial.texto\n let tools = inicial.tools\n\n const aplicar = (evento: ChatEvent) => {\n switch (evento.type) {\n case 'token':\n texto += evento.data.content\n updateConversation(chatId, messageId, { content: texto })\n break\n\n case 'tool_start':\n tools = [\n ...tools,\n {\n id: evento.data.id,\n name: evento.data.name,\n args: evento.data.args,\n running: true,\n },\n ]\n updateConversation(chatId, messageId, { tools })\n break\n\n case 'tool_end':\n tools = tools.map((tool) =>\n tool.id === evento.data.id\n ? {\n ...tool,\n running: false,\n awaitingApproval: false,\n result: evento.data.content,\n isError: evento.data.is_error,\n }\n : tool,\n )\n updateConversation(chatId, messageId, { tools })\n break\n\n case 'approval_required': {\n // O tool_start já marcou estas ferramentas como \"running\".\n // Elas não estão executando: estão paradas esperando o\n // clique — senão o chip giraria para sempre.\n const pausadas = new Set(\n evento.data.calls.map((call) => call.id),\n )\n tools = tools.map((tool) =>\n pausadas.has(tool.id)\n ? { ...tool, running: false, awaitingApproval: true }\n : tool,\n )\n updateConversation(chatId, messageId, {\n tools,\n pendingApproval: evento.data,\n })\n break\n }\n\n case 'input_required':\n // Diferente da aprovação, aqui nenhuma ferramenta foi\n // pedida ao ERP: o agente só percebeu que faltam campos.\n // Por isso não há chip de ferramenta para ajustar.\n updateConversation(chatId, messageId, {\n pendingInput: evento.data,\n })\n break\n\n case 'done':\n // O done é a fonte autoritativa do texto DESTA requisição —\n // se algum token se perdeu, ele corrige.\n //\n // Numa retomada, porém, o que o agente disse ANTES da pausa\n // não vem nele (o backend acumula as falas por requisição):\n // veio em `inicial.texto`. Sem concatenar, a bolha encolhia\n // para só a frase final — \"Vou criar a área para você…\"\n // virava \"Nada foi criado\" — e o agente parecia ter\n // esquecido tudo. No primeiro envio `inicial.texto` é '',\n // então nada muda ali.\n texto = inicial.texto + evento.data.content\n updateConversation(chatId, messageId, { content: texto })\n break\n\n case 'error':\n updateConversation(chatId, messageId, {\n content: evento.data.message || AI_ERROR_MESSAGE,\n isError: true,\n })\n break\n }\n }\n\n try {\n await executar(aplicar)\n } catch {\n updateConversation(chatId, messageId, {\n content: texto || AI_ERROR_MESSAGE,\n isError: !texto,\n })\n } finally {\n setIsTyping(false)\n }\n }\n\n const sendMessage = async (chatId: string, prompt: string) => {\n const messageId = createAiMessage(chatId)\n await consumirStream(\n chatId,\n messageId,\n (onEvent) => streamChat({ prompt, conversationId: chatId, onEvent }),\n { texto: '', tools: [] },\n )\n }\n\n const createConversation = async (chatId: string, prompt: string) => {\n setSelectedConversation(chatId)\n await sendMessage(chatId, prompt)\n }\n\n const handleSend = async (prompt: string) => {\n setIsTyping(true)\n if (selectedConversation) {\n creteMyMessage(selectedConversation, prompt)\n await sendMessage(selectedConversation, prompt)\n } else {\n const newId = uniqueId('ai-chat-')\n pushChatHistory({\n id: newId,\n title: prompt,\n lastConversation: '',\n createdTime: dayjs().unix(),\n updatedTime: dayjs().unix(),\n enable: false,\n })\n creteMyMessage(newId, prompt)\n await createConversation(newId, prompt)\n }\n }\n\n /**\n * Aprova ou nega a operação pendente e retoma a conversa.\n *\n * Continua escrevendo na mesma mensagem: por isso o acumulador parte do\n * conteúdo e das ferramentas que já estão lá.\n */\n const handleApproval = async (\n chatId: string,\n messageId: string,\n approved: boolean,\n ) => {\n const mensagem = usGenerativeChatStore\n .getState()\n .chatHistory.find((chat) => chat.id === chatId)\n ?.conversation?.find((item) => item.id === messageId)\n\n if (!mensagem?.pendingApproval) {\n return\n }\n\n setIsTyping(true)\n // Some com o card antes da chamada: dois cliques rápidos enviariam duas\n // retomadas, e a segunda falha (o interrupt já foi consumido).\n updateConversation(chatId, messageId, { pendingApproval: undefined })\n\n await consumirStream(\n chatId,\n messageId,\n (onEvent) =>\n resumeChat({ approved, conversationId: chatId, onEvent }),\n { texto: mensagem.content ?? '', tools: mensagem.tools ?? [] },\n )\n }\n\n /**\n * Envia os dados que faltavam (ou o cancelamento) e retoma a conversa.\n *\n * Mesma mecânica do `handleApproval`: continua na MESMA mensagem, então o\n * acumulador parte do que já está lá.\n */\n const handleDataSubmit = async (\n chatId: string,\n messageId: string,\n dados: Record<string, unknown> | null,\n ) => {\n const mensagem = usGenerativeChatStore\n .getState()\n .chatHistory.find((chat) => chat.id === chatId)\n ?.conversation?.find((item) => item.id === messageId)\n\n if (!mensagem?.pendingInput) {\n return\n }\n\n setIsTyping(true)\n // Some com o formulário antes da chamada: dois envios mandariam duas\n // retomadas, e a segunda falha (o interrupt já foi consumido).\n updateConversation(chatId, messageId, { pendingInput: undefined })\n\n await consumirStream(\n chatId,\n messageId,\n (onEvent) => resumeChat({ dados, conversationId: chatId, onEvent }),\n { texto: mensagem.content ?? '', tools: mensagem.tools ?? [] },\n )\n }\n\n return {\n handleSend,\n handleApproval,\n handleDataSubmit,\n }\n}\n\nexport default useChatSend\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useChatSend.js","sources":["../../../../../../../lib/@ecme/views/concepts/ai/Chat/hooks/useChatSend.ts"],"sourcesContent":["import { usGenerativeChatStore } from '../store/generativeChatStore'\nimport { resumeChat, streamChat } from '@/services/AiService'\nimport { useAuth } from '@/auth'\nimport dayjs from 'dayjs'\nimport uniqueId from 'lodash/uniqueId'\nimport { novoIdDeConversa } from '../utils'\nimport type { ChatEvent, Conversation, ToolCall } from '../types'\n\n/** Resposta genérica exibida no chat quando a comunicação com a IA falha. */\nconst AI_ERROR_MESSAGE =\n 'Desculpe, estou com um pequeno problema de comunicação e não consigo te atender no momento. Tente novamente em instantes.'\n\nconst useChatSend = () => {\n const { user } = useAuth()\n const {\n selectedConversation,\n setSelectedConversation,\n pushChatHistory,\n pushConversation,\n updateConversation,\n setIsTyping,\n } = usGenerativeChatStore()\n\n const creteMyMessage = (id: string, prompt: string) => {\n pushConversation(id, {\n id: uniqueId('ai-conversation-'),\n sender: {\n id: user.userId ?? 'me',\n name: user.userName ?? 'Você',\n avatarImageUrl: user.avatar ?? undefined,\n },\n content: prompt,\n timestamp: dayjs().toDate(),\n type: 'regular',\n isMyMessage: true,\n })\n }\n\n /**\n * Cria a mensagem da IA vazia e devolve o id, para o streaming preenchê-la.\n *\n * `fresh: false` é obrigatório: `fresh` liga a animação de máquina de\n * escrever do ChatCustomContent, que reinicia do zero a cada mudança de\n * conteúdo — com streaming, o texto ficaria piscando e voltando ao início.\n * A animação agora vem do servidor.\n */\n const createAiMessage = (\n chatId: string,\n options?: Partial<Conversation>,\n ) => {\n const messageId = uniqueId('ai-conversation-')\n pushConversation(chatId, {\n id: messageId,\n sender: {\n id: 'ai',\n name: 'Chat AI',\n avatarImageUrl: '/img/thumbs/ai.jpg',\n },\n content: '',\n timestamp: dayjs().toDate(),\n type: 'regular',\n isMyMessage: false,\n fresh: false,\n ...options,\n })\n return messageId\n }\n\n /**\n * Consome um stream escrevendo numa mensagem que já existe.\n *\n * Compartilhado pelo envio e pela retomada de aprovação: quando o usuário\n * aprova, a resposta continua na MESMA mensagem, então o acumulador de\n * texto e de ferramentas precisa partir do que já está lá.\n */\n const consumirStream = async (\n chatId: string,\n messageId: string,\n executar: (onEvent: (evento: ChatEvent) => void) => Promise<void>,\n inicial: { texto: string; tools: ToolCall[] },\n ) => {\n // Acumulados localmente: o store guarda o resultado, mas ler de volta a\n // cada token para concatenar seria uma corrida com o próprio set().\n let texto = inicial.texto\n let tools = inicial.tools\n\n const aplicar = (evento: ChatEvent) => {\n switch (evento.type) {\n case 'token':\n texto += evento.data.content\n updateConversation(chatId, messageId, { content: texto })\n break\n\n case 'tool_start':\n tools = [\n ...tools,\n {\n id: evento.data.id,\n name: evento.data.name,\n args: evento.data.args,\n running: true,\n },\n ]\n updateConversation(chatId, messageId, { tools })\n break\n\n case 'tool_end':\n tools = tools.map((tool) =>\n tool.id === evento.data.id\n ? {\n ...tool,\n running: false,\n awaitingApproval: false,\n result: evento.data.content,\n isError: evento.data.is_error,\n }\n : tool,\n )\n updateConversation(chatId, messageId, { tools })\n break\n\n case 'approval_required': {\n // O tool_start já marcou estas ferramentas como \"running\".\n // Elas não estão executando: estão paradas esperando o\n // clique — senão o chip giraria para sempre.\n const pausadas = new Set(\n evento.data.calls.map((call) => call.id),\n )\n tools = tools.map((tool) =>\n pausadas.has(tool.id)\n ? { ...tool, running: false, awaitingApproval: true }\n : tool,\n )\n updateConversation(chatId, messageId, {\n tools,\n pendingApproval: evento.data,\n })\n break\n }\n\n case 'input_required':\n // Diferente da aprovação, aqui nenhuma ferramenta foi\n // pedida ao ERP: o agente só percebeu que faltam campos.\n // Por isso não há chip de ferramenta para ajustar.\n updateConversation(chatId, messageId, {\n pendingInput: evento.data,\n })\n break\n\n case 'done':\n // O done é a fonte autoritativa do texto DESTA requisição —\n // se algum token se perdeu, ele corrige.\n //\n // Numa retomada, porém, o que o agente disse ANTES da pausa\n // não vem nele (o backend acumula as falas por requisição):\n // veio em `inicial.texto`. Sem concatenar, a bolha encolhia\n // para só a frase final — \"Vou criar a área para você…\"\n // virava \"Nada foi criado\" — e o agente parecia ter\n // esquecido tudo. No primeiro envio `inicial.texto` é '',\n // então nada muda ali.\n texto = inicial.texto + evento.data.content\n updateConversation(chatId, messageId, { content: texto })\n break\n\n case 'error':\n updateConversation(chatId, messageId, {\n content: evento.data.message || AI_ERROR_MESSAGE,\n isError: true,\n })\n break\n }\n }\n\n try {\n await executar(aplicar)\n } catch {\n updateConversation(chatId, messageId, {\n content: texto || AI_ERROR_MESSAGE,\n isError: !texto,\n })\n } finally {\n setIsTyping(false)\n }\n }\n\n const sendMessage = async (chatId: string, prompt: string) => {\n const messageId = createAiMessage(chatId)\n await consumirStream(\n chatId,\n messageId,\n (onEvent) => streamChat({ prompt, conversationId: chatId, onEvent }),\n { texto: '', tools: [] },\n )\n }\n\n const createConversation = async (chatId: string, prompt: string) => {\n setSelectedConversation(chatId)\n await sendMessage(chatId, prompt)\n }\n\n const handleSend = async (prompt: string) => {\n setIsTyping(true)\n if (selectedConversation) {\n creteMyMessage(selectedConversation, prompt)\n await sendMessage(selectedConversation, prompt)\n } else {\n const newId = novoIdDeConversa()\n pushChatHistory({\n id: newId,\n title: prompt,\n lastConversation: '',\n createdTime: dayjs().unix(),\n updatedTime: dayjs().unix(),\n enable: true,\n })\n creteMyMessage(newId, prompt)\n await createConversation(newId, prompt)\n }\n }\n\n /**\n * Aprova ou nega a operação pendente e retoma a conversa.\n *\n * Continua escrevendo na mesma mensagem: por isso o acumulador parte do\n * conteúdo e das ferramentas que já estão lá.\n */\n const handleApproval = async (\n chatId: string,\n messageId: string,\n approved: boolean,\n ) => {\n const mensagem = usGenerativeChatStore\n .getState()\n .chatHistory.find((chat) => chat.id === chatId)\n ?.conversation?.find((item) => item.id === messageId)\n\n if (!mensagem?.pendingApproval) {\n return\n }\n\n setIsTyping(true)\n // Some com o card antes da chamada: dois cliques rápidos enviariam duas\n // retomadas, e a segunda falha (o interrupt já foi consumido).\n updateConversation(chatId, messageId, { pendingApproval: undefined })\n\n await consumirStream(\n chatId,\n messageId,\n (onEvent) =>\n resumeChat({ approved, conversationId: chatId, onEvent }),\n { texto: mensagem.content ?? '', tools: mensagem.tools ?? [] },\n )\n }\n\n /**\n * Envia os dados que faltavam (ou o cancelamento) e retoma a conversa.\n *\n * Mesma mecânica do `handleApproval`: continua na MESMA mensagem, então o\n * acumulador parte do que já está lá.\n */\n const handleDataSubmit = async (\n chatId: string,\n messageId: string,\n dados: Record<string, unknown> | null,\n ) => {\n const mensagem = usGenerativeChatStore\n .getState()\n .chatHistory.find((chat) => chat.id === chatId)\n ?.conversation?.find((item) => item.id === messageId)\n\n if (!mensagem?.pendingInput) {\n return\n }\n\n setIsTyping(true)\n // Some com o formulário antes da chamada: dois envios mandariam duas\n // retomadas, e a segunda falha (o interrupt já foi consumido).\n updateConversation(chatId, messageId, { pendingInput: undefined })\n\n await consumirStream(\n chatId,\n messageId,\n (onEvent) => resumeChat({ dados, conversationId: chatId, onEvent }),\n { texto: mensagem.content ?? '', tools: mensagem.tools ?? [] },\n )\n }\n\n return {\n handleSend,\n handleApproval,\n handleDataSubmit,\n }\n}\n\nexport default useChatSend\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { useState, useEffect } from "react";
|
|
2
|
+
import { apiGetChatHistory } from "../../../../../services/AiService.js";
|
|
3
|
+
import { usGenerativeChatStore } from "../store/generativeChatStore.js";
|
|
4
|
+
import { mensagemDoHistorico } from "../utils.js";
|
|
5
|
+
const useConversationMessages = () => {
|
|
6
|
+
const { selectedConversation, chatHistory, setConversationMessages } = usGenerativeChatStore();
|
|
7
|
+
const [carregando, setCarregando] = useState(false);
|
|
8
|
+
const pendente = chatHistory.find((chat) => chat.id === selectedConversation)?.loaded === false;
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
if (!selectedConversation || !pendente) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
let cancelado = false;
|
|
14
|
+
setCarregando(true);
|
|
15
|
+
const gravar = (antigas) => {
|
|
16
|
+
const naTela = usGenerativeChatStore.getState().chatHistory.find((chat) => chat.id === selectedConversation)?.conversation ?? [];
|
|
17
|
+
setConversationMessages(selectedConversation, [...antigas, ...naTela]);
|
|
18
|
+
};
|
|
19
|
+
apiGetChatHistory(selectedConversation).then((resposta) => {
|
|
20
|
+
if (cancelado) return;
|
|
21
|
+
gravar((resposta[0]?.conversation ?? []).map(mensagemDoHistorico));
|
|
22
|
+
}).catch(() => {
|
|
23
|
+
if (!cancelado) gravar([]);
|
|
24
|
+
}).finally(() => {
|
|
25
|
+
if (!cancelado) setCarregando(false);
|
|
26
|
+
});
|
|
27
|
+
return () => {
|
|
28
|
+
cancelado = true;
|
|
29
|
+
setCarregando(false);
|
|
30
|
+
};
|
|
31
|
+
}, [selectedConversation, pendente, setConversationMessages]);
|
|
32
|
+
return { carregando };
|
|
33
|
+
};
|
|
34
|
+
export {
|
|
35
|
+
useConversationMessages as default
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=useConversationMessages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useConversationMessages.js","sources":["../../../../../../../lib/@ecme/views/concepts/ai/Chat/hooks/useConversationMessages.ts"],"sourcesContent":["import { useEffect, useState } from 'react'\nimport { apiGetChatHistory } from '@/services/AiService'\nimport { usGenerativeChatStore } from '../store/generativeChatStore'\nimport { mensagemDoHistorico } from '../utils'\nimport type { Conversation, HistoryChat } from '../types'\n\n/**\n * Busca as mensagens da conversa selecionada quando ela veio da lista do\n * backend e ainda não foi aberta nesta sessão.\n *\n * Busca uma vez por conversa: depois disso `loaded` fica true e as mensagens\n * novas chegam pelo streaming, como em qualquer conversa.\n */\nconst useConversationMessages = () => {\n const { selectedConversation, chatHistory, setConversationMessages } =\n usGenerativeChatStore()\n const [carregando, setCarregando] = useState(false)\n\n const pendente =\n chatHistory.find((chat) => chat.id === selectedConversation)?.loaded ===\n false\n\n useEffect(() => {\n if (!selectedConversation || !pendente) {\n return\n }\n\n // Trocar de conversa no meio da busca não pode gravar a resposta\n // atrasada na tela errada.\n let cancelado = false\n setCarregando(true)\n\n // O usuário pode ter enviado algo enquanto a busca corria: o que já\n // está na tela vem depois do histórico, e não some.\n const gravar = (antigas: Conversation[]) => {\n const naTela =\n usGenerativeChatStore\n .getState()\n .chatHistory.find((chat) => chat.id === selectedConversation)\n ?.conversation ?? []\n setConversationMessages(selectedConversation, [...antigas, ...naTela])\n }\n\n apiGetChatHistory<HistoryChat[]>(selectedConversation)\n .then((resposta) => {\n if (cancelado) return\n gravar((resposta[0]?.conversation ?? []).map(mensagemDoHistorico))\n })\n .catch(() => {\n // Marca como carregada mesmo assim: sem isto, cada render\n // tentaria de novo. A conversa segue utilizável, porque a\n // memória está no backend.\n if (!cancelado) gravar([])\n })\n .finally(() => {\n if (!cancelado) setCarregando(false)\n })\n\n return () => {\n cancelado = true\n setCarregando(false)\n }\n }, [selectedConversation, pendente, setConversationMessages])\n\n return { carregando }\n}\n\nexport default useConversationMessages\n"],"names":[],"mappings":";;;;AAaA,MAAM,0BAA0B,MAAM;AAClC,QAAM,EAAE,sBAAsB,aAAa,wBAAA,IACvC,sBAAA;AACJ,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,KAAK;AAElD,QAAM,WACF,YAAY,KAAK,CAAC,SAAS,KAAK,OAAO,oBAAoB,GAAG,WAC9D;AAEJ,YAAU,MAAM;AACZ,QAAI,CAAC,wBAAwB,CAAC,UAAU;AACpC;AAAA,IACJ;AAIA,QAAI,YAAY;AAChB,kBAAc,IAAI;AAIlB,UAAM,SAAS,CAAC,YAA4B;AACxC,YAAM,SACF,sBACK,SAAA,EACA,YAAY,KAAK,CAAC,SAAS,KAAK,OAAO,oBAAoB,GAC1D,gBAAgB,CAAA;AAC1B,8BAAwB,sBAAsB,CAAC,GAAG,SAAS,GAAG,MAAM,CAAC;AAAA,IACzE;AAEA,sBAAiC,oBAAoB,EAChD,KAAK,CAAC,aAAa;AAChB,UAAI,UAAW;AACf,cAAQ,SAAS,CAAC,GAAG,gBAAgB,IAAI,IAAI,mBAAmB,CAAC;AAAA,IACrE,CAAC,EACA,MAAM,MAAM;AAIT,UAAI,CAAC,UAAW,QAAO,EAAE;AAAA,IAC7B,CAAC,EACA,QAAQ,MAAM;AACX,UAAI,CAAC,UAAW,eAAc,KAAK;AAAA,IACvC,CAAC;AAEL,WAAO,MAAM;AACT,kBAAY;AACZ,oBAAc,KAAK;AAAA,IACvB;AAAA,EACJ,GAAG,CAAC,sBAAsB,UAAU,uBAAuB,CAAC;AAE5D,SAAO,EAAE,WAAA;AACb;"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { create } from "zustand";
|
|
2
|
+
import { useSessionUser } from "../../../../../store/authStore.js";
|
|
2
3
|
const initialState = {
|
|
3
4
|
selectedConversation: "",
|
|
4
5
|
selectedConversationRecord: [],
|
|
@@ -12,6 +13,13 @@ const initialState = {
|
|
|
12
13
|
};
|
|
13
14
|
const usGenerativeChatStore = create((set, get) => ({
|
|
14
15
|
...initialState,
|
|
16
|
+
// Arrays novos: `setSelectedConversationRecord` muta o array no lugar, e
|
|
17
|
+
// reusar o do initialState traria de volta o que ele acumulou.
|
|
18
|
+
reset: () => set(() => ({
|
|
19
|
+
...initialState,
|
|
20
|
+
selectedConversationRecord: [],
|
|
21
|
+
chatHistory: []
|
|
22
|
+
})),
|
|
15
23
|
setSelectedConversation: (payload) => set(() => ({ selectedConversation: payload })),
|
|
16
24
|
setChatHistory: (payload) => set(() => ({ chatHistory: payload })),
|
|
17
25
|
setChatHistoryName: (payload) => set(() => {
|
|
@@ -33,7 +41,16 @@ const usGenerativeChatStore = create((set, get) => ({
|
|
|
33
41
|
}
|
|
34
42
|
return { selectedConversationRecord: record };
|
|
35
43
|
}),
|
|
36
|
-
|
|
44
|
+
// Conversa criada nesta sessão já nasce carregada: as mensagens estão aqui,
|
|
45
|
+
// não há o que buscar no backend.
|
|
46
|
+
pushChatHistory: (payload) => set(() => ({
|
|
47
|
+
chatHistory: [{ loaded: true, ...payload }, ...get().chatHistory]
|
|
48
|
+
})),
|
|
49
|
+
setConversationMessages: (id, conversation) => set(() => ({
|
|
50
|
+
chatHistory: get().chatHistory.map(
|
|
51
|
+
(chat) => chat.id === id ? { ...chat, conversation, loaded: true } : chat
|
|
52
|
+
)
|
|
53
|
+
})),
|
|
37
54
|
pushConversation: (id, conversation) => set(() => ({
|
|
38
55
|
chatHistory: get().chatHistory.map(
|
|
39
56
|
(chat) => chat.id === id ? {
|
|
@@ -80,6 +97,13 @@ const usGenerativeChatStore = create((set, get) => ({
|
|
|
80
97
|
return { chatHistory };
|
|
81
98
|
})
|
|
82
99
|
}));
|
|
100
|
+
useSessionUser.subscribe((atual, anterior) => {
|
|
101
|
+
const trocouUsuario = atual.user.userId !== anterior.user.userId;
|
|
102
|
+
const saiu = anterior.session.signedIn && !atual.session.signedIn;
|
|
103
|
+
if (trocouUsuario || saiu) {
|
|
104
|
+
usGenerativeChatStore.getState().reset();
|
|
105
|
+
}
|
|
106
|
+
});
|
|
83
107
|
export {
|
|
84
108
|
usGenerativeChatStore
|
|
85
109
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generativeChatStore.js","sources":["../../../../../../../lib/@ecme/views/concepts/ai/Chat/store/generativeChatStore.ts"],"sourcesContent":["import { create } from 'zustand'\nimport type { ChatHistories, ChatHistory, Conversation } from '../types'\n\ntype RenameDialog = {\n id: string\n title: string\n open: boolean\n}\n\nexport type GenerativeChatState = {\n selectedConversation: string\n selectedConversationRecord: string[]\n chatHistory: ChatHistories\n renameDialog: RenameDialog\n isTyping: boolean\n}\n\ntype GenerativeChatAction = {\n setSelectedConversation: (payload: string) => void\n setSelectedConversationRecord: (payload: string) => void\n setChatHistory: (payload: ChatHistories) => void\n setChatHistoryName: (payload: { id: string; title: string }) => void\n setRenameDialog: (payload: RenameDialog) => void\n setIsTyping: (payload: boolean) => void\n pushChatHistory: (payload: ChatHistory) => void\n pushConversation: (id: string, conversation: Conversation) => void\n updateConversation: (\n chatId: string,\n messageId: string,\n patch: Partial<Conversation>,\n ) => void\n disabledChatFresh: (id: string) => void\n}\n\nconst initialState: GenerativeChatState = {\n selectedConversation: '',\n selectedConversationRecord: [],\n chatHistory: [],\n renameDialog: {\n id: '',\n title: '',\n open: false,\n },\n isTyping: false,\n}\n\nexport const usGenerativeChatStore = create<\n GenerativeChatState & GenerativeChatAction\n>((set, get) => ({\n ...initialState,\n setSelectedConversation: (payload) =>\n set(() => ({ selectedConversation: payload })),\n setChatHistory: (payload) => set(() => ({ chatHistory: payload })),\n setChatHistoryName: (payload) =>\n set(() => {\n const chatHistory = get().chatHistory.map((chat) => {\n if (chat.id === payload.id) {\n chat.title = payload.title\n }\n return chat\n })\n return { chatHistory }\n }),\n setRenameDialog: (payload) => set(() => ({ renameDialog: payload })),\n setSelectedConversationRecord: (payload) =>\n set(() => {\n let record = get().selectedConversationRecord\n\n if (record.includes(payload)) {\n record = record.filter((item) => item !== payload)\n } else {\n record.push(payload)\n }\n\n return { selectedConversationRecord: record }\n }),\n pushChatHistory: (payload) =>\n set(() => ({
|
|
1
|
+
{"version":3,"file":"generativeChatStore.js","sources":["../../../../../../../lib/@ecme/views/concepts/ai/Chat/store/generativeChatStore.ts"],"sourcesContent":["import { create } from 'zustand'\nimport { useSessionUser } from '@/store/authStore'\nimport type { ChatHistories, ChatHistory, Conversation } from '../types'\n\ntype RenameDialog = {\n id: string\n title: string\n open: boolean\n}\n\nexport type GenerativeChatState = {\n selectedConversation: string\n selectedConversationRecord: string[]\n chatHistory: ChatHistories\n renameDialog: RenameDialog\n isTyping: boolean\n}\n\ntype GenerativeChatAction = {\n setSelectedConversation: (payload: string) => void\n setSelectedConversationRecord: (payload: string) => void\n setChatHistory: (payload: ChatHistories) => void\n setChatHistoryName: (payload: { id: string; title: string }) => void\n setRenameDialog: (payload: RenameDialog) => void\n setIsTyping: (payload: boolean) => void\n pushChatHistory: (payload: ChatHistory) => void\n pushConversation: (id: string, conversation: Conversation) => void\n /** Grava as mensagens buscadas no backend e marca a conversa como carregada. */\n setConversationMessages: (id: string, conversation: Conversation[]) => void\n updateConversation: (\n chatId: string,\n messageId: string,\n patch: Partial<Conversation>,\n ) => void\n disabledChatFresh: (id: string) => void\n /** Volta ao estado inicial. Chamado sozinho quando o usuário da sessão muda. */\n reset: () => void\n}\n\nconst initialState: GenerativeChatState = {\n selectedConversation: '',\n selectedConversationRecord: [],\n chatHistory: [],\n renameDialog: {\n id: '',\n title: '',\n open: false,\n },\n isTyping: false,\n}\n\nexport const usGenerativeChatStore = create<\n GenerativeChatState & GenerativeChatAction\n>((set, get) => ({\n ...initialState,\n // Arrays novos: `setSelectedConversationRecord` muta o array no lugar, e\n // reusar o do initialState traria de volta o que ele acumulou.\n reset: () =>\n set(() => ({\n ...initialState,\n selectedConversationRecord: [],\n chatHistory: [],\n })),\n setSelectedConversation: (payload) =>\n set(() => ({ selectedConversation: payload })),\n setChatHistory: (payload) => set(() => ({ chatHistory: payload })),\n setChatHistoryName: (payload) =>\n set(() => {\n const chatHistory = get().chatHistory.map((chat) => {\n if (chat.id === payload.id) {\n chat.title = payload.title\n }\n return chat\n })\n return { chatHistory }\n }),\n setRenameDialog: (payload) => set(() => ({ renameDialog: payload })),\n setSelectedConversationRecord: (payload) =>\n set(() => {\n let record = get().selectedConversationRecord\n\n if (record.includes(payload)) {\n record = record.filter((item) => item !== payload)\n } else {\n record.push(payload)\n }\n\n return { selectedConversationRecord: record }\n }),\n // Conversa criada nesta sessão já nasce carregada: as mensagens estão aqui,\n // não há o que buscar no backend.\n pushChatHistory: (payload) =>\n set(() => ({\n chatHistory: [{ loaded: true, ...payload }, ...get().chatHistory],\n })),\n setConversationMessages: (id, conversation) =>\n set(() => ({\n chatHistory: get().chatHistory.map((chat) =>\n chat.id === id ? { ...chat, conversation, loaded: true } : chat,\n ),\n })),\n pushConversation: (id, conversation) =>\n set(() => ({\n chatHistory: get().chatHistory.map((chat) =>\n chat.id === id\n ? {\n ...chat,\n conversation: [\n ...(chat.conversation ?? []),\n conversation,\n ],\n }\n : chat,\n ),\n })),\n /**\n * Atualiza UMA mensagem de uma conversa.\n *\n * Imutavel de proposito: o streaming chama isto a cada token, e mutar o\n * objeto no lugar faria o React perder atualizacoes — a re-renderizacao\n * dependeria da identidade do array externo mudar por acaso.\n */\n updateConversation: (chatId, messageId, patch) =>\n set(() => ({\n chatHistory: get().chatHistory.map((chat) =>\n chat.id === chatId\n ? {\n ...chat,\n conversation: chat.conversation?.map((mensagem) =>\n mensagem.id === messageId\n ? { ...mensagem, ...patch }\n : mensagem,\n ),\n }\n : chat,\n ),\n })),\n setIsTyping: (payload) => set(() => ({ isTyping: payload })),\n disabledChatFresh: () =>\n set(() => {\n const chatHistory = get().chatHistory.map((chat) => {\n if (chat.id === get().selectedConversation) {\n chat.conversation = chat.conversation?.map(\n (conversation) => {\n if (conversation.fresh) {\n conversation.fresh = false\n }\n return conversation\n },\n )\n }\n return chat\n })\n return { chatHistory }\n }),\n}))\n\n/**\n * O chat pertence ao usuário da sessão: trocou o usuário, zera o chat.\n *\n * Login e logout acontecem sem recarregar a página, e este store é um singleton\n * do módulo. Sem isto, o próximo usuário via as conversas do anterior.\n *\n * Olha o `signedIn` além do `userId` porque o logout faz `setUser({})`, e o\n * `setUser` faz MERGE: o `userId` antigo continua lá depois de sair.\n *\n * É uma assinatura, e não um efeito de componente, para zerar ANTES do próximo\n * render: a lista antiga nem chega a piscar na tela.\n */\nuseSessionUser.subscribe((atual, anterior) => {\n const trocouUsuario = atual.user.userId !== anterior.user.userId\n const saiu = anterior.session.signedIn && !atual.session.signedIn\n if (trocouUsuario || saiu) {\n usGenerativeChatStore.getState().reset()\n }\n})\n"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
import dayjs from "dayjs";
|
|
2
|
+
const novoIdDeConversa = () => crypto.randomUUID();
|
|
3
|
+
const resumoParaHistorico = (resumo) => ({
|
|
4
|
+
...resumo,
|
|
5
|
+
lastConversation: "",
|
|
6
|
+
enable: true,
|
|
7
|
+
loaded: false
|
|
8
|
+
});
|
|
9
|
+
const mensagemDoHistorico = (mensagem) => ({
|
|
10
|
+
...mensagem,
|
|
11
|
+
timestamp: dayjs.unix(mensagem.timestamp).toDate()
|
|
12
|
+
});
|
|
1
13
|
const getStringPosition = (string, subString, index) => {
|
|
2
14
|
return string.split(subString, index).join(" ").length;
|
|
3
15
|
};
|
|
@@ -15,6 +27,9 @@ const getCurrentNodeOverflow = (arr, pos) => {
|
|
|
15
27
|
};
|
|
16
28
|
export {
|
|
17
29
|
getCurrentNodeOverflow,
|
|
18
|
-
getStringPosition
|
|
30
|
+
getStringPosition,
|
|
31
|
+
mensagemDoHistorico,
|
|
32
|
+
novoIdDeConversa,
|
|
33
|
+
resumoParaHistorico
|
|
19
34
|
};
|
|
20
35
|
//# sourceMappingURL=utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../../../../../../lib/@ecme/views/concepts/ai/Chat/utils.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../../../../../lib/@ecme/views/concepts/ai/Chat/utils.ts"],"sourcesContent":["import dayjs from 'dayjs'\nimport type {\n ChatHistory,\n Conversation,\n ConversationSummary,\n HistoryMessage,\n} from './types'\n\n/**\n * Id de uma conversa nova.\n *\n * Precisa ser único entre recargas: o backend guarda a memória por este id.\n * Um contador por página (como o `uniqueId` do lodash) recomeça no F5, e o\n * \"novo chat\" herdaria a memória de uma conversa antiga.\n */\nexport const novoIdDeConversa = (): string => crypto.randomUUID()\n\n/** Conversa da lista do backend, ainda sem as mensagens. */\nexport const resumoParaHistorico = (\n resumo: ConversationSummary,\n): ChatHistory => ({\n ...resumo,\n lastConversation: '',\n enable: true,\n loaded: false,\n})\n\n/** Mensagem do /ai/chat/history no formato do chat (timestamp em Date). */\nexport const mensagemDoHistorico = (mensagem: HistoryMessage): Conversation => ({\n ...mensagem,\n timestamp: dayjs.unix(mensagem.timestamp).toDate(),\n})\n\nexport const getStringPosition = (\n string: string,\n subString: string,\n index: number,\n): number => {\n return string.split(subString, index).join(' ').length\n}\n\nexport const getCurrentNodeOverflow = (\n arr: number[],\n pos: number,\n): [number, number] => {\n let acc = 0\n let index = 0\n for (let i = 0; i < arr.length; i++) {\n if (acc + arr[i] > pos) {\n break\n }\n\n index++\n\n acc += arr[i]\n }\n\n return [index, pos - acc]\n}\n"],"names":[],"mappings":";AAeO,MAAM,mBAAmB,MAAc,OAAO,WAAA;AAG9C,MAAM,sBAAsB,CAC/B,YACe;AAAA,EACf,GAAG;AAAA,EACH,kBAAkB;AAAA,EAClB,QAAQ;AAAA,EACR,QAAQ;AACZ;AAGO,MAAM,sBAAsB,CAAC,cAA4C;AAAA,EAC5E,GAAG;AAAA,EACH,WAAW,MAAM,KAAK,SAAS,SAAS,EAAE,OAAA;AAC9C;AAEO,MAAM,oBAAoB,CAC7B,QACA,WACA,UACS;AACT,SAAO,OAAO,MAAM,WAAW,KAAK,EAAE,KAAK,GAAG,EAAE;AACpD;AAEO,MAAM,yBAAyB,CAClC,KACA,QACmB;AACnB,MAAI,MAAM;AACV,MAAI,QAAQ;AACZ,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACjC,QAAI,MAAM,IAAI,CAAC,IAAI,KAAK;AACpB;AAAA,IACJ;AAEA;AAEA,WAAO,IAAI,CAAC;AAAA,EAChB;AAEA,SAAO,CAAC,OAAO,MAAM,GAAG;AAC5B;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PostLoginLayout.d.ts","sourceRoot":"","sources":["../../../../../../lib/@ecme/components/layouts/PostLoginLayout/PostLoginLayout.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"PostLoginLayout.d.ts","sourceRoot":"","sources":["../../../../../../lib/@ecme/components/layouts/PostLoginLayout/PostLoginLayout.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAa1C,UAAU,oBAAqB,SAAQ,WAAW;IAChD,UAAU,EAAE,UAAU,CAAC;IACvB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAsBD,QAAA,MAAM,eAAe,GAAI,oDAKtB,oBAAoB,4CA8BtB,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
type OrbeAiChatDrawerProps = {
|
|
2
|
+
open: boolean;
|
|
3
|
+
onClose: () => void;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* Drawer de conversas DENTRO do painel do widget.
|
|
7
|
+
*
|
|
8
|
+
* Não usa o Drawer do ui: ele é portalizado no body com overlay em z-30 e
|
|
9
|
+
* abriria atrás do widget (z-40 / z-[9999]), cobrindo a página inteira. Aqui é
|
|
10
|
+
* `absolute`, então fica recortado pelo painel em qualquer tamanho.
|
|
11
|
+
*/
|
|
12
|
+
declare const OrbeAiChatDrawer: ({ open, onClose }: OrbeAiChatDrawerProps) => import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export default OrbeAiChatDrawer;
|
|
14
|
+
//# sourceMappingURL=OrbeAiChatDrawer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OrbeAiChatDrawer.d.ts","sourceRoot":"","sources":["../../../../../../lib/@ecme/components/template/OrbeAiWidget/OrbeAiChatDrawer.tsx"],"names":[],"mappings":"AAUA,KAAK,qBAAqB,GAAG;IACzB,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,EAAE,MAAM,IAAI,CAAA;CACtB,CAAA;AAKD;;;;;;GAMG;AACH,QAAA,MAAM,gBAAgB,GAAI,mBAAmB,qBAAqB,4CAgHjE,CAAA;AAED,eAAe,gBAAgB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OrbeAiWidget.d.ts","sourceRoot":"","sources":["../../../../../../lib/@ecme/components/template/OrbeAiWidget/OrbeAiWidget.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"OrbeAiWidget.d.ts","sourceRoot":"","sources":["../../../../../../lib/@ecme/components/template/OrbeAiWidget/OrbeAiWidget.tsx"],"names":[],"mappings":"AAkBA,QAAA,MAAM,YAAY,+CAsIjB,CAAA;AAED,eAAe,YAAY,CAAA"}
|
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
import type { PointerEvent as ReactPointerEvent } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* `right`/`bottom` são offsets a partir das bordas direita/inferior do
|
|
4
|
+
* viewport — a mesma referência do botão (FAB, `bottom-6 right-6`). Assim,
|
|
5
|
+
* resolução e zoom movem painel e botão juntos.
|
|
6
|
+
*/
|
|
2
7
|
export type Rect = {
|
|
3
|
-
|
|
4
|
-
|
|
8
|
+
right: number;
|
|
9
|
+
bottom: number;
|
|
5
10
|
width: number;
|
|
6
11
|
height: number;
|
|
7
12
|
};
|
|
8
13
|
export type ResizeDirection = 'top' | 'bottom' | 'left' | 'right' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
14
|
+
export declare const MARGIN = 12;
|
|
9
15
|
/**
|
|
10
|
-
* Painel redimensionável por qualquer borda/canto
|
|
11
|
-
*
|
|
12
|
-
*
|
|
16
|
+
* Painel redimensionável por qualquer borda/canto, ancorado no botão. Cada
|
|
17
|
+
* direção move sua borda mantendo a oposta fixa. O tamanho nunca é alterado
|
|
18
|
+
* por mudança de viewport: quem limita é o max-width/max-height do painel.
|
|
13
19
|
*/
|
|
14
20
|
declare const useResizablePanel: () => {
|
|
15
21
|
rect: Rect;
|
|
16
22
|
startResize: (event: ReactPointerEvent, direction: ResizeDirection) => void;
|
|
23
|
+
anchor: () => void;
|
|
17
24
|
};
|
|
18
25
|
export default useResizablePanel;
|
|
19
26
|
//# sourceMappingURL=useResizablePanel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useResizablePanel.d.ts","sourceRoot":"","sources":["../../../../../../lib/@ecme/components/template/OrbeAiWidget/useResizablePanel.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,IAAI,iBAAiB,EAAE,MAAM,OAAO,CAAA;AAE9D,MAAM,MAAM,IAAI,GAAG;IAAE,
|
|
1
|
+
{"version":3,"file":"useResizablePanel.d.ts","sourceRoot":"","sources":["../../../../../../lib/@ecme/components/template/OrbeAiWidget/useResizablePanel.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,IAAI,iBAAiB,EAAE,MAAM,OAAO,CAAA;AAE9D;;;;GAIG;AACH,MAAM,MAAM,IAAI,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAEnF,MAAM,MAAM,eAAe,GACrB,KAAK,GACL,QAAQ,GACR,MAAM,GACN,OAAO,GACP,UAAU,GACV,WAAW,GACX,aAAa,GACb,cAAc,CAAA;AAIpB,eAAO,MAAM,MAAM,KAAK,CAAA;AAmBxB;;;;GAIG;AACH,QAAA,MAAM,iBAAiB;;yBAmBP,iBAAiB,aAAa,eAAe;;CA2E5D,CAAA;AAED,eAAe,iBAAiB,CAAA"}
|
|
@@ -7,6 +7,8 @@ export interface DropdownMenuProps extends CommonProps, DropdownToggleSharedProp
|
|
|
7
7
|
activeKey?: string;
|
|
8
8
|
title?: string | ReactNode;
|
|
9
9
|
menuClass?: string;
|
|
10
|
+
/** Classes do wrapper flutuante (portal). Útil para subir o z-index acima de painéis fixos. */
|
|
11
|
+
floatingClass?: string;
|
|
10
12
|
trigger?: 'click' | 'hover' | 'context';
|
|
11
13
|
placement?: Placement;
|
|
12
14
|
onOpen?: (bool: boolean) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DropdownMenu.d.ts","sourceRoot":"","sources":["../../../../../../lib/@ecme/components/ui/Dropdown/DropdownMenu.tsx"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAA;AACjE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAA;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,KAAK,EAAE,SAAS,EAA0B,SAAS,EAAE,GAAG,EAAE,MAAM,OAAO,CAAA;AAE9E,MAAM,WAAW,iBACb,SAAQ,WAAW,EACf,yBAAyB,EACzB,0BAA0B;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,CAAA;IACvC,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IAChC,GAAG,CAAC,EAAE,GAAG,CAAC,WAAW,GAAG,eAAe,CAAC,CAAA;CAC3C;AAED,MAAM,MAAM,eAAe,GAAG;IAC1B,kBAAkB,EAAE,MAAM,IAAI,CAAA;IAC9B,mBAAmB,EAAE,MAAM,IAAI,CAAA;CAClC,CAAA;AAED,QAAA,MAAM,YAAY,GAAI,OAAO,iBAAiB,GAAG,SAAS,CAAC,WAAW,CAAC,
|
|
1
|
+
{"version":3,"file":"DropdownMenu.d.ts","sourceRoot":"","sources":["../../../../../../lib/@ecme/components/ui/Dropdown/DropdownMenu.tsx"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAA;AACjE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAA;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,KAAK,EAAE,SAAS,EAA0B,SAAS,EAAE,GAAG,EAAE,MAAM,OAAO,CAAA;AAE9E,MAAM,WAAW,iBACb,SAAQ,WAAW,EACf,yBAAyB,EACzB,0BAA0B;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,+FAA+F;IAC/F,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,CAAA;IACvC,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IAChC,GAAG,CAAC,EAAE,GAAG,CAAC,WAAW,GAAG,eAAe,CAAC,CAAA;CAC3C;AAED,MAAM,MAAM,eAAe,GAAG;IAC1B,kBAAkB,EAAE,MAAM,IAAI,CAAA;IAC9B,mBAAmB,EAAE,MAAM,IAAI,CAAA;CAClC,CAAA;AAED,QAAA,MAAM,YAAY,GAAI,OAAO,iBAAiB,GAAG,SAAS,CAAC,WAAW,CAAC,4CA2QtE,CAAA;AAED,eAAe,YAAY,CAAA"}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { ChatEvent } from '@/views/concepts/ai/Chat/types';
|
|
2
2
|
export declare const AI_API_URL: string;
|
|
3
3
|
export declare function apiGetChatHistory<T>(conversationId?: string): Promise<T>;
|
|
4
|
+
/** Conversas do usuário (só o resumo), a mais recente primeiro. */
|
|
5
|
+
export declare function apiGetConversations<T>(): Promise<T>;
|
|
6
|
+
export declare function apiRenameConversation(conversationId: string, title: string): Promise<void>;
|
|
7
|
+
/** Apaga a conversa e toda a memória dela no backend. */
|
|
8
|
+
export declare function apiDeleteConversation(conversationId: string): Promise<void>;
|
|
4
9
|
export type StreamChatParams = {
|
|
5
10
|
prompt: string;
|
|
6
11
|
/** Identifica a conversa; o backend usa como thread da memoria. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiService.d.ts","sourceRoot":"","sources":["../../../../lib/@ecme/services/AiService.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAA;AA0B/D,eAAO,MAAM,UAAU,QAAgB,CAAA;AAcvC,wBAAsB,iBAAiB,CAAC,CAAC,EAAE,cAAc,CAAC,EAAE,MAAM,cAMjE;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,mEAAmE;IACnE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,OAAO,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,CAAA;CACvC,CAAA;AAED;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IACtC,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,OAAO,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,CAAA;CACvC,CAAA;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,EAC7B,MAAM,EACN,cAAc,EACd,MAAM,EACN,OAAO,GACV,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAOlC;AAED;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAAC,EAC7B,QAAQ,EACR,KAAK,EACL,cAAc,EACd,MAAM,EACN,OAAO,GACV,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAOlC;AAiCD,wBAAsB,YAAY,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnE,MAAM,EAAE,CAAC,cAOZ;AAED,wBAAsB,aAAa,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpE,IAAI,EAAE,CAAC,cAOV"}
|
|
1
|
+
{"version":3,"file":"AiService.d.ts","sourceRoot":"","sources":["../../../../lib/@ecme/services/AiService.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAA;AA0B/D,eAAO,MAAM,UAAU,QAAgB,CAAA;AAcvC,wBAAsB,iBAAiB,CAAC,CAAC,EAAE,cAAc,CAAC,EAAE,MAAM,cAMjE;AAED,mEAAmE;AACnE,wBAAsB,mBAAmB,CAAC,CAAC,gBAK1C;AAED,wBAAsB,qBAAqB,CAAC,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,iBAMhF;AAED,yDAAyD;AACzD,wBAAsB,qBAAqB,CAAC,cAAc,EAAE,MAAM,iBAKjE;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,mEAAmE;IACnE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,OAAO,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,CAAA;CACvC,CAAA;AAED;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IACtC,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,OAAO,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,CAAA;CACvC,CAAA;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,EAC7B,MAAM,EACN,cAAc,EACd,MAAM,EACN,OAAO,GACV,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAOlC;AAED;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAAC,EAC7B,QAAQ,EACR,KAAK,EACL,cAAc,EACd,MAAM,EACN,OAAO,GACV,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAOlC;AAiCD,wBAAsB,YAAY,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnE,MAAM,EAAE,CAAC,cAOZ;AAED,wBAAsB,aAAa,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpE,IAAI,EAAE,CAAC,cAOV"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
type ChatHistoryProps = {
|
|
2
2
|
queryText?: string;
|
|
3
3
|
onClick?: () => void;
|
|
4
|
+
/** Repassado ao menu de cada item (ex.: subir o z-index dentro do widget). */
|
|
5
|
+
dropdownFloatingClass?: string;
|
|
4
6
|
};
|
|
5
|
-
declare const ChatHistory: ({ queryText, onClick }: ChatHistoryProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
declare const ChatHistory: ({ queryText, onClick, dropdownFloatingClass, }: ChatHistoryProps) => import("react/jsx-runtime").JSX.Element;
|
|
6
8
|
export default ChatHistory;
|
|
7
9
|
//# sourceMappingURL=ChatHistory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatHistory.d.ts","sourceRoot":"","sources":["../../../../../../../../lib/@ecme/views/concepts/ai/Chat/components/ChatHistory.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ChatHistory.d.ts","sourceRoot":"","sources":["../../../../../../../../lib/@ecme/views/concepts/ai/Chat/components/ChatHistory.tsx"],"names":[],"mappings":"AAMA,KAAK,gBAAgB,GAAG;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,8EAA8E;IAC9E,qBAAqB,CAAC,EAAE,MAAM,CAAA;CACjC,CAAA;AAED,QAAA,MAAM,WAAW,GAAI,gDAIlB,gBAAgB,4CA0DlB,CAAA;AAED,eAAe,WAAW,CAAA"}
|
|
@@ -3,9 +3,9 @@ type ChatHistoryItemProps = {
|
|
|
3
3
|
conversation: string;
|
|
4
4
|
active?: boolean;
|
|
5
5
|
onDelete?: () => void;
|
|
6
|
-
onArchive?: () => void;
|
|
7
6
|
onRename?: () => void;
|
|
8
7
|
onClick?: () => void;
|
|
8
|
+
dropdownFloatingClass?: string;
|
|
9
9
|
};
|
|
10
10
|
declare const ChatHistoryItem: (props: ChatHistoryItemProps) => import("react/jsx-runtime").JSX.Element;
|
|
11
11
|
export default ChatHistoryItem;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatHistoryItem.d.ts","sourceRoot":"","sources":["../../../../../../../../lib/@ecme/views/concepts/ai/Chat/components/ChatHistoryItem.tsx"],"names":[],"mappings":"AAQA,KAAK,oBAAoB,GAAG;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,
|
|
1
|
+
{"version":3,"file":"ChatHistoryItem.d.ts","sourceRoot":"","sources":["../../../../../../../../lib/@ecme/views/concepts/ai/Chat/components/ChatHistoryItem.tsx"],"names":[],"mappings":"AAQA,KAAK,oBAAoB,GAAG;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,qBAAqB,CAAC,EAAE,MAAM,CAAA;CACjC,CAAA;AAED,QAAA,MAAM,eAAe,GAAI,OAAO,oBAAoB,4CAuFnD,CAAA;AAED,eAAe,eAAe,CAAA"}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
type ChatHistoryRenameDialogProps = {
|
|
2
|
+
/** Classes do overlay (ex.: subir o z-index acima do widget flutuante). */
|
|
3
|
+
overlayClassName?: string;
|
|
4
|
+
};
|
|
5
|
+
declare const ChatHistoryRenameDialog: ({ overlayClassName, }: ChatHistoryRenameDialogProps) => import("react/jsx-runtime").JSX.Element;
|
|
2
6
|
export default ChatHistoryRenameDialog;
|
|
3
7
|
//# sourceMappingURL=ChatHistoryRenameDialog.d.ts.map
|
package/dist/@types/@ecme/views/concepts/ai/Chat/components/ChatHistoryRenameDialog.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatHistoryRenameDialog.d.ts","sourceRoot":"","sources":["../../../../../../../../lib/@ecme/views/concepts/ai/Chat/components/ChatHistoryRenameDialog.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ChatHistoryRenameDialog.d.ts","sourceRoot":"","sources":["../../../../../../../../lib/@ecme/views/concepts/ai/Chat/components/ChatHistoryRenameDialog.tsx"],"names":[],"mappings":"AAoBA,KAAK,4BAA4B,GAAG;IAChC,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC5B,CAAA;AAED,QAAA,MAAM,uBAAuB,GAAI,uBAE9B,4BAA4B,4CAkF9B,CAAA;AAED,eAAe,uBAAuB,CAAA"}
|