@vibe-forge/client 0.4.0 → 0.5.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/cli.cjs +1 -0
- package/dist/assets/{arc-DgIxeTMg.js → arc-C4ymrcSQ.js} +1 -1
- package/dist/assets/{blockDiagram-c4efeb88-CEAob3X9.js → blockDiagram-c4efeb88-CeB7-kgP.js} +1 -1
- package/dist/assets/{c4Diagram-c83219d4-DwIxpDKd.js → c4Diagram-c83219d4-C935Im8S.js} +1 -1
- package/dist/assets/channel-84s1ACzD.js +1 -0
- package/dist/assets/{classDiagram-beda092f-Cz1q8u_0.js → classDiagram-beda092f-B9IV13KI.js} +1 -1
- package/dist/assets/{classDiagram-v2-2358418a-CImgTuwd.js → classDiagram-v2-2358418a-CXF_K4fE.js} +1 -1
- package/dist/assets/clone-B2E8tddE.js +1 -0
- package/dist/assets/{createText-1719965b-C1_HJcCc.js → createText-1719965b-DwX8iC5F.js} +1 -1
- package/dist/assets/{edges-96097737-BU8qStzd.js → edges-96097737-9P1uH1RE.js} +1 -1
- package/dist/assets/{erDiagram-0228fc6a-DNA1Fz2L.js → erDiagram-0228fc6a-ixeGTFvg.js} +1 -1
- package/dist/assets/{flowDb-c6c81e3f-DjiCStMN.js → flowDb-c6c81e3f-G1gSTTBI.js} +1 -1
- package/dist/assets/{flowDiagram-50d868cf-CSDi0-RD.js → flowDiagram-50d868cf-CzrG99nD.js} +1 -1
- package/dist/assets/flowDiagram-v2-4f6560a1-CJfJYbME.js +1 -0
- package/dist/assets/{flowchart-elk-definition-6af322e1-DrhIMas7.js → flowchart-elk-definition-6af322e1-sFCoysWa.js} +1 -1
- package/dist/assets/{ganttDiagram-a2739b55-CTZnUP5z.js → ganttDiagram-a2739b55-Ccsk_Lru.js} +1 -1
- package/dist/assets/{gitGraphDiagram-82fe8481-COOW7jTi.js → gitGraphDiagram-82fe8481-CwathJ6H.js} +1 -1
- package/dist/assets/{graph-CIkpD4Kx.js → graph-DRCU-8Rz.js} +1 -1
- package/dist/assets/{index-5325376f-aVVRRTIu.js → index-5325376f-Bq-fg2i_.js} +1 -1
- package/dist/assets/{index-D1giUI7r.css → index-CHMuZ5-1.css} +1 -1
- package/dist/assets/{index-DRSI_ZIL.js → index-cGZvDhhU.js} +165 -137
- package/dist/assets/{infoDiagram-8eee0895-DQpZ1LVD.js → infoDiagram-8eee0895-JBcUkJ6T.js} +1 -1
- package/dist/assets/{journeyDiagram-c64418c1-DoKguIuk.js → journeyDiagram-c64418c1-DsdQU-R8.js} +1 -1
- package/dist/assets/{layout-Tnmha8Nh.js → layout-s0slG1OL.js} +1 -1
- package/dist/assets/{line-BQR2SOyl.js → line-CymFqgW6.js} +1 -1
- package/dist/assets/{linear-DlG0eemV.js → linear-lDQVZ6aQ.js} +1 -1
- package/dist/assets/{mermaid.core-BnwYO0He.js → mermaid.core-Cmlqga_E.js} +4 -4
- package/dist/assets/{mindmap-definition-8da855dc-BllYwDID.js → mindmap-definition-8da855dc-CqqTDJn_.js} +1 -1
- package/dist/assets/{pieDiagram-a8764435-DwCkhPVc.js → pieDiagram-a8764435-BL2Ajx7Z.js} +1 -1
- package/dist/assets/{quadrantDiagram-1e28029f-c40GKTU0.js → quadrantDiagram-1e28029f-ClL_3ASt.js} +1 -1
- package/dist/assets/{requirementDiagram-08caed73-DnQp2Tk6.js → requirementDiagram-08caed73-CB1RgE3K.js} +1 -1
- package/dist/assets/{sankeyDiagram-a04cb91d-CnJrs13b.js → sankeyDiagram-a04cb91d-tgleEYiD.js} +1 -1
- package/dist/assets/{sequenceDiagram-c5b8d532-1YBwnpKu.js → sequenceDiagram-c5b8d532-DlatQT5R.js} +1 -1
- package/dist/assets/{stateDiagram-1ecb1508-BFBxQ6Fh.js → stateDiagram-1ecb1508-B--MLqRs.js} +1 -1
- package/dist/assets/{stateDiagram-v2-c2b004d7-Dmechvv2.js → stateDiagram-v2-c2b004d7-CRMZ6Dpx.js} +1 -1
- package/dist/assets/{styles-b4e223ce-DWWfWX8O.js → styles-b4e223ce-CPiYHfUz.js} +1 -1
- package/dist/assets/{styles-ca3715f6-CKKvZxaU.js → styles-ca3715f6-B9UKPAzX.js} +1 -1
- package/dist/assets/{styles-d45a18b0-dKMOUh9p.js → styles-d45a18b0-BC1Ak1So.js} +1 -1
- package/dist/assets/{svgDrawCommon-b86b1483-CBgjChPM.js → svgDrawCommon-b86b1483-DV8R0g-n.js} +1 -1
- package/dist/assets/{timeline-definition-faaaa080-NCt-HHmb.js → timeline-definition-faaaa080-CiqGS5DC.js} +1 -1
- package/dist/assets/{xychartDiagram-f5964ef8-BJhXS4dG.js → xychartDiagram-f5964ef8-h6VSD3GE.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +7 -6
- package/src/api/sessions.ts +3 -1
- package/src/components/Chat.tsx +6 -0
- package/src/components/ConfigView.tsx +25 -25
- package/src/components/chat/ChatHistoryView.tsx +10 -0
- package/src/components/chat/Sender/Sender.scss +80 -17
- package/src/components/chat/Sender/Sender.tsx +22 -0
- package/src/components/config/ConfigSourceSwitch.tsx +12 -34
- package/src/components/config/channelDefinitions.ts +2 -2
- package/src/components/config/recordEditors/ChannelRecordEditor.tsx +33 -33
- package/src/components/sidebar/SessionItem.scss +17 -0
- package/src/components/sidebar/SessionItem.tsx +21 -13
- package/src/hooks/chat/use-chat-adapter.ts +81 -0
- package/src/hooks/chat/use-chat-models.tsx +73 -9
- package/src/hooks/chat/use-chat-session-actions.ts +9 -3
- package/src/hooks/chat/use-chat-session-messages.ts +17 -5
- package/src/hooks/chat/use-chat-session.ts +7 -1
- package/src/resources/adapters.ts +20 -0
- package/dist/assets/channel-DhtnrNJ6.js +0 -1
- package/dist/assets/clone-7bHB6YkC.js +0 -1
- package/dist/assets/flowDiagram-v2-4f6560a1-_13Sz5Wh.js +0 -1
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { createElement, type ReactNode } from 'react'
|
|
2
|
+
import { useEffect, useMemo, useState } from 'react'
|
|
3
|
+
import useSWR from 'swr'
|
|
4
|
+
|
|
5
|
+
import { getConfig } from '#~/api.js'
|
|
6
|
+
import type { ConfigResponse } from '@vibe-forge/core'
|
|
7
|
+
import { getAdapterDisplay } from '#~/resources/adapters.js'
|
|
8
|
+
|
|
9
|
+
const ADAPTER_STORAGE_KEY = 'vf_chat_adapter'
|
|
10
|
+
|
|
11
|
+
export function useChatAdapter() {
|
|
12
|
+
const [selectedAdapter, setSelectedAdapter] = useState<string | undefined>(() => {
|
|
13
|
+
try {
|
|
14
|
+
const raw = localStorage.getItem(ADAPTER_STORAGE_KEY)
|
|
15
|
+
return raw == null || raw.trim() === '' ? undefined : raw
|
|
16
|
+
} catch {
|
|
17
|
+
return undefined
|
|
18
|
+
}
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const { data: configRes } = useSWR<ConfigResponse>('/api/config', getConfig)
|
|
22
|
+
|
|
23
|
+
const mergedAdapters = useMemo(() => {
|
|
24
|
+
return configRes?.sources?.merged?.adapters ?? {}
|
|
25
|
+
}, [configRes?.sources?.merged?.adapters])
|
|
26
|
+
|
|
27
|
+
const defaultAdapter = configRes?.sources?.merged?.general?.defaultAdapter
|
|
28
|
+
|
|
29
|
+
const adapterOptions = useMemo<Array<{ value: string; label: ReactNode }>>(() => {
|
|
30
|
+
const keys = Object.keys(mergedAdapters)
|
|
31
|
+
return keys.map((key) => {
|
|
32
|
+
const display = getAdapterDisplay(key)
|
|
33
|
+
return {
|
|
34
|
+
value: key,
|
|
35
|
+
label: createElement('span', { className: 'adapter-option' }, [
|
|
36
|
+
display.icon != null
|
|
37
|
+
? createElement('img', {
|
|
38
|
+
key: 'icon',
|
|
39
|
+
className: 'adapter-option__icon',
|
|
40
|
+
src: display.icon,
|
|
41
|
+
alt: '',
|
|
42
|
+
'aria-hidden': true
|
|
43
|
+
})
|
|
44
|
+
: null,
|
|
45
|
+
createElement('span', { key: 'text', className: 'adapter-option__text' }, display.title)
|
|
46
|
+
])
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
}, [mergedAdapters])
|
|
50
|
+
|
|
51
|
+
// Auto-select: use stored value if valid, else config default, else first available
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
const keys = Object.keys(mergedAdapters)
|
|
54
|
+
if (keys.length === 0) {
|
|
55
|
+
setSelectedAdapter(undefined)
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
setSelectedAdapter((prev) => {
|
|
59
|
+
if (prev != null && keys.includes(prev)) return prev
|
|
60
|
+
if (defaultAdapter && keys.includes(defaultAdapter as string)) return defaultAdapter as string
|
|
61
|
+
return keys[0]
|
|
62
|
+
})
|
|
63
|
+
}, [defaultAdapter, mergedAdapters])
|
|
64
|
+
|
|
65
|
+
// Persist to localStorage
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
try {
|
|
68
|
+
if (selectedAdapter == null || selectedAdapter.trim() === '') {
|
|
69
|
+
localStorage.removeItem(ADAPTER_STORAGE_KEY)
|
|
70
|
+
} else {
|
|
71
|
+
localStorage.setItem(ADAPTER_STORAGE_KEY, selectedAdapter)
|
|
72
|
+
}
|
|
73
|
+
} catch {}
|
|
74
|
+
}, [selectedAdapter])
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
selectedAdapter,
|
|
78
|
+
setSelectedAdapter,
|
|
79
|
+
adapterOptions
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
|
|
2
2
|
import { useTranslation } from 'react-i18next'
|
|
3
3
|
import useSWR from 'swr'
|
|
4
4
|
|
|
5
|
-
import type { ConfigResponse, ModelServiceConfig, RecommendedModelConfig } from '@vibe-forge/core'
|
|
5
|
+
import type { AdapterBuiltinModel, ConfigResponse, ModelServiceConfig, RecommendedModelConfig } from '@vibe-forge/core'
|
|
6
6
|
import { getConfig } from '#~/api.js'
|
|
7
7
|
|
|
8
8
|
export interface ModelSelectOption {
|
|
@@ -16,7 +16,11 @@ export interface ModelSelectGroup {
|
|
|
16
16
|
options: ModelSelectOption[]
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export function useChatModels(
|
|
19
|
+
export function useChatModels({
|
|
20
|
+
selectedAdapter
|
|
21
|
+
}: {
|
|
22
|
+
selectedAdapter?: string
|
|
23
|
+
} = {}) {
|
|
20
24
|
const { t } = useTranslation()
|
|
21
25
|
const [selectedModel, setSelectedModel] = useState<string | undefined>(() => {
|
|
22
26
|
try {
|
|
@@ -41,6 +45,30 @@ export function useChatModels() {
|
|
|
41
45
|
))
|
|
42
46
|
}, [configRes?.sources?.merged?.general?.recommendedModels])
|
|
43
47
|
|
|
48
|
+
const adapterBuiltinModels = useMemo(() => {
|
|
49
|
+
const raw = configRes?.sources?.merged?.adapterBuiltinModels
|
|
50
|
+
return (raw ?? {}) as Record<string, AdapterBuiltinModel[]>
|
|
51
|
+
}, [configRes?.sources?.merged?.adapterBuiltinModels])
|
|
52
|
+
|
|
53
|
+
const activeBuiltinModels = useMemo(() => {
|
|
54
|
+
if (selectedAdapter && adapterBuiltinModels[selectedAdapter]) {
|
|
55
|
+
return { [selectedAdapter]: adapterBuiltinModels[selectedAdapter] }
|
|
56
|
+
}
|
|
57
|
+
return adapterBuiltinModels
|
|
58
|
+
}, [adapterBuiltinModels, selectedAdapter])
|
|
59
|
+
|
|
60
|
+
const activeBuiltinModelValues = useMemo(() => (
|
|
61
|
+
Object.values(activeBuiltinModels).flat().map(model => model.value)
|
|
62
|
+
), [activeBuiltinModels])
|
|
63
|
+
|
|
64
|
+
const builtinModelSet = useMemo(() => {
|
|
65
|
+
const set = new Set<string>()
|
|
66
|
+
for (const models of Object.values(activeBuiltinModels)) {
|
|
67
|
+
for (const m of models) set.add(m.value)
|
|
68
|
+
}
|
|
69
|
+
return set
|
|
70
|
+
}, [activeBuiltinModels])
|
|
71
|
+
|
|
44
72
|
const modelServiceEntries = useMemo(() => Object.entries(mergedModelServices), [mergedModelServices])
|
|
45
73
|
|
|
46
74
|
const availableModels = useMemo(() => {
|
|
@@ -61,7 +89,7 @@ export function useChatModels() {
|
|
|
61
89
|
const availableModelValues = useMemo(() => availableModels.map(item => item.model), [availableModels])
|
|
62
90
|
const availableModelKey = useMemo(() => availableModelValues.join('|'), [availableModelValues])
|
|
63
91
|
const availableModelSet = useMemo(() => new Set(availableModelValues), [availableModelKey])
|
|
64
|
-
const hasAvailableModels = availableModelValues.length > 0
|
|
92
|
+
const hasAvailableModels = availableModelValues.length > 0 || builtinModelSet.size > 0
|
|
65
93
|
const modelToService = useMemo(() => {
|
|
66
94
|
const map = new Map<string, { key: string; title: string }>()
|
|
67
95
|
for (const entry of availableModels) {
|
|
@@ -76,25 +104,35 @@ export function useChatModels() {
|
|
|
76
104
|
const formatModelWithService = useCallback((model: string | undefined) => {
|
|
77
105
|
const normalizedModel = typeof model === 'string' ? model.trim() : ''
|
|
78
106
|
if (normalizedModel === '') return undefined
|
|
107
|
+
// Builtin adapter models pass through as-is (no service prefix)
|
|
108
|
+
if (builtinModelSet.has(normalizedModel)) return normalizedModel
|
|
79
109
|
if (normalizedModel.includes(',')) return normalizedModel
|
|
80
110
|
const resolvedService = modelToService.get(normalizedModel)?.key ?? defaultModelService
|
|
81
111
|
return resolvedService ? `${resolvedService},${normalizedModel}` : normalizedModel
|
|
82
|
-
}, [defaultModelService, modelToService])
|
|
112
|
+
}, [builtinModelSet, defaultModelService, modelToService])
|
|
83
113
|
const resolvedDefaultModel = useMemo(() => {
|
|
84
|
-
if (
|
|
114
|
+
if (defaultModel && builtinModelSet.has(defaultModel)) return defaultModel
|
|
115
|
+
if (activeBuiltinModelValues.length > 0) {
|
|
116
|
+
return activeBuiltinModelValues[0]
|
|
117
|
+
}
|
|
85
118
|
if (defaultModel && availableModelSet.has(defaultModel)) return defaultModel
|
|
86
119
|
if (defaultModelService && mergedModelServices[defaultModelService]) {
|
|
87
120
|
const service = mergedModelServices[defaultModelService]
|
|
88
121
|
const models = Array.isArray(service?.models) ? service?.models.filter(item => typeof item === 'string') : []
|
|
89
122
|
if (models.length > 0) return models[0]
|
|
90
123
|
}
|
|
91
|
-
return availableModelValues[0]
|
|
124
|
+
if (availableModelValues.length > 0) return availableModelValues[0]
|
|
125
|
+
// Fall back to first builtin model from the active adapter
|
|
126
|
+
const firstBuiltin = Object.values(activeBuiltinModels).flat()[0]
|
|
127
|
+
return firstBuiltin?.value
|
|
92
128
|
}, [
|
|
129
|
+
activeBuiltinModels,
|
|
130
|
+
activeBuiltinModelValues,
|
|
93
131
|
availableModelSet,
|
|
94
132
|
availableModelValues,
|
|
133
|
+
builtinModelSet,
|
|
95
134
|
defaultModel,
|
|
96
135
|
defaultModelService,
|
|
97
|
-
hasAvailableModels,
|
|
98
136
|
mergedModelServices
|
|
99
137
|
])
|
|
100
138
|
const selectedModelWithService = useMemo(() => (
|
|
@@ -107,10 +145,13 @@ export function useChatModels() {
|
|
|
107
145
|
return
|
|
108
146
|
}
|
|
109
147
|
setSelectedModel((prev) => {
|
|
110
|
-
if (prev != null
|
|
148
|
+
if (prev != null) {
|
|
149
|
+
const isValid = availableModelSet.has(prev) || builtinModelSet.has(prev)
|
|
150
|
+
if (isValid) return prev
|
|
151
|
+
}
|
|
111
152
|
return resolvedDefaultModel
|
|
112
153
|
})
|
|
113
|
-
}, [availableModelSet, hasAvailableModels, resolvedDefaultModel])
|
|
154
|
+
}, [availableModelSet, builtinModelSet, hasAvailableModels, resolvedDefaultModel, selectedAdapter])
|
|
114
155
|
|
|
115
156
|
useEffect(() => {
|
|
116
157
|
try {
|
|
@@ -235,8 +276,31 @@ export function useChatModels() {
|
|
|
235
276
|
options: recommendedOptions
|
|
236
277
|
})
|
|
237
278
|
}
|
|
279
|
+
|
|
280
|
+
// Adapter builtin model groups (filtered to active adapter)
|
|
281
|
+
for (const [adapterKey, models] of Object.entries(activeBuiltinModels)) {
|
|
282
|
+
if (!Array.isArray(models) || models.length === 0) continue
|
|
283
|
+
const adapterTitle = t('chat.modelGroupBuiltin', {
|
|
284
|
+
adapter: adapterKey,
|
|
285
|
+
defaultValue: `${adapterKey} (Default)`
|
|
286
|
+
})
|
|
287
|
+
groups.push({
|
|
288
|
+
label: (
|
|
289
|
+
<div className='model-group-label'>
|
|
290
|
+
<div className='model-group-title'>{adapterTitle}</div>
|
|
291
|
+
</div>
|
|
292
|
+
),
|
|
293
|
+
options: models.map(m => buildOption({
|
|
294
|
+
value: m.value,
|
|
295
|
+
title: m.title,
|
|
296
|
+
description: m.description
|
|
297
|
+
}))
|
|
298
|
+
})
|
|
299
|
+
}
|
|
300
|
+
|
|
238
301
|
return [...groups, ...serviceGroups]
|
|
239
302
|
}, [
|
|
303
|
+
activeBuiltinModels,
|
|
240
304
|
availableModelSet,
|
|
241
305
|
modelToService,
|
|
242
306
|
mergedModelServices,
|
|
@@ -4,9 +4,9 @@ import { useTranslation } from 'react-i18next'
|
|
|
4
4
|
import { useNavigate } from 'react-router-dom'
|
|
5
5
|
import { useSWRConfig } from 'swr'
|
|
6
6
|
|
|
7
|
-
import type { ChatMessageContent, Session } from '@vibe-forge/core'
|
|
8
7
|
import { createSession } from '#~/api.js'
|
|
9
8
|
import { connectionManager } from '#~/connectionManager.js'
|
|
9
|
+
import type { ChatMessageContent, Session } from '@vibe-forge/core'
|
|
10
10
|
import type { PermissionMode } from './use-chat-permission-mode'
|
|
11
11
|
|
|
12
12
|
export function useChatSessionActions({
|
|
@@ -14,12 +14,14 @@ export function useChatSessionActions({
|
|
|
14
14
|
modelForQuery,
|
|
15
15
|
hasAvailableModels,
|
|
16
16
|
permissionMode,
|
|
17
|
+
adapter,
|
|
17
18
|
onClearMessages
|
|
18
19
|
}: {
|
|
19
20
|
session?: Session
|
|
20
21
|
modelForQuery?: string
|
|
21
22
|
hasAvailableModels: boolean
|
|
22
23
|
permissionMode: PermissionMode
|
|
24
|
+
adapter?: string
|
|
23
25
|
onClearMessages: () => void
|
|
24
26
|
}) {
|
|
25
27
|
const { message } = App.useApp()
|
|
@@ -40,7 +42,8 @@ export function useChatSessionActions({
|
|
|
40
42
|
setIsCreating(true)
|
|
41
43
|
try {
|
|
42
44
|
const { session: newSession } = await createSession(undefined, text.trim(), undefined, modelForQuery, {
|
|
43
|
-
permissionMode
|
|
45
|
+
permissionMode,
|
|
46
|
+
adapter
|
|
44
47
|
})
|
|
45
48
|
|
|
46
49
|
await mutate('/api/sessions', (prev: { sessions: Session[] } | undefined) => {
|
|
@@ -65,6 +68,7 @@ export function useChatSessionActions({
|
|
|
65
68
|
text: text.trim()
|
|
66
69
|
})
|
|
67
70
|
}, [
|
|
71
|
+
adapter,
|
|
68
72
|
hasAvailableModels,
|
|
69
73
|
isThinking,
|
|
70
74
|
message,
|
|
@@ -87,7 +91,8 @@ export function useChatSessionActions({
|
|
|
87
91
|
setIsCreating(true)
|
|
88
92
|
try {
|
|
89
93
|
const { session: newSession } = await createSession(undefined, undefined, content, modelForQuery, {
|
|
90
|
-
permissionMode
|
|
94
|
+
permissionMode,
|
|
95
|
+
adapter
|
|
91
96
|
})
|
|
92
97
|
|
|
93
98
|
await mutate('/api/sessions', (prev: { sessions: Session[] } | undefined) => {
|
|
@@ -113,6 +118,7 @@ export function useChatSessionActions({
|
|
|
113
118
|
content
|
|
114
119
|
})
|
|
115
120
|
}, [
|
|
121
|
+
adapter,
|
|
116
122
|
hasAvailableModels,
|
|
117
123
|
isThinking,
|
|
118
124
|
message,
|
|
@@ -2,9 +2,9 @@ import { App } from 'antd'
|
|
|
2
2
|
import { useEffect, useRef, useState } from 'react'
|
|
3
3
|
import { useSWRConfig } from 'swr'
|
|
4
4
|
|
|
5
|
-
import type { AskUserQuestionParams, ChatMessage, Session, SessionInfo, WSEvent } from '@vibe-forge/core'
|
|
6
5
|
import { getSessionMessages } from '#~/api.js'
|
|
7
6
|
import { connectionManager } from '#~/connectionManager.js'
|
|
7
|
+
import type { AskUserQuestionParams, ChatMessage, Session, SessionInfo, WSEvent } from '@vibe-forge/core'
|
|
8
8
|
import type { PermissionMode } from './use-chat-permission-mode'
|
|
9
9
|
|
|
10
10
|
const applyMessageEvent = (currentMessages: ChatMessage[], data: WSEvent) => {
|
|
@@ -38,11 +38,13 @@ export function useChatSessionMessages({
|
|
|
38
38
|
session,
|
|
39
39
|
modelForQuery,
|
|
40
40
|
permissionMode,
|
|
41
|
+
adapter,
|
|
41
42
|
setInteractionRequest
|
|
42
43
|
}: {
|
|
43
44
|
session?: Session
|
|
44
45
|
modelForQuery?: string
|
|
45
46
|
permissionMode: PermissionMode
|
|
47
|
+
adapter?: string
|
|
46
48
|
setInteractionRequest: (value: { id: string; payload: AskUserQuestionParams } | null) => void
|
|
47
49
|
}) {
|
|
48
50
|
const { message } = App.useApp()
|
|
@@ -53,6 +55,7 @@ export function useChatSessionMessages({
|
|
|
53
55
|
const isInitialLoadRef = useRef<boolean>(true)
|
|
54
56
|
const lastConnectedModelRef = useRef<string | undefined>(undefined)
|
|
55
57
|
const lastConnectedPermissionModeRef = useRef<string | undefined>(undefined)
|
|
58
|
+
const lastConnectedAdapterRef = useRef<string | undefined>(undefined)
|
|
56
59
|
|
|
57
60
|
useEffect(() => {
|
|
58
61
|
setMessages([])
|
|
@@ -141,23 +144,32 @@ export function useChatSessionMessages({
|
|
|
141
144
|
lastConnectedPermissionModeRef.current != null &&
|
|
142
145
|
normalizedPermissionMode !== lastConnectedPermissionModeRef.current &&
|
|
143
146
|
session?.status !== 'running'
|
|
144
|
-
|
|
147
|
+
const normalizedAdapter = adapter ?? ''
|
|
148
|
+
const adapterChanged = adapter != null &&
|
|
149
|
+
lastConnectedAdapterRef.current != null &&
|
|
150
|
+
normalizedAdapter !== lastConnectedAdapterRef.current &&
|
|
151
|
+
session?.status !== 'running'
|
|
152
|
+
if (modelChanged || permissionModeChanged || adapterChanged) {
|
|
145
153
|
connectionManager.send(session.id, { type: 'terminate_session' })
|
|
146
154
|
connectionManager.close(session.id)
|
|
147
155
|
}
|
|
148
156
|
lastConnectedModelRef.current = normalizedModel
|
|
149
157
|
lastConnectedPermissionModeRef.current = normalizedPermissionMode
|
|
158
|
+
lastConnectedAdapterRef.current = normalizedAdapter
|
|
150
159
|
|
|
151
160
|
const timer = setTimeout(() => {
|
|
152
161
|
if (isDisposed) return
|
|
153
162
|
|
|
154
163
|
const connectionParams: Record<string, string> = {}
|
|
155
|
-
|
|
156
|
-
|
|
164
|
+
if (modelForQuery) {
|
|
165
|
+
connectionParams.model = modelForQuery
|
|
157
166
|
}
|
|
158
167
|
if (permissionMode) {
|
|
159
168
|
connectionParams.permissionMode = permissionMode
|
|
160
169
|
}
|
|
170
|
+
if (adapter) {
|
|
171
|
+
connectionParams.adapter = adapter
|
|
172
|
+
}
|
|
161
173
|
|
|
162
174
|
cleanup = connectionManager.connect(session.id, {
|
|
163
175
|
onOpen() {
|
|
@@ -239,7 +251,7 @@ export function useChatSessionMessages({
|
|
|
239
251
|
clearTimeout(timer)
|
|
240
252
|
cleanup?.()
|
|
241
253
|
}
|
|
242
|
-
}, [message, modelForQuery, mutate, permissionMode, session?.id, session?.status, setInteractionRequest])
|
|
254
|
+
}, [adapter, message, modelForQuery, mutate, permissionMode, session?.id, session?.status, setInteractionRequest])
|
|
243
255
|
|
|
244
256
|
return {
|
|
245
257
|
messages,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useTranslation } from 'react-i18next'
|
|
2
2
|
|
|
3
3
|
import type { Session } from '@vibe-forge/core'
|
|
4
|
+
import { useChatAdapter } from './use-chat-adapter'
|
|
4
5
|
import { useChatInteraction } from './use-chat-interaction'
|
|
5
6
|
import { useChatModels } from './use-chat-models'
|
|
6
7
|
import { useChatPermissionMode } from './use-chat-permission-mode'
|
|
@@ -13,13 +14,14 @@ export function useChatSession({
|
|
|
13
14
|
session?: Session
|
|
14
15
|
}) {
|
|
15
16
|
const { t } = useTranslation()
|
|
17
|
+
const { selectedAdapter, setSelectedAdapter, adapterOptions } = useChatAdapter()
|
|
16
18
|
const {
|
|
17
19
|
selectedModel,
|
|
18
20
|
selectedModelWithService,
|
|
19
21
|
setSelectedModel,
|
|
20
22
|
modelOptions,
|
|
21
23
|
hasAvailableModels
|
|
22
|
-
} = useChatModels()
|
|
24
|
+
} = useChatModels({ selectedAdapter })
|
|
23
25
|
const { permissionMode, setPermissionMode, permissionModeOptions } = useChatPermissionMode()
|
|
24
26
|
const { activeView, setActiveView } = useChatView()
|
|
25
27
|
const { interactionRequest, setInteractionRequest, handleInteractionResponse } = useChatInteraction({
|
|
@@ -29,6 +31,7 @@ export function useChatSession({
|
|
|
29
31
|
session,
|
|
30
32
|
modelForQuery: selectedModelWithService,
|
|
31
33
|
permissionMode,
|
|
34
|
+
adapter: selectedAdapter,
|
|
32
35
|
setInteractionRequest
|
|
33
36
|
})
|
|
34
37
|
const isThinking = session?.status === 'running'
|
|
@@ -51,6 +54,9 @@ export function useChatSession({
|
|
|
51
54
|
permissionMode,
|
|
52
55
|
setPermissionMode,
|
|
53
56
|
permissionModeOptions,
|
|
57
|
+
selectedAdapter,
|
|
58
|
+
setSelectedAdapter,
|
|
59
|
+
adapterOptions,
|
|
54
60
|
hasAvailableModels,
|
|
55
61
|
modelUnavailable: !hasAvailableModels
|
|
56
62
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { adapterDisplayName as claudeCodeDisplayName, adapterIcon as claudeCodeIcon } from '@vibe-forge/adapter-claude-code/icon'
|
|
2
|
+
import { adapterDisplayName as codexDisplayName, adapterIcon as codexIcon } from '@vibe-forge/adapter-codex/icon'
|
|
3
|
+
|
|
4
|
+
export const adapterDisplayMap = {
|
|
5
|
+
'claude-code': {
|
|
6
|
+
title: claudeCodeDisplayName,
|
|
7
|
+
icon: claudeCodeIcon
|
|
8
|
+
},
|
|
9
|
+
codex: {
|
|
10
|
+
title: codexDisplayName,
|
|
11
|
+
icon: codexIcon
|
|
12
|
+
}
|
|
13
|
+
} as const
|
|
14
|
+
|
|
15
|
+
export const getAdapterDisplay = (adapterKey: string) => {
|
|
16
|
+
return adapterDisplayMap[adapterKey as keyof typeof adapterDisplayMap] ?? {
|
|
17
|
+
title: adapterKey,
|
|
18
|
+
icon: undefined
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{al as o,am as n}from"./mermaid.core-BnwYO0He.js";const l=(a,r)=>o.lang.round(n.parse(a)[r]);export{l as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{a as r}from"./graph-CIkpD4Kx.js";var a=4;function n(o){return r(o,a)}export{n as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{f as o,p as e}from"./flowDb-c6c81e3f-DjiCStMN.js";import{f as a,g as t}from"./styles-d45a18b0-dKMOUh9p.js";import{ar as i}from"./mermaid.core-BnwYO0He.js";import"./graph-CIkpD4Kx.js";import"./layout-Tnmha8Nh.js";import"./index-DRSI_ZIL.js";import"./index-5325376f-aVVRRTIu.js";import"./clone-7bHB6YkC.js";import"./edges-96097737-BU8qStzd.js";import"./createText-1719965b-C1_HJcCc.js";import"./line-BQR2SOyl.js";import"./array-BKyUJesY.js";import"./path-CbwjOpE9.js";import"./channel-DhtnrNJ6.js";const n={parser:e,db:o,renderer:t,styles:a,init:r=>{r.flowchart||(r.flowchart={}),r.flowchart.arrowMarkerAbsolute=r.arrowMarkerAbsolute,i({flowchart:{arrowMarkerAbsolute:r.arrowMarkerAbsolute}}),t.setConf(r.flowchart),o.clear(),o.setGen("gen-2")}};export{n as diagram};
|