@vibe-forge/client 0.2.0-alpha.9 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/cli.cjs +1 -1
  2. package/dist/assets/{arc-CybT1Fs2.js → arc-DgIxeTMg.js} +1 -1
  3. package/dist/assets/{blockDiagram-c4efeb88-BY5Aoa-D.js → blockDiagram-c4efeb88-CEAob3X9.js} +1 -1
  4. package/dist/assets/{c4Diagram-c83219d4-F42hTbzS.js → c4Diagram-c83219d4-DwIxpDKd.js} +1 -1
  5. package/dist/assets/channel-DhtnrNJ6.js +1 -0
  6. package/dist/assets/{classDiagram-beda092f-D-tIPp-3.js → classDiagram-beda092f-Cz1q8u_0.js} +1 -1
  7. package/dist/assets/{classDiagram-v2-2358418a-J57aCe6u.js → classDiagram-v2-2358418a-CImgTuwd.js} +1 -1
  8. package/dist/assets/clone-7bHB6YkC.js +1 -0
  9. package/dist/assets/{createText-1719965b-ByfEqOF-.js → createText-1719965b-C1_HJcCc.js} +1 -1
  10. package/dist/assets/devicon-BWlTeAUU.woff +0 -0
  11. package/dist/assets/devicon-CirD-cQx.ttf +0 -0
  12. package/dist/assets/devicon-Dg8iWy0i.svg +1211 -0
  13. package/dist/assets/devicon-TqfHp33-.eot +0 -0
  14. package/dist/assets/{edges-96097737-CMEArkOa.js → edges-96097737-BU8qStzd.js} +1 -1
  15. package/dist/assets/{erDiagram-0228fc6a-Cf8mX2aj.js → erDiagram-0228fc6a-DNA1Fz2L.js} +1 -1
  16. package/dist/assets/{flowDb-c6c81e3f-DG6WKyo7.js → flowDb-c6c81e3f-DjiCStMN.js} +1 -1
  17. package/dist/assets/{flowDiagram-50d868cf-CstUxz-w.js → flowDiagram-50d868cf-CSDi0-RD.js} +1 -1
  18. package/dist/assets/flowDiagram-v2-4f6560a1-_13Sz5Wh.js +1 -0
  19. package/dist/assets/{flowchart-elk-definition-6af322e1--4CRoQ-H.js → flowchart-elk-definition-6af322e1-DrhIMas7.js} +1 -1
  20. package/dist/assets/{ganttDiagram-a2739b55-DYgHcKd-.js → ganttDiagram-a2739b55-CTZnUP5z.js} +1 -1
  21. package/dist/assets/{gitGraphDiagram-82fe8481-DDSVpfsd.js → gitGraphDiagram-82fe8481-COOW7jTi.js} +1 -1
  22. package/dist/assets/{graph-CRWF39gX.js → graph-CIkpD4Kx.js} +1 -1
  23. package/dist/assets/{index-5325376f-W1hft795.js → index-5325376f-aVVRRTIu.js} +1 -1
  24. package/dist/assets/index-D1giUI7r.css +1 -0
  25. package/dist/assets/index-DRSI_ZIL.js +514 -0
  26. package/dist/assets/{infoDiagram-8eee0895-D4SHcix6.js → infoDiagram-8eee0895-DQpZ1LVD.js} +1 -1
  27. package/dist/assets/{journeyDiagram-c64418c1-MWgCkVoE.js → journeyDiagram-c64418c1-DoKguIuk.js} +1 -1
  28. package/dist/assets/{layout-C88ObkCf.js → layout-Tnmha8Nh.js} +1 -1
  29. package/dist/assets/{line-C7WAYMt5.js → line-BQR2SOyl.js} +1 -1
  30. package/dist/assets/{linear-C4msxfcU.js → linear-DlG0eemV.js} +1 -1
  31. package/dist/assets/{mermaid.core-Cabag9SZ.js → mermaid.core-BnwYO0He.js} +6 -6
  32. package/dist/assets/{mindmap-definition-8da855dc-CeS8ETXx.js → mindmap-definition-8da855dc-BllYwDID.js} +1 -1
  33. package/dist/assets/{pieDiagram-a8764435-BvjyKnq5.js → pieDiagram-a8764435-DwCkhPVc.js} +1 -1
  34. package/dist/assets/{quadrantDiagram-1e28029f-DzYvpbNM.js → quadrantDiagram-1e28029f-c40GKTU0.js} +1 -1
  35. package/dist/assets/{requirementDiagram-08caed73-DHIoDbyo.js → requirementDiagram-08caed73-DnQp2Tk6.js} +1 -1
  36. package/dist/assets/{sankeyDiagram-a04cb91d-BFSGnQGs.js → sankeyDiagram-a04cb91d-CnJrs13b.js} +1 -1
  37. package/dist/assets/{sequenceDiagram-c5b8d532-_LM3BJ5-.js → sequenceDiagram-c5b8d532-1YBwnpKu.js} +1 -1
  38. package/dist/assets/{stateDiagram-1ecb1508-DwORjOzl.js → stateDiagram-1ecb1508-BFBxQ6Fh.js} +1 -1
  39. package/dist/assets/{stateDiagram-v2-c2b004d7-B4cAWWz1.js → stateDiagram-v2-c2b004d7-Dmechvv2.js} +1 -1
  40. package/dist/assets/{styles-b4e223ce-D_rmV3B_.js → styles-b4e223ce-DWWfWX8O.js} +1 -1
  41. package/dist/assets/{styles-ca3715f6-BFx4VuFc.js → styles-ca3715f6-CKKvZxaU.js} +1 -1
  42. package/dist/assets/{styles-d45a18b0-BE3106vL.js → styles-d45a18b0-dKMOUh9p.js} +1 -1
  43. package/dist/assets/{svgDrawCommon-b86b1483-DwDTO1op.js → svgDrawCommon-b86b1483-CBgjChPM.js} +1 -1
  44. package/dist/assets/{timeline-definition-faaaa080-C4b8qUQZ.js → timeline-definition-faaaa080-NCt-HHmb.js} +1 -1
  45. package/dist/assets/{xychartDiagram-f5964ef8-BRJ9Z4u-.js → xychartDiagram-f5964ef8-BJhXS4dG.js} +1 -1
  46. package/dist/index.html +2 -7
  47. package/index.html +0 -5
  48. package/package.json +11 -6
  49. package/src/App.tsx +2 -0
  50. package/src/api/README.md +26 -0
  51. package/src/api/automation.ts +88 -0
  52. package/src/api/base.ts +54 -0
  53. package/src/api/benchmark.ts +45 -0
  54. package/src/api/config.ts +24 -0
  55. package/src/api/knowledge.ts +72 -0
  56. package/src/api/projects.ts +15 -0
  57. package/src/api/sessions.ts +82 -0
  58. package/src/api/types.ts +20 -0
  59. package/src/api.ts +44 -241
  60. package/src/components/AutomationView/AutomationView.scss +5 -1
  61. package/src/components/AutomationView/RuleFormPanel.tsx +3 -2
  62. package/src/components/AutomationView/TaskList.scss +4 -6
  63. package/src/components/AutomationView/TaskList.tsx +2 -1
  64. package/src/components/AutomationView/TriggerList.scss +4 -1
  65. package/src/components/BenchmarkView/BenchmarkCasePanel.scss +267 -0
  66. package/src/components/BenchmarkView/BenchmarkCasePanel.tsx +309 -0
  67. package/src/components/BenchmarkView/BenchmarkSidebar.scss +182 -0
  68. package/src/components/BenchmarkView/BenchmarkSidebar.tsx +262 -0
  69. package/src/components/BenchmarkView/BenchmarkView.scss +78 -0
  70. package/src/components/BenchmarkView/index.tsx +197 -0
  71. package/src/components/BenchmarkView/types.ts +10 -0
  72. package/src/components/BenchmarkView/utils.ts +21 -0
  73. package/src/components/Chat.tsx +37 -29
  74. package/src/components/{chat/CodeBlock.tsx → CodeBlock.tsx} +3 -1
  75. package/src/components/ConfigView.tsx +13 -1
  76. package/src/components/{chat/MarkdownContent.tsx → MarkdownContent.tsx} +1 -1
  77. package/src/components/NavRail.tsx +7 -0
  78. package/src/components/chat/ChatHeader.scss +37 -19
  79. package/src/components/chat/ChatHeader.tsx +6 -9
  80. package/src/components/chat/ChatHistoryView.tsx +89 -45
  81. package/src/components/chat/CurrentTodoList.tsx +10 -9
  82. package/src/components/chat/{MessageItem.scss → Messages/MessageItem.scss} +14 -0
  83. package/src/components/chat/{MessageItem.tsx → Messages/MessageItem.tsx} +30 -8
  84. package/src/components/chat/{messageUtils.ts → Messages/message-utils.ts} +1 -1
  85. package/src/components/chat/NewSessionGuide.scss +35 -13
  86. package/src/components/chat/NewSessionGuide.tsx +20 -10
  87. package/src/components/chat/{Sender.scss → Sender/Sender.scss} +80 -0
  88. package/src/components/chat/{Sender.tsx → Sender/Sender.tsx} +161 -5
  89. package/src/components/chat/tools/DefaultTool.tsx +184 -21
  90. package/src/components/chat/tools/adapter-claude/BashTool.scss +67 -51
  91. package/src/components/chat/tools/adapter-claude/BashTool.tsx +83 -49
  92. package/src/components/chat/tools/adapter-claude/GlobTool.scss +0 -79
  93. package/src/components/chat/tools/adapter-claude/GlobTool.tsx +16 -36
  94. package/src/components/chat/tools/adapter-claude/GrepTool.scss +0 -87
  95. package/src/components/chat/tools/adapter-claude/GrepTool.tsx +22 -41
  96. package/src/components/chat/tools/adapter-claude/LSTool.scss +0 -79
  97. package/src/components/chat/tools/adapter-claude/LSTool.tsx +15 -15
  98. package/src/components/chat/tools/adapter-claude/ReadTool.scss +0 -55
  99. package/src/components/chat/tools/adapter-claude/ReadTool.tsx +20 -42
  100. package/src/components/chat/tools/adapter-claude/TodoTool.scss +8 -23
  101. package/src/components/chat/tools/adapter-claude/TodoTool.tsx +24 -11
  102. package/src/components/chat/tools/adapter-claude/WriteTool.scss +21 -69
  103. package/src/components/chat/tools/adapter-claude/WriteTool.tsx +22 -58
  104. package/src/components/chat/tools/adapter-claude/index.ts +4 -10
  105. package/src/components/chat/tools/adapter-claude/utils.ts +54 -0
  106. package/src/components/chat/tools/core/ToolCallBox.scss +356 -0
  107. package/src/components/chat/{ToolGroup.tsx → tools/core/ToolGroup.tsx} +26 -7
  108. package/src/components/chat/{ToolRenderer.tsx → tools/core/ToolRenderer.tsx} +6 -4
  109. package/src/components/chat/tools/plugin-chrome-devtools/ChromeDevtoolsTool.scss +11 -0
  110. package/src/components/chat/tools/plugin-chrome-devtools/ChromeDevtoolsTool.tsx +75 -0
  111. package/src/components/chat/tools/plugin-chrome-devtools/index.ts +45 -0
  112. package/src/components/chat/tools/task/GetTaskInfoTool.scss +2 -27
  113. package/src/components/chat/tools/task/GetTaskInfoTool.tsx +48 -38
  114. package/src/components/chat/tools/task/ListTasksTool.scss +3 -28
  115. package/src/components/chat/tools/task/ListTasksTool.tsx +11 -8
  116. package/src/components/chat/tools/task/StartTasksTool.scss +3 -28
  117. package/src/components/chat/tools/task/StartTasksTool.tsx +14 -17
  118. package/src/components/chat/tools/task/components/TaskRow.scss +105 -0
  119. package/src/components/chat/tools/task/components/TaskRow.tsx +163 -0
  120. package/src/components/chat/tools/task/components/TaskToolCard.scss +15 -15
  121. package/src/components/chat/tools/task/components/TaskToolCard.tsx +8 -6
  122. package/src/components/config/AppSettingsPanel.tsx +33 -0
  123. package/src/components/config/ConfigSectionForm.tsx +12 -1
  124. package/src/components/config/channelDefinitions.ts +6 -0
  125. package/src/components/config/configSchema.ts +10 -1
  126. package/src/components/config/recordEditors/ChannelRecordEditor.scss +1 -0
  127. package/src/components/config/recordEditors/ChannelRecordEditor.tsx +397 -0
  128. package/src/components/config/recordEditors/index.tsx +1 -0
  129. package/src/components/knowledge-base/KnowledgeBaseView.tsx +51 -3
  130. package/src/components/knowledge-base/components/RuleItem.tsx +79 -0
  131. package/src/components/knowledge-base/components/RuleList.scss +5 -0
  132. package/src/components/knowledge-base/components/RuleList.tsx +70 -0
  133. package/src/components/knowledge-base/components/RulesTab.tsx +32 -7
  134. package/src/components/knowledge-base/components/SpecItem.tsx +1 -1
  135. package/src/hooks/chat/use-chat-interaction.ts +26 -0
  136. package/src/{components/chat/useChatModels.tsx → hooks/chat/use-chat-models.tsx} +65 -16
  137. package/src/hooks/chat/use-chat-permission-mode.ts +47 -0
  138. package/src/hooks/chat/use-chat-scroll.ts +51 -0
  139. package/src/hooks/chat/use-chat-session-actions.ts +147 -0
  140. package/src/hooks/chat/use-chat-session-messages.ts +250 -0
  141. package/src/hooks/chat/use-chat-session.ts +57 -0
  142. package/src/hooks/chat/use-chat-view.ts +39 -0
  143. package/src/main.tsx +10 -13
  144. package/src/resources/locales/en.json +73 -0
  145. package/src/resources/locales/zh.json +73 -0
  146. package/src/runtime-config.ts +52 -0
  147. package/src/store/index.ts +2 -0
  148. package/src/vite-env.d.ts +11 -0
  149. package/src/ws.ts +5 -3
  150. package/vite.config.ts +12 -4
  151. package/dist/assets/channel-DrWdSpqV.js +0 -1
  152. package/dist/assets/clone-D0cC8LLB.js +0 -1
  153. package/dist/assets/flowDiagram-v2-4f6560a1-Bf_DH7dp.js +0 -1
  154. package/dist/assets/index-CNMzWvKV.js +0 -497
  155. package/dist/assets/index-PEmISxiy.css +0 -1
  156. package/src/components/chat/ToolCallBox.scss +0 -137
  157. package/src/components/chat/useChatSession.ts +0 -370
  158. /package/src/components/{chat/CodeBlock.scss → CodeBlock.scss} +0 -0
  159. /package/src/components/chat/{MessageFooter.tsx → Messages/MessageFooter.tsx} +0 -0
  160. /package/src/components/chat/{CompletionMenu.scss → Sender/CompletionMenu.scss} +0 -0
  161. /package/src/components/chat/{CompletionMenu.tsx → Sender/CompletionMenu.tsx} +0 -0
  162. /package/src/components/chat/{ThinkingStatus.scss → Sender/ThinkingStatus.scss} +0 -0
  163. /package/src/components/chat/{ThinkingStatus.tsx → Sender/ThinkingStatus.tsx} +0 -0
  164. /package/src/components/chat/{ToolCallBox.tsx → tools/core/ToolCallBox.tsx} +0 -0
  165. /package/src/components/chat/{ToolGroup.scss → tools/core/ToolGroup.scss} +0 -0
  166. /package/src/{components/chat/safeSerialize.ts → utils/safe-serialize.ts} +0 -0
@@ -0,0 +1,250 @@
1
+ import { App } from 'antd'
2
+ import { useEffect, useRef, useState } from 'react'
3
+ import { useSWRConfig } from 'swr'
4
+
5
+ import type { AskUserQuestionParams, ChatMessage, Session, SessionInfo, WSEvent } from '@vibe-forge/core'
6
+ import { getSessionMessages } from '#~/api.js'
7
+ import { connectionManager } from '#~/connectionManager.js'
8
+ import type { PermissionMode } from './use-chat-permission-mode'
9
+
10
+ const applyMessageEvent = (currentMessages: ChatMessage[], data: WSEvent) => {
11
+ if (data.type !== 'message') return currentMessages
12
+ const exists = currentMessages.find((msg) => msg.id === data.message.id)
13
+ if (exists != null) {
14
+ return currentMessages.map((msg) => (msg.id === data.message.id ? data.message : msg))
15
+ }
16
+ return [...currentMessages, data.message]
17
+ }
18
+
19
+ const applyToolResultEvent = (currentMessages: ChatMessage[], data: WSEvent): ChatMessage[] => {
20
+ if (data.type !== 'tool_result') return currentMessages
21
+ const status = data.isError === true ? 'error' : 'success'
22
+ return currentMessages.map((msg) => {
23
+ if (msg.toolCall != null && msg.toolCall.id === data.toolCallId) {
24
+ return {
25
+ ...msg,
26
+ toolCall: {
27
+ ...msg.toolCall,
28
+ status,
29
+ output: data.output
30
+ }
31
+ }
32
+ }
33
+ return msg
34
+ })
35
+ }
36
+
37
+ export function useChatSessionMessages({
38
+ session,
39
+ modelForQuery,
40
+ permissionMode,
41
+ setInteractionRequest
42
+ }: {
43
+ session?: Session
44
+ modelForQuery?: string
45
+ permissionMode: PermissionMode
46
+ setInteractionRequest: (value: { id: string; payload: AskUserQuestionParams } | null) => void
47
+ }) {
48
+ const { message } = App.useApp()
49
+ const { mutate } = useSWRConfig()
50
+ const [messages, setMessages] = useState<ChatMessage[]>([])
51
+ const [sessionInfo, setSessionInfo] = useState<SessionInfo | null>(null)
52
+ const [isReady, setIsReady] = useState(false)
53
+ const isInitialLoadRef = useRef<boolean>(true)
54
+ const lastConnectedModelRef = useRef<string | undefined>(undefined)
55
+ const lastConnectedPermissionModeRef = useRef<string | undefined>(undefined)
56
+
57
+ useEffect(() => {
58
+ setMessages([])
59
+ setSessionInfo(null)
60
+ setIsReady(false)
61
+ setInteractionRequest(null)
62
+ isInitialLoadRef.current = true
63
+
64
+ if (session?.id == null || session.id === '') {
65
+ setIsReady(true)
66
+ lastConnectedModelRef.current = undefined
67
+ lastConnectedPermissionModeRef.current = undefined
68
+ return
69
+ }
70
+
71
+ let isDisposed = false
72
+
73
+ const fetchHistory = async () => {
74
+ try {
75
+ const res = await getSessionMessages(session.id)
76
+ if (isDisposed) return
77
+ const events = res.messages as WSEvent[]
78
+
79
+ if (res.session) {
80
+ const updatedSession = res.session
81
+ void mutate('/api/sessions', (prev: { sessions: Session[] } | undefined) => {
82
+ if (prev?.sessions == null) return prev
83
+ const newSessions = prev.sessions.map((s: Session) =>
84
+ s.id === updatedSession.id ? { ...s, ...updatedSession } : s
85
+ )
86
+ return { ...prev, sessions: newSessions }
87
+ }, false)
88
+ }
89
+
90
+ if (res.interaction) {
91
+ setInteractionRequest(res.interaction)
92
+ }
93
+
94
+ let currentMessages: ChatMessage[] = []
95
+ let currentSessionInfo: SessionInfo | null = null
96
+
97
+ for (const data of events) {
98
+ currentMessages = applyMessageEvent(currentMessages, data)
99
+ currentMessages = applyToolResultEvent(currentMessages, data)
100
+ if (data.type === 'session_info') {
101
+ if (data.info != null && data.info.type !== 'summary') {
102
+ currentSessionInfo = data.info
103
+ }
104
+ }
105
+ }
106
+
107
+ setMessages(currentMessages)
108
+ setSessionInfo(currentSessionInfo)
109
+
110
+ setTimeout(() => {
111
+ if (isDisposed) return
112
+ setIsReady(true)
113
+ isInitialLoadRef.current = false
114
+ }, 100)
115
+ } catch (err) {
116
+ console.error('Failed to fetch history messages:', err)
117
+ }
118
+ }
119
+
120
+ void fetchHistory()
121
+
122
+ return () => {
123
+ isDisposed = true
124
+ }
125
+ }, [mutate, session?.id, setInteractionRequest])
126
+
127
+ useEffect(() => {
128
+ if (session?.id == null || session.id === '') {
129
+ return
130
+ }
131
+
132
+ let isDisposed = false
133
+ let cleanup: (() => void) | undefined
134
+ const normalizedModel = modelForQuery ?? ''
135
+ const modelChanged = modelForQuery != null &&
136
+ lastConnectedModelRef.current != null &&
137
+ normalizedModel !== lastConnectedModelRef.current &&
138
+ session?.status !== 'running'
139
+ const normalizedPermissionMode = permissionMode ?? ''
140
+ const permissionModeChanged = permissionMode != null &&
141
+ lastConnectedPermissionModeRef.current != null &&
142
+ normalizedPermissionMode !== lastConnectedPermissionModeRef.current &&
143
+ session?.status !== 'running'
144
+ if (modelChanged || permissionModeChanged) {
145
+ connectionManager.send(session.id, { type: 'terminate_session' })
146
+ connectionManager.close(session.id)
147
+ }
148
+ lastConnectedModelRef.current = normalizedModel
149
+ lastConnectedPermissionModeRef.current = normalizedPermissionMode
150
+
151
+ const timer = setTimeout(() => {
152
+ if (isDisposed) return
153
+
154
+ const connectionParams: Record<string, string> = {}
155
+ if (modelForQuery) {
156
+ connectionParams.model = modelForQuery
157
+ }
158
+ if (permissionMode) {
159
+ connectionParams.permissionMode = permissionMode
160
+ }
161
+
162
+ cleanup = connectionManager.connect(session.id, {
163
+ onOpen() {
164
+ },
165
+ onMessage(data: WSEvent) {
166
+ if (isDisposed) return
167
+ if (data.type === 'error') {
168
+ void message.error(data.message)
169
+ return
170
+ }
171
+
172
+ if (data.type === 'session_updated') {
173
+ void mutate('/api/sessions', (prev: { sessions: Session[] } | undefined) => {
174
+ if (prev?.sessions == null) return prev
175
+ const updatedSession = data.session as Session | { id: string; isDeleted: boolean }
176
+
177
+ if ('isDeleted' in updatedSession && updatedSession.isDeleted) {
178
+ return {
179
+ ...prev,
180
+ sessions: prev.sessions.filter((s: Session) => s.id !== updatedSession.id)
181
+ }
182
+ }
183
+
184
+ const typedUpdatedSession = updatedSession as Session
185
+ const newSessions = prev.sessions.map((s: Session) =>
186
+ s.id === typedUpdatedSession.id ? { ...s, ...typedUpdatedSession } : s
187
+ )
188
+
189
+ if (
190
+ !newSessions.some((s: Session) => s.id === typedUpdatedSession.id) && !('isDeleted' in updatedSession)
191
+ ) {
192
+ newSessions.unshift(typedUpdatedSession)
193
+ }
194
+
195
+ return { ...prev, sessions: newSessions }
196
+ }, false)
197
+ return
198
+ }
199
+
200
+ if (data.type === 'message') {
201
+ setMessages((current) => applyMessageEvent(current, data))
202
+ return
203
+ }
204
+
205
+ if (data.type === 'session_info') {
206
+ if (data.info != null && data.info.type === 'summary') {
207
+ void mutate('/api/sessions')
208
+ } else {
209
+ setSessionInfo(data.info ?? null)
210
+ if (isInitialLoadRef.current) {
211
+ setTimeout(() => {
212
+ if (isDisposed) return
213
+ if (isInitialLoadRef.current) {
214
+ setIsReady(true)
215
+ isInitialLoadRef.current = false
216
+ }
217
+ }, 100)
218
+ }
219
+ }
220
+ return
221
+ }
222
+
223
+ if (data.type === 'tool_result') {
224
+ setMessages((current) => applyToolResultEvent(current, data))
225
+ return
226
+ }
227
+
228
+ if (data.type === 'interaction_request') {
229
+ setInteractionRequest({ id: data.id, payload: data.payload })
230
+ }
231
+ },
232
+ onClose() {
233
+ }
234
+ }, Object.keys(connectionParams).length > 0 ? connectionParams : undefined)
235
+ }, modelChanged ? 200 : 100)
236
+
237
+ return () => {
238
+ isDisposed = true
239
+ clearTimeout(timer)
240
+ cleanup?.()
241
+ }
242
+ }, [message, modelForQuery, mutate, permissionMode, session?.id, session?.status, setInteractionRequest])
243
+
244
+ return {
245
+ messages,
246
+ setMessages,
247
+ sessionInfo,
248
+ isReady
249
+ }
250
+ }
@@ -0,0 +1,57 @@
1
+ import { useTranslation } from 'react-i18next'
2
+
3
+ import type { Session } from '@vibe-forge/core'
4
+ import { useChatInteraction } from './use-chat-interaction'
5
+ import { useChatModels } from './use-chat-models'
6
+ import { useChatPermissionMode } from './use-chat-permission-mode'
7
+ import { useChatSessionMessages } from './use-chat-session-messages'
8
+ import { useChatView } from './use-chat-view'
9
+
10
+ export function useChatSession({
11
+ session
12
+ }: {
13
+ session?: Session
14
+ }) {
15
+ const { t } = useTranslation()
16
+ const {
17
+ selectedModel,
18
+ selectedModelWithService,
19
+ setSelectedModel,
20
+ modelOptions,
21
+ hasAvailableModels
22
+ } = useChatModels()
23
+ const { permissionMode, setPermissionMode, permissionModeOptions } = useChatPermissionMode()
24
+ const { activeView, setActiveView } = useChatView()
25
+ const { interactionRequest, setInteractionRequest, handleInteractionResponse } = useChatInteraction({
26
+ sessionId: session?.id
27
+ })
28
+ const { messages, setMessages, sessionInfo, isReady } = useChatSessionMessages({
29
+ session,
30
+ modelForQuery: selectedModelWithService,
31
+ permissionMode,
32
+ setInteractionRequest
33
+ })
34
+ const isThinking = session?.status === 'running'
35
+
36
+ return {
37
+ messages,
38
+ sessionInfo,
39
+ interactionRequest,
40
+ isReady,
41
+ isThinking,
42
+ activeView,
43
+ setActiveView,
44
+ handleInteractionResponse,
45
+ setMessages,
46
+ placeholder: !session?.id ? t('chat.newSessionPlaceholder') : undefined,
47
+ modelOptions,
48
+ selectedModel,
49
+ modelForQuery: selectedModelWithService,
50
+ setSelectedModel,
51
+ permissionMode,
52
+ setPermissionMode,
53
+ permissionModeOptions,
54
+ hasAvailableModels,
55
+ modelUnavailable: !hasAvailableModels
56
+ }
57
+ }
@@ -0,0 +1,39 @@
1
+ import { useCallback, useEffect } from 'react'
2
+
3
+ import { useQueryParams } from '#~/hooks/useQueryParams.js'
4
+ import type { ChatHeaderView } from '#~/components/chat/ChatHeader.js'
5
+
6
+ const normalizeView = (value: string): ChatHeaderView => {
7
+ if (value === 'timeline' || value === 'settings' || value === 'history') {
8
+ return value
9
+ }
10
+ return 'history'
11
+ }
12
+
13
+ export function useChatView() {
14
+ const { values: queryValues, update: updateQuery } = useQueryParams<{ view: string }>({
15
+ keys: ['view'],
16
+ defaults: {
17
+ view: 'history'
18
+ },
19
+ omit: {
20
+ view: (value) => value === 'history'
21
+ }
22
+ })
23
+
24
+ const activeView = normalizeView(queryValues.view)
25
+ const setActiveView = useCallback((view: ChatHeaderView) => {
26
+ updateQuery({ view })
27
+ }, [updateQuery])
28
+
29
+ useEffect(() => {
30
+ if (activeView !== queryValues.view) {
31
+ updateQuery({ view: activeView })
32
+ }
33
+ }, [activeView, queryValues.view, updateQuery])
34
+
35
+ return {
36
+ activeView,
37
+ setActiveView
38
+ }
39
+ }
package/src/main.tsx CHANGED
@@ -1,3 +1,5 @@
1
+ import 'devicon/devicon.min.css'
2
+
1
3
  import './styles/global.scss'
2
4
  import './i18n'
3
5
 
@@ -8,30 +10,25 @@ import { createRoot } from 'react-dom/client'
8
10
  import { BrowserRouter } from 'react-router-dom'
9
11
  import { SWRConfig } from 'swr'
10
12
 
13
+ import { fetchApiJson } from '#~/api/base.js'
14
+ import { getClientBase } from '#~/runtime-config.js'
15
+
11
16
  import App from './App'
12
17
 
13
18
  const root = createRoot(document.getElementById('root')!)
19
+
20
+ const clientBase = getClientBase()
21
+
14
22
  root.render(
15
23
  <React.StrictMode>
16
24
  <ConfigProvider locale={zhCN} theme={{ token: { colorPrimary: '#000000' } }}>
17
25
  <AntdApp>
18
26
  <SWRConfig
19
27
  value={{
20
- fetcher: async (path: string) => {
21
- const serverHost = (import.meta.env.__VF_PROJECT_AI_SERVER_HOST__ != null &&
22
- import.meta.env.__VF_PROJECT_AI_SERVER_HOST__ !== '')
23
- ? import.meta.env.__VF_PROJECT_AI_SERVER_HOST__
24
- : window.location.hostname
25
- const serverPort = (import.meta.env.__VF_PROJECT_AI_SERVER_PORT__ != null &&
26
- import.meta.env.__VF_PROJECT_AI_SERVER_PORT__ !== '')
27
- ? import.meta.env.__VF_PROJECT_AI_SERVER_PORT__
28
- : '8787'
29
- const baseUrl = `http://${serverHost}:${serverPort}`
30
- return fetch(`${baseUrl}${path}`).then(async (r) => r.json() as Promise<unknown>)
31
- }
28
+ fetcher: async (path: string) => fetchApiJson<unknown>(path)
32
29
  }}
33
30
  >
34
- <BrowserRouter>
31
+ <BrowserRouter basename={clientBase}>
35
32
  <App />
36
33
  </BrowserRouter>
37
34
  </SWRConfig>
@@ -13,6 +13,7 @@
13
13
  "settings": "Settings",
14
14
  "language": "Language",
15
15
  "automation": "Automation",
16
+ "benchmark": "Benchmark",
16
17
  "delete": "Delete",
17
18
  "deleteSession": "Delete Session",
18
19
  "deleteSessionConfirm": "Are you sure you want to delete this session? This action cannot be undone.",
@@ -175,6 +176,58 @@
175
176
  "runStarted": "Task started",
176
177
  "runFailed": "Start failed"
177
178
  },
179
+ "benchmark": {
180
+ "title": "Benchmark",
181
+ "sidebarHint": "Choose a category and case, inspect the task goal, and launch a run.",
182
+ "category": "Category",
183
+ "categoryCount": "{{count}} categories",
184
+ "caseCount": "{{count}} cases",
185
+ "caseTree": "Case Tree",
186
+ "expandAll": "Expand All",
187
+ "collapseAll": "Collapse All",
188
+ "runSelected": "Run Selected ({{count}})",
189
+ "runAll": "Run All",
190
+ "caseId": "Case:",
191
+ "searchPlaceholder": "Search category, title, or summary",
192
+ "emptyCases": "No benchmark cases",
193
+ "noSummary": "No summary",
194
+ "configTitle": "Case Config",
195
+ "baseCommit": "Base Commit",
196
+ "setupCommand": "Setup Command",
197
+ "testCommand": "Test Command",
198
+ "timeoutSec": "Timeout (sec)",
199
+ "runState": "Run State",
200
+ "noActiveRun": "No active benchmark run",
201
+ "runStatus": "Status",
202
+ "progress": "Progress",
203
+ "lastMessage": "Last Message",
204
+ "taskGoal": "Task Goal",
205
+ "resultTitle": "Latest Result",
206
+ "noResult": "No result yet",
207
+ "finalScore": "Final Score",
208
+ "lastRunAt": "Last Run",
209
+ "testScore": "Test Score",
210
+ "goalScore": "Goal Score",
211
+ "referenceScore": "Reference Score",
212
+ "changedFiles": "Changed Files",
213
+ "noChangedFiles": "No changed files recorded",
214
+ "testExitCode": "Test Exit Code",
215
+ "durationMs": "Duration (ms)",
216
+ "issues": "Issues",
217
+ "noIssues": "No issues",
218
+ "concurrency": "Concurrency",
219
+ "runCategory": "Run Category",
220
+ "runCase": "Run Case",
221
+ "runStarted": "Benchmark started",
222
+ "categoryRunStarted": "Category benchmark started",
223
+ "runCompleted": "Benchmark completed",
224
+ "runFailed": "Benchmark run failed",
225
+ "status": {
226
+ "pass": "Pass",
227
+ "partial": "Partial",
228
+ "fail": "Fail"
229
+ }
230
+ },
178
231
  "knowledge": {
179
232
  "title": "Project Knowledge Base",
180
233
  "subtitle": "Manage skills, entities, flows, and rules for this project",
@@ -253,6 +306,9 @@
253
306
  "modelSearchPlaceholder": "Search models or services",
254
307
  "modelUnavailable": "No models available",
255
308
  "modelConfigRequired": "Add a model service in config before starting a session",
309
+ "imageTooLarge": "Image must be smaller than 5MB",
310
+ "imageReadFailed": "Failed to read image",
311
+ "imageNotSupportedInInteraction": "Images are not supported for this interaction",
256
312
  "modelGroupRecommended": "Recommended Models",
257
313
  "availableTools": "Available Tools",
258
314
  "toolsCount": "{{count}} tools",
@@ -351,6 +407,12 @@
351
407
  "todo": "Task Planning",
352
408
  "call": "call",
353
409
  "reading": "Reading file...",
410
+ "offset": "offset",
411
+ "limit": "limit",
412
+ "timeout": "timeout",
413
+ "runInBackground": "run in background",
414
+ "dangerouslyDisableSandbox": "sandbox disabled",
415
+ "viewCommand": "View command",
354
416
  "unknown": "Unknown tool"
355
417
  },
356
418
  "sessionSettings": "Session Settings",
@@ -402,6 +464,7 @@
402
464
  "shortcutPlaceholder": "Press shortcut",
403
465
  "clearShortcut": "Clear shortcut",
404
466
  "newModelServiceName": "New model service name",
467
+ "newChannelName": "New channel name",
405
468
  "newAdapterName": "New adapter name",
406
469
  "newPluginName": "New plugin name",
407
470
  "newMcpServerName": "New MCP server name",
@@ -421,6 +484,8 @@
421
484
  "defaultModelPlaceholder": "Select model",
422
485
  "titlePlaceholder": "Enter title",
423
486
  "descriptionPlaceholder": "Enter description",
487
+ "channelType": "Channel Type",
488
+ "unknownChannelType": "Unknown type",
424
489
  "complexValue": "Complex value",
425
490
  "tagsPlaceholder": "Type and press Enter",
426
491
  "types": {
@@ -754,12 +819,20 @@
754
819
  "general": "General",
755
820
  "conversation": "Conversation",
756
821
  "modelServices": "Model Services",
822
+ "channels": "Channels",
757
823
  "adapters": "Adapters",
758
824
  "plugins": "Plugins",
759
825
  "mcp": "MCP",
760
826
  "shortcuts": "Shortcuts",
827
+ "appearance": "Appearance",
761
828
  "experiments": "Experiments",
762
829
  "about": "About"
830
+ },
831
+ "appSettings": {
832
+ "announcements": {
833
+ "label": "Show announcements",
834
+ "desc": "Show announcements when creating a new session"
835
+ }
763
836
  }
764
837
  }
765
838
  }
@@ -13,6 +13,7 @@
13
13
  "settings": "设置",
14
14
  "language": "语言",
15
15
  "automation": "自动化任务",
16
+ "benchmark": "评测",
16
17
  "delete": "删除",
17
18
  "deleteSession": "删除会话",
18
19
  "deleteSessionConfirm": "确定要删除这个会话吗?此操作不可撤销。",
@@ -176,6 +177,58 @@
176
177
  "runStarted": "已启动任务",
177
178
  "runFailed": "启动失败"
178
179
  },
180
+ "benchmark": {
181
+ "title": "评测",
182
+ "sidebarHint": "选择 category 和 case,查看任务目标并触发跑分。",
183
+ "category": "分类",
184
+ "categoryCount": "{{count}} 个分类",
185
+ "caseCount": "{{count}} 个用例",
186
+ "caseTree": "用例树",
187
+ "expandAll": "展开全部",
188
+ "collapseAll": "折叠全部",
189
+ "runSelected": "运行已选 ({{count}})",
190
+ "runAll": "运行全部",
191
+ "caseId": "用例:",
192
+ "searchPlaceholder": "搜索分类、标题或摘要",
193
+ "emptyCases": "暂无 benchmark 用例",
194
+ "noSummary": "暂无摘要",
195
+ "configTitle": "用例配置",
196
+ "baseCommit": "基线 Commit",
197
+ "setupCommand": "初始化命令",
198
+ "testCommand": "测试命令",
199
+ "timeoutSec": "超时(秒)",
200
+ "runState": "运行状态",
201
+ "noActiveRun": "当前没有运行中的 benchmark 任务",
202
+ "runStatus": "运行状态",
203
+ "progress": "进度",
204
+ "lastMessage": "最新消息",
205
+ "taskGoal": "任务目标",
206
+ "resultTitle": "最近结果",
207
+ "noResult": "暂无结果",
208
+ "finalScore": "总分",
209
+ "lastRunAt": "最近运行",
210
+ "testScore": "测试分",
211
+ "goalScore": "目标分",
212
+ "referenceScore": "参考分",
213
+ "changedFiles": "改动文件数",
214
+ "noChangedFiles": "暂无改动文件记录",
215
+ "testExitCode": "测试退出码",
216
+ "durationMs": "耗时(毫秒)",
217
+ "issues": "问题",
218
+ "noIssues": "暂无问题",
219
+ "concurrency": "并发",
220
+ "runCategory": "运行当前分类",
221
+ "runCase": "运行当前用例",
222
+ "runStarted": "Benchmark 已启动",
223
+ "categoryRunStarted": "分类跑分已启动",
224
+ "runCompleted": "Benchmark 已完成",
225
+ "runFailed": "Benchmark 运行失败",
226
+ "status": {
227
+ "pass": "通过",
228
+ "partial": "部分完成",
229
+ "fail": "失败"
230
+ }
231
+ },
179
232
  "knowledge": {
180
233
  "title": "项目知识库",
181
234
  "subtitle": "管理当前项目的技能、实体、流程与规则",
@@ -254,6 +307,9 @@
254
307
  "modelSearchPlaceholder": "搜索模型或服务",
255
308
  "modelUnavailable": "暂无可用模型",
256
309
  "modelConfigRequired": "请先在配置中添加模型服务后再开始会话",
310
+ "imageTooLarge": "图片大小不能超过 5MB",
311
+ "imageReadFailed": "图片读取失败",
312
+ "imageNotSupportedInInteraction": "当前交互不支持图片",
257
313
  "modelGroupRecommended": "推荐模型",
258
314
  "availableTools": "可用工具",
259
315
  "toolsCount": "{{count}} 个工具",
@@ -352,6 +408,12 @@
352
408
  "todo": "任务规划",
353
409
  "call": "调用",
354
410
  "reading": "正在读取文件...",
411
+ "offset": "offset",
412
+ "limit": "limit",
413
+ "timeout": "timeout",
414
+ "runInBackground": "后台执行",
415
+ "dangerouslyDisableSandbox": "禁用沙箱",
416
+ "viewCommand": "查看指令",
355
417
  "unknown": "未知工具"
356
418
  },
357
419
  "sessionSettings": "会话设置",
@@ -403,6 +465,7 @@
403
465
  "shortcutPlaceholder": "按下快捷键",
404
466
  "clearShortcut": "清除快捷键",
405
467
  "newModelServiceName": "新增模型服务名称",
468
+ "newChannelName": "新增频道名称",
406
469
  "newAdapterName": "新增适配器名称",
407
470
  "newPluginName": "新增插件名称",
408
471
  "newMcpServerName": "新增 MCP 服务名称",
@@ -422,6 +485,8 @@
422
485
  "defaultModelPlaceholder": "请选择模型",
423
486
  "titlePlaceholder": "请输入标题",
424
487
  "descriptionPlaceholder": "请输入描述",
488
+ "channelType": "频道类型",
489
+ "unknownChannelType": "未知类型",
425
490
  "complexValue": "复杂结构",
426
491
  "tagsPlaceholder": "输入后回车",
427
492
  "types": {
@@ -755,12 +820,20 @@
755
820
  "general": "通用",
756
821
  "conversation": "会话",
757
822
  "modelServices": "模型服务",
823
+ "channels": "频道",
758
824
  "adapters": "适配器",
759
825
  "plugins": "插件",
760
826
  "mcp": "MCP",
761
827
  "shortcuts": "快捷键",
828
+ "appearance": "外观",
762
829
  "experiments": "实验功能",
763
830
  "about": "关于"
831
+ },
832
+ "appSettings": {
833
+ "announcements": {
834
+ "label": "显示公告",
835
+ "desc": "新建会话时展示公告信息"
836
+ }
764
837
  }
765
838
  }
766
839
  }