allow the user to edit assistant messages like in LM Studio
This commit is contained in:
parent
a1cef450de
commit
7a53228341
13
.vscode/settings.json
vendored
13
.vscode/settings.json
vendored
@ -1,4 +1,15 @@
|
|||||||
{
|
{
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||||
"editor.formatOnSave": true
|
"editor.formatOnSave": true,
|
||||||
|
"eslint.workingDirectories": [
|
||||||
|
{
|
||||||
|
"directory": "./web-app"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"directory": "./electron"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"directory": "./docs"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -659,64 +659,89 @@ __metadata:
|
|||||||
|
|
||||||
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fassistant-extension%40workspace%3Aassistant-extension":
|
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fassistant-extension%40workspace%3Aassistant-extension":
|
||||||
version: 0.1.10
|
version: 0.1.10
|
||||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=5531aa&locator=%40janhq%2Fassistant-extension%40workspace%3Aassistant-extension"
|
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=7c4a2a&locator=%40janhq%2Fassistant-extension%40workspace%3Aassistant-extension"
|
||||||
dependencies:
|
dependencies:
|
||||||
rxjs: "npm:^7.8.1"
|
rxjs: "npm:^7.8.1"
|
||||||
ulidx: "npm:^2.3.0"
|
ulidx: "npm:^2.3.0"
|
||||||
checksum: 10c0/ee7fe21267cf795dba890781d1e7807a6cb3ecb915ce9ecbd3a8386a2ebc916a8b70a775ce5d9d9f74d2ec29e20b65cea4ef6cdd0ea250a8ff2d5e6bd2237b1e
|
checksum: 10c0/4708652e05a82d5fb6111708b0f6a9d764ac14032613b8d0edacaaa32d08593a0e4226f50806165da57fde8ad8e3dfe52a141b0d093a45d749a460f5cf869889
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fconversational-extension%40workspace%3Aconversational-extension":
|
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fconversational-extension%40workspace%3Aconversational-extension":
|
||||||
version: 0.1.10
|
version: 0.1.10
|
||||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=5531aa&locator=%40janhq%2Fconversational-extension%40workspace%3Aconversational-extension"
|
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=7c4a2a&locator=%40janhq%2Fconversational-extension%40workspace%3Aconversational-extension"
|
||||||
dependencies:
|
dependencies:
|
||||||
rxjs: "npm:^7.8.1"
|
rxjs: "npm:^7.8.1"
|
||||||
ulidx: "npm:^2.3.0"
|
ulidx: "npm:^2.3.0"
|
||||||
checksum: 10c0/ee7fe21267cf795dba890781d1e7807a6cb3ecb915ce9ecbd3a8386a2ebc916a8b70a775ce5d9d9f74d2ec29e20b65cea4ef6cdd0ea250a8ff2d5e6bd2237b1e
|
checksum: 10c0/4708652e05a82d5fb6111708b0f6a9d764ac14032613b8d0edacaaa32d08593a0e4226f50806165da57fde8ad8e3dfe52a141b0d093a45d749a460f5cf869889
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fdownload-extension%40workspace%3Adownload-extension":
|
||||||
|
version: 0.1.10
|
||||||
|
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=7c4a2a&locator=%40janhq%2Fdownload-extension%40workspace%3Adownload-extension"
|
||||||
|
dependencies:
|
||||||
|
rxjs: "npm:^7.8.1"
|
||||||
|
ulidx: "npm:^2.3.0"
|
||||||
|
checksum: 10c0/4708652e05a82d5fb6111708b0f6a9d764ac14032613b8d0edacaaa32d08593a0e4226f50806165da57fde8ad8e3dfe52a141b0d093a45d749a460f5cf869889
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fengine-management-extension%40workspace%3Aengine-management-extension":
|
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fengine-management-extension%40workspace%3Aengine-management-extension":
|
||||||
version: 0.1.10
|
version: 0.1.10
|
||||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=5531aa&locator=%40janhq%2Fengine-management-extension%40workspace%3Aengine-management-extension"
|
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=7c4a2a&locator=%40janhq%2Fengine-management-extension%40workspace%3Aengine-management-extension"
|
||||||
dependencies:
|
dependencies:
|
||||||
rxjs: "npm:^7.8.1"
|
rxjs: "npm:^7.8.1"
|
||||||
ulidx: "npm:^2.3.0"
|
ulidx: "npm:^2.3.0"
|
||||||
checksum: 10c0/ee7fe21267cf795dba890781d1e7807a6cb3ecb915ce9ecbd3a8386a2ebc916a8b70a775ce5d9d9f74d2ec29e20b65cea4ef6cdd0ea250a8ff2d5e6bd2237b1e
|
checksum: 10c0/4708652e05a82d5fb6111708b0f6a9d764ac14032613b8d0edacaaa32d08593a0e4226f50806165da57fde8ad8e3dfe52a141b0d093a45d749a460f5cf869889
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fhardware-management-extension%40workspace%3Ahardware-management-extension":
|
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fhardware-management-extension%40workspace%3Ahardware-management-extension":
|
||||||
version: 0.1.10
|
version: 0.1.10
|
||||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=5531aa&locator=%40janhq%2Fhardware-management-extension%40workspace%3Ahardware-management-extension"
|
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=7c4a2a&locator=%40janhq%2Fhardware-management-extension%40workspace%3Ahardware-management-extension"
|
||||||
dependencies:
|
dependencies:
|
||||||
rxjs: "npm:^7.8.1"
|
rxjs: "npm:^7.8.1"
|
||||||
ulidx: "npm:^2.3.0"
|
ulidx: "npm:^2.3.0"
|
||||||
checksum: 10c0/ee7fe21267cf795dba890781d1e7807a6cb3ecb915ce9ecbd3a8386a2ebc916a8b70a775ce5d9d9f74d2ec29e20b65cea4ef6cdd0ea250a8ff2d5e6bd2237b1e
|
checksum: 10c0/4708652e05a82d5fb6111708b0f6a9d764ac14032613b8d0edacaaa32d08593a0e4226f50806165da57fde8ad8e3dfe52a141b0d093a45d749a460f5cf869889
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Finference-cortex-extension%40workspace%3Ainference-cortex-extension":
|
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Finference-cortex-extension%40workspace%3Ainference-cortex-extension":
|
||||||
version: 0.1.10
|
version: 0.1.10
|
||||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=5531aa&locator=%40janhq%2Finference-cortex-extension%40workspace%3Ainference-cortex-extension"
|
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=7c4a2a&locator=%40janhq%2Finference-cortex-extension%40workspace%3Ainference-cortex-extension"
|
||||||
dependencies:
|
dependencies:
|
||||||
rxjs: "npm:^7.8.1"
|
rxjs: "npm:^7.8.1"
|
||||||
ulidx: "npm:^2.3.0"
|
ulidx: "npm:^2.3.0"
|
||||||
checksum: 10c0/ee7fe21267cf795dba890781d1e7807a6cb3ecb915ce9ecbd3a8386a2ebc916a8b70a775ce5d9d9f74d2ec29e20b65cea4ef6cdd0ea250a8ff2d5e6bd2237b1e
|
checksum: 10c0/4708652e05a82d5fb6111708b0f6a9d764ac14032613b8d0edacaaa32d08593a0e4226f50806165da57fde8ad8e3dfe52a141b0d093a45d749a460f5cf869889
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fmodel-extension%40workspace%3Amodel-extension":
|
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fmodel-extension%40workspace%3Amodel-extension":
|
||||||
version: 0.1.10
|
version: 0.1.10
|
||||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=5531aa&locator=%40janhq%2Fmodel-extension%40workspace%3Amodel-extension"
|
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=7c4a2a&locator=%40janhq%2Fmodel-extension%40workspace%3Amodel-extension"
|
||||||
dependencies:
|
dependencies:
|
||||||
rxjs: "npm:^7.8.1"
|
rxjs: "npm:^7.8.1"
|
||||||
ulidx: "npm:^2.3.0"
|
ulidx: "npm:^2.3.0"
|
||||||
checksum: 10c0/ee7fe21267cf795dba890781d1e7807a6cb3ecb915ce9ecbd3a8386a2ebc916a8b70a775ce5d9d9f74d2ec29e20b65cea4ef6cdd0ea250a8ff2d5e6bd2237b1e
|
checksum: 10c0/4708652e05a82d5fb6111708b0f6a9d764ac14032613b8d0edacaaa32d08593a0e4226f50806165da57fde8ad8e3dfe52a141b0d093a45d749a460f5cf869889
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@janhq/download-extension@workspace:download-extension":
|
||||||
|
version: 0.0.0-use.local
|
||||||
|
resolution: "@janhq/download-extension@workspace:download-extension"
|
||||||
|
dependencies:
|
||||||
|
"@janhq/core": ../../core/package.tgz
|
||||||
|
"@tauri-apps/api": "npm:^2.5.0"
|
||||||
|
cpx: "npm:^1.5.0"
|
||||||
|
rimraf: "npm:^3.0.2"
|
||||||
|
rolldown: "npm:1.0.0-beta.1"
|
||||||
|
run-script-os: "npm:^1.1.6"
|
||||||
|
typescript: "npm:5.3.3"
|
||||||
|
vitest: "npm:^3.0.6"
|
||||||
|
languageName: unknown
|
||||||
|
linkType: soft
|
||||||
|
|
||||||
"@janhq/engine-management-extension@workspace:engine-management-extension":
|
"@janhq/engine-management-extension@workspace:engine-management-extension":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@janhq/engine-management-extension@workspace:engine-management-extension"
|
resolution: "@janhq/engine-management-extension@workspace:engine-management-extension"
|
||||||
@ -1436,6 +1461,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@tauri-apps/api@npm:^2.5.0":
|
||||||
|
version: 2.5.0
|
||||||
|
resolution: "@tauri-apps/api@npm:2.5.0"
|
||||||
|
checksum: 10c0/8eeb28049d48f5f89a5419cdf313bb159305204b193a5f27ebddbe0704ff43037c8b2e78518de831d7393e00178f0c0ac66cef1a57b99c632de71eca29f562c0
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@tybys/wasm-util@npm:^0.9.0":
|
"@tybys/wasm-util@npm:^0.9.0":
|
||||||
version: 0.9.0
|
version: 0.9.0
|
||||||
resolution: "@tybys/wasm-util@npm:0.9.0"
|
resolution: "@tybys/wasm-util@npm:0.9.0"
|
||||||
|
|||||||
@ -44,6 +44,7 @@
|
|||||||
"fzf": "^0.5.2",
|
"fzf": "^0.5.2",
|
||||||
"i18next": "^25.0.1",
|
"i18next": "^25.0.1",
|
||||||
"katex": "^0.16.22",
|
"katex": "^0.16.22",
|
||||||
|
"lodash.clonedeep": "^4.5.0",
|
||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
"lucide-react": "^0.503.0",
|
"lucide-react": "^0.503.0",
|
||||||
"motion": "^12.10.5",
|
"motion": "^12.10.5",
|
||||||
@ -76,6 +77,7 @@
|
|||||||
"@eslint/js": "^9.22.0",
|
"@eslint/js": "^9.22.0",
|
||||||
"@tanstack/router-plugin": "^1.116.1",
|
"@tanstack/router-plugin": "^1.116.1",
|
||||||
"@types/culori": "^2.1.1",
|
"@types/culori": "^2.1.1",
|
||||||
|
"@types/lodash.clonedeep": "^4",
|
||||||
"@types/lodash.debounce": "^4",
|
"@types/lodash.debounce": "^4",
|
||||||
"@types/node": "^22.14.1",
|
"@types/node": "^22.14.1",
|
||||||
"@types/react": "^19.0.10",
|
"@types/react": "^19.0.10",
|
||||||
|
|||||||
@ -26,7 +26,6 @@ import {
|
|||||||
} from '@/components/ui/dialog'
|
} from '@/components/ui/dialog'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { Textarea } from '@/components/ui/textarea'
|
import { Textarea } from '@/components/ui/textarea'
|
||||||
import { toast } from 'sonner'
|
|
||||||
import {
|
import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
TooltipContent,
|
TooltipContent,
|
||||||
@ -73,6 +72,57 @@ const CopyButton = ({ text }: { text: string }) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const EditDialog = ({
|
||||||
|
message,
|
||||||
|
setMessage,
|
||||||
|
}: {
|
||||||
|
message: string
|
||||||
|
setMessage: (message: string) => void
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Dialog>
|
||||||
|
<DialogTrigger>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<div className="flex outline-0 items-center gap-1 hover:text-accent transition-colors cursor-pointer group relative">
|
||||||
|
<IconPencil size={16} />
|
||||||
|
</div>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
<p>Edit</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</DialogTrigger>
|
||||||
|
<DialogContent className="w-3/4 h-3/4">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Edit Message</DialogTitle>
|
||||||
|
<Textarea
|
||||||
|
value={message}
|
||||||
|
onChange={(e) => {
|
||||||
|
setMessage(e.target.value)
|
||||||
|
}}
|
||||||
|
className="mt-2 resize-none h-full w-full"
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
// Prevent key from being captured by parent components
|
||||||
|
e.stopPropagation()
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<DialogFooter className="mt-2 flex items-center">
|
||||||
|
<DialogClose asChild>
|
||||||
|
<Button variant="link" size="sm" className="hover:no-underline">
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</DialogClose>
|
||||||
|
<DialogClose asChild>
|
||||||
|
<Button disabled={!message}>Save</Button>
|
||||||
|
</DialogClose>
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogHeader>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Use memo to prevent unnecessary re-renders, but allow re-renders when props change
|
// Use memo to prevent unnecessary re-renders, but allow re-renders when props change
|
||||||
export const ThreadContent = memo(
|
export const ThreadContent = memo(
|
||||||
(
|
(
|
||||||
@ -84,10 +134,9 @@ export const ThreadContent = memo(
|
|||||||
streamTools?: any
|
streamTools?: any
|
||||||
contextOverflowModal?: React.ReactNode | null
|
contextOverflowModal?: React.ReactNode | null
|
||||||
showContextOverflowModal?: () => Promise<unknown>
|
showContextOverflowModal?: () => Promise<unknown>
|
||||||
|
updateMessage: (item: ThreadMessage, message: string) => void
|
||||||
}
|
}
|
||||||
) => {
|
) => {
|
||||||
const [message, setMessage] = useState(item.content?.[0]?.text?.value || '')
|
|
||||||
|
|
||||||
// Use useMemo to stabilize the components prop
|
// Use useMemo to stabilize the components prop
|
||||||
const linkComponents = useMemo(
|
const linkComponents = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
@ -167,30 +216,6 @@ export const ThreadContent = memo(
|
|||||||
}
|
}
|
||||||
}, [deleteMessage, getMessages, item])
|
}, [deleteMessage, getMessages, item])
|
||||||
|
|
||||||
const editMessage = useCallback(
|
|
||||||
(messageId: string) => {
|
|
||||||
const threadMessages = getMessages(item.thread_id)
|
|
||||||
|
|
||||||
const index = threadMessages.findIndex((msg) => msg.id === messageId)
|
|
||||||
if (index === -1) return
|
|
||||||
|
|
||||||
// Delete all messages after the edited message
|
|
||||||
for (let i = threadMessages.length - 1; i >= index; i--) {
|
|
||||||
deleteMessage(threadMessages[i].thread_id, threadMessages[i].id)
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMessage(message, item.showContextOverflowModal)
|
|
||||||
},
|
|
||||||
[
|
|
||||||
deleteMessage,
|
|
||||||
getMessages,
|
|
||||||
item.thread_id,
|
|
||||||
message,
|
|
||||||
sendMessage,
|
|
||||||
item.showContextOverflowModal,
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
const isToolCalls =
|
const isToolCalls =
|
||||||
item.metadata &&
|
item.metadata &&
|
||||||
'tool_calls' in item.metadata &&
|
'tool_calls' in item.metadata &&
|
||||||
@ -217,62 +242,12 @@ export const ThreadContent = memo(
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-end gap-2 text-main-view-fg/60 text-xs mt-2">
|
<div className="flex items-center justify-end gap-2 text-main-view-fg/60 text-xs mt-2">
|
||||||
<Dialog>
|
<EditDialog
|
||||||
<DialogTrigger>
|
message={item.content?.[0].text.value}
|
||||||
<Tooltip>
|
setMessage={(message) => {
|
||||||
<TooltipTrigger asChild>
|
item.updateMessage(item, message)
|
||||||
<div className="flex outline-0 items-center gap-1 hover:text-accent transition-colors cursor-pointer group relative">
|
}}
|
||||||
<IconPencil size={16} />
|
/>
|
||||||
</div>
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent>
|
|
||||||
<p>Edit</p>
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
</DialogTrigger>
|
|
||||||
<DialogContent>
|
|
||||||
<DialogHeader>
|
|
||||||
<DialogTitle>Edit Message</DialogTitle>
|
|
||||||
<Textarea
|
|
||||||
value={message}
|
|
||||||
onChange={(e) => {
|
|
||||||
setMessage(e.target.value)
|
|
||||||
}}
|
|
||||||
className="mt-2 resize-none"
|
|
||||||
onKeyDown={(e) => {
|
|
||||||
// Prevent key from being captured by parent components
|
|
||||||
e.stopPropagation()
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<DialogFooter className="mt-2 flex items-center">
|
|
||||||
<DialogClose asChild>
|
|
||||||
<Button
|
|
||||||
variant="link"
|
|
||||||
size="sm"
|
|
||||||
className="hover:no-underline"
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</Button>
|
|
||||||
</DialogClose>
|
|
||||||
<DialogClose asChild>
|
|
||||||
<Button
|
|
||||||
disabled={!message}
|
|
||||||
onClick={() => {
|
|
||||||
editMessage(item.id)
|
|
||||||
toast.success('Edit Message', {
|
|
||||||
id: 'edit-message',
|
|
||||||
description:
|
|
||||||
'Message edited successfully. Please wait for the model to respond.',
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Save
|
|
||||||
</Button>
|
|
||||||
</DialogClose>
|
|
||||||
</DialogFooter>
|
|
||||||
</DialogHeader>
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<button
|
<button
|
||||||
@ -369,6 +344,12 @@ export const ThreadContent = memo(
|
|||||||
'hidden'
|
'hidden'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
<EditDialog
|
||||||
|
message={item.content?.[0]?.text.value}
|
||||||
|
setMessage={(message) =>
|
||||||
|
item.updateMessage(item, message)
|
||||||
|
}
|
||||||
|
/>
|
||||||
<CopyButton text={item.content?.[0]?.text.value || ''} />
|
<CopyButton text={item.content?.[0]?.text.value || ''} />
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { useEffect, useMemo, useRef, useState } from 'react'
|
|||||||
import { createFileRoute, useParams } from '@tanstack/react-router'
|
import { createFileRoute, useParams } from '@tanstack/react-router'
|
||||||
import { UIEventHandler } from 'react'
|
import { UIEventHandler } from 'react'
|
||||||
import debounce from 'lodash.debounce'
|
import debounce from 'lodash.debounce'
|
||||||
|
import cloneDeep from 'lodash.clonedeep'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { ArrowDown } from 'lucide-react'
|
import { ArrowDown } from 'lucide-react'
|
||||||
|
|
||||||
@ -19,6 +20,7 @@ import DropdownAssistant from '@/containers/DropdownAssistant'
|
|||||||
import { useAssistant } from '@/hooks/useAssistant'
|
import { useAssistant } from '@/hooks/useAssistant'
|
||||||
import { useAppearance } from '@/hooks/useAppearance'
|
import { useAppearance } from '@/hooks/useAppearance'
|
||||||
import { useOutOfContextPromiseModal } from '@/containers/dialogs/OutOfContextDialog'
|
import { useOutOfContextPromiseModal } from '@/containers/dialogs/OutOfContextDialog'
|
||||||
|
import { ContentType, ThreadMessage } from '@janhq/core'
|
||||||
|
|
||||||
// as route.threadsDetail
|
// as route.threadsDetail
|
||||||
export const Route = createFileRoute('/threads/$threadId')({
|
export const Route = createFileRoute('/threads/$threadId')({
|
||||||
@ -179,6 +181,26 @@ function ThreadDetail() {
|
|||||||
lastScrollTopRef.current = scrollTop
|
lastScrollTopRef.current = scrollTop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateMessage = (item: ThreadMessage, message: string) => {
|
||||||
|
const newMessages: ThreadMessage[] = messages.map((m) => {
|
||||||
|
if (m.id === item.id) {
|
||||||
|
const msg: ThreadMessage = cloneDeep(m)
|
||||||
|
msg.content = [
|
||||||
|
{
|
||||||
|
type: ContentType.Text,
|
||||||
|
text: {
|
||||||
|
value: message,
|
||||||
|
annotations: m.content[0].text?.annotations ?? [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
})
|
||||||
|
setMessages(threadId, newMessages)
|
||||||
|
}
|
||||||
|
|
||||||
// Use a shorter debounce time for more responsive scrolling
|
// Use a shorter debounce time for more responsive scrolling
|
||||||
const debouncedScroll = debounce(handleDOMScroll)
|
const debouncedScroll = debounce(handleDOMScroll)
|
||||||
|
|
||||||
@ -243,6 +265,7 @@ function ThreadDetail() {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
index={index}
|
index={index}
|
||||||
|
updateMessage={updateMessage}
|
||||||
showContextOverflowModal={showModal}
|
showContextOverflowModal={showModal}
|
||||||
contextOverflowModal={contextOverflowModalComponent}
|
contextOverflowModal={contextOverflowModalComponent}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user