@vibe-forge/client 0.10.0 → 0.11.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.
- package/dist/assets/{arc-CCXV7u3V.js → arc-M4HYfcHs.js} +1 -1
- package/dist/assets/{blockDiagram-c4efeb88-Bm52FmvT.js → blockDiagram-c4efeb88-CUrDjrxj.js} +1 -1
- package/dist/assets/{c4Diagram-c83219d4-C8tTEpcK.js → c4Diagram-c83219d4-BMEtqlFp.js} +1 -1
- package/dist/assets/channel-Cj3Cp2OJ.js +1 -0
- package/dist/assets/{classDiagram-beda092f-CNAIBAH1.js → classDiagram-beda092f-BOmDJ0Ml.js} +1 -1
- package/dist/assets/{classDiagram-v2-2358418a-BHeZAVdc.js → classDiagram-v2-2358418a-BODzX2MB.js} +1 -1
- package/dist/assets/clone-B7Q9B1dS.js +1 -0
- package/dist/assets/{createText-1719965b-BS2hLG8t.js → createText-1719965b-B9Dd8zcR.js} +1 -1
- package/dist/assets/{cssMode-WHcTFAOU.js → cssMode-DLxG92Ot.js} +1 -1
- package/dist/assets/{edges-96097737-C07f4iWA.js → edges-96097737-CuZFd43m.js} +1 -1
- package/dist/assets/{erDiagram-0228fc6a-BytsAWUs.js → erDiagram-0228fc6a-8g9lu2-Z.js} +1 -1
- package/dist/assets/{flowDb-c6c81e3f-CQJkOpAs.js → flowDb-c6c81e3f-BlBS1tdN.js} +1 -1
- package/dist/assets/{flowDiagram-50d868cf-CD5Tng2S.js → flowDiagram-50d868cf-u6mWflpF.js} +1 -1
- package/dist/assets/flowDiagram-v2-4f6560a1-G3v545eF.js +1 -0
- package/dist/assets/{flowchart-elk-definition-6af322e1-ylso-GWH.js → flowchart-elk-definition-6af322e1-BDqI2NFr.js} +1 -1
- package/dist/assets/{freemarker2-U_9Jyyr3.js → freemarker2-tVtpTMPu.js} +1 -1
- package/dist/assets/{ganttDiagram-a2739b55-Cg98bJx5.js → ganttDiagram-a2739b55-CDQjx9Wu.js} +1 -1
- package/dist/assets/{gitGraphDiagram-82fe8481-7Yp4hz0N.js → gitGraphDiagram-82fe8481-DUHFKRVA.js} +1 -1
- package/dist/assets/{graph-Ig3nvzvL.js → graph-2HKPi5B_.js} +1 -1
- package/dist/assets/{handlebars-DQyCBwHe.js → handlebars-D00tgNd8.js} +1 -1
- package/dist/assets/{html-CNC2AT5k.js → html-B-TDzBiR.js} +1 -1
- package/dist/assets/{htmlMode-DlATk4xW.js → htmlMode-ClycqSTM.js} +1 -1
- package/dist/assets/{index-5325376f-C4zed9sb.js → index-5325376f-DPrJpRQ-.js} +1 -1
- package/dist/assets/{index-Dbx0JG0p.js → index-CAHZZEoo.js} +319 -323
- package/dist/assets/{index-DRLsOoqb.css → index-Di7lePfb.css} +1 -1
- package/dist/assets/{infoDiagram-8eee0895-C8oSBaFs.js → infoDiagram-8eee0895-Co5tS1I5.js} +1 -1
- package/dist/assets/{javascript-9wv9uKW4.js → javascript-zbkwarmb.js} +1 -1
- package/dist/assets/{journeyDiagram-c64418c1-D5kJldvy.js → journeyDiagram-c64418c1-k_qioHgy.js} +1 -1
- package/dist/assets/{jsonMode-45dv39mU.js → jsonMode-C3CSpzBF.js} +1 -1
- package/dist/assets/{layout-DYNFLnIl.js → layout-CjOXKxvs.js} +1 -1
- package/dist/assets/{line-1gvOYQYZ.js → line-C-XnQrKR.js} +1 -1
- package/dist/assets/{linear-DHGm6Zdw.js → linear-C7MMERzS.js} +1 -1
- package/dist/assets/{liquid-BGoxrdXO.js → liquid-5G37EU6K.js} +1 -1
- package/dist/assets/{lspLanguageFeatures-CpCCXhrd.js → lspLanguageFeatures-zaDMuhCE.js} +1 -1
- package/dist/assets/{mdx-Dc2iMbEw.js → mdx-Bc-LY0gi.js} +1 -1
- package/dist/assets/{mermaid.core-Cq2bBFF1.js → mermaid.core-CechbHof.js} +4 -4
- package/dist/assets/{mindmap-definition-8da855dc-y5l6GRVh.js → mindmap-definition-8da855dc-ejftCDGb.js} +1 -1
- package/dist/assets/{pieDiagram-a8764435-PNROcv9y.js → pieDiagram-a8764435-DY__X3Qj.js} +1 -1
- package/dist/assets/{python-DjYAge7h.js → python-vK2Ff2J5.js} +1 -1
- package/dist/assets/{quadrantDiagram-1e28029f-CFJ3VPpp.js → quadrantDiagram-1e28029f-azIZCv_2.js} +1 -1
- package/dist/assets/{razor-OIY8fx_i.js → razor-BipjBJKu.js} +1 -1
- package/dist/assets/{requirementDiagram-08caed73-BpzDIINS.js → requirementDiagram-08caed73-C4EB0Xs2.js} +1 -1
- package/dist/assets/{sankeyDiagram-a04cb91d-CH69-iIn.js → sankeyDiagram-a04cb91d-PNhR6YWu.js} +1 -1
- package/dist/assets/{sequenceDiagram-c5b8d532-yBBEeVFU.js → sequenceDiagram-c5b8d532-4c-qV-Ri.js} +1 -1
- package/dist/assets/{stateDiagram-1ecb1508-BvF4sign.js → stateDiagram-1ecb1508-CnURumPE.js} +1 -1
- package/dist/assets/{stateDiagram-v2-c2b004d7-BeyT7Ghx.js → stateDiagram-v2-c2b004d7-DR2qHTPg.js} +1 -1
- package/dist/assets/{styles-b4e223ce-C58zxmK6.js → styles-b4e223ce-B2PWXT_i.js} +1 -1
- package/dist/assets/{styles-ca3715f6-DCE5sFi5.js → styles-ca3715f6-DEhgVF5H.js} +1 -1
- package/dist/assets/{styles-d45a18b0-CG-C1aM8.js → styles-d45a18b0-DyzccA5F.js} +1 -1
- package/dist/assets/{svgDrawCommon-b86b1483-F-K8GeDd.js → svgDrawCommon-b86b1483-C_1tMhxp.js} +1 -1
- package/dist/assets/{timeline-definition-faaaa080-DPv4uqVX.js → timeline-definition-faaaa080-FdaC0dQH.js} +1 -1
- package/dist/assets/{tsMode-BtU8ZELV.js → tsMode-CrMC5T3_.js} +1 -1
- package/dist/assets/{typescript-CJHgISWo.js → typescript-CRfPu8v7.js} +1 -1
- package/dist/assets/{xml-C_TJw4Bi.js → xml-jlRvQfFI.js} +1 -1
- package/dist/assets/{xychartDiagram-f5964ef8-BmXlhBzX.js → xychartDiagram-f5964ef8-sxjv75h9.js} +1 -1
- package/dist/assets/{yaml-BujeJOJ6.js → yaml-B47_IHOH.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +10 -10
- package/src/components/chat/ChatHistoryView.tsx +92 -14
- package/src/components/chat/messages/MessageItem.scss +10 -0
- package/src/components/chat/messages/MessageItem.tsx +5 -1
- 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 +74 -207
- 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 +133 -0
- package/src/components/chat/tools/adapter-claude/claude-tool-edit-builders.ts +102 -0
- package/src/components/chat/tools/adapter-claude/claude-tool-field-sections.tsx +168 -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 +344 -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 +20 -26
- 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/tool-content-presence.ts +57 -0
- package/src/components/chat/tools/core/tool-display.ts +192 -0
- package/src/components/chat/tools/core/tool-result-content-utils.ts +171 -0
- package/src/components/chat/tools/core/tool-summary.ts +194 -0
- package/src/components/chat/tools/plugin-chrome-devtools/ChromeDevtoolsTool.tsx +66 -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/use-chat-scroll.ts +2 -2
- package/src/hooks/chat/use-chat-session-messages.ts +24 -18
- package/src/hooks/chat/use-chat-session.ts +2 -2
- package/src/resources/locales/en.json +81 -0
- package/src/resources/locales/zh.json +81 -0
- package/src/routes/ChatRoute.tsx +40 -15
- package/src/utils/strip-ansi.ts +26 -0
- package/dist/assets/channel-gq_WMRvv.js +0 -1
- package/dist/assets/clone-XxGY7A5N.js +0 -1
- package/dist/assets/flowDiagram-v2-4f6560a1-DIBOANLV.js +0 -1
|
@@ -5,6 +5,8 @@ import React, { useMemo } from 'react'
|
|
|
5
5
|
import { useTranslation } from 'react-i18next'
|
|
6
6
|
|
|
7
7
|
import { ToolCallBox } from '../core/ToolCallBox'
|
|
8
|
+
import { ToolSummaryHeader } from '../core/ToolSummaryHeader'
|
|
9
|
+
import { getToolTargetPresentation } from '../core/tool-display'
|
|
8
10
|
import { defineToolRender } from '../defineToolRender'
|
|
9
11
|
import { TaskRow } from './components/TaskRow'
|
|
10
12
|
|
|
@@ -53,18 +55,33 @@ export const GetTaskInfoTool = defineToolRender(({ item, resultItem }) => {
|
|
|
53
55
|
})()
|
|
54
56
|
: []
|
|
55
57
|
const titleFallback = t('chat.tools.task')
|
|
58
|
+
const taskIdPresentation = getToolTargetPresentation(taskResult?.taskId ?? inputTaskId)
|
|
59
|
+
const errorMeta = resultItem?.is_error === true
|
|
60
|
+
? (
|
|
61
|
+
<span className='tool-status tool-status--error'>
|
|
62
|
+
<span className='material-symbols-rounded'>error</span>
|
|
63
|
+
</span>
|
|
64
|
+
)
|
|
65
|
+
: undefined
|
|
56
66
|
|
|
57
67
|
return (
|
|
58
|
-
<div className='tool-group get-task-info-tool'>
|
|
68
|
+
<div className='tool-group tool-group--compact get-task-info-tool'>
|
|
59
69
|
<ToolCallBox
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
<span className='
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
70
|
+
variant='inline'
|
|
71
|
+
defaultExpanded={false}
|
|
72
|
+
header={({ isExpanded, isCollapsible }) => (
|
|
73
|
+
<ToolSummaryHeader
|
|
74
|
+
icon={<span className='material-symbols-rounded'>info</span>}
|
|
75
|
+
title={t('chat.tools.getTaskInfo')}
|
|
76
|
+
target={taskIdPresentation.text}
|
|
77
|
+
targetTitle={taskIdPresentation.title}
|
|
78
|
+
targetMonospace={taskIdPresentation.monospace}
|
|
79
|
+
expanded={isExpanded}
|
|
80
|
+
collapsible={isCollapsible}
|
|
81
|
+
meta={errorMeta}
|
|
82
|
+
metaTitle={errorMeta == null ? undefined : t('chat.result')}
|
|
83
|
+
/>
|
|
84
|
+
)}
|
|
68
85
|
content={
|
|
69
86
|
<div className='tool-content'>
|
|
70
87
|
{taskResult
|
|
@@ -4,6 +4,7 @@ import React, { useMemo } from 'react'
|
|
|
4
4
|
import { useTranslation } from 'react-i18next'
|
|
5
5
|
|
|
6
6
|
import { ToolCallBox } from '../core/ToolCallBox'
|
|
7
|
+
import { ToolSummaryHeader } from '../core/ToolSummaryHeader'
|
|
7
8
|
import { defineToolRender } from '../defineToolRender'
|
|
8
9
|
import { TaskRow } from './components/TaskRow'
|
|
9
10
|
|
|
@@ -29,18 +30,30 @@ export const ListTasksTool = defineToolRender(({ resultItem }) => {
|
|
|
29
30
|
const text = resultItem.content[0].text.trim()
|
|
30
31
|
return JSON.parse(text) as TaskResult[]
|
|
31
32
|
}, [resultItem?.content])
|
|
33
|
+
const errorMeta = resultItem?.is_error === true
|
|
34
|
+
? (
|
|
35
|
+
<span className='tool-status tool-status--error'>
|
|
36
|
+
<span className='material-symbols-rounded'>error</span>
|
|
37
|
+
</span>
|
|
38
|
+
)
|
|
39
|
+
: undefined
|
|
32
40
|
|
|
33
41
|
return (
|
|
34
|
-
<div className='tool-group list-tasks-tool'>
|
|
42
|
+
<div className='tool-group tool-group--compact list-tasks-tool'>
|
|
35
43
|
<ToolCallBox
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
<span className='
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
variant='inline'
|
|
45
|
+
defaultExpanded={false}
|
|
46
|
+
header={({ isExpanded, isCollapsible }) => (
|
|
47
|
+
<ToolSummaryHeader
|
|
48
|
+
icon={<span className='material-symbols-rounded'>list_alt</span>}
|
|
49
|
+
title={t('chat.tools.listTasks')}
|
|
50
|
+
target={t('chat.tools.taskCount', { count: taskResults.length })}
|
|
51
|
+
expanded={isExpanded}
|
|
52
|
+
collapsible={isCollapsible}
|
|
53
|
+
meta={errorMeta}
|
|
54
|
+
metaTitle={errorMeta == null ? undefined : t('chat.result')}
|
|
55
|
+
/>
|
|
56
|
+
)}
|
|
44
57
|
content={
|
|
45
58
|
<div className='tool-content'>
|
|
46
59
|
<div className='list-tasks-tool__list'>
|
|
@@ -5,6 +5,7 @@ import React, { useMemo } from 'react'
|
|
|
5
5
|
import { useTranslation } from 'react-i18next'
|
|
6
6
|
|
|
7
7
|
import { ToolCallBox } from '../core/ToolCallBox'
|
|
8
|
+
import { ToolSummaryHeader } from '../core/ToolSummaryHeader'
|
|
8
9
|
import { defineToolRender } from '../defineToolRender'
|
|
9
10
|
import { TaskRow } from './components/TaskRow'
|
|
10
11
|
|
|
@@ -39,18 +40,30 @@ export const StartTasksTool = defineToolRender(({ item, resultItem }) => {
|
|
|
39
40
|
}, [resultItem?.content])
|
|
40
41
|
|
|
41
42
|
const { taskResults } = parsedResult
|
|
43
|
+
const errorMeta = resultItem?.is_error === true
|
|
44
|
+
? (
|
|
45
|
+
<span className='tool-status tool-status--error'>
|
|
46
|
+
<span className='material-symbols-rounded'>error</span>
|
|
47
|
+
</span>
|
|
48
|
+
)
|
|
49
|
+
: undefined
|
|
42
50
|
|
|
43
51
|
return (
|
|
44
|
-
<div className='tool-group start-tasks-tool'>
|
|
52
|
+
<div className='tool-group tool-group--compact start-tasks-tool'>
|
|
45
53
|
<ToolCallBox
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
<span className='
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
variant='inline'
|
|
55
|
+
defaultExpanded={false}
|
|
56
|
+
header={({ isExpanded, isCollapsible }) => (
|
|
57
|
+
<ToolSummaryHeader
|
|
58
|
+
icon={<span className='material-symbols-rounded'>playlist_add</span>}
|
|
59
|
+
title={t('chat.tools.startTasks')}
|
|
60
|
+
target={t('chat.tools.taskCount', { count: tasks.length })}
|
|
61
|
+
expanded={isExpanded}
|
|
62
|
+
collapsible={isCollapsible}
|
|
63
|
+
meta={errorMeta}
|
|
64
|
+
metaTitle={errorMeta == null ? undefined : t('chat.result')}
|
|
65
|
+
/>
|
|
66
|
+
)}
|
|
54
67
|
content={
|
|
55
68
|
<div className='tool-content'>
|
|
56
69
|
<div className='start-tasks-tool__list'>
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import type { AskUserQuestionParams, Session, WSEvent } from '@vibe-forge/core'
|
|
2
2
|
|
|
3
|
+
import { stripAnsi } from '#~/utils/strip-ansi'
|
|
4
|
+
|
|
3
5
|
export interface InteractionRequestState {
|
|
4
6
|
id: string
|
|
5
7
|
payload: AskUserQuestionParams
|
|
6
8
|
}
|
|
7
9
|
|
|
8
|
-
export interface
|
|
10
|
+
export interface ChatErrorState {
|
|
9
11
|
kind: 'connection' | 'session'
|
|
10
12
|
message: string
|
|
13
|
+
code?: string
|
|
14
|
+
reason?: 'error' | 'closed'
|
|
11
15
|
}
|
|
12
16
|
|
|
13
17
|
export interface FatalSessionErrorState {
|
|
@@ -15,6 +19,8 @@ export interface FatalSessionErrorState {
|
|
|
15
19
|
code?: string
|
|
16
20
|
}
|
|
17
21
|
|
|
22
|
+
const normalizeErrorMessage = (value: string) => stripAnsi(value).trim()
|
|
23
|
+
|
|
18
24
|
export const getFatalSessionError = (event: WSEvent): FatalSessionErrorState | null => {
|
|
19
25
|
if (event?.type !== 'error') {
|
|
20
26
|
return null
|
|
@@ -24,20 +30,34 @@ export const getFatalSessionError = (event: WSEvent): FatalSessionErrorState | n
|
|
|
24
30
|
return null
|
|
25
31
|
}
|
|
26
32
|
|
|
33
|
+
const code = event.data != null && typeof event.data === 'object' &&
|
|
34
|
+
'code' in event.data &&
|
|
35
|
+
typeof event.data.code === 'string' &&
|
|
36
|
+
event.data.code.trim() !== ''
|
|
37
|
+
? event.data.code
|
|
38
|
+
: undefined
|
|
39
|
+
|
|
27
40
|
if (event.data != null && typeof event.data === 'object' && 'message' in event.data) {
|
|
28
41
|
const message = event.data.message
|
|
29
|
-
if (typeof message === 'string'
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
42
|
+
if (typeof message === 'string') {
|
|
43
|
+
const normalizedMessage = normalizeErrorMessage(message)
|
|
44
|
+
if (normalizedMessage !== '') {
|
|
45
|
+
return {
|
|
46
|
+
message: normalizedMessage,
|
|
47
|
+
code
|
|
48
|
+
}
|
|
35
49
|
}
|
|
36
50
|
}
|
|
37
51
|
}
|
|
38
52
|
|
|
39
|
-
if (typeof event.message === 'string'
|
|
40
|
-
|
|
53
|
+
if (typeof event.message === 'string') {
|
|
54
|
+
const normalizedMessage = normalizeErrorMessage(event.message)
|
|
55
|
+
if (normalizedMessage !== '') {
|
|
56
|
+
return {
|
|
57
|
+
message: normalizedMessage,
|
|
58
|
+
code
|
|
59
|
+
}
|
|
60
|
+
}
|
|
41
61
|
}
|
|
42
62
|
|
|
43
63
|
return null
|
|
@@ -2,7 +2,7 @@ import { useCallback, useEffect, useRef, useState } from 'react'
|
|
|
2
2
|
|
|
3
3
|
const SCROLL_THRESHOLD = 80
|
|
4
4
|
|
|
5
|
-
export function useChatScroll({
|
|
5
|
+
export function useChatScroll({ contentVersion }: { contentVersion: number }) {
|
|
6
6
|
const messagesEndRef = useRef<HTMLDivElement>(null)
|
|
7
7
|
const messagesContainerRef = useRef<HTMLDivElement>(null)
|
|
8
8
|
const messagesContentRef = useRef<HTMLDivElement>(null)
|
|
@@ -39,7 +39,7 @@ export function useChatScroll({ messagesLength }: { messagesLength: number }) {
|
|
|
39
39
|
|
|
40
40
|
useEffect(() => {
|
|
41
41
|
updateScrollState()
|
|
42
|
-
}, [
|
|
42
|
+
}, [contentVersion, updateScrollState])
|
|
43
43
|
|
|
44
44
|
return {
|
|
45
45
|
messagesEndRef,
|
|
@@ -2,11 +2,13 @@ import { useCallback, useEffect, useRef, useState } from 'react'
|
|
|
2
2
|
import { useTranslation } from 'react-i18next'
|
|
3
3
|
import { useSWRConfig } from 'swr'
|
|
4
4
|
|
|
5
|
-
import { getSessionMessages } from '#~/api.js'
|
|
6
|
-
import { connectionManager } from '#~/connectionManager.js'
|
|
7
5
|
import type { AskUserQuestionParams, ChatMessage, Session, WSEvent } from '@vibe-forge/core'
|
|
8
6
|
import type { SessionInfo } from '@vibe-forge/types'
|
|
9
|
-
|
|
7
|
+
|
|
8
|
+
import { getSessionMessages } from '#~/api.js'
|
|
9
|
+
import { connectionManager } from '#~/connectionManager.js'
|
|
10
|
+
|
|
11
|
+
import type { ChatErrorState } from './interaction-state'
|
|
10
12
|
import {
|
|
11
13
|
applyInteractionStateEvent,
|
|
12
14
|
findLatestFatalError,
|
|
@@ -63,7 +65,7 @@ export function useChatSessionMessages({
|
|
|
63
65
|
const [messages, setMessages] = useState<ChatMessage[]>([])
|
|
64
66
|
const [sessionInfo, setSessionInfo] = useState<SessionInfo | null>(null)
|
|
65
67
|
const [isReady, setIsReady] = useState(false)
|
|
66
|
-
const [
|
|
68
|
+
const [errorState, setErrorState] = useState<ChatErrorState | null>(null)
|
|
67
69
|
const [retryCount, setRetryCount] = useState(0)
|
|
68
70
|
const isInitialLoadRef = useRef<boolean>(true)
|
|
69
71
|
const lastConnectedModelRef = useRef<string | undefined>(undefined)
|
|
@@ -124,11 +126,12 @@ export function useChatSessionMessages({
|
|
|
124
126
|
|
|
125
127
|
interactionRequestRef.current = restoredInteraction
|
|
126
128
|
setInteractionRequest(restoredInteraction)
|
|
127
|
-
|
|
129
|
+
setErrorState(
|
|
128
130
|
restoredInteraction == null && res.session?.status === 'failed' && latestFatalError != null
|
|
129
131
|
? {
|
|
130
132
|
kind: 'session',
|
|
131
|
-
message: latestFatalError.message
|
|
133
|
+
message: latestFatalError.message,
|
|
134
|
+
code: latestFatalError.code
|
|
132
135
|
}
|
|
133
136
|
: null
|
|
134
137
|
)
|
|
@@ -174,7 +177,7 @@ export function useChatSessionMessages({
|
|
|
174
177
|
const retryConnection = useCallback(() => {
|
|
175
178
|
if (session?.id == null || session.id === '') return
|
|
176
179
|
expectedCloseRef.current = true
|
|
177
|
-
|
|
180
|
+
setErrorState(null)
|
|
178
181
|
connectionManager.close(session.id)
|
|
179
182
|
setRetryCount((count) => count + 1)
|
|
180
183
|
}, [session?.id])
|
|
@@ -183,7 +186,7 @@ export function useChatSessionMessages({
|
|
|
183
186
|
setMessages([])
|
|
184
187
|
setSessionInfo(null)
|
|
185
188
|
setIsReady(false)
|
|
186
|
-
|
|
189
|
+
setErrorState(null)
|
|
187
190
|
setInteractionRequest(null)
|
|
188
191
|
interactionRequestRef.current = null
|
|
189
192
|
isInitialLoadRef.current = true
|
|
@@ -249,7 +252,7 @@ export function useChatSessionMessages({
|
|
|
249
252
|
session?.status !== 'running'
|
|
250
253
|
if (modelChanged || effortChanged || permissionModeChanged || adapterChanged) {
|
|
251
254
|
expectedCloseRef.current = true
|
|
252
|
-
|
|
255
|
+
setErrorState(null)
|
|
253
256
|
connectionManager.send(session.id, { type: 'terminate_session' })
|
|
254
257
|
connectionManager.close(session.id)
|
|
255
258
|
}
|
|
@@ -278,7 +281,7 @@ export function useChatSessionMessages({
|
|
|
278
281
|
cleanup = connectionManager.connect(session.id, {
|
|
279
282
|
onOpen() {
|
|
280
283
|
expectedCloseRef.current = false
|
|
281
|
-
|
|
284
|
+
setErrorState((current) => current?.kind === 'session' ? current : null)
|
|
282
285
|
},
|
|
283
286
|
onMessage(data: WSEvent) {
|
|
284
287
|
if (isDisposed) return
|
|
@@ -287,7 +290,7 @@ export function useChatSessionMessages({
|
|
|
287
290
|
interactionRequestRef.current = nextInteraction
|
|
288
291
|
setInteractionRequest(nextInteraction)
|
|
289
292
|
if (nextInteraction != null) {
|
|
290
|
-
|
|
293
|
+
setErrorState(null)
|
|
291
294
|
}
|
|
292
295
|
}
|
|
293
296
|
if (data.type === 'interaction_response') {
|
|
@@ -297,9 +300,10 @@ export function useChatSessionMessages({
|
|
|
297
300
|
if (data.type === 'error') {
|
|
298
301
|
const fatalError = getFatalSessionError(data)
|
|
299
302
|
if (fatalError != null) {
|
|
300
|
-
|
|
303
|
+
setErrorState({
|
|
301
304
|
kind: 'session',
|
|
302
|
-
message: fatalError.message
|
|
305
|
+
message: fatalError.message,
|
|
306
|
+
code: fatalError.code
|
|
303
307
|
})
|
|
304
308
|
}
|
|
305
309
|
return
|
|
@@ -367,9 +371,10 @@ export function useChatSessionMessages({
|
|
|
367
371
|
},
|
|
368
372
|
onError() {
|
|
369
373
|
if (isDisposed) return
|
|
370
|
-
|
|
374
|
+
setErrorState({
|
|
371
375
|
kind: 'connection',
|
|
372
|
-
message: t('chat.connectionError')
|
|
376
|
+
message: t('chat.connectionError'),
|
|
377
|
+
reason: 'error'
|
|
373
378
|
})
|
|
374
379
|
},
|
|
375
380
|
onClose() {
|
|
@@ -378,10 +383,11 @@ export function useChatSessionMessages({
|
|
|
378
383
|
expectedCloseRef.current = false
|
|
379
384
|
return
|
|
380
385
|
}
|
|
381
|
-
|
|
386
|
+
setErrorState((current) =>
|
|
382
387
|
current ?? {
|
|
383
388
|
kind: 'connection',
|
|
384
|
-
message: t('chat.connectionClosed')
|
|
389
|
+
message: t('chat.connectionClosed'),
|
|
390
|
+
reason: 'closed'
|
|
385
391
|
}
|
|
386
392
|
)
|
|
387
393
|
}
|
|
@@ -414,7 +420,7 @@ export function useChatSessionMessages({
|
|
|
414
420
|
setMessages,
|
|
415
421
|
sessionInfo,
|
|
416
422
|
isReady,
|
|
417
|
-
|
|
423
|
+
errorState,
|
|
418
424
|
retryConnection,
|
|
419
425
|
reconcileAfterInteraction
|
|
420
426
|
}
|
|
@@ -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,
|
|
@@ -324,11 +324,22 @@
|
|
|
324
324
|
"modelSearchPlaceholder": "Search models or services",
|
|
325
325
|
"modelUnavailable": "No models available",
|
|
326
326
|
"modelConfigRequired": "Add a model service in config before starting a session",
|
|
327
|
+
"modelConfigRequiredTitle": "Model setup required",
|
|
328
|
+
"modelConfigRequiredHelp": "Add at least one model service, then retry sending from the composer.",
|
|
327
329
|
"connectionErrorTitle": "Connection error",
|
|
330
|
+
"connectionClosedTitle": "Connection closed",
|
|
328
331
|
"sessionErrorTitle": "Task failed",
|
|
329
332
|
"connectionError": "WebSocket connection failed. Check the server and try again.",
|
|
330
333
|
"connectionClosed": "WebSocket connection closed. Try reconnecting.",
|
|
334
|
+
"connectionErrorHelp": "Streaming updates stopped before the session could recover. Retry to resubscribe to the running session.",
|
|
335
|
+
"connectionClosedHelp": "The current stream has ended unexpectedly. Retry to reconnect and continue receiving new messages.",
|
|
336
|
+
"sessionErrorHelp": "Check the latest tool output or terminal logs, then continue from the most recent user message if needed.",
|
|
337
|
+
"sessionErrorCode": "Error code: {{code}}",
|
|
331
338
|
"retryConnection": "Retry",
|
|
339
|
+
"debugMockLabel": "Debug Preview",
|
|
340
|
+
"debugMockConnectionErrorMessage": "Unable to reach the session stream. The websocket handshake timed out before any updates arrived.",
|
|
341
|
+
"debugMockConnectionClosedMessage": "The connection dropped after the assistant started responding. No further tokens will arrive until you reconnect.",
|
|
342
|
+
"debugMockSessionErrorMessage": "The runtime hit its session timeout while waiting for a downstream tool result and stopped this turn.",
|
|
332
343
|
"permissionRequestBadge": "Permission request",
|
|
333
344
|
"permissionRequestTitleWithTool": "Requesting permission to use 【{{tool}}】. Choose how to proceed.",
|
|
334
345
|
"permissionSubject": "Scope",
|
|
@@ -547,9 +558,30 @@
|
|
|
547
558
|
"startTasksFailed": "Failed",
|
|
548
559
|
"startTasksLogs": "Task Logs",
|
|
549
560
|
"task": "Task",
|
|
561
|
+
"taskCount": "{{count}} tasks",
|
|
550
562
|
"taskExitCode": "Exit: {{code}}",
|
|
551
563
|
"writeSuccess": "Write Success",
|
|
552
564
|
"writeFailed": "Write Failed",
|
|
565
|
+
"askUserQuestion": "Ask User Question",
|
|
566
|
+
"globTool": "Glob",
|
|
567
|
+
"grepTool": "Grep",
|
|
568
|
+
"editTool": "Edit File",
|
|
569
|
+
"lsTool": "List Directory",
|
|
570
|
+
"notebookEdit": "Notebook Edit",
|
|
571
|
+
"webFetch": "Web Fetch",
|
|
572
|
+
"webSearch": "Web Search",
|
|
573
|
+
"booleanOn": "On",
|
|
574
|
+
"booleanOff": "Off",
|
|
575
|
+
"diffSplit": "Split",
|
|
576
|
+
"diffInline": "Inline",
|
|
577
|
+
"skill": "Skill",
|
|
578
|
+
"enterPlanMode": "Enter Plan Mode",
|
|
579
|
+
"exitPlanMode": "Exit Plan Mode",
|
|
580
|
+
"taskCreate": "Create Task",
|
|
581
|
+
"taskGet": "Get Task",
|
|
582
|
+
"taskUpdate": "Update Task",
|
|
583
|
+
"taskList": "List Tasks",
|
|
584
|
+
"claudeTask": "Claude Task",
|
|
553
585
|
"todo": "Task Planning",
|
|
554
586
|
"call": "call",
|
|
555
587
|
"reading": "Reading file...",
|
|
@@ -559,6 +591,55 @@
|
|
|
559
591
|
"runInBackground": "run in background",
|
|
560
592
|
"dangerouslyDisableSandbox": "sandbox disabled",
|
|
561
593
|
"viewCommand": "View command",
|
|
594
|
+
"noParameters": "No parameters",
|
|
595
|
+
"groupSummaryCount": "{{name}} {{count}}x",
|
|
596
|
+
"groupSummaryMoreCount": "+{{count}}x",
|
|
597
|
+
"singleSelect": "single",
|
|
598
|
+
"multiSelect": "multi",
|
|
599
|
+
"fields": {
|
|
600
|
+
"activeForm": "Active Form",
|
|
601
|
+
"addBlockedBy": "Add Blocked By",
|
|
602
|
+
"addBlocks": "Add Blocks",
|
|
603
|
+
"allowedDomains": "Allowed Domains",
|
|
604
|
+
"allowedPrompts": "Allowed Prompts",
|
|
605
|
+
"answers": "Answers",
|
|
606
|
+
"args": "Args",
|
|
607
|
+
"blockedDomains": "Blocked Domains",
|
|
608
|
+
"cellId": "Cell ID",
|
|
609
|
+
"cellType": "Cell Type",
|
|
610
|
+
"command": "Command",
|
|
611
|
+
"content": "Content",
|
|
612
|
+
"description": "Description",
|
|
613
|
+
"disableSandbox": "Disable Sandbox",
|
|
614
|
+
"details": "Details",
|
|
615
|
+
"editMode": "Edit Mode",
|
|
616
|
+
"glob": "Glob",
|
|
617
|
+
"ignore": "Ignore",
|
|
618
|
+
"limit": "Limit",
|
|
619
|
+
"maxTurns": "Max Turns",
|
|
620
|
+
"metadata": "Metadata",
|
|
621
|
+
"model": "Model",
|
|
622
|
+
"mode": "Mode",
|
|
623
|
+
"newSource": "New Source",
|
|
624
|
+
"newString": "New String",
|
|
625
|
+
"oldString": "Old String",
|
|
626
|
+
"owner": "Owner",
|
|
627
|
+
"offset": "Offset",
|
|
628
|
+
"path": "Path",
|
|
629
|
+
"prompt": "Prompt",
|
|
630
|
+
"pushToRemote": "Push To Remote",
|
|
631
|
+
"questions": "Questions",
|
|
632
|
+
"remoteSession": "Remote Session",
|
|
633
|
+
"remoteSessionUrl": "Remote Session URL",
|
|
634
|
+
"replaceAll": "Replace All",
|
|
635
|
+
"resume": "Resume",
|
|
636
|
+
"runInBackground": "Run In Background",
|
|
637
|
+
"status": "Status",
|
|
638
|
+
"subagentType": "Subagent Type",
|
|
639
|
+
"subject": "Subject",
|
|
640
|
+
"timeout": "Timeout",
|
|
641
|
+
"todos": "Todos"
|
|
642
|
+
},
|
|
562
643
|
"unknown": "Unknown tool"
|
|
563
644
|
},
|
|
564
645
|
"terminal": {
|
|
@@ -325,11 +325,22 @@
|
|
|
325
325
|
"modelSearchPlaceholder": "搜索模型或服务",
|
|
326
326
|
"modelUnavailable": "暂无可用模型",
|
|
327
327
|
"modelConfigRequired": "请先在配置中添加模型服务后再开始会话",
|
|
328
|
+
"modelConfigRequiredTitle": "需要先配置模型服务",
|
|
329
|
+
"modelConfigRequiredHelp": "至少添加一个模型服务后,再回到输入框重新发送消息。",
|
|
328
330
|
"connectionErrorTitle": "连接异常",
|
|
331
|
+
"connectionClosedTitle": "连接已断开",
|
|
329
332
|
"sessionErrorTitle": "任务失败",
|
|
330
333
|
"connectionError": "WebSocket 连接失败,请检查服务状态后重试",
|
|
331
334
|
"connectionClosed": "WebSocket 连接已关闭,请重试",
|
|
335
|
+
"connectionErrorHelp": "当前流式更新还没恢复就中断了。重试连接后可以重新订阅这个会话的实时输出。",
|
|
336
|
+
"connectionClosedHelp": "当前消息流意外结束了。重试连接后,可以继续接收这个会话后续的新消息。",
|
|
337
|
+
"sessionErrorHelp": "可以先检查最近一次工具输出或终端日志,再决定是否从最近一条用户消息继续。",
|
|
338
|
+
"sessionErrorCode": "错误码:{{code}}",
|
|
332
339
|
"retryConnection": "重试连接",
|
|
340
|
+
"debugMockLabel": "调试预览",
|
|
341
|
+
"debugMockConnectionErrorMessage": "无法连上当前会话的消息流,WebSocket 握手在收到任何更新前就超时了。",
|
|
342
|
+
"debugMockConnectionClosedMessage": "assistant 已经开始回复,但连接中途断开;在重新连接前,不会再收到新的 token。",
|
|
343
|
+
"debugMockSessionErrorMessage": "runtime 在等待下游工具结果时触发了会话超时,这一轮任务已经停止。",
|
|
333
344
|
"permissionRequestBadge": "权限请求",
|
|
334
345
|
"permissionRequestTitleWithTool": "正在请求使用【{{tool}}】的调用权限,请选择通过",
|
|
335
346
|
"permissionSubject": "审批范围",
|
|
@@ -548,9 +559,30 @@
|
|
|
548
559
|
"startTasksFailed": "失败",
|
|
549
560
|
"startTasksLogs": "任务日志",
|
|
550
561
|
"task": "任务",
|
|
562
|
+
"taskCount": "{{count}} 个任务",
|
|
551
563
|
"taskExitCode": "退出码: {{code}}",
|
|
552
564
|
"writeSuccess": "写入成功",
|
|
553
565
|
"writeFailed": "写入失败",
|
|
566
|
+
"askUserQuestion": "询问问题",
|
|
567
|
+
"globTool": "Glob",
|
|
568
|
+
"grepTool": "Grep",
|
|
569
|
+
"editTool": "编辑文件",
|
|
570
|
+
"lsTool": "浏览目录",
|
|
571
|
+
"notebookEdit": "编辑 Notebook",
|
|
572
|
+
"webFetch": "抓取网页",
|
|
573
|
+
"webSearch": "网页搜索",
|
|
574
|
+
"booleanOn": "开启",
|
|
575
|
+
"booleanOff": "关闭",
|
|
576
|
+
"diffSplit": "双栏",
|
|
577
|
+
"diffInline": "单栏",
|
|
578
|
+
"skill": "技能",
|
|
579
|
+
"enterPlanMode": "进入计划模式",
|
|
580
|
+
"exitPlanMode": "退出计划模式",
|
|
581
|
+
"taskCreate": "创建任务",
|
|
582
|
+
"taskGet": "获取任务",
|
|
583
|
+
"taskUpdate": "更新任务",
|
|
584
|
+
"taskList": "列出任务",
|
|
585
|
+
"claudeTask": "Claude 任务",
|
|
554
586
|
"todo": "任务规划",
|
|
555
587
|
"call": "调用",
|
|
556
588
|
"reading": "正在读取文件...",
|
|
@@ -560,6 +592,55 @@
|
|
|
560
592
|
"runInBackground": "后台执行",
|
|
561
593
|
"dangerouslyDisableSandbox": "禁用沙箱",
|
|
562
594
|
"viewCommand": "查看指令",
|
|
595
|
+
"noParameters": "无参数",
|
|
596
|
+
"groupSummaryCount": "{{name}} {{count}} 次",
|
|
597
|
+
"groupSummaryMoreCount": "+{{count}} 次",
|
|
598
|
+
"singleSelect": "单选",
|
|
599
|
+
"multiSelect": "多选",
|
|
600
|
+
"fields": {
|
|
601
|
+
"activeForm": "当前表述",
|
|
602
|
+
"addBlockedBy": "新增阻塞源",
|
|
603
|
+
"addBlocks": "新增阻塞项",
|
|
604
|
+
"allowedDomains": "允许域名",
|
|
605
|
+
"allowedPrompts": "允许的提示",
|
|
606
|
+
"answers": "回答",
|
|
607
|
+
"args": "参数",
|
|
608
|
+
"blockedDomains": "屏蔽域名",
|
|
609
|
+
"cellId": "单元 ID",
|
|
610
|
+
"cellType": "单元类型",
|
|
611
|
+
"command": "命令",
|
|
612
|
+
"content": "内容",
|
|
613
|
+
"description": "说明",
|
|
614
|
+
"disableSandbox": "禁用沙箱",
|
|
615
|
+
"details": "详情",
|
|
616
|
+
"editMode": "编辑模式",
|
|
617
|
+
"glob": "Glob",
|
|
618
|
+
"ignore": "忽略项",
|
|
619
|
+
"limit": "Limit",
|
|
620
|
+
"maxTurns": "最大轮次",
|
|
621
|
+
"metadata": "元数据",
|
|
622
|
+
"model": "模型",
|
|
623
|
+
"mode": "模式",
|
|
624
|
+
"newSource": "新内容",
|
|
625
|
+
"newString": "新字符串",
|
|
626
|
+
"oldString": "旧字符串",
|
|
627
|
+
"owner": "负责人",
|
|
628
|
+
"offset": "Offset",
|
|
629
|
+
"path": "路径",
|
|
630
|
+
"prompt": "提示词",
|
|
631
|
+
"pushToRemote": "推送到远端",
|
|
632
|
+
"questions": "问题",
|
|
633
|
+
"remoteSession": "远端会话",
|
|
634
|
+
"remoteSessionUrl": "远端会话地址",
|
|
635
|
+
"replaceAll": "全量替换",
|
|
636
|
+
"resume": "恢复",
|
|
637
|
+
"runInBackground": "后台执行",
|
|
638
|
+
"status": "状态",
|
|
639
|
+
"subagentType": "子代理类型",
|
|
640
|
+
"subject": "主题",
|
|
641
|
+
"timeout": "超时",
|
|
642
|
+
"todos": "待办事项"
|
|
643
|
+
},
|
|
563
644
|
"unknown": "未知工具"
|
|
564
645
|
},
|
|
565
646
|
"terminal": {
|