Skip to content

Commit 631a4f1

Browse files
authored
Merge pull request langgenius#42 from langgenius/feat/support-agent
feat: support agent
2 parents 3de8abd + 25ba4ac commit 631a4f1

File tree

27 files changed

+1118
-75
lines changed

27 files changed

+1118
-75
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { type NextRequest } from 'next/server'
2+
import { NextResponse } from 'next/server'
3+
import { client, getInfo } from '@/app/api/utils/common'
4+
5+
export async function POST(request: NextRequest, { params }: {
6+
params: { conversationId: string }
7+
}) {
8+
const body = await request.json()
9+
const {
10+
auto_generate,
11+
name,
12+
} = body
13+
const { conversationId } = params
14+
const { user } = getInfo(request)
15+
16+
// auto generate name
17+
const { data } = await client.renameConversation(conversationId, name, user, auto_generate)
18+
return NextResponse.json(data)
19+
}

app/components/base/app-icon/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import classNames from 'classnames'
33
import style from './style.module.css'
44

55
export type AppIconProps = {
6-
size?: 'tiny' | 'small' | 'medium' | 'large'
6+
size?: 'xs' | 'tiny' | 'small' | 'medium' | 'large'
77
rounded?: boolean
88
icon?: string
99
background?: string
Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
.appIcon {
22
@apply flex items-center justify-center relative w-9 h-9 text-lg bg-teal-100 rounded-lg grow-0 shrink-0;
33
}
4+
45
.appIcon.large {
56
@apply w-10 h-10;
67
}
8+
79
.appIcon.small {
810
@apply w-8 h-8;
911
}
12+
13+
.appIcon.xs {
14+
@apply w-3 h-3 text-base;
15+
}
16+
1017
.appIcon.tiny {
1118
@apply w-6 h-6 text-base;
1219
}
20+
1321
.appIcon.rounded {
1422
@apply rounded-full;
15-
}
23+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"icon": {
3+
"type": "element",
4+
"isRootNode": true,
5+
"name": "svg",
6+
"attributes": {
7+
"width": "12",
8+
"height": "12",
9+
"viewBox": "0 0 12 12",
10+
"fill": "none",
11+
"xmlns": "http://www.w3.org/2000/svg"
12+
},
13+
"children": [
14+
{
15+
"type": "element",
16+
"name": "g",
17+
"attributes": {
18+
"id": "chevron-down"
19+
},
20+
"children": [
21+
{
22+
"type": "element",
23+
"name": "path",
24+
"attributes": {
25+
"id": "Icon",
26+
"d": "M3 4.5L6 7.5L9 4.5",
27+
"stroke": "currentColor",
28+
"stroke-width": "1.5",
29+
"stroke-linecap": "round",
30+
"stroke-linejoin": "round"
31+
},
32+
"children": []
33+
}
34+
]
35+
}
36+
]
37+
},
38+
"name": "ChevronDown"
39+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// GENERATE BY script
2+
// DON NOT EDIT IT MANUALLY
3+
4+
import * as React from 'react'
5+
import data from './data.json'
6+
import IconBase from '@/app/components/base/icons/IconBase'
7+
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
8+
9+
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
10+
props,
11+
ref,
12+
) => <IconBase {...props} ref={ref} data={data as IconData} />)
13+
14+
Icon.displayName = 'ChevronDown'
15+
16+
export default Icon
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{
2+
"icon": {
3+
"type": "element",
4+
"isRootNode": true,
5+
"name": "svg",
6+
"attributes": {
7+
"width": "12",
8+
"height": "12",
9+
"viewBox": "0 0 12 12",
10+
"fill": "none",
11+
"xmlns": "http://www.w3.org/2000/svg"
12+
},
13+
"children": [
14+
{
15+
"type": "element",
16+
"name": "g",
17+
"attributes": {
18+
"clip-path": "url(#clip0_7847_32895)"
19+
},
20+
"children": [
21+
{
22+
"type": "element",
23+
"name": "path",
24+
"attributes": {
25+
"d": "M10.5 2.5C10.5 3.32843 8.48528 4 6 4C3.51472 4 1.5 3.32843 1.5 2.5M10.5 2.5C10.5 1.67157 8.48528 1 6 1C3.51472 1 1.5 1.67157 1.5 2.5M10.5 2.5V9.5C10.5 10.33 8.5 11 6 11C3.5 11 1.5 10.33 1.5 9.5V2.5M10.5 6C10.5 6.83 8.5 7.5 6 7.5C3.5 7.5 1.5 6.83 1.5 6",
26+
"stroke": "#667085",
27+
"stroke-width": "1.25",
28+
"stroke-linecap": "round",
29+
"stroke-linejoin": "round"
30+
},
31+
"children": []
32+
}
33+
]
34+
},
35+
{
36+
"type": "element",
37+
"name": "defs",
38+
"attributes": {},
39+
"children": [
40+
{
41+
"type": "element",
42+
"name": "clipPath",
43+
"attributes": {
44+
"id": "clip0_7847_32895"
45+
},
46+
"children": [
47+
{
48+
"type": "element",
49+
"name": "rect",
50+
"attributes": {
51+
"width": "12",
52+
"height": "12",
53+
"fill": "white"
54+
},
55+
"children": []
56+
}
57+
]
58+
}
59+
]
60+
}
61+
]
62+
},
63+
"name": "DataSet"
64+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// GENERATE BY script
2+
// DON NOT EDIT IT MANUALLY
3+
4+
import * as React from 'react'
5+
import data from './data.json'
6+
import IconBase from '@/app/components/base/icons/IconBase'
7+
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
8+
9+
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
10+
props,
11+
ref,
12+
) => <IconBase {...props} ref={ref} data={data as IconData} />)
13+
14+
Icon.displayName = 'DataSet'
15+
16+
export default Icon
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"icon": {
3+
"type": "element",
4+
"isRootNode": true,
5+
"name": "svg",
6+
"attributes": {
7+
"width": "16",
8+
"height": "16",
9+
"viewBox": "0 0 16 16",
10+
"fill": "none",
11+
"xmlns": "http://www.w3.org/2000/svg"
12+
},
13+
"children": [
14+
{
15+
"type": "element",
16+
"name": "g",
17+
"attributes": {
18+
"id": "check-circle"
19+
},
20+
"children": [
21+
{
22+
"type": "element",
23+
"name": "path",
24+
"attributes": {
25+
"id": "Solid",
26+
"fill-rule": "evenodd",
27+
"clip-rule": "evenodd",
28+
"d": "M8 0.666626C3.94992 0.666626 0.666672 3.94987 0.666672 7.99996C0.666672 12.05 3.94992 15.3333 8 15.3333C12.0501 15.3333 15.3333 12.05 15.3333 7.99996C15.3333 3.94987 12.0501 0.666626 8 0.666626ZM11.4714 6.47136C11.7318 6.21101 11.7318 5.7889 11.4714 5.52855C11.2111 5.26821 10.7889 5.26821 10.5286 5.52855L7 9.05715L5.47141 7.52855C5.21106 7.2682 4.78895 7.2682 4.5286 7.52855C4.26825 7.7889 4.26825 8.21101 4.5286 8.47136L6.5286 10.4714C6.78895 10.7317 7.21106 10.7317 7.47141 10.4714L11.4714 6.47136Z",
29+
"fill": "currentColor"
30+
},
31+
"children": []
32+
}
33+
]
34+
}
35+
]
36+
},
37+
"name": "CheckCircle"
38+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// GENERATE BY script
2+
// DON NOT EDIT IT MANUALLY
3+
4+
import * as React from 'react'
5+
import data from './data.json'
6+
import IconBase from '@/app/components/base/icons/IconBase'
7+
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
8+
9+
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
10+
props,
11+
ref,
12+
) => <IconBase {...props} ref={ref} data={data as IconData} />)
13+
14+
Icon.displayName = 'CheckCircle'
15+
16+
export default Icon

app/components/chat/answer/index.tsx

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ import { useTranslation } from 'react-i18next'
66
import LoadingAnim from '../loading-anim'
77
import type { FeedbackFunc, IChatItem } from '../type'
88
import s from '../style.module.css'
9+
import ImageGallery from '../../base/image-gallery'
10+
import Thought from '../thought'
911
import { randomString } from '@/utils/string'
10-
import type { MessageRating } from '@/types/app'
12+
import type { MessageRating, VisionFile } from '@/types/app'
1113
import Tooltip from '@/app/components/base/tooltip'
1214
import { Markdown } from '@/app/components/base/markdown'
15+
import type { Emoji } from '@/types/tools'
1316

1417
const OperationBtn = ({ innerContent, onClick, className }: { innerContent: React.ReactNode; onClick?: () => void; className?: string }) => (
1518
<div
@@ -55,11 +58,20 @@ type IAnswerProps = {
5558
feedbackDisabled: boolean
5659
onFeedback?: FeedbackFunc
5760
isResponsing?: boolean
61+
allToolIcons?: Record<string, string | Emoji>
5862
}
5963

6064
// The component needs to maintain its own state to control whether to display input component
61-
const Answer: FC<IAnswerProps> = ({ item, feedbackDisabled = false, onFeedback, isResponsing }) => {
62-
const { id, content, feedback } = item
65+
const Answer: FC<IAnswerProps> = ({
66+
item,
67+
feedbackDisabled = false,
68+
onFeedback,
69+
isResponsing,
70+
allToolIcons,
71+
}) => {
72+
const { id, content, feedback, agent_thoughts } = item
73+
const isAgentMode = !!agent_thoughts && agent_thoughts.length > 0
74+
6375
const { t } = useTranslation()
6476

6577
/**
@@ -121,6 +133,37 @@ const Answer: FC<IAnswerProps> = ({ item, feedbackDisabled = false, onFeedback,
121133
)
122134
}
123135

136+
const getImgs = (list?: VisionFile[]) => {
137+
if (!list)
138+
return []
139+
return list.filter(file => file.type === 'image' && file.belongs_to === 'assistant')
140+
}
141+
142+
const agentModeAnswer = (
143+
<div>
144+
{agent_thoughts?.map((item, index) => (
145+
<div key={index}>
146+
{item.thought && (
147+
<Markdown content={item.thought} />
148+
)}
149+
{/* {item.tool} */}
150+
{/* perhaps not use tool */}
151+
{!!item.tool && (
152+
<Thought
153+
thought={item}
154+
allToolIcons={allToolIcons || {}}
155+
isFinished={!!item.observation || !isResponsing}
156+
/>
157+
)}
158+
159+
{getImgs(item.message_files).length > 0 && (
160+
<ImageGallery srcs={getImgs(item.message_files).map(item => item.url)} />
161+
)}
162+
</div>
163+
))}
164+
</div>
165+
)
166+
124167
return (
125168
<div key={id}>
126169
<div className='flex items-start'>
@@ -134,21 +177,17 @@ const Answer: FC<IAnswerProps> = ({ item, feedbackDisabled = false, onFeedback,
134177
<div className={`${s.answerWrap}`}>
135178
<div className={`${s.answer} relative text-sm text-gray-900`}>
136179
<div className={'ml-2 py-3 px-4 bg-gray-100 rounded-tr-2xl rounded-b-2xl'}>
137-
{item.isOpeningStatement && (
138-
<div className='flex items-center mb-1 gap-1'>
139-
<OpeningStatementIcon />
140-
<div className='text-xs text-gray-500'>{t('app.chat.openingStatementTitle')}</div>
141-
</div>
142-
)}
143-
{(isResponsing && !content)
180+
{(isResponsing && (isAgentMode ? (!content && (agent_thoughts || []).filter(item => !!item.thought || !!item.tool).length === 0) : !content))
144181
? (
145182
<div className='flex items-center justify-center w-6 h-5'>
146183
<LoadingAnim type='text' />
147184
</div>
148185
)
149-
: (
150-
<Markdown content={content} />
151-
)}
186+
: (isAgentMode
187+
? agentModeAnswer
188+
: (
189+
<Markdown content={content} />
190+
))}
152191
</div>
153192
<div className='absolute top-[-14px] right-[-14px] flex flex-row justify-end gap-1'>
154193
{!feedbackDisabled && !item.feedbackDisabled && renderItemOperation()}

0 commit comments

Comments
 (0)