@pheem49/mint 1.8.2 → 1.10.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/Cargo.lock +55 -3
- package/Cargo.toml +2 -1
- package/Release_Note.md +297 -107
- package/bin/mint +0 -0
- package/crates/mint-cli/Cargo.toml +1 -0
- package/crates/mint-cli/src/actions.rs +233 -0
- package/crates/mint-cli/src/agent.rs +382 -127
- package/crates/mint-cli/src/gmail.rs +22 -2
- package/crates/mint-cli/src/image.rs +8 -8
- package/crates/mint-cli/src/interactive.rs +2888 -0
- package/crates/mint-cli/src/main.rs +391 -2506
- package/crates/mint-cli/src/markdown.rs +294 -0
- package/crates/mint-cli/src/onboard.rs +152 -109
- package/crates/mint-cli/src/setup.rs +143 -143
- package/crates/mint-cli/src/updater.rs +48 -6
- package/crates/mint-core/Cargo.toml +1 -0
- package/crates/mint-core/src/agent_loop.rs +1 -0
- package/crates/mint-core/src/api_server.rs +431 -65
- package/crates/mint-core/src/browser.rs +630 -102
- package/crates/mint-core/src/channels.rs +105 -6
- package/crates/mint-core/src/chat.rs +174 -11
- package/crates/mint-core/src/code_tools.rs +47 -31
- package/crates/mint-core/src/config.rs +302 -17
- package/crates/mint-core/src/image_gen.rs +299 -38
- package/crates/mint-core/src/lib.rs +10 -7
- package/crates/mint-core/src/mcp.rs +119 -6
- package/crates/mint-core/src/memory.rs +6 -1
- package/crates/mint-core/src/orchestration.rs +237 -96
- package/crates/mint-core/src/pictures.rs +67 -5
- package/crates/mint-core/src/semantic.rs +1 -1
- package/crates/mint-core/src/shell.rs +1 -1
- package/crates/mint-core/src/skills.rs +128 -25
- package/crates/mint-core/src/video_gen.rs +235 -0
- package/package.json +8 -2
- package/shared-modules/linux-audio/fluidsynth2-static.json +9 -3
- package/shared-modules/linux-audio/fluidsynth2.json +8 -2
- package/shared-modules/linux-audio/lilv.json +26 -19
- package/shared-modules/linux-audio/lv2.json +0 -1
- package/shared-modules/luajit/luajit.json +2 -2
- package/skills-lock.json +41 -0
- package/src/renderer/index-web.html +1 -1
- package/src/renderer/index.html +1 -1
- package/src/renderer/shared/components/AgentActivityTable.tsx +25 -6
- package/src/renderer/shared/constants/slashCommands.ts +27 -0
- package/src/renderer/shared/platform.ts +3 -0
- package/src/renderer/shared/types.ts +4 -0
- package/src/renderer/shared/utils/approval.tsx +86 -7
- package/src/renderer/shared/utils/fileIcons.ts +135 -0
- package/src/renderer/shared/utils/markdown.tsx +217 -88
- package/src/renderer/shared/utils/slashCommandProcessor.ts +239 -0
- package/src/renderer/src/components/ChatPanel.tsx +486 -69
- package/src/renderer/src/components/DashboardSidebar.tsx +11 -2
- package/src/renderer/src/components/ImageStudioPanel.tsx +87 -4
- package/src/renderer/src/components/MintDashboard.tsx +195 -7
- package/src/renderer/src/components/PicturesLibrary.tsx +156 -15
- package/src/renderer/src/components/Settings/AgentsTab.tsx +21 -2
- package/src/renderer/src/components/Settings/AutomationTab.tsx +316 -18
- package/src/renderer/src/components/Settings/GeneralTab.tsx +795 -413
- package/src/renderer/src/components/Settings/PluginsTab.tsx +304 -70
- package/src/renderer/src/components/Settings/ThemeTab.tsx +6 -1
- package/src/renderer/src/components/SettingsWindow.tsx +106 -3
- package/src/renderer/src/components/VeoStudioPanel.tsx +549 -0
- package/src/renderer/src/components/WorkspacePanel.tsx +7 -125
- package/src/renderer/src/css/image-studio.css +106 -0
- package/src/renderer/src/css/settings.css +158 -0
- package/src/renderer/src/css/styles.css +368 -1
- package/src/renderer/src/css/veo-studio.css +626 -0
- package/src/renderer/src/index.css +1 -0
- package/src/renderer/src/tauri.ts +144 -17
- package/src/renderer/src-web/components/ChatPanel.tsx +385 -93
- package/src/renderer/src-web/components/DashboardSidebar.tsx +16 -1
- package/src/renderer/src-web/components/ImageStudioPanel.tsx +87 -4
- package/src/renderer/src-web/components/MintDashboard.tsx +156 -5
- package/src/renderer/src-web/components/PicturesLibrary.tsx +155 -15
- package/src/renderer/src-web/components/Settings/AgentsTab.tsx +21 -2
- package/src/renderer/src-web/components/Settings/AutomationTab.tsx +316 -18
- package/src/renderer/src-web/components/Settings/GeneralTab.tsx +795 -411
- package/src/renderer/src-web/components/Settings/PluginsTab.tsx +304 -70
- package/src/renderer/src-web/components/Settings/ThemeTab.tsx +6 -1
- package/src/renderer/src-web/components/SettingsWindow.tsx +110 -3
- package/src/renderer/src-web/components/VeoStudioPanel.tsx +549 -0
- package/src/renderer/src-web/css/image-studio.css +106 -0
- package/src/renderer/src-web/css/settings.css +158 -0
- package/src/renderer/src-web/css/styles.css +369 -1
- package/src/renderer/src-web/css/veo-studio.css +650 -0
- package/src/renderer/src-web/index.css +1 -0
- package/src/renderer/src-web/tauri.ts +135 -16
- package/src-tauri/src/desktop.rs +18 -16
- package/src-tauri/src/discord_rpc.rs +1 -1
- package/src-tauri/src/lib.rs +155 -25
- package/src-tauri/src/webhooks.rs +45 -31
- package/src-tauri/src/workflows.rs +1 -0
- package/src-tauri/tauri.conf.json +1 -1
- package/temp_gridgeist/AGENTS.md +8 -0
- package/temp_gridgeist/CHANGELOG.md +130 -0
- package/temp_gridgeist/LICENSE +21 -0
- package/temp_gridgeist/README.md +323 -0
- package/temp_gridgeist/README.th.md +325 -0
- package/temp_gridgeist/skills/gridgeist/SKILL.md +88 -0
- package/temp_gridgeist/skills/gridgeist/agents/openai.yaml +9 -0
- package/temp_gridgeist/skills/gridgeist/assets/gridgeist-small.svg +10 -0
- package/temp_gridgeist/skills/gridgeist/assets/gridgeist.png +0 -0
- package/temp_gridgeist/skills/gridgeist/assets/gridgeist.svg +18 -0
- package/temp_gridgeist/skills/gridgeist/references/design-language.md +88 -0
- package/temp_gridgeist/skills/gridgeist/references/review-checklist.md +128 -0
- package/temp_gridgeist/skills/gridgeist/references/system-contract.md +109 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useState } from 'react'
|
|
2
2
|
|
|
3
|
-
export type DashboardView = 'chat' | 'pictures' | 'model' | 'imagine' | 'workflows'
|
|
3
|
+
export type DashboardView = 'chat' | 'pictures' | 'model' | 'imagine' | 'workflows' | 'veo'
|
|
4
4
|
|
|
5
5
|
interface ChatSessionItem {
|
|
6
6
|
id: string
|
|
@@ -119,6 +119,21 @@ export default function DashboardSidebar({
|
|
|
119
119
|
</span>
|
|
120
120
|
<span>Image Studio</span>
|
|
121
121
|
</button>
|
|
122
|
+
<button className={`sidebar-top-action ${view === 'veo' ? 'is-active' : ''}`} onClick={() => onSetView('veo')}>
|
|
123
|
+
<span aria-hidden="true" style={{ display: 'inline-flex', alignItems: 'center' }}>
|
|
124
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
|
|
125
|
+
<rect x="2" y="2" width="20" height="20" rx="2.18" ry="2.18"></rect>
|
|
126
|
+
<line x1="7" y1="2" x2="7" y2="22"></line>
|
|
127
|
+
<line x1="17" y1="2" x2="17" y2="22"></line>
|
|
128
|
+
<line x1="2" y1="12" x2="22" y2="12"></line>
|
|
129
|
+
<line x1="2" y1="7" x2="7" y2="7"></line>
|
|
130
|
+
<line x1="2" y1="17" x2="7" y2="17"></line>
|
|
131
|
+
<line x1="17" y1="17" x2="22" y2="17"></line>
|
|
132
|
+
<line x1="17" y1="7" x2="22" y2="7"></line>
|
|
133
|
+
</svg>
|
|
134
|
+
</span>
|
|
135
|
+
<span>Veo Studio</span>
|
|
136
|
+
</button>
|
|
122
137
|
|
|
123
138
|
<div className="sidebar-section">
|
|
124
139
|
<div className="sidebar-section-title">Conversation CLI</div>
|
|
@@ -55,9 +55,10 @@ const PROVIDER_MODELS: Record<string, { value: string; label: string }[]> = {
|
|
|
55
55
|
],
|
|
56
56
|
replicate: [
|
|
57
57
|
{ value: 'black-forest-labs/flux-1.1-pro', label: 'FLUX 1.1 Pro (Default)' },
|
|
58
|
+
{ value: 'timbrooks/instruct-pix2pix', label: 'InstructPix2Pix (Image Editing)' },
|
|
59
|
+
{ value: 'black-forest-labs/flux-fill-dev', label: 'FLUX Fill (Inpainting)' },
|
|
58
60
|
{ value: 'black-forest-labs/flux-schnell', label: 'FLUX Schnell (fast)' },
|
|
59
61
|
{ value: 'stability-ai/sdxl', label: 'SDXL' },
|
|
60
|
-
{ value: 'bytedance/sdxl-lightning-4step', label: 'SDXL Lightning' },
|
|
61
62
|
],
|
|
62
63
|
}
|
|
63
64
|
|
|
@@ -146,6 +147,36 @@ export default function ImageStudioPanel({ view, onRefreshPictures, onSendToChat
|
|
|
146
147
|
|
|
147
148
|
const effectiveModel = selectedModel === 'custom' ? customModel.trim() : selectedModel
|
|
148
149
|
|
|
150
|
+
const [inputImage, setInputImage] = useState<string | null>(null)
|
|
151
|
+
const [isDragging, setIsDragging] = useState(false)
|
|
152
|
+
const fileInputRef = useRef<HTMLInputElement>(null)
|
|
153
|
+
|
|
154
|
+
const handleImageUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
155
|
+
const file = e.target.files?.[0]
|
|
156
|
+
if (!file) return
|
|
157
|
+
const reader = new FileReader()
|
|
158
|
+
reader.onload = (evt) => {
|
|
159
|
+
if (typeof evt.target?.result === 'string') {
|
|
160
|
+
setInputImage(evt.target.result)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
reader.readAsDataURL(file)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const handleDrop = (e: React.DragEvent) => {
|
|
167
|
+
e.preventDefault()
|
|
168
|
+
setIsDragging(false)
|
|
169
|
+
const file = e.dataTransfer.files?.[0]
|
|
170
|
+
if (!file || !file.type.startsWith('image/')) return
|
|
171
|
+
const reader = new FileReader()
|
|
172
|
+
reader.onload = (evt) => {
|
|
173
|
+
if (typeof evt.target?.result === 'string') {
|
|
174
|
+
setInputImage(evt.target.result)
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
reader.readAsDataURL(file)
|
|
178
|
+
}
|
|
179
|
+
|
|
149
180
|
const handleGenerate = useCallback(async () => {
|
|
150
181
|
const trimmed = prompt.trim()
|
|
151
182
|
if (!trimmed || generating) return
|
|
@@ -161,6 +192,8 @@ export default function ImageStudioPanel({ view, onRefreshPictures, onSendToChat
|
|
|
161
192
|
numImages,
|
|
162
193
|
model: effectiveModel || undefined,
|
|
163
194
|
provider: selectedProvider,
|
|
195
|
+
imageDataUri: inputImage || undefined,
|
|
196
|
+
mode: inputImage ? 'edit' : 'generate',
|
|
164
197
|
}
|
|
165
198
|
|
|
166
199
|
try {
|
|
@@ -176,7 +209,7 @@ export default function ImageStudioPanel({ view, onRefreshPictures, onSendToChat
|
|
|
176
209
|
} finally {
|
|
177
210
|
setGenerating(false)
|
|
178
211
|
}
|
|
179
|
-
}, [prompt, negativePrompt, aspectRatio, numImages, generating, onRefreshPictures, selectedProvider, effectiveModel])
|
|
212
|
+
}, [prompt, negativePrompt, aspectRatio, numImages, generating, onRefreshPictures, selectedProvider, effectiveModel, inputImage])
|
|
180
213
|
|
|
181
214
|
const handleKeyDown = (e: React.KeyboardEvent) => {
|
|
182
215
|
if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {
|
|
@@ -299,11 +332,61 @@ export default function ImageStudioPanel({ view, onRefreshPictures, onSendToChat
|
|
|
299
332
|
</div>
|
|
300
333
|
)}
|
|
301
334
|
|
|
335
|
+
{/* Image Editing / Source Image Attachment */}
|
|
336
|
+
<div className="img-studio-field">
|
|
337
|
+
<label className="img-studio-label">
|
|
338
|
+
Source Image (Optional for Image Editing)
|
|
339
|
+
<span className="img-studio-label-hint">Upload an image to edit / inpaint</span>
|
|
340
|
+
</label>
|
|
341
|
+
{inputImage ? (
|
|
342
|
+
<div className="img-studio-preview-card">
|
|
343
|
+
<img src={inputImage} alt="Input source" className="img-studio-preview-thumb" />
|
|
344
|
+
<div className="img-studio-preview-info">
|
|
345
|
+
<div className="img-studio-preview-title">
|
|
346
|
+
<span>Source Image Attached</span>
|
|
347
|
+
</div>
|
|
348
|
+
<div className="img-studio-preview-subtitle">Ready for Image Editing</div>
|
|
349
|
+
</div>
|
|
350
|
+
<button
|
|
351
|
+
type="button"
|
|
352
|
+
className="img-studio-preview-remove"
|
|
353
|
+
onClick={() => setInputImage(null)}
|
|
354
|
+
>
|
|
355
|
+
✕ Remove
|
|
356
|
+
</button>
|
|
357
|
+
</div>
|
|
358
|
+
) : (
|
|
359
|
+
<div
|
|
360
|
+
className={`img-studio-dropzone ${isDragging ? 'is-dragging' : ''}`}
|
|
361
|
+
onClick={() => fileInputRef.current?.click()}
|
|
362
|
+
onDragOver={(e) => { e.preventDefault(); setIsDragging(true); }}
|
|
363
|
+
onDragLeave={() => setIsDragging(false)}
|
|
364
|
+
onDrop={handleDrop}
|
|
365
|
+
>
|
|
366
|
+
<input
|
|
367
|
+
ref={fileInputRef}
|
|
368
|
+
type="file"
|
|
369
|
+
accept="image/*"
|
|
370
|
+
onChange={handleImageUpload}
|
|
371
|
+
disabled={generating}
|
|
372
|
+
style={{ display: 'none' }}
|
|
373
|
+
/>
|
|
374
|
+
<svg className="img-studio-dropzone-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
375
|
+
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
|
|
376
|
+
<polyline points="17 8 12 3 7 8"/>
|
|
377
|
+
<line x1="12" y1="3" x2="12" y2="15"/>
|
|
378
|
+
</svg>
|
|
379
|
+
<div className="img-studio-dropzone-text">Click or Drag & Drop image here</div>
|
|
380
|
+
<div className="img-studio-dropzone-subtext">PNG, JPG, WEBP up to 10MB</div>
|
|
381
|
+
</div>
|
|
382
|
+
)}
|
|
383
|
+
</div>
|
|
384
|
+
|
|
302
385
|
{/* Prompt */}
|
|
303
386
|
<div className="img-studio-field">
|
|
304
387
|
<label className="img-studio-label" htmlFor="img-studio-prompt">
|
|
305
|
-
Prompt
|
|
306
|
-
<span className="img-studio-label-hint">Describe the image you want</span>
|
|
388
|
+
{inputImage ? 'Editing Instruction Prompt' : 'Prompt'}
|
|
389
|
+
<span className="img-studio-label-hint">{inputImage ? 'Describe what to edit or remove' : 'Describe the image you want'}</span>
|
|
307
390
|
</label>
|
|
308
391
|
<textarea
|
|
309
392
|
id="img-studio-prompt"
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
getRecentInteractions,
|
|
8
8
|
saveSystemInteraction,
|
|
9
9
|
getRuntimeStatus,
|
|
10
|
+
setActiveModel,
|
|
10
11
|
listChatSessions,
|
|
11
12
|
listSavedPictures,
|
|
12
13
|
saveInteractionAgentActivity,
|
|
@@ -25,6 +26,7 @@ import ChatPanel from './ChatPanel'
|
|
|
25
26
|
import DashboardSidebar, { type DashboardView } from './DashboardSidebar'
|
|
26
27
|
import PicturesLibrary from './PicturesLibrary'
|
|
27
28
|
import ImageStudioPanel from './ImageStudioPanel'
|
|
29
|
+
import VeoStudioPanel from './VeoStudioPanel'
|
|
28
30
|
import {
|
|
29
31
|
errorMessage,
|
|
30
32
|
readImage,
|
|
@@ -32,6 +34,8 @@ import {
|
|
|
32
34
|
createTrimmedImagePreview,
|
|
33
35
|
applyThemeStyles,
|
|
34
36
|
} from '../../shared/utils/ui'
|
|
37
|
+
import { executeSlashCommand } from '../../shared/utils/slashCommandProcessor'
|
|
38
|
+
|
|
35
39
|
|
|
36
40
|
const DEFAULT_CONFIG = {
|
|
37
41
|
theme: 'dark',
|
|
@@ -84,6 +88,7 @@ export default function MintDashboard() {
|
|
|
84
88
|
const [sending, setSending] = useState(false)
|
|
85
89
|
const [sendingMessage, setSendingMessage] = useState('')
|
|
86
90
|
const [sendingImageCount, setSendingImageCount] = useState(0)
|
|
91
|
+
const [sendingVideoCount, setSendingVideoCount] = useState(0)
|
|
87
92
|
const [streamedReply, setStreamedReply] = useState('')
|
|
88
93
|
const [streamedResponse, setStreamedResponse] = useState<ChatResponse | null>(null)
|
|
89
94
|
const [streamingConversationId, setStreamingConversationId] = useState<string | null>(null)
|
|
@@ -92,6 +97,7 @@ export default function MintDashboard() {
|
|
|
92
97
|
const [thinkingExpanded, setThinkingExpanded] = useState<Record<string, boolean>>({})
|
|
93
98
|
const liveThinkingOpenRef = useRef(true)
|
|
94
99
|
const [imageAttachments, setImageAttachments] = useState<Array<{ dataUri: string; name: string; previewDataUri?: string }>>([])
|
|
100
|
+
const [videoAttachments, setVideoAttachments] = useState<Array<{ dataUri: string; name: string }>>([])
|
|
95
101
|
const [documentAttachment, setDocumentAttachment] = useState<DocumentAttachment | null>(null)
|
|
96
102
|
const [pendingApproval, setPendingApproval] = useState<any | null>(null)
|
|
97
103
|
const [sidebarCollapsed, setSidebarCollapsed] = useState(() => window.localStorage.getItem('mint:sidebar-collapsed') === 'true')
|
|
@@ -225,10 +231,25 @@ export default function MintDashboard() {
|
|
|
225
231
|
if (failure?.status === 'rejected') setError(errorMessage(failure.reason))
|
|
226
232
|
setDashboardDataReady(true)
|
|
227
233
|
})
|
|
234
|
+
const handleWindowFocus = () => {
|
|
235
|
+
getRuntimeStatus().then(setStatus).catch(() => {})
|
|
236
|
+
window.settingsApi?.getSettings?.().then((loaded: any) => {
|
|
237
|
+
if (loaded) {
|
|
238
|
+
setSettingsConfig(loaded)
|
|
239
|
+
applyThemeStyles(loaded)
|
|
240
|
+
}
|
|
241
|
+
}).catch(() => {})
|
|
242
|
+
}
|
|
243
|
+
window.addEventListener('focus', handleWindowFocus)
|
|
244
|
+
|
|
228
245
|
window.api?.onSettingsChanged?.((loaded: any) => {
|
|
229
246
|
setSettingsConfig(loaded)
|
|
230
247
|
applyThemeStyles(loaded)
|
|
248
|
+
getRuntimeStatus().then(setStatus).catch(() => {})
|
|
231
249
|
})
|
|
250
|
+
return () => {
|
|
251
|
+
window.removeEventListener('focus', handleWindowFocus)
|
|
252
|
+
}
|
|
232
253
|
}, [])
|
|
233
254
|
|
|
234
255
|
useEffect(() => {
|
|
@@ -304,6 +325,7 @@ export default function MintDashboard() {
|
|
|
304
325
|
promptText: string,
|
|
305
326
|
options: {
|
|
306
327
|
imageAttachments?: Array<{ dataUri: string; name: string; previewDataUri?: string }>
|
|
328
|
+
videoAttachments?: Array<{ dataUri: string; name: string }>
|
|
307
329
|
audioDataUri?: string | null
|
|
308
330
|
documentAttachment?: DocumentAttachment | null
|
|
309
331
|
systemInstruction?: string
|
|
@@ -312,14 +334,17 @@ export default function MintDashboard() {
|
|
|
312
334
|
) {
|
|
313
335
|
if (sending) return
|
|
314
336
|
const outgoingImages = options.imageAttachments ?? []
|
|
337
|
+
const outgoingVideos = options.videoAttachments ?? []
|
|
315
338
|
const outgoingDocument = options.documentAttachment ?? null
|
|
316
339
|
const shouldUseAgentMode = agentMode || promptText.toLowerCase().startsWith('search web:')
|
|
317
340
|
const outgoingImage = outgoingImages.map((img) => img.dataUri).join(' ')
|
|
341
|
+
const outgoingVideo = outgoingVideos.map((vid) => vid.dataUri).join(' ')
|
|
318
342
|
const outgoingImageCount = outgoingImages.length
|
|
319
343
|
setSending(true)
|
|
320
344
|
setStreamingConversationId(conversationId)
|
|
321
345
|
setSendingMessage(promptText)
|
|
322
346
|
setSendingImageCount(outgoingImageCount)
|
|
347
|
+
setSendingVideoCount(outgoingVideos.length)
|
|
323
348
|
setError('')
|
|
324
349
|
setStreamedReply('')
|
|
325
350
|
setStreamedResponse(null)
|
|
@@ -330,6 +355,7 @@ export default function MintDashboard() {
|
|
|
330
355
|
if (options.clearComposer) {
|
|
331
356
|
setMessage('')
|
|
332
357
|
setImageAttachments([])
|
|
358
|
+
setVideoAttachments([])
|
|
333
359
|
setDocumentAttachment(null)
|
|
334
360
|
}
|
|
335
361
|
|
|
@@ -339,6 +365,7 @@ export default function MintDashboard() {
|
|
|
339
365
|
(chunk) => setStreamedReply((current) => `${current}${chunk}`),
|
|
340
366
|
outgoingImage,
|
|
341
367
|
options.audioDataUri ?? null,
|
|
368
|
+
outgoingVideo,
|
|
342
369
|
options.systemInstruction ?? '',
|
|
343
370
|
(progress) => {
|
|
344
371
|
progressSnapshot.push(progress)
|
|
@@ -379,6 +406,7 @@ export default function MintDashboard() {
|
|
|
379
406
|
setAgentActivitySnapshots((current) => mergeActivitySnapshots(current, enrichedHistory))
|
|
380
407
|
await refreshChatSessions()
|
|
381
408
|
await refreshPictures()
|
|
409
|
+
getRuntimeStatus().then(setStatus).catch(() => {})
|
|
382
410
|
setStreamedReply('')
|
|
383
411
|
setStreamedResponse(null)
|
|
384
412
|
} catch (reason) {
|
|
@@ -388,6 +416,7 @@ export default function MintDashboard() {
|
|
|
388
416
|
setStreamingConversationId(null)
|
|
389
417
|
setSendingMessage('')
|
|
390
418
|
setSendingImageCount(0)
|
|
419
|
+
setSendingVideoCount(0)
|
|
391
420
|
}
|
|
392
421
|
}
|
|
393
422
|
|
|
@@ -395,12 +424,77 @@ export default function MintDashboard() {
|
|
|
395
424
|
event.preventDefault()
|
|
396
425
|
const trimmed = message.trim()
|
|
397
426
|
const currentImages = imageAttachments
|
|
427
|
+
const currentVideos = videoAttachments
|
|
398
428
|
const currentDocument = documentAttachment
|
|
399
|
-
const hasAttachments = currentImages.length > 0 || Boolean(currentDocument)
|
|
429
|
+
const hasAttachments = currentImages.length > 0 || currentVideos.length > 0 || Boolean(currentDocument)
|
|
400
430
|
if ((!trimmed && !hasAttachments) || sending) return
|
|
401
|
-
|
|
431
|
+
|
|
432
|
+
if (trimmed.startsWith('/')) {
|
|
433
|
+
const activeP = status?.activeProvider || ''
|
|
434
|
+
const activeM = settingsConfig?.model || ''
|
|
435
|
+
const slashResult = executeSlashCommand(trimmed, {
|
|
436
|
+
activeProvider: activeP,
|
|
437
|
+
activeModel: activeM,
|
|
438
|
+
availableProviders: status?.availableProviders || [],
|
|
439
|
+
interactionsCount: interactions.length,
|
|
440
|
+
fastMode: settingsConfig?.fastMode ?? false,
|
|
441
|
+
multiAgent: settingsConfig?.multiAgent ?? false,
|
|
442
|
+
})
|
|
443
|
+
|
|
444
|
+
if (slashResult.handled) {
|
|
445
|
+
setMessage('')
|
|
446
|
+
setImageAttachments([])
|
|
447
|
+
setVideoAttachments([])
|
|
448
|
+
setDocumentAttachment(null)
|
|
449
|
+
|
|
450
|
+
if (slashResult.action === 'set_agent_mode') {
|
|
451
|
+
setAgentMode(true)
|
|
452
|
+
if (slashResult.payload?.prompt) {
|
|
453
|
+
await sendPrompt(slashResult.payload.prompt, { clearComposer: true })
|
|
454
|
+
}
|
|
455
|
+
return
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (slashResult.action === 'open_image_picker') {
|
|
459
|
+
document.getElementById('vision-file-input')?.click()
|
|
460
|
+
return
|
|
461
|
+
} else if (slashResult.action === 'open_plugins') {
|
|
462
|
+
setView('settings')
|
|
463
|
+
return
|
|
464
|
+
} else if (slashResult.action === 'generate_veo') {
|
|
465
|
+
setView('veo_studio')
|
|
466
|
+
return
|
|
467
|
+
} else if (slashResult.action === 'set_provider_model' && slashResult.payload?.target) {
|
|
468
|
+
const target = slashResult.payload.target
|
|
469
|
+
if (status?.availableProviders.includes(target)) {
|
|
470
|
+
setActiveModel(target).then(() => getRuntimeStatus().then(setStatus)).catch(() => {})
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
if (slashResult.systemText) {
|
|
475
|
+
const systemMsg = {
|
|
476
|
+
id: Date.now(),
|
|
477
|
+
userText: trimmed,
|
|
478
|
+
aiText: slashResult.systemText,
|
|
479
|
+
createdAt: new Date().toISOString(),
|
|
480
|
+
provider: 'system',
|
|
481
|
+
model: 'mint-cli',
|
|
482
|
+
}
|
|
483
|
+
setInteractions((prev) => [...prev, systemMsg])
|
|
484
|
+
saveSystemInteraction(conversationId, trimmed, slashResult.systemText || '', 'system', 'mint-cli').catch(() => {})
|
|
485
|
+
}
|
|
486
|
+
return
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
const promptText = trimmed || (
|
|
491
|
+
currentImages.length > 0 ? (currentImages.length > 1 ? 'Describe these images.' : 'Describe this image.') :
|
|
492
|
+
currentVideos.length > 0 ? (currentVideos.length > 1 ? 'Describe these videos.' : 'Describe this video.') :
|
|
493
|
+
'Summarize this document.'
|
|
494
|
+
)
|
|
402
495
|
await sendPrompt(promptText, {
|
|
403
496
|
imageAttachments: currentImages,
|
|
497
|
+
videoAttachments: currentVideos,
|
|
404
498
|
documentAttachment: currentDocument,
|
|
405
499
|
clearComposer: true,
|
|
406
500
|
})
|
|
@@ -430,6 +524,28 @@ export default function MintDashboard() {
|
|
|
430
524
|
event.target.value = ''
|
|
431
525
|
}
|
|
432
526
|
}
|
|
527
|
+
const MAX_VIDEO_BYTES = 25 * 1024 * 1024 // 25 MB
|
|
528
|
+
async function selectVideo(event: ChangeEvent<HTMLInputElement>) {
|
|
529
|
+
const file = event.target.files?.[0]
|
|
530
|
+
if (!file) return
|
|
531
|
+
try {
|
|
532
|
+
if (file.size > MAX_VIDEO_BYTES) {
|
|
533
|
+
setError(`Video is too large. Maximum allowed is ${Math.round(MAX_VIDEO_BYTES / (1024 * 1024))} MB.`)
|
|
534
|
+
return
|
|
535
|
+
}
|
|
536
|
+
const dataUri = await new Promise<string>((resolve, reject) => {
|
|
537
|
+
const reader = new FileReader()
|
|
538
|
+
reader.onload = () => resolve(reader.result as string)
|
|
539
|
+
reader.onerror = reject
|
|
540
|
+
reader.readAsDataURL(file)
|
|
541
|
+
})
|
|
542
|
+
setVideoAttachments((current) => [...current, { dataUri, name: file.name }])
|
|
543
|
+
} catch (reason) {
|
|
544
|
+
setError(errorMessage(reason))
|
|
545
|
+
} finally {
|
|
546
|
+
event.target.value = ''
|
|
547
|
+
}
|
|
548
|
+
}
|
|
433
549
|
|
|
434
550
|
function pasteImage(clipboardData: DataTransfer) {
|
|
435
551
|
let file: File | null = null
|
|
@@ -606,6 +722,11 @@ export default function MintDashboard() {
|
|
|
606
722
|
else if (provider === 'huggingface') providerName = 'HF'
|
|
607
723
|
else if (provider === 'local_openai') providerName = 'Local'
|
|
608
724
|
else if (provider === 'ollama') providerName = 'Ollama'
|
|
725
|
+
else if (provider.startsWith('custom:')) {
|
|
726
|
+
const id = provider.replace(/^custom:/, '')
|
|
727
|
+
const cp = (settingsConfig?.customProviders ?? []).find((p: any) => p.id === id)
|
|
728
|
+
providerName = cp?.displayName || id
|
|
729
|
+
}
|
|
609
730
|
|
|
610
731
|
if (providerName && providerName === provider) {
|
|
611
732
|
providerName = providerName.charAt(0).toUpperCase() + providerName.slice(1)
|
|
@@ -623,13 +744,21 @@ export default function MintDashboard() {
|
|
|
623
744
|
case 'huggingface': return config.hfModel || 'meta-llama/Meta-Llama-3-8B-Instruct'
|
|
624
745
|
case 'local_openai': return config.localModelName || 'llama3'
|
|
625
746
|
case 'ollama': return config.ollamaModel || 'llama3:latest'
|
|
626
|
-
default:
|
|
747
|
+
default: {
|
|
748
|
+
if (provider.startsWith('custom:')) {
|
|
749
|
+
const id = provider.replace(/^custom:/, '')
|
|
750
|
+
const cp = (config.customProviders ?? []).find((p: any) => p.id === id)
|
|
751
|
+
return (config.customModelSelections ?? {})[id] ?? cp?.models[0]?.modelId ?? ''
|
|
752
|
+
}
|
|
753
|
+
return ''
|
|
754
|
+
}
|
|
627
755
|
}
|
|
628
756
|
}
|
|
629
757
|
|
|
630
758
|
async function changeProvider(provider: string) {
|
|
631
759
|
try {
|
|
632
760
|
const config = await window.settingsApi.getSettings()
|
|
761
|
+
if (config.aiProvider === provider) return
|
|
633
762
|
config.aiProvider = provider
|
|
634
763
|
await window.settingsApi.saveSettings(config)
|
|
635
764
|
setSettingsConfig(config)
|
|
@@ -638,7 +767,7 @@ export default function MintDashboard() {
|
|
|
638
767
|
// Record system event in chat history
|
|
639
768
|
const activeModel = getActiveModelName(config, provider)
|
|
640
769
|
const displayName = formatProviderChangeText(provider, activeModel)
|
|
641
|
-
await saveSystemInteraction(conversationId, displayName, 'system', 'provider_change')
|
|
770
|
+
await saveSystemInteraction(conversationId, displayName, '', 'system', 'provider_change')
|
|
642
771
|
await refreshHistory()
|
|
643
772
|
} catch (reason) {
|
|
644
773
|
setError(errorMessage(reason))
|
|
@@ -649,6 +778,8 @@ export default function MintDashboard() {
|
|
|
649
778
|
try {
|
|
650
779
|
const config = await window.settingsApi.getSettings()
|
|
651
780
|
const provider = config.aiProvider
|
|
781
|
+
const currentModel = getActiveModelName(config, provider)
|
|
782
|
+
if (currentModel === modelName) return
|
|
652
783
|
if (provider === 'gemini') {
|
|
653
784
|
config.geminiModel = modelName
|
|
654
785
|
} else if (provider === 'openai') {
|
|
@@ -665,6 +796,12 @@ export default function MintDashboard() {
|
|
|
665
796
|
config.localModelName = modelName
|
|
666
797
|
} else if (provider === 'ollama') {
|
|
667
798
|
config.ollamaModel = modelName
|
|
799
|
+
} else if (provider.startsWith('custom:')) {
|
|
800
|
+
const id = provider.replace(/^custom:/, '')
|
|
801
|
+
config.customModelSelections = {
|
|
802
|
+
...(config.customModelSelections ?? {}),
|
|
803
|
+
[id]: modelName
|
|
804
|
+
}
|
|
668
805
|
}
|
|
669
806
|
await window.settingsApi.saveSettings(config)
|
|
670
807
|
setSettingsConfig(config)
|
|
@@ -672,7 +809,7 @@ export default function MintDashboard() {
|
|
|
672
809
|
|
|
673
810
|
// Record system event in chat history
|
|
674
811
|
const displayName = formatProviderChangeText(provider, modelName)
|
|
675
|
-
await saveSystemInteraction(conversationId, displayName, 'system', 'provider_change')
|
|
812
|
+
await saveSystemInteraction(conversationId, displayName, '', 'system', 'provider_change')
|
|
676
813
|
await refreshHistory()
|
|
677
814
|
} catch (reason) {
|
|
678
815
|
setError(errorMessage(reason))
|
|
@@ -724,11 +861,13 @@ export default function MintDashboard() {
|
|
|
724
861
|
streamedReply={streamingConversationId === conversationId ? streamedReply : ''}
|
|
725
862
|
streamedResponse={streamingConversationId === conversationId ? streamedResponse : null}
|
|
726
863
|
agentProgress={streamingConversationId === conversationId ? agentProgress : []}
|
|
864
|
+
sendingVideoCount={streamingConversationId === conversationId ? sendingVideoCount : 0}
|
|
727
865
|
agentActivitySnapshots={agentActivitySnapshots}
|
|
728
866
|
thinkingExpanded={thinkingExpanded}
|
|
729
867
|
onThinkingExpandedChange={handleThinkingExpandedChange}
|
|
730
868
|
message={message}
|
|
731
869
|
imageAttachments={imageAttachments}
|
|
870
|
+
videoAttachments={videoAttachments}
|
|
732
871
|
documentName={documentAttachment?.filename ?? ''}
|
|
733
872
|
pendingApproval={streamingConversationId === conversationId ? pendingApproval : null}
|
|
734
873
|
smartContext={smartContext}
|
|
@@ -738,6 +877,7 @@ export default function MintDashboard() {
|
|
|
738
877
|
welcomeInteraction={MOCK_WELCOME_INTERACTION}
|
|
739
878
|
onSubmit={handleSubmit}
|
|
740
879
|
onSelectImage={selectImage}
|
|
880
|
+
onSelectVideo={selectVideo}
|
|
741
881
|
onSelectDocument={selectDocument}
|
|
742
882
|
onPasteImage={pasteImage}
|
|
743
883
|
onSetMessage={setMessage}
|
|
@@ -745,6 +885,9 @@ export default function MintDashboard() {
|
|
|
745
885
|
onRemoveImage={(idx: number) => {
|
|
746
886
|
setImageAttachments((current) => current.filter((_, i) => i !== idx))
|
|
747
887
|
}}
|
|
888
|
+
onRemoveVideo={(idx: number) => {
|
|
889
|
+
setVideoAttachments((current) => current.filter((_, i) => i !== idx))
|
|
890
|
+
}}
|
|
748
891
|
onRemoveDocument={() => setDocumentAttachment(null)}
|
|
749
892
|
onStartWebSearch={startWebSearch}
|
|
750
893
|
onCaptureScreen={captureScreen}
|
|
@@ -768,6 +911,14 @@ export default function MintDashboard() {
|
|
|
768
911
|
}}
|
|
769
912
|
onToggleMobileSidebar={() => setMobileSidebarOpen(!mobileSidebarOpen)}
|
|
770
913
|
/>
|
|
914
|
+
<VeoStudioPanel
|
|
915
|
+
view={view}
|
|
916
|
+
onSendToChat={(imgPrompt) => {
|
|
917
|
+
setView('chat')
|
|
918
|
+
setMessage(imgPrompt)
|
|
919
|
+
}}
|
|
920
|
+
onToggleMobileSidebar={() => setMobileSidebarOpen(!mobileSidebarOpen)}
|
|
921
|
+
/>
|
|
771
922
|
</div>
|
|
772
923
|
<div className={`startup-loading ${startupReady ? 'is-hidden' : ''}`} aria-live="polite" aria-busy={!startupReady}>
|
|
773
924
|
<div className="startup-loading-content">
|