@pheem49/mint 1.9.0 → 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 +285 -140
- 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 +287 -43
- package/crates/mint-cli/src/gmail.rs +22 -2
- package/crates/mint-cli/src/interactive.rs +2888 -0
- package/crates/mint-cli/src/main.rs +336 -2854
- package/crates/mint-cli/src/markdown.rs +294 -0
- package/crates/mint-cli/src/onboard.rs +44 -1
- 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 +376 -13
- package/crates/mint-core/src/browser.rs +629 -101
- package/crates/mint-core/src/channels.rs +105 -6
- package/crates/mint-core/src/chat.rs +52 -4
- package/crates/mint-core/src/code_tools.rs +29 -11
- package/crates/mint-core/src/config.rs +118 -0
- package/crates/mint-core/src/image_gen.rs +294 -33
- package/crates/mint-core/src/lib.rs +5 -2
- package/crates/mint-core/src/mcp.rs +119 -6
- package/crates/mint-core/src/orchestration.rs +133 -11
- package/crates/mint-core/src/pictures.rs +64 -1
- package/crates/mint-core/src/skills.rs +82 -6
- package/crates/mint-core/src/video_gen.rs +235 -0
- package/package.json +8 -2
- 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/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/markdown.tsx +217 -88
- package/src/renderer/shared/utils/slashCommandProcessor.ts +239 -0
- package/src/renderer/src/components/ChatPanel.tsx +461 -64
- 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 +150 -5
- package/src/renderer/src/components/PicturesLibrary.tsx +156 -15
- package/src/renderer/src/components/Settings/AutomationTab.tsx +316 -18
- package/src/renderer/src/components/Settings/GeneralTab.tsx +762 -634
- 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 +38 -2
- package/src/renderer/src/components/VeoStudioPanel.tsx +549 -0
- 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 +352 -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 +360 -88
- 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 +137 -4
- package/src/renderer/src-web/components/PicturesLibrary.tsx +155 -15
- package/src/renderer/src-web/components/Settings/AutomationTab.tsx +316 -18
- package/src/renderer/src-web/components/Settings/GeneralTab.tsx +762 -629
- 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 +35 -2
- 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 +353 -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/lib.rs +114 -8
- 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, useEffect, useRef } from 'react'
|
|
2
2
|
|
|
3
|
-
export type DashboardView = 'chat' | 'pictures' | 'model' | 'workspace' | 'imagine' | 'workflows'
|
|
3
|
+
export type DashboardView = 'chat' | 'pictures' | 'model' | 'workspace' | 'imagine' | 'workflows' | 'veo'
|
|
4
4
|
|
|
5
5
|
interface ChatSessionItem {
|
|
6
6
|
id: string
|
|
@@ -181,7 +181,7 @@ export default function DashboardSidebar({
|
|
|
181
181
|
</button>
|
|
182
182
|
|
|
183
183
|
<div className="sidebar-more-container" ref={moreContainerRef}>
|
|
184
|
-
<button className={`sidebar-top-action ${isMoreOpen || view === 'imagine' || view === 'workflows' ? 'is-active' : ''}`} onClick={() => setIsMoreOpen(!isMoreOpen)}>
|
|
184
|
+
<button className={`sidebar-top-action ${isMoreOpen || view === 'imagine' || view === 'workflows' || view === 'veo' ? 'is-active' : ''}`} onClick={() => setIsMoreOpen(!isMoreOpen)}>
|
|
185
185
|
<span aria-hidden="true" style={{ display: 'inline-flex', alignItems: 'center' }}>
|
|
186
186
|
<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">
|
|
187
187
|
<circle cx="12" cy="12" r="1.5"></circle>
|
|
@@ -214,6 +214,15 @@ export default function DashboardSidebar({
|
|
|
214
214
|
</span>
|
|
215
215
|
<span>Workflow (Beta)</span>
|
|
216
216
|
</button>
|
|
217
|
+
<button className={`popover-item ${view === 'veo' ? 'active' : ''}`} onClick={() => { onSetView('veo'); setIsMoreOpen(false); }}>
|
|
218
|
+
<span aria-hidden="true" style={{ display: 'inline-flex', alignItems: 'center' }}>
|
|
219
|
+
<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">
|
|
220
|
+
<polygon points="23 7 16 12 23 17 23 7"></polygon>
|
|
221
|
+
<rect x="1" y="5" width="15" height="14" rx="2" ry="2"></rect>
|
|
222
|
+
</svg>
|
|
223
|
+
</span>
|
|
224
|
+
<span>Veo Studio</span>
|
|
225
|
+
</button>
|
|
217
226
|
</div>
|
|
218
227
|
)}
|
|
219
228
|
</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
|
selectWorkspaceDirectory,
|
|
@@ -27,6 +28,7 @@ import {
|
|
|
27
28
|
import ChatPanel from './ChatPanel'
|
|
28
29
|
import DashboardSidebar, { type DashboardView } from './DashboardSidebar'
|
|
29
30
|
import ImageStudioPanel from './ImageStudioPanel'
|
|
31
|
+
import VeoStudioPanel from './VeoStudioPanel'
|
|
30
32
|
import ModelPanel from './ModelPanel'
|
|
31
33
|
import type { ModelInteraction } from './ModelPanel'
|
|
32
34
|
import PicturesLibrary from './PicturesLibrary'
|
|
@@ -39,6 +41,8 @@ import {
|
|
|
39
41
|
createTrimmedImagePreview,
|
|
40
42
|
applyThemeStyles,
|
|
41
43
|
} from '../../shared/utils/ui'
|
|
44
|
+
import { executeSlashCommand } from '../../shared/utils/slashCommandProcessor'
|
|
45
|
+
|
|
42
46
|
|
|
43
47
|
const EXPRESSIONS = [
|
|
44
48
|
"Default",
|
|
@@ -108,6 +112,7 @@ export default function MintDashboard() {
|
|
|
108
112
|
const [sending, setSending] = useState(false)
|
|
109
113
|
const [sendingMessage, setSendingMessage] = useState('')
|
|
110
114
|
const [sendingImageCount, setSendingImageCount] = useState(0)
|
|
115
|
+
const [sendingVideoCount, setSendingVideoCount] = useState(0)
|
|
111
116
|
const [streamedReply, setStreamedReply] = useState('')
|
|
112
117
|
const [streamedResponse, setStreamedResponse] = useState<ChatResponse | null>(null)
|
|
113
118
|
const [streamingConversationId, setStreamingConversationId] = useState<string | null>(null)
|
|
@@ -116,6 +121,7 @@ export default function MintDashboard() {
|
|
|
116
121
|
const [thinkingExpanded, setThinkingExpanded] = useState<Record<string, boolean>>({})
|
|
117
122
|
const liveThinkingOpenRef = useRef(true)
|
|
118
123
|
const [imageAttachments, setImageAttachments] = useState<Array<{ dataUri: string; name: string; previewDataUri?: string }>>([])
|
|
124
|
+
const [videoAttachments, setVideoAttachments] = useState<Array<{ dataUri: string; name: string }>>([])
|
|
119
125
|
const [documentAttachment, setDocumentAttachment] = useState<DocumentAttachment | null>(null)
|
|
120
126
|
const [pendingApproval, setPendingApproval] = useState<any | null>(null)
|
|
121
127
|
const [sessionAutoApproved, setSessionAutoApproved] = useState(false)
|
|
@@ -280,9 +286,21 @@ export default function MintDashboard() {
|
|
|
280
286
|
setImageAttachments((current) => [...current, { dataUri: image, previewDataUri, name: 'Screen capture' }])
|
|
281
287
|
})
|
|
282
288
|
})
|
|
289
|
+
const handleWindowFocus = () => {
|
|
290
|
+
getRuntimeStatus().then(setStatus).catch(() => {})
|
|
291
|
+
window.settingsApi?.getSettings?.().then((loaded: any) => {
|
|
292
|
+
if (loaded) {
|
|
293
|
+
setSettingsConfig(loaded)
|
|
294
|
+
applyThemeStyles(loaded)
|
|
295
|
+
}
|
|
296
|
+
}).catch(() => {})
|
|
297
|
+
}
|
|
298
|
+
window.addEventListener('focus', handleWindowFocus)
|
|
299
|
+
|
|
283
300
|
window.api?.onSettingsChanged?.((loaded: any) => {
|
|
284
301
|
setSettingsConfig(loaded)
|
|
285
302
|
applyThemeStyles(loaded)
|
|
303
|
+
getRuntimeStatus().then(setStatus).catch(() => {})
|
|
286
304
|
})
|
|
287
305
|
|
|
288
306
|
const unlistenPromise = listen<any>('tool-approval-requested', (event) => {
|
|
@@ -298,6 +316,7 @@ export default function MintDashboard() {
|
|
|
298
316
|
setProactiveSuggestion(suggestion)
|
|
299
317
|
})
|
|
300
318
|
return () => {
|
|
319
|
+
window.removeEventListener('focus', handleWindowFocus)
|
|
301
320
|
unlistenPromise?.then?.((unlisten) => unlisten?.())
|
|
302
321
|
unlistenSpotlight?.then?.((unlisten) => unlisten?.())
|
|
303
322
|
unlistenVision?.then?.((unlisten) => unlisten?.())
|
|
@@ -407,6 +426,7 @@ export default function MintDashboard() {
|
|
|
407
426
|
setStreamingConversationId(null)
|
|
408
427
|
setSendingMessage('')
|
|
409
428
|
setSendingImageCount(0)
|
|
429
|
+
setSendingVideoCount(0)
|
|
410
430
|
}
|
|
411
431
|
}
|
|
412
432
|
|
|
@@ -414,6 +434,7 @@ export default function MintDashboard() {
|
|
|
414
434
|
promptText: string,
|
|
415
435
|
options: {
|
|
416
436
|
imageAttachments?: Array<{ dataUri: string; name: string; previewDataUri?: string }>
|
|
437
|
+
videoAttachments?: Array<{ dataUri: string; name: string }>
|
|
417
438
|
audioDataUri?: string | null
|
|
418
439
|
documentAttachment?: DocumentAttachment | null
|
|
419
440
|
systemInstruction?: string
|
|
@@ -422,14 +443,17 @@ export default function MintDashboard() {
|
|
|
422
443
|
) {
|
|
423
444
|
if (sending) return
|
|
424
445
|
const outgoingImages = options.imageAttachments ?? []
|
|
446
|
+
const outgoingVideos = options.videoAttachments ?? []
|
|
425
447
|
const outgoingDocument = options.documentAttachment ?? null
|
|
426
448
|
const shouldUseAgentMode = agentMode || promptText.toLowerCase().startsWith('search web:')
|
|
427
449
|
const outgoingImage = outgoingImages.map((img) => img.dataUri).join(' ')
|
|
450
|
+
const outgoingVideo = outgoingVideos.map((vid) => vid.dataUri).join(' ')
|
|
428
451
|
const outgoingImageCount = outgoingImages.length
|
|
429
452
|
setSending(true)
|
|
430
453
|
setStreamingConversationId(conversationId)
|
|
431
454
|
setSendingMessage(promptText)
|
|
432
455
|
setSendingImageCount(outgoingImageCount)
|
|
456
|
+
setSendingVideoCount(outgoingVideos.length)
|
|
433
457
|
setError('')
|
|
434
458
|
setStreamedReply('')
|
|
435
459
|
setStreamedResponse(null)
|
|
@@ -440,6 +464,7 @@ export default function MintDashboard() {
|
|
|
440
464
|
if (options.clearComposer) {
|
|
441
465
|
setMessage('')
|
|
442
466
|
setImageAttachments([])
|
|
467
|
+
setVideoAttachments([])
|
|
443
468
|
setDocumentAttachment(null)
|
|
444
469
|
}
|
|
445
470
|
|
|
@@ -449,6 +474,7 @@ export default function MintDashboard() {
|
|
|
449
474
|
(chunk) => setStreamedReply((current) => `${current}${chunk}`),
|
|
450
475
|
outgoingImage,
|
|
451
476
|
options.audioDataUri ?? null,
|
|
477
|
+
outgoingVideo,
|
|
452
478
|
options.systemInstruction ?? '',
|
|
453
479
|
(progress) => {
|
|
454
480
|
progressSnapshot.push(progress)
|
|
@@ -489,6 +515,7 @@ export default function MintDashboard() {
|
|
|
489
515
|
setAgentActivitySnapshots((current) => mergeActivitySnapshots(current, enrichedHistory))
|
|
490
516
|
await refreshChatSessions()
|
|
491
517
|
await refreshPictures()
|
|
518
|
+
getRuntimeStatus().then(setStatus).catch(() => {})
|
|
492
519
|
setStreamedReply('')
|
|
493
520
|
setStreamedResponse(null)
|
|
494
521
|
} catch (reason) {
|
|
@@ -498,6 +525,7 @@ export default function MintDashboard() {
|
|
|
498
525
|
setStreamingConversationId(null)
|
|
499
526
|
setSendingMessage('')
|
|
500
527
|
setSendingImageCount(0)
|
|
528
|
+
setSendingVideoCount(0)
|
|
501
529
|
}
|
|
502
530
|
}
|
|
503
531
|
|
|
@@ -516,12 +544,91 @@ export default function MintDashboard() {
|
|
|
516
544
|
event.preventDefault()
|
|
517
545
|
const trimmed = message.trim()
|
|
518
546
|
const currentImages = imageAttachments
|
|
547
|
+
const currentVideos = videoAttachments
|
|
519
548
|
const currentDocument = documentAttachment
|
|
520
|
-
const hasAttachments = currentImages.length > 0 || Boolean(currentDocument)
|
|
549
|
+
const hasAttachments = currentImages.length > 0 || currentVideos.length > 0 || Boolean(currentDocument)
|
|
521
550
|
if ((!trimmed && !hasAttachments) || sending) return
|
|
522
|
-
|
|
551
|
+
|
|
552
|
+
if (trimmed.startsWith('/')) {
|
|
553
|
+
const activeP = status?.activeProvider || ''
|
|
554
|
+
const activeM = settingsConfig?.model || ''
|
|
555
|
+
const slashResult = executeSlashCommand(trimmed, {
|
|
556
|
+
activeProvider: activeP,
|
|
557
|
+
activeModel: activeM,
|
|
558
|
+
availableProviders: status?.availableProviders || [],
|
|
559
|
+
workspacePath,
|
|
560
|
+
interactionsCount: interactions.length,
|
|
561
|
+
fastMode: settingsConfig?.fastMode ?? false,
|
|
562
|
+
multiAgent: settingsConfig?.multiAgent ?? false,
|
|
563
|
+
})
|
|
564
|
+
|
|
565
|
+
if (slashResult.handled) {
|
|
566
|
+
setMessage('')
|
|
567
|
+
setImageAttachments([])
|
|
568
|
+
setVideoAttachments([])
|
|
569
|
+
setDocumentAttachment(null)
|
|
570
|
+
|
|
571
|
+
if (slashResult.action === 'set_agent_mode') {
|
|
572
|
+
setAgentMode(true)
|
|
573
|
+
if (slashResult.payload?.prompt) {
|
|
574
|
+
await sendPrompt(slashResult.payload.prompt, { clearComposer: true })
|
|
575
|
+
}
|
|
576
|
+
return
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
if (slashResult.action === 'change_workspace') {
|
|
580
|
+
if (slashResult.payload?.path) {
|
|
581
|
+
setWorkspacePath(slashResult.payload.path)
|
|
582
|
+
} else {
|
|
583
|
+
selectWorkspaceDirectory().then((res) => {
|
|
584
|
+
if (res) setWorkspacePath(res)
|
|
585
|
+
}).catch(() => {})
|
|
586
|
+
}
|
|
587
|
+
} else if (slashResult.action === 'open_image_picker') {
|
|
588
|
+
document.getElementById('vision-file-input')?.click()
|
|
589
|
+
return
|
|
590
|
+
} else if (slashResult.action === 'paste_image') {
|
|
591
|
+
readClipboardImage().then((uri) => {
|
|
592
|
+
if (uri) setImageAttachments((curr) => [...curr, { dataUri: uri, name: 'Clipboard Image' }])
|
|
593
|
+
}).catch(() => {})
|
|
594
|
+
return
|
|
595
|
+
} else if (slashResult.action === 'open_plugins') {
|
|
596
|
+
setView('settings')
|
|
597
|
+
return
|
|
598
|
+
} else if (slashResult.action === 'generate_veo') {
|
|
599
|
+
setView('veo_studio')
|
|
600
|
+
return
|
|
601
|
+
} else if (slashResult.action === 'set_provider_model' && slashResult.payload?.target) {
|
|
602
|
+
const target = slashResult.payload.target
|
|
603
|
+
if (status?.availableProviders.includes(target)) {
|
|
604
|
+
setActiveModel(target).then(() => getRuntimeStatus().then(setStatus)).catch(() => {})
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
if (slashResult.systemText) {
|
|
609
|
+
const systemMsg = {
|
|
610
|
+
id: Date.now(),
|
|
611
|
+
userText: trimmed,
|
|
612
|
+
aiText: slashResult.systemText,
|
|
613
|
+
createdAt: new Date().toISOString(),
|
|
614
|
+
provider: 'system',
|
|
615
|
+
model: 'mint-cli',
|
|
616
|
+
}
|
|
617
|
+
setInteractions((prev) => [...prev, systemMsg])
|
|
618
|
+
saveSystemInteraction(conversationId, trimmed, slashResult.systemText || '', 'system', 'mint-cli').catch(() => {})
|
|
619
|
+
}
|
|
620
|
+
return
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
const promptText = trimmed || (
|
|
625
|
+
currentImages.length > 0 ? (currentImages.length > 1 ? 'Describe these images.' : 'Describe this image.') :
|
|
626
|
+
currentVideos.length > 0 ? (currentVideos.length > 1 ? 'Describe these videos.' : 'Describe this video.') :
|
|
627
|
+
'Summarize this document.'
|
|
628
|
+
)
|
|
523
629
|
await sendPrompt(promptText, {
|
|
524
630
|
imageAttachments: currentImages,
|
|
631
|
+
videoAttachments: currentVideos,
|
|
525
632
|
documentAttachment: currentDocument,
|
|
526
633
|
clearComposer: true,
|
|
527
634
|
})
|
|
@@ -551,6 +658,28 @@ export default function MintDashboard() {
|
|
|
551
658
|
event.target.value = ''
|
|
552
659
|
}
|
|
553
660
|
}
|
|
661
|
+
const MAX_VIDEO_BYTES = 25 * 1024 * 1024 // 25 MB
|
|
662
|
+
async function selectVideo(event: ChangeEvent<HTMLInputElement>) {
|
|
663
|
+
const file = event.target.files?.[0]
|
|
664
|
+
if (!file) return
|
|
665
|
+
try {
|
|
666
|
+
if (file.size > MAX_VIDEO_BYTES) {
|
|
667
|
+
setError(`Video is too large. Maximum allowed is ${Math.round(MAX_VIDEO_BYTES / (1024 * 1024))} MB.`)
|
|
668
|
+
return
|
|
669
|
+
}
|
|
670
|
+
const dataUri = await new Promise<string>((resolve, reject) => {
|
|
671
|
+
const reader = new FileReader()
|
|
672
|
+
reader.onload = () => resolve(reader.result as string)
|
|
673
|
+
reader.onerror = reject
|
|
674
|
+
reader.readAsDataURL(file)
|
|
675
|
+
})
|
|
676
|
+
setVideoAttachments((current) => [...current, { dataUri, name: file.name }])
|
|
677
|
+
} catch (reason) {
|
|
678
|
+
setError(errorMessage(reason))
|
|
679
|
+
} finally {
|
|
680
|
+
event.target.value = ''
|
|
681
|
+
}
|
|
682
|
+
}
|
|
554
683
|
|
|
555
684
|
function pasteImage(clipboardData: DataTransfer) {
|
|
556
685
|
let file: File | null = null
|
|
@@ -797,6 +926,7 @@ export default function MintDashboard() {
|
|
|
797
926
|
async function changeProvider(provider: string) {
|
|
798
927
|
try {
|
|
799
928
|
const config = await window.settingsApi.getSettings()
|
|
929
|
+
if (config.aiProvider === provider) return
|
|
800
930
|
config.aiProvider = provider
|
|
801
931
|
await window.settingsApi.saveSettings(config)
|
|
802
932
|
setSettingsConfig(config)
|
|
@@ -805,7 +935,7 @@ export default function MintDashboard() {
|
|
|
805
935
|
// Record system event in chat history
|
|
806
936
|
const activeModel = getActiveModelName(config, provider)
|
|
807
937
|
const displayName = formatProviderChangeText(provider, activeModel)
|
|
808
|
-
await saveSystemInteraction(conversationId, displayName, 'system', 'provider_change')
|
|
938
|
+
await saveSystemInteraction(conversationId, displayName, '', 'system', 'provider_change')
|
|
809
939
|
await refreshHistory()
|
|
810
940
|
} catch (reason) {
|
|
811
941
|
setError(errorMessage(reason))
|
|
@@ -816,6 +946,8 @@ export default function MintDashboard() {
|
|
|
816
946
|
try {
|
|
817
947
|
const config = await window.settingsApi.getSettings()
|
|
818
948
|
const provider = config.aiProvider
|
|
949
|
+
const currentModel = getActiveModelName(config, provider)
|
|
950
|
+
if (currentModel === modelName) return
|
|
819
951
|
if (provider === 'gemini') {
|
|
820
952
|
config.geminiModel = modelName
|
|
821
953
|
} else if (provider === 'openai') {
|
|
@@ -845,7 +977,7 @@ export default function MintDashboard() {
|
|
|
845
977
|
|
|
846
978
|
// Record system event in chat history
|
|
847
979
|
const displayName = formatProviderChangeText(provider, modelName)
|
|
848
|
-
await saveSystemInteraction(conversationId, displayName, 'system', 'provider_change')
|
|
980
|
+
await saveSystemInteraction(conversationId, displayName, '', 'system', 'provider_change')
|
|
849
981
|
await refreshHistory()
|
|
850
982
|
} catch (reason) {
|
|
851
983
|
setError(errorMessage(reason))
|
|
@@ -968,7 +1100,7 @@ export default function MintDashboard() {
|
|
|
968
1100
|
expressionIndex={expressionIndex}
|
|
969
1101
|
accessoryIndex={accessoryIndex}
|
|
970
1102
|
isLocked={isLocked}
|
|
971
|
-
isActive={modelVisible && view !== 'pictures' && view !== 'workspace' && view !== 'workflows'}
|
|
1103
|
+
isActive={modelVisible && view !== 'pictures' && view !== 'workspace' && view !== 'workflows' && view !== 'imagine' && view !== 'veo'}
|
|
972
1104
|
layoutPreset={layoutPreset}
|
|
973
1105
|
sending={sending}
|
|
974
1106
|
interactionEnabled={interactionEnabled}
|
|
@@ -990,11 +1122,13 @@ export default function MintDashboard() {
|
|
|
990
1122
|
streamedReply={streamingConversationId === conversationId ? streamedReply : ''}
|
|
991
1123
|
streamedResponse={streamingConversationId === conversationId ? streamedResponse : null}
|
|
992
1124
|
agentProgress={streamingConversationId === conversationId ? agentProgress : []}
|
|
1125
|
+
sendingVideoCount={streamingConversationId === conversationId ? sendingVideoCount : 0}
|
|
993
1126
|
agentActivitySnapshots={agentActivitySnapshots}
|
|
994
1127
|
thinkingExpanded={thinkingExpanded}
|
|
995
1128
|
onThinkingExpandedChange={handleThinkingExpandedChange}
|
|
996
1129
|
message={message}
|
|
997
1130
|
imageAttachments={imageAttachments}
|
|
1131
|
+
videoAttachments={videoAttachments}
|
|
998
1132
|
documentName={documentAttachment?.filename ?? ''}
|
|
999
1133
|
pendingApproval={streamingConversationId === conversationId ? pendingApproval : null}
|
|
1000
1134
|
smartContext={smartContext}
|
|
@@ -1005,6 +1139,7 @@ export default function MintDashboard() {
|
|
|
1005
1139
|
welcomeInteraction={MOCK_WELCOME_INTERACTION}
|
|
1006
1140
|
onSubmit={handleSubmit}
|
|
1007
1141
|
onSelectImage={selectImage}
|
|
1142
|
+
onSelectVideo={selectVideo}
|
|
1008
1143
|
onSelectDocument={selectDocument}
|
|
1009
1144
|
onPasteImage={pasteImage}
|
|
1010
1145
|
onSetMessage={setMessage}
|
|
@@ -1012,6 +1147,9 @@ export default function MintDashboard() {
|
|
|
1012
1147
|
onRemoveImage={(idx: number) => {
|
|
1013
1148
|
setImageAttachments((current) => current.filter((_, i) => i !== idx))
|
|
1014
1149
|
}}
|
|
1150
|
+
onRemoveVideo={(idx: number) => {
|
|
1151
|
+
setVideoAttachments((current) => current.filter((_, i) => i !== idx))
|
|
1152
|
+
}}
|
|
1015
1153
|
onRemoveDocument={() => setDocumentAttachment(null)}
|
|
1016
1154
|
onStartWebSearch={startWebSearch}
|
|
1017
1155
|
onCaptureScreen={captureScreen}
|
|
@@ -1034,6 +1172,13 @@ export default function MintDashboard() {
|
|
|
1034
1172
|
setMessage(imgPrompt)
|
|
1035
1173
|
}}
|
|
1036
1174
|
/>
|
|
1175
|
+
<VeoStudioPanel
|
|
1176
|
+
view={view}
|
|
1177
|
+
onSendToChat={(vidPrompt) => {
|
|
1178
|
+
setView('chat')
|
|
1179
|
+
setMessage(vidPrompt)
|
|
1180
|
+
}}
|
|
1181
|
+
/>
|
|
1037
1182
|
<WorkflowBuilderPanel
|
|
1038
1183
|
view={view}
|
|
1039
1184
|
onShowToast={showToast}
|