pragma-so 0.1.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/index.ts +882 -0
- package/index.ts +3 -0
- package/package.json +53 -0
- package/server/connectorBinaries.ts +103 -0
- package/server/connectorRegistry.ts +158 -0
- package/server/conversation/adapterRegistry.ts +53 -0
- package/server/conversation/adapters/claudeAdapter.ts +138 -0
- package/server/conversation/adapters/codexAdapter.ts +142 -0
- package/server/conversation/adapters.ts +224 -0
- package/server/conversation/executeRunner.ts +1191 -0
- package/server/conversation/gitWorkflow.ts +1037 -0
- package/server/conversation/models.ts +23 -0
- package/server/conversation/pragmaCli.ts +34 -0
- package/server/conversation/prompts.ts +335 -0
- package/server/conversation/store.ts +805 -0
- package/server/conversation/titleGenerator.ts +106 -0
- package/server/conversation/turnRunner.ts +365 -0
- package/server/conversation/types.ts +134 -0
- package/server/db.ts +837 -0
- package/server/http/middleware.ts +31 -0
- package/server/http/schemas.ts +430 -0
- package/server/http/validators.ts +38 -0
- package/server/index.ts +6560 -0
- package/server/process/runCommand.ts +142 -0
- package/server/stores/agentStore.ts +167 -0
- package/server/stores/connectorStore.ts +299 -0
- package/server/stores/humanStore.ts +28 -0
- package/server/stores/skillStore.ts +127 -0
- package/server/stores/taskStore.ts +371 -0
- package/shared/net.ts +24 -0
- package/tsconfig.json +14 -0
- package/ui/index.html +14 -0
- package/ui/public/favicon-32.png +0 -0
- package/ui/public/favicon.png +0 -0
- package/ui/src/App.jsx +1338 -0
- package/ui/src/api.js +954 -0
- package/ui/src/components/CodeView.jsx +319 -0
- package/ui/src/components/ConnectionsView.jsx +1004 -0
- package/ui/src/components/ContextView.jsx +315 -0
- package/ui/src/components/ConversationDrawer.jsx +963 -0
- package/ui/src/components/EmptyPane.jsx +20 -0
- package/ui/src/components/FeedView.jsx +773 -0
- package/ui/src/components/FilesView.jsx +257 -0
- package/ui/src/components/InlineChatView.jsx +158 -0
- package/ui/src/components/InputBar.jsx +476 -0
- package/ui/src/components/OnboardingModal.jsx +112 -0
- package/ui/src/components/OutputPanel.jsx +658 -0
- package/ui/src/components/PlanProposalPanel.jsx +177 -0
- package/ui/src/components/RightPanel.jsx +951 -0
- package/ui/src/components/SettingsView.jsx +186 -0
- package/ui/src/components/Sidebar.jsx +247 -0
- package/ui/src/components/TestingPane.jsx +198 -0
- package/ui/src/components/testing/ApiTesterPanel.jsx +187 -0
- package/ui/src/components/testing/LogViewerPanel.jsx +64 -0
- package/ui/src/components/testing/TerminalPanel.jsx +104 -0
- package/ui/src/components/testing/WebPreviewPanel.jsx +78 -0
- package/ui/src/hooks/useAgents.js +81 -0
- package/ui/src/hooks/useConversation.js +252 -0
- package/ui/src/hooks/useTasks.js +161 -0
- package/ui/src/hooks/useWorkspace.js +259 -0
- package/ui/src/lib/agentIcon.js +10 -0
- package/ui/src/lib/conversationUtils.js +575 -0
- package/ui/src/main.jsx +10 -0
- package/ui/src/styles.css +6899 -0
- package/ui/vite.config.mjs +6 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { useEffect, useMemo, useState } from 'react'
|
|
2
|
+
import { FileCode2, FileImage, FileSpreadsheet, FileText, FileType2 } from 'lucide-react'
|
|
3
|
+
import Papa from 'papaparse'
|
|
4
|
+
import ReactMarkdown from 'react-markdown'
|
|
5
|
+
import remarkGfm from 'remark-gfm'
|
|
6
|
+
import {
|
|
7
|
+
fetchWorkspaceOutputFiles,
|
|
8
|
+
workspaceOutputContentUrl,
|
|
9
|
+
workspaceOutputDownloadUrl,
|
|
10
|
+
} from '../api'
|
|
11
|
+
|
|
12
|
+
const IMAGE_EXTENSIONS = new Set(['.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg'])
|
|
13
|
+
|
|
14
|
+
function ext(path) {
|
|
15
|
+
const index = path.lastIndexOf('.')
|
|
16
|
+
if (index === -1) return ''
|
|
17
|
+
return path.slice(index).toLowerCase()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function previewKind(path) {
|
|
21
|
+
const extension = ext(path)
|
|
22
|
+
if (extension === '.md') return 'markdown'
|
|
23
|
+
if (extension === '.html' || extension === '.htm') return 'html'
|
|
24
|
+
if (extension === '.csv') return 'csv'
|
|
25
|
+
if (IMAGE_EXTENSIONS.has(extension)) return 'image'
|
|
26
|
+
return 'download'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function fileName(path) {
|
|
30
|
+
const segments = String(path || '').split('/').filter(Boolean)
|
|
31
|
+
return segments[segments.length - 1] || path
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function fileIcon(path) {
|
|
35
|
+
const extension = ext(path)
|
|
36
|
+
if (extension === '.md' || extension === '.txt') return FileText
|
|
37
|
+
if (extension === '.html' || extension === '.htm' || extension === '.js' || extension === '.ts') return FileCode2
|
|
38
|
+
if (extension === '.csv') return FileSpreadsheet
|
|
39
|
+
if (IMAGE_EXTENSIONS.has(extension)) return FileImage
|
|
40
|
+
return FileType2
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function formatBytes(value) {
|
|
44
|
+
if (!Number.isFinite(value) || value < 0) return ''
|
|
45
|
+
if (value < 1024) return `${value} B`
|
|
46
|
+
if (value < 1024 * 1024) return `${(value / 1024).toFixed(1)} KB`
|
|
47
|
+
return `${(value / (1024 * 1024)).toFixed(1)} MB`
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function parseCsv(text) {
|
|
51
|
+
const parsed = Papa.parse(text, { skipEmptyLines: 'greedy' })
|
|
52
|
+
if (parsed.errors.length > 0) {
|
|
53
|
+
throw new Error(parsed.errors[0].message || 'Failed to parse CSV.')
|
|
54
|
+
}
|
|
55
|
+
if (!Array.isArray(parsed.data)) return []
|
|
56
|
+
return parsed.data.map((row) => (Array.isArray(row) ? row : [String(row)]))
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function FilesView() {
|
|
60
|
+
const [files, setFiles] = useState([])
|
|
61
|
+
const [loading, setLoading] = useState(false)
|
|
62
|
+
const [error, setError] = useState('')
|
|
63
|
+
const [selectedPath, setSelectedPath] = useState('')
|
|
64
|
+
const [previewText, setPreviewText] = useState('')
|
|
65
|
+
const [previewLoading, setPreviewLoading] = useState(false)
|
|
66
|
+
const [previewError, setPreviewError] = useState('')
|
|
67
|
+
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
void loadFiles()
|
|
70
|
+
}, [])
|
|
71
|
+
|
|
72
|
+
async function loadFiles() {
|
|
73
|
+
setLoading(true)
|
|
74
|
+
setError('')
|
|
75
|
+
try {
|
|
76
|
+
const data = await fetchWorkspaceOutputFiles()
|
|
77
|
+
const nextFiles = Array.isArray(data.files) ? data.files : []
|
|
78
|
+
setFiles(nextFiles)
|
|
79
|
+
} catch (err) {
|
|
80
|
+
setError(err instanceof Error ? err.message : String(err))
|
|
81
|
+
setFiles([])
|
|
82
|
+
} finally {
|
|
83
|
+
setLoading(false)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
if (!files.length) {
|
|
89
|
+
setSelectedPath('')
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
setSelectedPath((current) => {
|
|
93
|
+
if (current && files.some((f) => f.path === current)) return current
|
|
94
|
+
return files[0].path
|
|
95
|
+
})
|
|
96
|
+
}, [files])
|
|
97
|
+
|
|
98
|
+
const selectedFile = useMemo(() => {
|
|
99
|
+
return files.find((f) => f.path === selectedPath) || null
|
|
100
|
+
}, [files, selectedPath])
|
|
101
|
+
|
|
102
|
+
const selectedKind = previewKind(selectedPath || '')
|
|
103
|
+
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
if (!selectedPath) {
|
|
106
|
+
setPreviewText('')
|
|
107
|
+
setPreviewError('')
|
|
108
|
+
setPreviewLoading(false)
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
if (selectedKind !== 'markdown' && selectedKind !== 'csv') {
|
|
112
|
+
setPreviewText('')
|
|
113
|
+
setPreviewError('')
|
|
114
|
+
setPreviewLoading(false)
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const controller = new AbortController()
|
|
119
|
+
setPreviewLoading(true)
|
|
120
|
+
setPreviewError('')
|
|
121
|
+
|
|
122
|
+
void fetch(workspaceOutputContentUrl(selectedPath), { signal: controller.signal })
|
|
123
|
+
.then(async (response) => {
|
|
124
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`)
|
|
125
|
+
return response.text()
|
|
126
|
+
})
|
|
127
|
+
.then((text) => setPreviewText(text))
|
|
128
|
+
.catch((err) => {
|
|
129
|
+
if (controller.signal.aborted) return
|
|
130
|
+
setPreviewError(err instanceof Error ? err.message : String(err))
|
|
131
|
+
})
|
|
132
|
+
.finally(() => {
|
|
133
|
+
if (!controller.signal.aborted) setPreviewLoading(false)
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
return () => controller.abort()
|
|
137
|
+
}, [selectedPath, selectedKind])
|
|
138
|
+
|
|
139
|
+
const contentUrl = selectedPath ? workspaceOutputContentUrl(selectedPath) : ''
|
|
140
|
+
const downloadUrl = selectedPath ? workspaceOutputDownloadUrl(selectedPath) : ''
|
|
141
|
+
|
|
142
|
+
if (loading) {
|
|
143
|
+
return (
|
|
144
|
+
<div className="files-view">
|
|
145
|
+
<div className="files-empty"><div className="muted">Loading files...</div></div>
|
|
146
|
+
</div>
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (error) {
|
|
151
|
+
return (
|
|
152
|
+
<div className="files-view">
|
|
153
|
+
<div className="files-empty"><div className="error">Error: {error}</div></div>
|
|
154
|
+
</div>
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (files.length === 0) {
|
|
159
|
+
return (
|
|
160
|
+
<div className="files-view">
|
|
161
|
+
<div className="files-empty">
|
|
162
|
+
<div className="files-empty-inner">
|
|
163
|
+
<div className="files-empty-icon">
|
|
164
|
+
<FileType2 size={32} strokeWidth={1.4} />
|
|
165
|
+
</div>
|
|
166
|
+
<div className="files-empty-title">No output files yet</div>
|
|
167
|
+
<div className="files-empty-desc">Files generated by tasks will appear here.</div>
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
</div>
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return (
|
|
175
|
+
<div className="files-view">
|
|
176
|
+
<div className="files-sidebar">
|
|
177
|
+
<div className="files-sidebar-header">
|
|
178
|
+
<span className="files-section-title">Output Files</span>
|
|
179
|
+
<span className="files-count">{files.length}</span>
|
|
180
|
+
</div>
|
|
181
|
+
<div className="files-list">
|
|
182
|
+
{files.map((file) => {
|
|
183
|
+
const Icon = fileIcon(file.path)
|
|
184
|
+
return (
|
|
185
|
+
<button
|
|
186
|
+
key={file.path}
|
|
187
|
+
className={`files-item ${selectedPath === file.path ? 'active' : ''}`}
|
|
188
|
+
onClick={() => setSelectedPath(file.path)}
|
|
189
|
+
title={file.path}
|
|
190
|
+
>
|
|
191
|
+
<span className="files-item-icon"><Icon size={15} strokeWidth={1.8} /></span>
|
|
192
|
+
<span className="files-item-name">{fileName(file.path)}</span>
|
|
193
|
+
<span className="files-item-size">{formatBytes(file.size)}</span>
|
|
194
|
+
</button>
|
|
195
|
+
)
|
|
196
|
+
})}
|
|
197
|
+
</div>
|
|
198
|
+
</div>
|
|
199
|
+
<div className="files-content">
|
|
200
|
+
{selectedFile && (
|
|
201
|
+
<>
|
|
202
|
+
<div className="files-preview-header">
|
|
203
|
+
<div className="files-preview-path">{selectedFile.path}</div>
|
|
204
|
+
<a className="output-download-btn" href={downloadUrl}>
|
|
205
|
+
Save to Downloads
|
|
206
|
+
</a>
|
|
207
|
+
</div>
|
|
208
|
+
|
|
209
|
+
{previewLoading && <div className="muted">Loading preview...</div>}
|
|
210
|
+
{previewError && <div className="error">Error: {previewError}</div>}
|
|
211
|
+
|
|
212
|
+
{!previewLoading && !previewError && selectedKind === 'markdown' && (
|
|
213
|
+
<div className="output-markdown-preview">
|
|
214
|
+
<ReactMarkdown remarkPlugins={[remarkGfm]}>{previewText}</ReactMarkdown>
|
|
215
|
+
</div>
|
|
216
|
+
)}
|
|
217
|
+
|
|
218
|
+
{!previewLoading && !previewError && selectedKind === 'html' && (
|
|
219
|
+
<iframe className="output-html-preview" src={contentUrl} title={selectedFile.path} />
|
|
220
|
+
)}
|
|
221
|
+
|
|
222
|
+
{!previewLoading && !previewError && selectedKind === 'image' && (
|
|
223
|
+
<div className="output-image-wrap">
|
|
224
|
+
<img src={contentUrl} alt={selectedFile.path} className="output-image-preview" />
|
|
225
|
+
</div>
|
|
226
|
+
)}
|
|
227
|
+
|
|
228
|
+
{!previewLoading && !previewError && selectedKind === 'csv' && (
|
|
229
|
+
<div className="output-csv-wrap">
|
|
230
|
+
<table className="output-csv-table">
|
|
231
|
+
<tbody>
|
|
232
|
+
{parseCsv(previewText).map((row, rowIndex) => (
|
|
233
|
+
<tr key={`row-${rowIndex}`}>
|
|
234
|
+
{row.map((cell, cellIndex) => (
|
|
235
|
+
<td key={`cell-${rowIndex}-${cellIndex}`}>{cell}</td>
|
|
236
|
+
))}
|
|
237
|
+
</tr>
|
|
238
|
+
))}
|
|
239
|
+
</tbody>
|
|
240
|
+
</table>
|
|
241
|
+
</div>
|
|
242
|
+
)}
|
|
243
|
+
|
|
244
|
+
{!previewLoading && !previewError && selectedKind === 'download' && (
|
|
245
|
+
<div className="output-fallback-preview">
|
|
246
|
+
<div className="muted">Preview is not supported for this file type.</div>
|
|
247
|
+
<a className="output-download-btn" href={downloadUrl}>
|
|
248
|
+
Save to Downloads
|
|
249
|
+
</a>
|
|
250
|
+
</div>
|
|
251
|
+
)}
|
|
252
|
+
</>
|
|
253
|
+
)}
|
|
254
|
+
</div>
|
|
255
|
+
</div>
|
|
256
|
+
)
|
|
257
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react'
|
|
2
|
+
import { Sparkles, Info, ChevronRight } from 'lucide-react'
|
|
3
|
+
import ReactMarkdown from 'react-markdown'
|
|
4
|
+
import remarkGfm from 'remark-gfm'
|
|
5
|
+
import { InputBar } from './InputBar'
|
|
6
|
+
|
|
7
|
+
function ToolGroup({ entry }) {
|
|
8
|
+
const [expanded, setExpanded] = useState(false)
|
|
9
|
+
return (
|
|
10
|
+
<div>
|
|
11
|
+
<div className="conv-tool-group" onClick={() => setExpanded((e) => !e)}>
|
|
12
|
+
<ChevronRight
|
|
13
|
+
size={12}
|
|
14
|
+
strokeWidth={2}
|
|
15
|
+
className={`conv-tool-group-chevron${expanded ? ' expanded' : ''}`}
|
|
16
|
+
/>
|
|
17
|
+
<span className="conv-tool-group-summary">{entry.summary}</span>
|
|
18
|
+
</div>
|
|
19
|
+
{expanded && (
|
|
20
|
+
<div className="conv-tool-group-items">
|
|
21
|
+
{entry.tools.map((t) => (
|
|
22
|
+
<div key={t.id} className="conv-tool">
|
|
23
|
+
<span className="conv-tool-label">{t.label || t.name || 'Tool'}</span>
|
|
24
|
+
{t.summary ? <span className="conv-tool-summary">{t.summary}</span> : null}
|
|
25
|
+
</div>
|
|
26
|
+
))}
|
|
27
|
+
</div>
|
|
28
|
+
)}
|
|
29
|
+
</div>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function renderEntry(entry) {
|
|
34
|
+
if (entry.type === 'tool_group') {
|
|
35
|
+
return <ToolGroup key={entry.id} entry={entry} />
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (entry.type === 'tool') {
|
|
39
|
+
return (
|
|
40
|
+
<div key={entry.id} className="conv-tool">
|
|
41
|
+
<span className="conv-tool-label">{entry.label || entry.name || 'Tool'}</span>
|
|
42
|
+
{entry.summary ? (
|
|
43
|
+
<span className="conv-tool-summary">{entry.summary}</span>
|
|
44
|
+
) : null}
|
|
45
|
+
</div>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (entry.type === 'status') {
|
|
50
|
+
return (
|
|
51
|
+
<div key={entry.id} className="conv-status">
|
|
52
|
+
<Info size={12} strokeWidth={2} />
|
|
53
|
+
<span>{entry.content}</span>
|
|
54
|
+
</div>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const isUser = entry.type === 'user'
|
|
59
|
+
const assistantName =
|
|
60
|
+
typeof entry.agentName === 'string' && entry.agentName.trim()
|
|
61
|
+
? entry.agentName.trim()
|
|
62
|
+
: 'Assistant'
|
|
63
|
+
const assistantEmoji =
|
|
64
|
+
typeof entry.agentEmoji === 'string' && entry.agentEmoji.trim()
|
|
65
|
+
? entry.agentEmoji.trim()
|
|
66
|
+
: ''
|
|
67
|
+
|
|
68
|
+
if (isUser) {
|
|
69
|
+
return (
|
|
70
|
+
<div key={entry.id} className="conv-msg conv-msg-user">
|
|
71
|
+
<div className="conv-msg-bubble">
|
|
72
|
+
<div className="conv-msg-text">{entry.content}</div>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<div key={entry.id} className="conv-msg conv-msg-assistant">
|
|
80
|
+
<div className="conv-msg-avatar">
|
|
81
|
+
{assistantEmoji ? (
|
|
82
|
+
<span className="conv-msg-avatar-emoji">{assistantEmoji}</span>
|
|
83
|
+
) : (
|
|
84
|
+
<Sparkles size={14} strokeWidth={2} />
|
|
85
|
+
)}
|
|
86
|
+
</div>
|
|
87
|
+
<div className="conv-msg-body">
|
|
88
|
+
<div className="conv-msg-role">{assistantName}</div>
|
|
89
|
+
<div className="conv-msg-markdown">
|
|
90
|
+
<ReactMarkdown remarkPlugins={[remarkGfm]}>{entry.content || ''}</ReactMarkdown>
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function InlineChatView({
|
|
98
|
+
entries = [],
|
|
99
|
+
loading = false,
|
|
100
|
+
error = '',
|
|
101
|
+
onSubmit,
|
|
102
|
+
onStop,
|
|
103
|
+
onOpenOrchestratorConfig,
|
|
104
|
+
value,
|
|
105
|
+
onValueChange,
|
|
106
|
+
disabled = false,
|
|
107
|
+
}) {
|
|
108
|
+
const bodyRef = useRef(null)
|
|
109
|
+
const isNearBottomRef = useRef(true)
|
|
110
|
+
|
|
111
|
+
const handleMessagesScroll = useCallback(() => {
|
|
112
|
+
const el = bodyRef.current
|
|
113
|
+
if (!el) return
|
|
114
|
+
const threshold = 80
|
|
115
|
+
isNearBottomRef.current =
|
|
116
|
+
el.scrollHeight - el.scrollTop - el.clientHeight <= threshold
|
|
117
|
+
}, [])
|
|
118
|
+
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
if (!bodyRef.current || !isNearBottomRef.current) {
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
bodyRef.current.scrollTop = bodyRef.current.scrollHeight
|
|
124
|
+
}, [entries, loading, error])
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
<div className="inline-chat-view">
|
|
128
|
+
<div className="inline-chat-messages" ref={bodyRef} onScroll={handleMessagesScroll}>
|
|
129
|
+
{entries.length === 0 && (
|
|
130
|
+
<div className="muted" style={{ padding: '8px 0' }}>No messages yet.</div>
|
|
131
|
+
)}
|
|
132
|
+
{entries.map(renderEntry)}
|
|
133
|
+
{loading && (
|
|
134
|
+
<div className="conv-thinking-indicator">
|
|
135
|
+
<span className="conv-thinking-dot" />
|
|
136
|
+
<span className="conv-thinking-dot" />
|
|
137
|
+
<span className="conv-thinking-dot" />
|
|
138
|
+
</div>
|
|
139
|
+
)}
|
|
140
|
+
{error && (
|
|
141
|
+
<div className="error" style={{ padding: '4px 0' }}>Error: {error}</div>
|
|
142
|
+
)}
|
|
143
|
+
</div>
|
|
144
|
+
<InputBar
|
|
145
|
+
disabled={disabled}
|
|
146
|
+
loading={loading}
|
|
147
|
+
onStop={onStop}
|
|
148
|
+
onOpenOrchestratorConfig={onOpenOrchestratorConfig}
|
|
149
|
+
hideMode
|
|
150
|
+
lockedMode="chat"
|
|
151
|
+
embedded
|
|
152
|
+
value={value}
|
|
153
|
+
onValueChange={onValueChange}
|
|
154
|
+
onSubmit={onSubmit}
|
|
155
|
+
/>
|
|
156
|
+
</div>
|
|
157
|
+
)
|
|
158
|
+
}
|