Skip to content

Commit 043284f

Browse files
urmauurlouis-jan
andauthored
chore: reasoning block (#4551)
* chore: reasoning text block * chore: update interface support all theme * chore: update failed test * chore: update state collapsed based on message index * fix: use reserve_id instead of message index * chore: clean up * chore: fix loading indicator --------- Co-authored-by: Louis <[email protected]>
1 parent f2bb9c9 commit 043284f

File tree

8 files changed

+127
-62
lines changed

8 files changed

+127
-62
lines changed

extensions/yarn.lock

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -509,61 +509,61 @@ __metadata:
509509

510510
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fassistant-extension%40workspace%3Aassistant-extension":
511511
version: 0.1.10
512-
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=546b6d&locator=%40janhq%2Fassistant-extension%40workspace%3Aassistant-extension"
512+
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=af6a7b&locator=%40janhq%2Fassistant-extension%40workspace%3Aassistant-extension"
513513
dependencies:
514514
rxjs: "npm:^7.8.1"
515515
ulidx: "npm:^2.3.0"
516-
checksum: 10c0/abb0aeb570396ef5d2fe482410a178f422ced7da132fa28f92b930eba191439a6a9b3567641c283eb6bf6413ace2950669393fc8f1e415d442e22d7107c23a44
516+
checksum: 10c0/482f1f5363ca64f48a40c3d2937ac07dcf42a6d2dd6c82356359cec986e9312611f84ca8cdaed4ef338d978cd163909a2708d75f8e957aa51b09447aae83eca0
517517
languageName: node
518518
linkType: hard
519519

520520
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fconversational-extension%40workspace%3Aconversational-extension":
521521
version: 0.1.10
522-
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=546b6d&locator=%40janhq%2Fconversational-extension%40workspace%3Aconversational-extension"
522+
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=af6a7b&locator=%40janhq%2Fconversational-extension%40workspace%3Aconversational-extension"
523523
dependencies:
524524
rxjs: "npm:^7.8.1"
525525
ulidx: "npm:^2.3.0"
526-
checksum: 10c0/abb0aeb570396ef5d2fe482410a178f422ced7da132fa28f92b930eba191439a6a9b3567641c283eb6bf6413ace2950669393fc8f1e415d442e22d7107c23a44
526+
checksum: 10c0/482f1f5363ca64f48a40c3d2937ac07dcf42a6d2dd6c82356359cec986e9312611f84ca8cdaed4ef338d978cd163909a2708d75f8e957aa51b09447aae83eca0
527527
languageName: node
528528
linkType: hard
529529

530530
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fengine-management-extension%40workspace%3Aengine-management-extension":
531531
version: 0.1.10
532-
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=546b6d&locator=%40janhq%2Fengine-management-extension%40workspace%3Aengine-management-extension"
532+
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=af6a7b&locator=%40janhq%2Fengine-management-extension%40workspace%3Aengine-management-extension"
533533
dependencies:
534534
rxjs: "npm:^7.8.1"
535535
ulidx: "npm:^2.3.0"
536-
checksum: 10c0/abb0aeb570396ef5d2fe482410a178f422ced7da132fa28f92b930eba191439a6a9b3567641c283eb6bf6413ace2950669393fc8f1e415d442e22d7107c23a44
536+
checksum: 10c0/482f1f5363ca64f48a40c3d2937ac07dcf42a6d2dd6c82356359cec986e9312611f84ca8cdaed4ef338d978cd163909a2708d75f8e957aa51b09447aae83eca0
537537
languageName: node
538538
linkType: hard
539539

540540
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Finference-cortex-extension%40workspace%3Ainference-cortex-extension":
541541
version: 0.1.10
542-
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=546b6d&locator=%40janhq%2Finference-cortex-extension%40workspace%3Ainference-cortex-extension"
542+
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=af6a7b&locator=%40janhq%2Finference-cortex-extension%40workspace%3Ainference-cortex-extension"
543543
dependencies:
544544
rxjs: "npm:^7.8.1"
545545
ulidx: "npm:^2.3.0"
546-
checksum: 10c0/abb0aeb570396ef5d2fe482410a178f422ced7da132fa28f92b930eba191439a6a9b3567641c283eb6bf6413ace2950669393fc8f1e415d442e22d7107c23a44
546+
checksum: 10c0/482f1f5363ca64f48a40c3d2937ac07dcf42a6d2dd6c82356359cec986e9312611f84ca8cdaed4ef338d978cd163909a2708d75f8e957aa51b09447aae83eca0
547547
languageName: node
548548
linkType: hard
549549

550550
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fmodel-extension%40workspace%3Amodel-extension":
551551
version: 0.1.10
552-
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=546b6d&locator=%40janhq%2Fmodel-extension%40workspace%3Amodel-extension"
552+
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=af6a7b&locator=%40janhq%2Fmodel-extension%40workspace%3Amodel-extension"
553553
dependencies:
554554
rxjs: "npm:^7.8.1"
555555
ulidx: "npm:^2.3.0"
556-
checksum: 10c0/abb0aeb570396ef5d2fe482410a178f422ced7da132fa28f92b930eba191439a6a9b3567641c283eb6bf6413ace2950669393fc8f1e415d442e22d7107c23a44
556+
checksum: 10c0/482f1f5363ca64f48a40c3d2937ac07dcf42a6d2dd6c82356359cec986e9312611f84ca8cdaed4ef338d978cd163909a2708d75f8e957aa51b09447aae83eca0
557557
languageName: node
558558
linkType: hard
559559

560560
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fmonitoring-extension%40workspace%3Amonitoring-extension":
561561
version: 0.1.10
562-
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=546b6d&locator=%40janhq%2Fmonitoring-extension%40workspace%3Amonitoring-extension"
562+
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=af6a7b&locator=%40janhq%2Fmonitoring-extension%40workspace%3Amonitoring-extension"
563563
dependencies:
564564
rxjs: "npm:^7.8.1"
565565
ulidx: "npm:^2.3.0"
566-
checksum: 10c0/abb0aeb570396ef5d2fe482410a178f422ced7da132fa28f92b930eba191439a6a9b3567641c283eb6bf6413ace2950669393fc8f1e415d442e22d7107c23a44
566+
checksum: 10c0/482f1f5363ca64f48a40c3d2937ac07dcf42a6d2dd6c82356359cec986e9312611f84ca8cdaed4ef338d978cd163909a2708d75f8e957aa51b09447aae83eca0
567567
languageName: node
568568
linkType: hard
569569

web/containers/Providers/ModelHandler.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,13 @@ export default function ModelHandler() {
290290
.catch(() => undefined)
291291
if (updatedMessage) {
292292
deleteMessage(message.id)
293-
addNewMessage(updatedMessage)
293+
addNewMessage({
294+
...updatedMessage,
295+
metadata: {
296+
...updatedMessage.metadata,
297+
reserve_id: message.id,
298+
},
299+
})
294300
setTokenSpeed((prev) =>
295301
prev ? { ...prev, message: updatedMessage.id } : undefined
296302
)

web/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
"slate-react": "0.110.3",
5757
"swr": "^2.2.5",
5858
"tailwind-merge": "^2.0.0",
59-
"tailwindcss": "3.3.5",
59+
"tailwindcss": "3.4.17",
6060
"ulidx": "^2.3.0",
6161
"use-debounce": "^10.0.0",
6262
"uuid": "^9.0.1",

web/screens/Thread/ThreadCenterPanel/ChatBody/index.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,12 @@ const ChatBody = memo(
160160
>
161161
{items.map((virtualRow) => (
162162
<div
163-
key={messages[virtualRow.index]?.id}
163+
key={
164+
(messages[virtualRow.index]?.metadata
165+
?.reserve_id as string) ??
166+
messages[virtualRow.index]?.id ??
167+
virtualRow.index
168+
}
164169
data-index={virtualRow.index}
165170
ref={virtualizer.measureElement}
166171
>
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import React from 'react'
2+
3+
import { atom, useAtom } from 'jotai'
4+
import { ChevronDown, ChevronUp, Loader } from 'lucide-react'
5+
6+
interface Props {
7+
text: string
8+
status: string
9+
id: string
10+
}
11+
12+
const thinkingBlockStateAtom = atom<{ [id: string]: boolean }>({})
13+
14+
const ThinkingBlock = ({ id, text, status }: Props) => {
15+
const [thinkingState, setThinkingState] = useAtom(thinkingBlockStateAtom)
16+
17+
const isExpanded = thinkingState[id] ?? false
18+
19+
const loading = !text.includes('</think>') && status === 'pending'
20+
21+
const handleClick = () => {
22+
setThinkingState((prev) => ({ ...prev, [id]: !isExpanded }))
23+
}
24+
25+
if (!text.replace(/<\/?think>/g, '').trim()) return null
26+
27+
return (
28+
<div className="mx-auto w-full">
29+
<div className="mb-4 rounded-lg border border-dashed border-[hsla(var(--app-border))] p-2">
30+
<div
31+
className="flex cursor-pointer items-center gap-3"
32+
onClick={handleClick}
33+
>
34+
{loading && (
35+
<Loader className="h-4 w-4 animate-spin text-[hsla(var(--primary-bg))]" />
36+
)}
37+
<button className="flex items-center gap-2 focus:outline-none">
38+
{isExpanded ? (
39+
<ChevronUp className="h-4 w-4" />
40+
) : (
41+
<ChevronDown className="h-4 w-4" />
42+
)}
43+
<span className="font-medium">
44+
{loading ? 'Thinking...' : 'Thought'}
45+
</span>
46+
</button>
47+
</div>
48+
49+
{isExpanded && (
50+
<div className="mt-2 pl-6 text-[hsla(var(--text-secondary))]">
51+
{text.replace(/<\/?think>/g, '').trim()}
52+
</div>
53+
)}
54+
</div>
55+
</div>
56+
)
57+
}
58+
59+
export default ThinkingBlock

web/screens/Thread/ThreadCenterPanel/TextMessage/index.tsx

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import MessageToolbar from '../MessageToolbar'
1616
import DocMessage from './DocMessage'
1717
import ImageMessage from './ImageMessage'
1818
import { MarkdownTextMessage } from './MarkdownTextMessage'
19+
import ThinkingBlock from './ThinkingBlock'
1920

2021
import { activeAssistantAtom } from '@/helpers/atoms/Assistant.atom'
2122
import {
@@ -41,6 +42,21 @@ const MessageContainer: React.FC<
4142
[props.content]
4243
)
4344

45+
const { reasoningSegment, textSegment } = useMemo(() => {
46+
const isThinking = text.includes('<think>') && !text.includes('</think>')
47+
if (isThinking) return { reasoningSegment: text, textSegment: '' }
48+
49+
const match = text.match(/<think>([\s\S]*?)<\/think>/)
50+
if (match?.index === undefined)
51+
return { reasoningSegment: undefined, textSegment: text }
52+
53+
const splitIndex = match.index + match[0].length
54+
return {
55+
reasoningSegment: text.slice(0, splitIndex),
56+
textSegment: text.slice(splitIndex),
57+
}
58+
}, [text])
59+
4460
const image = useMemo(
4561
() =>
4662
props.content.find((e) => e.type === ContentType.Image)?.image_url?.url,
@@ -144,9 +160,16 @@ const MessageContainer: React.FC<
144160
)}
145161
dir="ltr"
146162
>
163+
{reasoningSegment && (
164+
<ThinkingBlock
165+
id={(props.metadata?.reserve_id as string) ?? props.id}
166+
text={reasoningSegment}
167+
status={props.status}
168+
/>
169+
)}
147170
<MarkdownTextMessage
148171
id={props.id}
149-
text={text}
172+
text={textSegment}
150173
isUser={isUser}
151174
/>
152175
</div>

web/tailwind.config.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ module.exports = {
1818
'slide-in': 'slide-in 1.2s cubic-bezier(.41,.73,.51,1.02)',
1919
'leave': 'leave 150ms ease-in forwards',
2020
'bounce-right': 'bounce-right 3s infinite',
21+
'spin': 'spin 2s linear infinite',
2122
},
2223
keyframes: {
2324
'wave': {
@@ -47,6 +48,10 @@ module.exports = {
4748
'40%': { transform: 'translateX(-8px)' },
4849
'60%': { transform: 'translateX(-4px)' },
4950
},
51+
'spin': {
52+
'0%': { transform: 'rotate(0deg)' },
53+
'100%': { transform: 'rotate(360deg)' },
54+
},
5055
},
5156
extend: {
5257
fontFamily: {

yarn.lock

Lines changed: 13 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,7 +1138,7 @@ __metadata:
11381138
slate-react: "npm:0.110.3"
11391139
swr: "npm:^2.2.5"
11401140
tailwind-merge: "npm:^2.0.0"
1141-
tailwindcss: "npm:3.3.5"
1141+
tailwindcss: "npm:3.4.17"
11421142
ts-jest: "npm:^29.2.5"
11431143
typescript: "npm:^5.3.3"
11441144
ulidx: "npm:^2.3.0"
@@ -6141,7 +6141,7 @@ __metadata:
61416141
languageName: node
61426142
linkType: hard
61436143

6144-
"chokidar@npm:^3.5.3, chokidar@npm:^3.6.0":
6144+
"chokidar@npm:^3.6.0":
61456145
version: 3.6.0
61466146
resolution: "chokidar@npm:3.6.0"
61476147
dependencies:
@@ -8451,7 +8451,7 @@ __metadata:
84518451
languageName: node
84528452
linkType: hard
84538453

8454-
"fast-glob@npm:^3.0.3, fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.0, fast-glob@npm:^3.3.2":
8454+
"fast-glob@npm:^3.0.3, fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.2":
84558455
version: 3.3.2
84568456
resolution: "fast-glob@npm:3.3.2"
84578457
dependencies:
@@ -11483,7 +11483,7 @@ __metadata:
1148311483
languageName: node
1148411484
linkType: hard
1148511485

11486-
"jiti@npm:^1.19.1, jiti@npm:^1.21.6":
11486+
"jiti@npm:^1.21.6":
1148711487
version: 1.21.7
1148811488
resolution: "jiti@npm:1.21.7"
1148911489
bin:
@@ -11946,7 +11946,7 @@ __metadata:
1194611946
languageName: node
1194711947
linkType: hard
1194811948

11949-
"lilconfig@npm:^2.0.3, lilconfig@npm:^2.0.5, lilconfig@npm:^2.1.0":
11949+
"lilconfig@npm:^2.0.3, lilconfig@npm:^2.0.5":
1195011950
version: 2.1.0
1195111951
resolution: "lilconfig@npm:2.1.0"
1195211952
checksum: 10c0/64645641aa8d274c99338e130554abd6a0190533c0d9eb2ce7ebfaf2e05c7d9961f3ffe2bfa39efd3b60c521ba3dd24fa236fe2775fc38501bf82bf49d4678b8
@@ -14609,7 +14609,7 @@ __metadata:
1460914609
languageName: node
1461014610
linkType: hard
1461114611

14612-
"postcss-load-config@npm:^4.0.1, postcss-load-config@npm:^4.0.2":
14612+
"postcss-load-config@npm:^4.0.2":
1461314613
version: 4.0.2
1461414614
resolution: "postcss-load-config@npm:4.0.2"
1461514615
dependencies:
@@ -14763,7 +14763,7 @@ __metadata:
1476314763
languageName: node
1476414764
linkType: hard
1476514765

14766-
"postcss-nested@npm:^6.0.1, postcss-nested@npm:^6.2.0":
14766+
"postcss-nested@npm:^6.2.0":
1476714767
version: 6.2.0
1476814768
resolution: "postcss-nested@npm:6.2.0"
1476914769
dependencies:
@@ -14908,7 +14908,7 @@ __metadata:
1490814908
languageName: node
1490914909
linkType: hard
1491014910

14911-
"postcss-selector-parser@npm:^6.0.10, postcss-selector-parser@npm:^6.0.11, postcss-selector-parser@npm:^6.0.4, postcss-selector-parser@npm:^6.0.5, postcss-selector-parser@npm:^6.0.9, postcss-selector-parser@npm:^6.1.1, postcss-selector-parser@npm:^6.1.2":
14911+
"postcss-selector-parser@npm:^6.0.10, postcss-selector-parser@npm:^6.0.4, postcss-selector-parser@npm:^6.0.5, postcss-selector-parser@npm:^6.0.9, postcss-selector-parser@npm:^6.1.1, postcss-selector-parser@npm:^6.1.2":
1491214912
version: 6.1.2
1491314913
resolution: "postcss-selector-parser@npm:6.1.2"
1491414914
dependencies:
@@ -14983,7 +14983,7 @@ __metadata:
1498314983
languageName: node
1498414984
linkType: hard
1498514985

14986-
"postcss@npm:^8.4.23, postcss@npm:^8.4.47":
14986+
"postcss@npm:^8.4.47":
1498714987
version: 8.4.49
1498814988
resolution: "postcss@npm:8.4.49"
1498914989
dependencies:
@@ -15959,7 +15959,7 @@ __metadata:
1595915959
languageName: node
1596015960
linkType: hard
1596115961

15962-
"resolve@npm:^1.1.7, resolve@npm:^1.11.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.2, resolve@npm:^1.22.4, resolve@npm:^1.22.8":
15962+
"resolve@npm:^1.1.7, resolve@npm:^1.11.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.4, resolve@npm:^1.22.8":
1596315963
version: 1.22.10
1596415964
resolution: "resolve@npm:1.22.10"
1596515965
dependencies:
@@ -15985,7 +15985,7 @@ __metadata:
1598515985
languageName: node
1598615986
linkType: hard
1598715987

15988-
"resolve@patch:resolve@npm%3A^1.1.7#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.11.0#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.22.2#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.22.8#optional!builtin<compat/resolve>":
15988+
"resolve@patch:resolve@npm%3A^1.1.7#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.11.0#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.22.8#optional!builtin<compat/resolve>":
1598915989
version: 1.22.10
1599015990
resolution: "resolve@patch:resolve@npm%3A1.22.10#optional!builtin<compat/resolve>::version=1.22.10&hash=c3c19d"
1599115991
dependencies:
@@ -17449,7 +17449,7 @@ __metadata:
1744917449
languageName: node
1745017450
linkType: hard
1745117451

17452-
"sucrase@npm:^3.32.0, sucrase@npm:^3.35.0":
17452+
"sucrase@npm:^3.35.0":
1745317453
version: 3.35.0
1745417454
resolution: "sucrase@npm:3.35.0"
1745517455
dependencies:
@@ -17561,40 +17561,7 @@ __metadata:
1756117561
languageName: node
1756217562
linkType: hard
1756317563

17564-
"tailwindcss@npm:3.3.5":
17565-
version: 3.3.5
17566-
resolution: "tailwindcss@npm:3.3.5"
17567-
dependencies:
17568-
"@alloc/quick-lru": "npm:^5.2.0"
17569-
arg: "npm:^5.0.2"
17570-
chokidar: "npm:^3.5.3"
17571-
didyoumean: "npm:^1.2.2"
17572-
dlv: "npm:^1.1.3"
17573-
fast-glob: "npm:^3.3.0"
17574-
glob-parent: "npm:^6.0.2"
17575-
is-glob: "npm:^4.0.3"
17576-
jiti: "npm:^1.19.1"
17577-
lilconfig: "npm:^2.1.0"
17578-
micromatch: "npm:^4.0.5"
17579-
normalize-path: "npm:^3.0.0"
17580-
object-hash: "npm:^3.0.0"
17581-
picocolors: "npm:^1.0.0"
17582-
postcss: "npm:^8.4.23"
17583-
postcss-import: "npm:^15.1.0"
17584-
postcss-js: "npm:^4.0.1"
17585-
postcss-load-config: "npm:^4.0.1"
17586-
postcss-nested: "npm:^6.0.1"
17587-
postcss-selector-parser: "npm:^6.0.11"
17588-
resolve: "npm:^1.22.2"
17589-
sucrase: "npm:^3.32.0"
17590-
bin:
17591-
tailwind: lib/cli.js
17592-
tailwindcss: lib/cli.js
17593-
checksum: 10c0/a57c0a9cdba9db19097e34e25b7e4690fab43f31ba200afc3bb9635a03036ca93e9884a17b616fb8a2486d57d2ecc9a06862ce4685b3ace57f7a67436e7594a0
17594-
languageName: node
17595-
linkType: hard
17596-
17597-
"tailwindcss@npm:^3.4.1":
17564+
"tailwindcss@npm:3.4.17, tailwindcss@npm:^3.4.1":
1759817565
version: 3.4.17
1759917566
resolution: "tailwindcss@npm:3.4.17"
1760017567
dependencies:

0 commit comments

Comments
 (0)