@vibe-forge/client 0.10.1 → 0.11.1
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/assets/{arc-C1rWFTer.js → arc-CSepokz3.js} +1 -1
- package/dist/assets/{blockDiagram-c4efeb88-DlZ9x70F.js → blockDiagram-c4efeb88-D0ARcoNf.js} +1 -1
- package/dist/assets/{c4Diagram-c83219d4-BKKxi__y.js → c4Diagram-c83219d4-BysYF9kP.js} +1 -1
- package/dist/assets/channel-CeKPk6Nd.js +1 -0
- package/dist/assets/{classDiagram-beda092f-CVGPySZq.js → classDiagram-beda092f-BG1GhIOL.js} +1 -1
- package/dist/assets/{classDiagram-v2-2358418a-7kp8GVVj.js → classDiagram-v2-2358418a-Dd08uGSH.js} +1 -1
- package/dist/assets/clone-CrkD2PuD.js +1 -0
- package/dist/assets/{createText-1719965b-Dykv8kT9.js → createText-1719965b-CigPEIEn.js} +1 -1
- package/dist/assets/{cssMode-B59COYVW.js → cssMode-MjflyEfm.js} +1 -1
- package/dist/assets/{edges-96097737-CkZ1ZBro.js → edges-96097737-DuTBJJRv.js} +1 -1
- package/dist/assets/{erDiagram-0228fc6a-281ADcRp.js → erDiagram-0228fc6a-Cp1bL7Y7.js} +1 -1
- package/dist/assets/{flowDb-c6c81e3f-BQjX_flP.js → flowDb-c6c81e3f-BfKbhiq5.js} +1 -1
- package/dist/assets/{flowDiagram-50d868cf-DMHZTjES.js → flowDiagram-50d868cf-m7gGc3PK.js} +1 -1
- package/dist/assets/flowDiagram-v2-4f6560a1-4ZU4bdp1.js +1 -0
- package/dist/assets/{flowchart-elk-definition-6af322e1-CI3yz4z8.js → flowchart-elk-definition-6af322e1-EVeTDRRK.js} +1 -1
- package/dist/assets/{freemarker2-DWnWjibn.js → freemarker2-Bb3-QAIN.js} +1 -1
- package/dist/assets/{ganttDiagram-a2739b55-B3IING9L.js → ganttDiagram-a2739b55-DslB2U0R.js} +1 -1
- package/dist/assets/{gitGraphDiagram-82fe8481-CnArIr_T.js → gitGraphDiagram-82fe8481-C-KFWMXL.js} +1 -1
- package/dist/assets/{graph-BZ1F0Yve.js → graph-CukaUc0o.js} +1 -1
- package/dist/assets/{handlebars-C1QH9qTz.js → handlebars-C4le-2Y6.js} +1 -1
- package/dist/assets/{html-D1NkqHjC.js → html-CjNiRs5S.js} +1 -1
- package/dist/assets/{htmlMode-DAZCE_rA.js → htmlMode-B73_3-We.js} +1 -1
- package/dist/assets/{index-5325376f-Da9zSHjA.js → index-5325376f-CVISZFPw.js} +1 -1
- package/dist/assets/{index-C0vjF3D0.js → index-BZosmb5_.js} +336 -336
- package/dist/assets/index-C1oh0w9H.css +32 -0
- package/dist/assets/{infoDiagram-8eee0895-DYbFvRM7.js → infoDiagram-8eee0895-DoirLE1K.js} +1 -1
- package/dist/assets/{javascript-CoMjGRHa.js → javascript-BDjnqJFP.js} +1 -1
- package/dist/assets/{journeyDiagram-c64418c1-Boebox0b.js → journeyDiagram-c64418c1-Ckn-p2CM.js} +1 -1
- package/dist/assets/{jsonMode-D__gAvuz.js → jsonMode-C-ftOc5j.js} +1 -1
- package/dist/assets/{layout-CTcHNbHp.js → layout-Z7yUG7hB.js} +1 -1
- package/dist/assets/{line-4AwinCz2.js → line-DPG_cfAy.js} +1 -1
- package/dist/assets/{linear-CeSMLzJW.js → linear--GSeVfMi.js} +1 -1
- package/dist/assets/{liquid-DZF6egdE.js → liquid-COiLZ9py.js} +1 -1
- package/dist/assets/{lspLanguageFeatures-6K4lv5S2.js → lspLanguageFeatures-DGmhryFq.js} +1 -1
- package/dist/assets/{mdx-Cnt4ka6w.js → mdx-BpL87Gej.js} +1 -1
- package/dist/assets/{mermaid.core-B0yG5s4D.js → mermaid.core-Cg1CCDo6.js} +4 -4
- package/dist/assets/{mindmap-definition-8da855dc-KJEvXMKj.js → mindmap-definition-8da855dc-CKDof1lD.js} +1 -1
- package/dist/assets/{pieDiagram-a8764435-17nFAXPJ.js → pieDiagram-a8764435-DwvCaZVE.js} +1 -1
- package/dist/assets/{python-DA3TtjDv.js → python-63dBmWV_.js} +1 -1
- package/dist/assets/{quadrantDiagram-1e28029f-Dt4vubi-.js → quadrantDiagram-1e28029f-CkzYBQpy.js} +1 -1
- package/dist/assets/{razor-CWDJgvX_.js → razor-C50tBqEZ.js} +1 -1
- package/dist/assets/{requirementDiagram-08caed73-H6aDyDK-.js → requirementDiagram-08caed73-Brgdjqf4.js} +1 -1
- package/dist/assets/{sankeyDiagram-a04cb91d-DxsVtbjI.js → sankeyDiagram-a04cb91d-CGkYexrs.js} +1 -1
- package/dist/assets/{sequenceDiagram-c5b8d532-BHa148XJ.js → sequenceDiagram-c5b8d532-D0wE-_J8.js} +1 -1
- package/dist/assets/{stateDiagram-1ecb1508-DgwBm8LO.js → stateDiagram-1ecb1508-BYb3NCXZ.js} +1 -1
- package/dist/assets/{stateDiagram-v2-c2b004d7-BK7IQLVc.js → stateDiagram-v2-c2b004d7-DrPqi4Pt.js} +1 -1
- package/dist/assets/{styles-b4e223ce-DzW27Bc-.js → styles-b4e223ce-DD66TIO4.js} +1 -1
- package/dist/assets/{styles-ca3715f6-Dex2GiLT.js → styles-ca3715f6-iy02LHIV.js} +1 -1
- package/dist/assets/{styles-d45a18b0-B6fGtDKS.js → styles-d45a18b0-BgqAgJyW.js} +1 -1
- package/dist/assets/{svgDrawCommon-b86b1483-B4HYgfV5.js → svgDrawCommon-b86b1483-CDq7ugnw.js} +1 -1
- package/dist/assets/{timeline-definition-faaaa080--QSbWb25.js → timeline-definition-faaaa080-DzcLLjK0.js} +1 -1
- package/dist/assets/{tsMode-ZM7ocZCH.js → tsMode-BFRFI4ct.js} +1 -1
- package/dist/assets/{typescript-CKWDmBCc.js → typescript-CBZQRAPv.js} +1 -1
- package/dist/assets/{xml-DuEUAzPi.js → xml-BpWm6upt.js} +1 -1
- package/dist/assets/{xychartDiagram-f5964ef8-D09Zkv2K.js → xychartDiagram-f5964ef8-zBN8FmLQ.js} +1 -1
- package/dist/assets/{yaml-DL7QPRYk.js → yaml-CqbJPiIP.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +10 -10
- package/src/api/git.ts +78 -0
- package/src/api.ts +24 -0
- package/src/components/chat/ChatHeader.tsx +4 -0
- package/src/components/chat/ChatHistoryView.tsx +22 -13
- package/src/components/chat/git-controls/BranchSwitcherDropdown.tsx +157 -0
- package/src/components/chat/git-controls/ChatGitControls.scss +616 -0
- package/src/components/chat/git-controls/ChatGitControls.tsx +151 -0
- package/src/components/chat/git-controls/GitCommitModal.tsx +199 -0
- package/src/components/chat/git-controls/GitCommitModalParts.tsx +151 -0
- package/src/components/chat/git-controls/GitOperationsDropdown.tsx +123 -0
- package/src/components/chat/git-controls/GitPushModal.tsx +106 -0
- package/src/components/chat/git-controls/GitWorktreeDropdown.tsx +68 -0
- package/src/components/chat/git-controls/git-branch-utils.ts +88 -0
- package/src/components/chat/git-controls/git-commit-utils.ts +79 -0
- package/src/components/chat/git-controls/git-mutation-utils.ts +69 -0
- package/src/components/chat/git-controls/git-operation-utils.ts +98 -0
- package/src/components/chat/git-controls/git-worktree-utils.ts +49 -0
- package/src/components/chat/git-controls/use-chat-git-commit.ts +185 -0
- package/src/components/chat/git-controls/use-chat-git-controls.ts +200 -0
- package/src/components/chat/git-controls/use-chat-git-push-state.ts +19 -0
- package/src/components/chat/git-controls/use-chat-git-worktrees.ts +39 -0
- package/src/components/chat/messages/MessageStatusNotice.scss +163 -0
- package/src/components/chat/messages/MessageStatusNotice.tsx +48 -0
- package/src/components/chat/messages/build-chat-history-status-notices.ts +138 -0
- package/src/components/chat/sender/@components/sender-body/SenderBody.tsx +0 -24
- package/src/components/chat/sender/@core/build-sender-controller-result.ts +0 -6
- package/src/components/chat/sender/@hooks/use-sender-controller.ts +0 -2
- package/src/components/chat/sender/@types/sender-props.ts +0 -3
- package/src/components/chat/sender/Sender.scss +0 -58
- package/src/components/chat/sender/Sender.tsx +0 -2
- package/src/components/chat/tools/DefaultTool.tsx +84 -208
- package/src/components/chat/tools/adapter-claude/ClaudeEditDiff.tsx +30 -0
- package/src/components/chat/tools/adapter-claude/GenericClaudeTool.scss +128 -0
- package/src/components/chat/tools/adapter-claude/GenericClaudeTool.tsx +119 -0
- package/src/components/chat/tools/adapter-claude/claude-tool-edit-builders.ts +109 -0
- package/src/components/chat/tools/adapter-claude/claude-tool-field-sections.tsx +83 -0
- package/src/components/chat/tools/adapter-claude/claude-tool-operation-builders.ts +135 -0
- package/src/components/chat/tools/adapter-claude/claude-tool-presentation.ts +61 -0
- package/src/components/chat/tools/adapter-claude/claude-tool-shared.ts +185 -0
- package/src/components/chat/tools/adapter-claude/claude-tool-summary.ts +76 -0
- package/src/components/chat/tools/adapter-claude/claude-tool-system-builders.ts +125 -0
- package/src/components/chat/tools/adapter-claude/claude-tool-task-builders.ts +148 -0
- package/src/components/chat/tools/adapter-claude/index.ts +24 -15
- package/src/components/chat/tools/core/ToolCallBox.scss +362 -36
- package/src/components/chat/tools/core/ToolCallBox.tsx +35 -13
- package/src/components/chat/tools/core/ToolDiffViewer.scss +138 -0
- package/src/components/chat/tools/core/ToolDiffViewer.tsx +180 -0
- package/src/components/chat/tools/core/ToolGroup.scss +52 -74
- package/src/components/chat/tools/core/ToolGroup.tsx +25 -40
- package/src/components/chat/tools/core/ToolRenderer.tsx +3 -3
- package/src/components/chat/tools/core/ToolResultContent.tsx +66 -0
- package/src/components/chat/tools/core/ToolSummaryHeader.tsx +67 -0
- package/src/components/chat/tools/core/generic-tool-presentation.ts +661 -0
- package/src/components/chat/tools/core/tool-content-presence.ts +57 -0
- package/src/components/chat/tools/core/tool-display.ts +203 -0
- package/src/components/chat/tools/core/tool-field-sections.tsx +132 -0
- package/src/components/chat/tools/core/tool-result-content-utils.ts +171 -0
- package/src/components/chat/tools/core/tool-summary.ts +206 -0
- package/src/components/chat/tools/plugin-chrome-devtools/ChromeDevtoolsTool.tsx +59 -53
- package/src/components/chat/tools/task/GetTaskInfoTool.tsx +26 -9
- package/src/components/chat/tools/task/ListTasksTool.tsx +22 -9
- package/src/components/chat/tools/task/StartTasksTool.tsx +22 -9
- package/src/hooks/chat/interaction-state.ts +29 -9
- package/src/hooks/chat/session-view-cache.ts +80 -0
- package/src/hooks/chat/use-chat-scroll.ts +2 -2
- package/src/hooks/chat/use-chat-session-messages.ts +139 -39
- package/src/hooks/chat/use-chat-session.ts +2 -2
- package/src/resources/locales/en.json +149 -0
- package/src/resources/locales/zh.json +149 -0
- package/src/routes/ChatRoute.tsx +24 -27
- package/src/utils/strip-ansi.ts +26 -0
- package/dist/assets/channel-F1aqMANO.js +0 -1
- package/dist/assets/clone-B-GCuXNo.js +0 -1
- package/dist/assets/flowDiagram-v2-4f6560a1-C5FzdVl1.js +0 -1
- package/dist/assets/index-vzEbM21t.css +0 -32
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
|
2
|
+
import type { SetStateAction } from 'react'
|
|
2
3
|
import { useTranslation } from 'react-i18next'
|
|
3
4
|
import { useSWRConfig } from 'swr'
|
|
4
5
|
|
|
5
|
-
import { getSessionMessages } from '#~/api.js'
|
|
6
|
-
import { connectionManager } from '#~/connectionManager.js'
|
|
7
6
|
import type { AskUserQuestionParams, ChatMessage, Session, WSEvent } from '@vibe-forge/core'
|
|
8
7
|
import type { SessionInfo } from '@vibe-forge/types'
|
|
9
|
-
|
|
8
|
+
|
|
9
|
+
import { getSessionMessages } from '#~/api.js'
|
|
10
|
+
import { connectionManager } from '#~/connectionManager.js'
|
|
11
|
+
|
|
12
|
+
import type { ChatErrorState, InteractionRequestState } from './interaction-state'
|
|
10
13
|
import {
|
|
11
14
|
applyInteractionStateEvent,
|
|
12
15
|
findLatestFatalError,
|
|
13
16
|
getFatalSessionError,
|
|
14
17
|
restoreInteractionStateFromHistory
|
|
15
18
|
} from './interaction-state'
|
|
19
|
+
import {
|
|
20
|
+
deleteChatSessionViewSnapshot,
|
|
21
|
+
restoreChatSessionViewSnapshot,
|
|
22
|
+
setChatSessionViewSnapshot
|
|
23
|
+
} from './session-view-cache'
|
|
24
|
+
import type { ChatSessionViewSnapshot } from './session-view-cache'
|
|
16
25
|
import type { ChatEffort } from './use-chat-effort'
|
|
17
26
|
import type { PermissionMode } from './use-chat-permission-mode'
|
|
18
27
|
|
|
@@ -60,10 +69,10 @@ export function useChatSessionMessages({
|
|
|
60
69
|
}) {
|
|
61
70
|
const { t } = useTranslation()
|
|
62
71
|
const { mutate } = useSWRConfig()
|
|
63
|
-
const [
|
|
72
|
+
const [messagesState, setMessagesState] = useState<ChatMessage[]>([])
|
|
64
73
|
const [sessionInfo, setSessionInfo] = useState<SessionInfo | null>(null)
|
|
65
74
|
const [isReady, setIsReady] = useState(false)
|
|
66
|
-
const [
|
|
75
|
+
const [errorState, setErrorState] = useState<ChatErrorState | null>(null)
|
|
67
76
|
const [retryCount, setRetryCount] = useState(0)
|
|
68
77
|
const isInitialLoadRef = useRef<boolean>(true)
|
|
69
78
|
const lastConnectedModelRef = useRef<string | undefined>(undefined)
|
|
@@ -72,13 +81,50 @@ export function useChatSessionMessages({
|
|
|
72
81
|
const lastConnectedAdapterRef = useRef<string | undefined>(undefined)
|
|
73
82
|
const lastObservedSessionStatusRef = useRef<Session['status'] | undefined>(session?.status)
|
|
74
83
|
const expectedCloseRef = useRef(false)
|
|
75
|
-
const interactionRequestRef = useRef<
|
|
84
|
+
const interactionRequestRef = useRef<InteractionRequestState | null>(null)
|
|
76
85
|
const activeSessionIdRef = useRef<string | undefined>(session?.id)
|
|
77
86
|
const historyRequestSeqRef = useRef(0)
|
|
78
87
|
const reconcileTimersRef = useRef<Array<ReturnType<typeof setTimeout>>>([])
|
|
88
|
+
const sessionViewCacheRef = useRef(new Map<string, ChatSessionViewSnapshot>())
|
|
79
89
|
|
|
80
90
|
activeSessionIdRef.current = session?.id
|
|
81
91
|
|
|
92
|
+
const updateSessionViewCache = useCallback((
|
|
93
|
+
sessionId: string,
|
|
94
|
+
patch: Partial<{
|
|
95
|
+
messages: ChatMessage[]
|
|
96
|
+
sessionInfo: SessionInfo | null
|
|
97
|
+
errorState: ChatErrorState | null
|
|
98
|
+
interactionRequest: InteractionRequestState | null
|
|
99
|
+
isHydrated: boolean
|
|
100
|
+
}>
|
|
101
|
+
) => {
|
|
102
|
+
return setChatSessionViewSnapshot(sessionViewCacheRef.current, sessionId, patch)
|
|
103
|
+
}, [])
|
|
104
|
+
|
|
105
|
+
const removeSessionViewCache = useCallback((sessionId: string) => {
|
|
106
|
+
deleteChatSessionViewSnapshot(sessionViewCacheRef.current, sessionId)
|
|
107
|
+
}, [])
|
|
108
|
+
|
|
109
|
+
const setMessages = useCallback((value: SetStateAction<ChatMessage[]>) => {
|
|
110
|
+
setMessagesState((current) => {
|
|
111
|
+
const next = typeof value === 'function'
|
|
112
|
+
? value(current)
|
|
113
|
+
: value
|
|
114
|
+
const sessionId = activeSessionIdRef.current
|
|
115
|
+
|
|
116
|
+
if (sessionId != null && sessionId !== '') {
|
|
117
|
+
const currentSnapshot = sessionViewCacheRef.current.get(sessionId)
|
|
118
|
+
updateSessionViewCache(sessionId, {
|
|
119
|
+
messages: next,
|
|
120
|
+
isHydrated: currentSnapshot?.isHydrated === true
|
|
121
|
+
})
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return next
|
|
125
|
+
})
|
|
126
|
+
}, [updateSessionViewCache])
|
|
127
|
+
|
|
82
128
|
const clearScheduledReconciles = useCallback(() => {
|
|
83
129
|
for (const timer of reconcileTimersRef.current) {
|
|
84
130
|
clearTimeout(timer)
|
|
@@ -121,17 +167,17 @@ export function useChatSessionMessages({
|
|
|
121
167
|
res.session?.status
|
|
122
168
|
)
|
|
123
169
|
const latestFatalError = findLatestFatalError(events)
|
|
170
|
+
const nextErrorState = restoredInteraction == null && res.session?.status === 'failed' && latestFatalError != null
|
|
171
|
+
? {
|
|
172
|
+
kind: 'session' as const,
|
|
173
|
+
message: latestFatalError.message,
|
|
174
|
+
code: latestFatalError.code
|
|
175
|
+
}
|
|
176
|
+
: null
|
|
124
177
|
|
|
125
178
|
interactionRequestRef.current = restoredInteraction
|
|
126
179
|
setInteractionRequest(restoredInteraction)
|
|
127
|
-
|
|
128
|
-
restoredInteraction == null && res.session?.status === 'failed' && latestFatalError != null
|
|
129
|
-
? {
|
|
130
|
-
kind: 'session',
|
|
131
|
-
message: latestFatalError.message
|
|
132
|
-
}
|
|
133
|
-
: null
|
|
134
|
-
)
|
|
180
|
+
setErrorState(nextErrorState)
|
|
135
181
|
|
|
136
182
|
for (const data of events) {
|
|
137
183
|
currentMessages = applyMessageEvent(currentMessages, data)
|
|
@@ -143,6 +189,14 @@ export function useChatSessionMessages({
|
|
|
143
189
|
}
|
|
144
190
|
}
|
|
145
191
|
|
|
192
|
+
updateSessionViewCache(sessionId, {
|
|
193
|
+
messages: currentMessages,
|
|
194
|
+
sessionInfo: currentSessionInfo,
|
|
195
|
+
errorState: nextErrorState,
|
|
196
|
+
interactionRequest: restoredInteraction,
|
|
197
|
+
isHydrated: true
|
|
198
|
+
})
|
|
199
|
+
|
|
146
200
|
setMessages(currentMessages)
|
|
147
201
|
setSessionInfo(currentSessionInfo)
|
|
148
202
|
|
|
@@ -158,7 +212,7 @@ export function useChatSessionMessages({
|
|
|
158
212
|
} catch (err) {
|
|
159
213
|
console.error('Failed to fetch history messages:', err)
|
|
160
214
|
}
|
|
161
|
-
}, [mutate, setInteractionRequest])
|
|
215
|
+
}, [mutate, setInteractionRequest, setMessages, updateSessionViewCache])
|
|
162
216
|
|
|
163
217
|
const reconcileAfterInteraction = useCallback(() => {
|
|
164
218
|
clearScheduledReconciles()
|
|
@@ -174,22 +228,21 @@ export function useChatSessionMessages({
|
|
|
174
228
|
const retryConnection = useCallback(() => {
|
|
175
229
|
if (session?.id == null || session.id === '') return
|
|
176
230
|
expectedCloseRef.current = true
|
|
177
|
-
|
|
231
|
+
setErrorState(null)
|
|
232
|
+
updateSessionViewCache(session.id, { errorState: null })
|
|
178
233
|
connectionManager.close(session.id)
|
|
179
234
|
setRetryCount((count) => count + 1)
|
|
180
|
-
}, [session?.id])
|
|
235
|
+
}, [session?.id, updateSessionViewCache])
|
|
181
236
|
|
|
182
237
|
useEffect(() => {
|
|
183
|
-
setMessages([])
|
|
184
|
-
setSessionInfo(null)
|
|
185
|
-
setIsReady(false)
|
|
186
|
-
setErrorBanner(null)
|
|
187
|
-
setInteractionRequest(null)
|
|
188
|
-
interactionRequestRef.current = null
|
|
189
|
-
isInitialLoadRef.current = true
|
|
190
|
-
|
|
191
238
|
if (session?.id == null || session.id === '') {
|
|
239
|
+
setMessagesState([])
|
|
240
|
+
setSessionInfo(null)
|
|
192
241
|
setIsReady(true)
|
|
242
|
+
setErrorState(null)
|
|
243
|
+
setInteractionRequest(null)
|
|
244
|
+
interactionRequestRef.current = null
|
|
245
|
+
isInitialLoadRef.current = true
|
|
193
246
|
lastConnectedModelRef.current = undefined
|
|
194
247
|
lastConnectedEffortRef.current = undefined
|
|
195
248
|
lastConnectedPermissionModeRef.current = undefined
|
|
@@ -198,6 +251,16 @@ export function useChatSessionMessages({
|
|
|
198
251
|
return
|
|
199
252
|
}
|
|
200
253
|
|
|
254
|
+
const restoredState = restoreChatSessionViewSnapshot(sessionViewCacheRef.current.get(session.id))
|
|
255
|
+
|
|
256
|
+
setMessagesState(restoredState.messages)
|
|
257
|
+
setSessionInfo(restoredState.sessionInfo)
|
|
258
|
+
setErrorState(restoredState.errorState)
|
|
259
|
+
setInteractionRequest(restoredState.interactionRequest)
|
|
260
|
+
interactionRequestRef.current = restoredState.interactionRequest
|
|
261
|
+
setIsReady(restoredState.isReady)
|
|
262
|
+
isInitialLoadRef.current = !restoredState.isReady
|
|
263
|
+
|
|
201
264
|
void refreshHistory()
|
|
202
265
|
|
|
203
266
|
return () => {
|
|
@@ -249,7 +312,7 @@ export function useChatSessionMessages({
|
|
|
249
312
|
session?.status !== 'running'
|
|
250
313
|
if (modelChanged || effortChanged || permissionModeChanged || adapterChanged) {
|
|
251
314
|
expectedCloseRef.current = true
|
|
252
|
-
|
|
315
|
+
setErrorState(null)
|
|
253
316
|
connectionManager.send(session.id, { type: 'terminate_session' })
|
|
254
317
|
connectionManager.close(session.id)
|
|
255
318
|
}
|
|
@@ -278,7 +341,13 @@ export function useChatSessionMessages({
|
|
|
278
341
|
cleanup = connectionManager.connect(session.id, {
|
|
279
342
|
onOpen() {
|
|
280
343
|
expectedCloseRef.current = false
|
|
281
|
-
|
|
344
|
+
setErrorState((current) => {
|
|
345
|
+
const next = current?.kind === 'session' ? current : null
|
|
346
|
+
updateSessionViewCache(session.id, {
|
|
347
|
+
errorState: next
|
|
348
|
+
})
|
|
349
|
+
return next
|
|
350
|
+
})
|
|
282
351
|
},
|
|
283
352
|
onMessage(data: WSEvent) {
|
|
284
353
|
if (isDisposed) return
|
|
@@ -286,8 +355,14 @@ export function useChatSessionMessages({
|
|
|
286
355
|
if (nextInteraction !== interactionRequestRef.current) {
|
|
287
356
|
interactionRequestRef.current = nextInteraction
|
|
288
357
|
setInteractionRequest(nextInteraction)
|
|
358
|
+
updateSessionViewCache(session.id, {
|
|
359
|
+
interactionRequest: nextInteraction
|
|
360
|
+
})
|
|
289
361
|
if (nextInteraction != null) {
|
|
290
|
-
|
|
362
|
+
setErrorState(null)
|
|
363
|
+
updateSessionViewCache(session.id, {
|
|
364
|
+
errorState: null
|
|
365
|
+
})
|
|
291
366
|
}
|
|
292
367
|
}
|
|
293
368
|
if (data.type === 'interaction_response') {
|
|
@@ -297,9 +372,14 @@ export function useChatSessionMessages({
|
|
|
297
372
|
if (data.type === 'error') {
|
|
298
373
|
const fatalError = getFatalSessionError(data)
|
|
299
374
|
if (fatalError != null) {
|
|
300
|
-
|
|
375
|
+
const nextErrorState = {
|
|
301
376
|
kind: 'session',
|
|
302
|
-
message: fatalError.message
|
|
377
|
+
message: fatalError.message,
|
|
378
|
+
code: fatalError.code
|
|
379
|
+
} satisfies ChatErrorState
|
|
380
|
+
setErrorState(nextErrorState)
|
|
381
|
+
updateSessionViewCache(session.id, {
|
|
382
|
+
errorState: nextErrorState
|
|
303
383
|
})
|
|
304
384
|
}
|
|
305
385
|
return
|
|
@@ -311,6 +391,7 @@ export function useChatSessionMessages({
|
|
|
311
391
|
const updatedSession = data.session as Session | { id: string; isDeleted: boolean }
|
|
312
392
|
|
|
313
393
|
if ('isDeleted' in updatedSession && updatedSession.isDeleted) {
|
|
394
|
+
removeSessionViewCache(updatedSession.id)
|
|
314
395
|
return {
|
|
315
396
|
...prev,
|
|
316
397
|
sessions: prev.sessions.filter((s: Session) => s.id !== updatedSession.id)
|
|
@@ -343,6 +424,9 @@ export function useChatSessionMessages({
|
|
|
343
424
|
void mutate('/api/sessions')
|
|
344
425
|
} else {
|
|
345
426
|
setSessionInfo(data.info ?? null)
|
|
427
|
+
updateSessionViewCache(session.id, {
|
|
428
|
+
sessionInfo: data.info ?? null
|
|
429
|
+
})
|
|
346
430
|
if (isInitialLoadRef.current) {
|
|
347
431
|
setTimeout(() => {
|
|
348
432
|
if (isDisposed) return
|
|
@@ -362,14 +446,23 @@ export function useChatSessionMessages({
|
|
|
362
446
|
}
|
|
363
447
|
|
|
364
448
|
if (data.type === 'interaction_request') {
|
|
449
|
+
interactionRequestRef.current = data
|
|
365
450
|
setInteractionRequest(data)
|
|
451
|
+
updateSessionViewCache(session.id, {
|
|
452
|
+
interactionRequest: data
|
|
453
|
+
})
|
|
366
454
|
}
|
|
367
455
|
},
|
|
368
456
|
onError() {
|
|
369
457
|
if (isDisposed) return
|
|
370
|
-
|
|
458
|
+
const nextErrorState = {
|
|
371
459
|
kind: 'connection',
|
|
372
|
-
message: t('chat.connectionError')
|
|
460
|
+
message: t('chat.connectionError'),
|
|
461
|
+
reason: 'error'
|
|
462
|
+
} satisfies ChatErrorState
|
|
463
|
+
setErrorState(nextErrorState)
|
|
464
|
+
updateSessionViewCache(session.id, {
|
|
465
|
+
errorState: nextErrorState
|
|
373
466
|
})
|
|
374
467
|
},
|
|
375
468
|
onClose() {
|
|
@@ -378,12 +471,17 @@ export function useChatSessionMessages({
|
|
|
378
471
|
expectedCloseRef.current = false
|
|
379
472
|
return
|
|
380
473
|
}
|
|
381
|
-
|
|
382
|
-
current ?? {
|
|
474
|
+
setErrorState((current) => {
|
|
475
|
+
const next = current ?? {
|
|
383
476
|
kind: 'connection',
|
|
384
|
-
message: t('chat.connectionClosed')
|
|
477
|
+
message: t('chat.connectionClosed'),
|
|
478
|
+
reason: 'closed'
|
|
385
479
|
}
|
|
386
|
-
|
|
480
|
+
updateSessionViewCache(session.id, {
|
|
481
|
+
errorState: next
|
|
482
|
+
})
|
|
483
|
+
return next
|
|
484
|
+
})
|
|
387
485
|
}
|
|
388
486
|
}, Object.keys(connectionParams).length > 0 ? connectionParams : undefined)
|
|
389
487
|
}, (modelChanged || effortChanged || permissionModeChanged || adapterChanged) ? 200 : 100)
|
|
@@ -406,15 +504,17 @@ export function useChatSessionMessages({
|
|
|
406
504
|
session?.id,
|
|
407
505
|
session?.status,
|
|
408
506
|
setInteractionRequest,
|
|
409
|
-
t
|
|
507
|
+
t,
|
|
508
|
+
removeSessionViewCache,
|
|
509
|
+
updateSessionViewCache
|
|
410
510
|
])
|
|
411
511
|
|
|
412
512
|
return {
|
|
413
|
-
messages,
|
|
513
|
+
messages: messagesState,
|
|
414
514
|
setMessages,
|
|
415
515
|
sessionInfo,
|
|
416
516
|
isReady,
|
|
417
|
-
|
|
517
|
+
errorState,
|
|
418
518
|
retryConnection,
|
|
419
519
|
reconcileAfterInteraction
|
|
420
520
|
}
|
|
@@ -45,7 +45,7 @@ export function useChatSession({
|
|
|
45
45
|
setMessages,
|
|
46
46
|
sessionInfo,
|
|
47
47
|
isReady,
|
|
48
|
-
|
|
48
|
+
errorState,
|
|
49
49
|
retryConnection,
|
|
50
50
|
reconcileAfterInteraction
|
|
51
51
|
} = useChatSessionMessages({
|
|
@@ -112,7 +112,7 @@ export function useChatSession({
|
|
|
112
112
|
sessionInfo,
|
|
113
113
|
interactionRequest,
|
|
114
114
|
isReady,
|
|
115
|
-
|
|
115
|
+
errorState,
|
|
116
116
|
retryConnection,
|
|
117
117
|
isThinking,
|
|
118
118
|
activeView,
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"batchRestoreSuccess": "Batch restored successfully",
|
|
25
25
|
"batchRestoreFailed": "Failed to restore some sessions",
|
|
26
26
|
"cancel": "Cancel",
|
|
27
|
+
"continue": "Continue",
|
|
27
28
|
"confirm": "Confirm",
|
|
28
29
|
"confirmAction": "Confirm {{action}}",
|
|
29
30
|
"startNewChat": "No active sessions found. Start a new chat!",
|
|
@@ -324,11 +325,22 @@
|
|
|
324
325
|
"modelSearchPlaceholder": "Search models or services",
|
|
325
326
|
"modelUnavailable": "No models available",
|
|
326
327
|
"modelConfigRequired": "Add a model service in config before starting a session",
|
|
328
|
+
"modelConfigRequiredTitle": "Model setup required",
|
|
329
|
+
"modelConfigRequiredHelp": "Add at least one model service, then retry sending from the composer.",
|
|
327
330
|
"connectionErrorTitle": "Connection error",
|
|
331
|
+
"connectionClosedTitle": "Connection closed",
|
|
328
332
|
"sessionErrorTitle": "Task failed",
|
|
329
333
|
"connectionError": "WebSocket connection failed. Check the server and try again.",
|
|
330
334
|
"connectionClosed": "WebSocket connection closed. Try reconnecting.",
|
|
335
|
+
"connectionErrorHelp": "Streaming updates stopped before the session could recover. Retry to resubscribe to the running session.",
|
|
336
|
+
"connectionClosedHelp": "The current stream has ended unexpectedly. Retry to reconnect and continue receiving new messages.",
|
|
337
|
+
"sessionErrorHelp": "Check the latest tool output or terminal logs, then continue from the most recent user message if needed.",
|
|
338
|
+
"sessionErrorCode": "Error code: {{code}}",
|
|
331
339
|
"retryConnection": "Retry",
|
|
340
|
+
"debugMockLabel": "Debug Preview",
|
|
341
|
+
"debugMockConnectionErrorMessage": "Unable to reach the session stream. The websocket handshake timed out before any updates arrived.",
|
|
342
|
+
"debugMockConnectionClosedMessage": "The connection dropped after the assistant started responding. No further tokens will arrive until you reconnect.",
|
|
343
|
+
"debugMockSessionErrorMessage": "The runtime hit its session timeout while waiting for a downstream tool result and stopped this turn.",
|
|
332
344
|
"permissionRequestBadge": "Permission request",
|
|
333
345
|
"permissionRequestTitleWithTool": "Requesting permission to use 【{{tool}}】. Choose how to proceed.",
|
|
334
346
|
"permissionSubject": "Scope",
|
|
@@ -427,6 +439,73 @@
|
|
|
427
439
|
"viewTimeline": "Timeline",
|
|
428
440
|
"viewTerminal": "Terminal",
|
|
429
441
|
"viewSettings": "Settings",
|
|
442
|
+
"gitBranchSwitcher": "Switch branch",
|
|
443
|
+
"gitOperations": "Git actions",
|
|
444
|
+
"gitWorktree": "Worktree",
|
|
445
|
+
"gitDetachedHead": "DETACHED",
|
|
446
|
+
"gitSearchBranches": "Search local or remote branches",
|
|
447
|
+
"gitBranchesLocal": "Local branches",
|
|
448
|
+
"gitBranchesWorktrees": "Other worktrees",
|
|
449
|
+
"gitBranchesRemote": "Remote branches",
|
|
450
|
+
"gitBranchCheckedOutInOtherWorktree": "Checked out in {{path}}",
|
|
451
|
+
"gitRemoteBranchCheckedOutInOtherWorktree": "Local branch already checked out in {{path}}",
|
|
452
|
+
"gitNoBranches": "No matching branches",
|
|
453
|
+
"gitCreateBranch": "Create branch",
|
|
454
|
+
"gitCreateBranchWithName": "Create branch {{branch}}",
|
|
455
|
+
"gitSwitchBranchSuccess": "Switched to {{branch}}",
|
|
456
|
+
"gitCreateBranchSuccess": "Created and switched to {{branch}}",
|
|
457
|
+
"gitCommitShort": "Commit",
|
|
458
|
+
"gitCommitAllChanges": "Commit all changes",
|
|
459
|
+
"gitCommitDialogTitle": "Commit all changes",
|
|
460
|
+
"gitCommitDescription": "This stages all current repository changes before committing.",
|
|
461
|
+
"gitCommitPanelTitle": "Commit changes",
|
|
462
|
+
"gitCommitPanelBranch": "Branch",
|
|
463
|
+
"gitCommitPanelChanges": "Changes",
|
|
464
|
+
"gitChangedFilesCount": "{{count}} files",
|
|
465
|
+
"gitCommitIncludeUnstagedChanges": "Include unstaged changes",
|
|
466
|
+
"gitCommitIncludeUnstagedChangesDescription": "Include unstaged and untracked files.",
|
|
467
|
+
"gitCommitOnlyStagedChangesDescription": "Commit staged changes only.",
|
|
468
|
+
"gitCommitSkipHooks": "Skip Git hooks",
|
|
469
|
+
"gitCommitSkipHooksDescription": "Skip pre-commit and commit-msg hooks.",
|
|
470
|
+
"gitCommitAmend": "Amend latest commit",
|
|
471
|
+
"gitCommitAmendDescription": "Fold into the latest commit. Current: {{subject}}",
|
|
472
|
+
"gitCommitAmendUnavailableDescription": "There is no existing commit to amend in this repository.",
|
|
473
|
+
"gitCommitMessageLabel": "Commit message",
|
|
474
|
+
"gitCommitMessageOptional": "Optional",
|
|
475
|
+
"gitCommitMessagePlaceholder": "Enter a commit message",
|
|
476
|
+
"gitCommitMessagePlaceholderAmend": "Leave blank to keep the latest commit message",
|
|
477
|
+
"gitCommitMessageAmendHint": "Leave it blank to reuse the latest commit message.",
|
|
478
|
+
"gitCommitMessageRequired": "Enter a commit message",
|
|
479
|
+
"gitCommitSuccess": "Commit created",
|
|
480
|
+
"gitCommitNoChanges": "There are no changes to commit",
|
|
481
|
+
"gitCommitNoStagedChanges": "There are no staged changes to commit",
|
|
482
|
+
"gitCommitNextStep": "Next step",
|
|
483
|
+
"gitCommitAndPush": "Commit and push",
|
|
484
|
+
"gitCommitAndPushSuccess": "Commit and push completed",
|
|
485
|
+
"gitCommitPushFailedAfterCommit": "Commit completed, but push failed: {{error}}",
|
|
486
|
+
"gitAmendSuccess": "Amend completed",
|
|
487
|
+
"gitAmendAndPushSuccess": "Amend and push completed",
|
|
488
|
+
"gitAmendUnavailable": "There is no commit available to amend",
|
|
489
|
+
"gitForcePush": "Force push",
|
|
490
|
+
"gitForcePushDescription": "Use force-with-lease for the remote branch.",
|
|
491
|
+
"gitForcePushHint": "Only replaces it when the remote has no newer commits.",
|
|
492
|
+
"gitPushNeedsSyncOrForce": "This branch is behind upstream. Sync first or enable force push.",
|
|
493
|
+
"gitPushShort": "Push",
|
|
494
|
+
"gitPush": "Push current branch",
|
|
495
|
+
"gitPushPanelTitle": "Push changes",
|
|
496
|
+
"gitPushPanelUpstream": "Upstream",
|
|
497
|
+
"gitPushPanelUpstreamHint": "The first push sets the upstream automatically.",
|
|
498
|
+
"gitForcePushSuccess": "Force push completed",
|
|
499
|
+
"gitPushSuccess": "Push completed",
|
|
500
|
+
"gitSyncShort": "Sync",
|
|
501
|
+
"gitSync": "Sync current branch",
|
|
502
|
+
"gitSyncSuccess": "Sync completed",
|
|
503
|
+
"gitStatusDirty": "Uncommitted changes",
|
|
504
|
+
"gitStatusClean": "Working tree clean",
|
|
505
|
+
"gitUpstreamStatus": "Ahead {{ahead}} / behind {{behind}}",
|
|
506
|
+
"gitNoUpstream": "No upstream configured",
|
|
507
|
+
"gitLocalBranch": "Local",
|
|
508
|
+
"gitRemoteBranch": "Remote · {{remote}}",
|
|
430
509
|
"deleteSessionTitle": "Delete session",
|
|
431
510
|
"deleteSessionDesc": "This will permanently remove the session and all messages. Proceed carefully.",
|
|
432
511
|
"timelineEmpty": "No events yet",
|
|
@@ -547,9 +626,30 @@
|
|
|
547
626
|
"startTasksFailed": "Failed",
|
|
548
627
|
"startTasksLogs": "Task Logs",
|
|
549
628
|
"task": "Task",
|
|
629
|
+
"taskCount": "{{count}} tasks",
|
|
550
630
|
"taskExitCode": "Exit: {{code}}",
|
|
551
631
|
"writeSuccess": "Write Success",
|
|
552
632
|
"writeFailed": "Write Failed",
|
|
633
|
+
"askUserQuestion": "Ask User Question",
|
|
634
|
+
"globTool": "Glob",
|
|
635
|
+
"grepTool": "Grep",
|
|
636
|
+
"editTool": "Edit File",
|
|
637
|
+
"lsTool": "List Directory",
|
|
638
|
+
"notebookEdit": "Notebook Edit",
|
|
639
|
+
"webFetch": "Web Fetch",
|
|
640
|
+
"webSearch": "Web Search",
|
|
641
|
+
"booleanOn": "On",
|
|
642
|
+
"booleanOff": "Off",
|
|
643
|
+
"diffSplit": "Split",
|
|
644
|
+
"diffInline": "Inline",
|
|
645
|
+
"skill": "Skill",
|
|
646
|
+
"enterPlanMode": "Enter Plan Mode",
|
|
647
|
+
"exitPlanMode": "Exit Plan Mode",
|
|
648
|
+
"taskCreate": "Create Task",
|
|
649
|
+
"taskGet": "Get Task",
|
|
650
|
+
"taskUpdate": "Update Task",
|
|
651
|
+
"taskList": "List Tasks",
|
|
652
|
+
"claudeTask": "Claude Task",
|
|
553
653
|
"todo": "Task Planning",
|
|
554
654
|
"call": "call",
|
|
555
655
|
"reading": "Reading file...",
|
|
@@ -559,6 +659,55 @@
|
|
|
559
659
|
"runInBackground": "run in background",
|
|
560
660
|
"dangerouslyDisableSandbox": "sandbox disabled",
|
|
561
661
|
"viewCommand": "View command",
|
|
662
|
+
"noParameters": "No parameters",
|
|
663
|
+
"groupSummaryCount": "{{name}} {{count}}x",
|
|
664
|
+
"groupSummaryMoreCount": "+{{count}}x",
|
|
665
|
+
"singleSelect": "single",
|
|
666
|
+
"multiSelect": "multi",
|
|
667
|
+
"fields": {
|
|
668
|
+
"activeForm": "Active Form",
|
|
669
|
+
"addBlockedBy": "Add Blocked By",
|
|
670
|
+
"addBlocks": "Add Blocks",
|
|
671
|
+
"allowedDomains": "Allowed Domains",
|
|
672
|
+
"allowedPrompts": "Allowed Prompts",
|
|
673
|
+
"answers": "Answers",
|
|
674
|
+
"args": "Args",
|
|
675
|
+
"blockedDomains": "Blocked Domains",
|
|
676
|
+
"cellId": "Cell ID",
|
|
677
|
+
"cellType": "Cell Type",
|
|
678
|
+
"command": "Command",
|
|
679
|
+
"content": "Content",
|
|
680
|
+
"description": "Description",
|
|
681
|
+
"disableSandbox": "Disable Sandbox",
|
|
682
|
+
"details": "Details",
|
|
683
|
+
"editMode": "Edit Mode",
|
|
684
|
+
"glob": "Glob",
|
|
685
|
+
"ignore": "Ignore",
|
|
686
|
+
"limit": "Limit",
|
|
687
|
+
"maxTurns": "Max Turns",
|
|
688
|
+
"metadata": "Metadata",
|
|
689
|
+
"model": "Model",
|
|
690
|
+
"mode": "Mode",
|
|
691
|
+
"newSource": "New Source",
|
|
692
|
+
"newString": "New String",
|
|
693
|
+
"oldString": "Old String",
|
|
694
|
+
"owner": "Owner",
|
|
695
|
+
"offset": "Offset",
|
|
696
|
+
"path": "Path",
|
|
697
|
+
"prompt": "Prompt",
|
|
698
|
+
"pushToRemote": "Push To Remote",
|
|
699
|
+
"questions": "Questions",
|
|
700
|
+
"remoteSession": "Remote Session",
|
|
701
|
+
"remoteSessionUrl": "Remote Session URL",
|
|
702
|
+
"replaceAll": "Replace All",
|
|
703
|
+
"resume": "Resume",
|
|
704
|
+
"runInBackground": "Run In Background",
|
|
705
|
+
"status": "Status",
|
|
706
|
+
"subagentType": "Subagent Type",
|
|
707
|
+
"subject": "Subject",
|
|
708
|
+
"timeout": "Timeout",
|
|
709
|
+
"todos": "Todos"
|
|
710
|
+
},
|
|
562
711
|
"unknown": "Unknown tool"
|
|
563
712
|
},
|
|
564
713
|
"terminal": {
|