groove-dev 0.27.144 → 0.27.146
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/CLAUDE.md +7 -0
- package/node_modules/@groove-dev/cli/package.json +1 -1
- package/node_modules/@groove-dev/daemon/package.json +1 -1
- package/node_modules/@groove-dev/daemon/src/api.js +12 -6
- package/node_modules/@groove-dev/daemon/src/conversations.js +59 -58
- package/node_modules/@groove-dev/daemon/src/introducer.js +20 -0
- package/node_modules/@groove-dev/daemon/src/process.js +262 -15
- package/node_modules/@groove-dev/daemon/src/providers/groove-network.js +1 -3
- package/node_modules/@groove-dev/daemon/src/rotator.js +15 -3
- package/node_modules/@groove-dev/daemon/src/routes/agents.js +49 -83
- package/node_modules/@groove-dev/daemon/templates/lab-general.json +12 -0
- package/node_modules/@groove-dev/daemon/templates/llama-cpp-setup.json +12 -0
- package/node_modules/@groove-dev/gui/dist/assets/index-BKbsE_hn.js +1011 -0
- package/node_modules/@groove-dev/gui/dist/assets/index-CEkPsSAm.css +1 -0
- package/node_modules/@groove-dev/gui/dist/index.html +2 -2
- package/node_modules/@groove-dev/gui/package.json +1 -1
- package/node_modules/@groove-dev/gui/src/components/agents/agent-feed.jsx +80 -95
- package/node_modules/@groove-dev/gui/src/components/agents/agent-panel.jsx +2 -70
- package/node_modules/@groove-dev/gui/src/components/agents/spawn-wizard.jsx +132 -4
- package/node_modules/@groove-dev/gui/src/components/chat/chat-header.jsx +3 -8
- package/node_modules/@groove-dev/gui/src/components/chat/chat-input.jsx +199 -75
- package/node_modules/@groove-dev/gui/src/components/chat/chat-messages.jsx +21 -4
- package/node_modules/@groove-dev/gui/src/components/chat/chat-view.jsx +10 -13
- package/node_modules/@groove-dev/gui/src/components/chat/model-picker.jsx +3 -3
- package/node_modules/@groove-dev/gui/src/components/lab/chat-playground.jsx +42 -34
- package/node_modules/@groove-dev/gui/src/components/lab/lab-assistant.jsx +9 -3
- package/node_modules/@groove-dev/gui/src/components/lab/metrics-panel.jsx +13 -3
- package/node_modules/@groove-dev/gui/src/components/lab/parameter-panel.jsx +66 -65
- package/node_modules/@groove-dev/gui/src/components/lab/preset-manager.jsx +17 -14
- package/node_modules/@groove-dev/gui/src/components/lab/runtime-config.jsx +124 -127
- package/node_modules/@groove-dev/gui/src/components/lab/system-prompt-editor.jsx +10 -8
- package/node_modules/@groove-dev/gui/src/components/layout/app-shell.jsx +2 -0
- package/node_modules/@groove-dev/gui/src/components/layout/status-bar.jsx +24 -1
- package/node_modules/@groove-dev/gui/src/components/ui/question-modal.jsx +107 -0
- package/node_modules/@groove-dev/gui/src/components/ui/sheet.jsx +2 -2
- package/node_modules/@groove-dev/gui/src/components/ui/slider.jsx +8 -8
- package/node_modules/@groove-dev/gui/src/lib/status.js +1 -0
- package/node_modules/@groove-dev/gui/src/stores/groove.js +49 -2
- package/node_modules/@groove-dev/gui/src/stores/slices/agents-slice.js +18 -2
- package/node_modules/@groove-dev/gui/src/stores/slices/chat-slice.js +14 -14
- package/node_modules/@groove-dev/gui/src/views/model-lab.jsx +68 -32
- package/node_modules/@groove-dev/gui/src/views/models.jsx +57 -36
- package/node_modules/axios/CHANGELOG.md +260 -0
- package/node_modules/axios/README.md +595 -223
- package/node_modules/axios/dist/axios.js +1460 -1090
- package/node_modules/axios/dist/axios.js.map +1 -1
- package/node_modules/axios/dist/axios.min.js +3 -3
- package/node_modules/axios/dist/axios.min.js.map +1 -1
- package/node_modules/axios/dist/browser/axios.cjs +1560 -1132
- package/node_modules/axios/dist/browser/axios.cjs.map +1 -1
- package/node_modules/axios/dist/esm/axios.js +1557 -1128
- package/node_modules/axios/dist/esm/axios.js.map +1 -1
- package/node_modules/axios/dist/esm/axios.min.js +2 -2
- package/node_modules/axios/dist/esm/axios.min.js.map +1 -1
- package/node_modules/axios/dist/node/axios.cjs +1594 -1057
- package/node_modules/axios/dist/node/axios.cjs.map +1 -1
- package/node_modules/axios/index.d.cts +40 -41
- package/node_modules/axios/index.d.ts +151 -227
- package/node_modules/axios/index.js +2 -0
- package/node_modules/axios/lib/adapters/adapters.js +4 -2
- package/node_modules/axios/lib/adapters/fetch.js +147 -16
- package/node_modules/axios/lib/adapters/http.js +306 -58
- package/node_modules/axios/lib/adapters/xhr.js +6 -2
- package/node_modules/axios/lib/core/Axios.js +7 -3
- package/node_modules/axios/lib/core/AxiosError.js +120 -34
- package/node_modules/axios/lib/core/AxiosHeaders.js +27 -25
- package/node_modules/axios/lib/core/buildFullPath.js +1 -1
- package/node_modules/axios/lib/core/dispatchRequest.js +19 -7
- package/node_modules/axios/lib/core/mergeConfig.js +21 -4
- package/node_modules/axios/lib/core/settle.js +7 -11
- package/node_modules/axios/lib/defaults/index.js +14 -9
- package/node_modules/axios/lib/env/data.js +1 -1
- package/node_modules/axios/lib/helpers/AxiosURLSearchParams.js +1 -2
- package/node_modules/axios/lib/helpers/buildURL.js +1 -1
- package/node_modules/axios/lib/helpers/cookies.js +14 -2
- package/node_modules/axios/lib/helpers/estimateDataURLDecodedBytes.js +28 -1
- package/node_modules/axios/lib/helpers/formDataToJSON.js +3 -1
- package/node_modules/axios/lib/helpers/formDataToStream.js +3 -2
- package/node_modules/axios/lib/helpers/parseProtocol.js +1 -1
- package/node_modules/axios/lib/helpers/progressEventReducer.js +5 -5
- package/node_modules/axios/lib/helpers/resolveConfig.js +54 -18
- package/node_modules/axios/lib/helpers/shouldBypassProxy.js +74 -2
- package/node_modules/axios/lib/helpers/toFormData.js +10 -2
- package/node_modules/axios/lib/helpers/validator.js +3 -1
- package/node_modules/axios/lib/utils.js +33 -21
- package/node_modules/axios/package.json +17 -24
- package/node_modules/follow-redirects/README.md +7 -5
- package/node_modules/follow-redirects/index.js +24 -1
- package/node_modules/follow-redirects/package.json +1 -1
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/daemon/package.json +1 -1
- package/packages/daemon/src/api.js +12 -6
- package/packages/daemon/src/conversations.js +59 -58
- package/packages/daemon/src/introducer.js +20 -0
- package/packages/daemon/src/process.js +262 -15
- package/packages/daemon/src/providers/groove-network.js +1 -3
- package/packages/daemon/src/rotator.js +15 -3
- package/packages/daemon/src/routes/agents.js +49 -83
- package/packages/daemon/templates/lab-general.json +12 -0
- package/packages/daemon/templates/llama-cpp-setup.json +12 -0
- package/packages/gui/dist/assets/index-BKbsE_hn.js +1011 -0
- package/packages/gui/dist/assets/index-CEkPsSAm.css +1 -0
- package/packages/gui/dist/index.html +2 -2
- package/packages/gui/package.json +1 -1
- package/packages/gui/src/components/agents/agent-feed.jsx +80 -95
- package/packages/gui/src/components/agents/agent-panel.jsx +2 -70
- package/packages/gui/src/components/agents/spawn-wizard.jsx +132 -4
- package/packages/gui/src/components/chat/chat-header.jsx +3 -8
- package/packages/gui/src/components/chat/chat-input.jsx +199 -75
- package/packages/gui/src/components/chat/chat-messages.jsx +21 -4
- package/packages/gui/src/components/chat/chat-view.jsx +10 -13
- package/packages/gui/src/components/chat/model-picker.jsx +3 -3
- package/packages/gui/src/components/lab/chat-playground.jsx +42 -34
- package/packages/gui/src/components/lab/lab-assistant.jsx +9 -3
- package/packages/gui/src/components/lab/metrics-panel.jsx +13 -3
- package/packages/gui/src/components/lab/parameter-panel.jsx +66 -65
- package/packages/gui/src/components/lab/preset-manager.jsx +17 -14
- package/packages/gui/src/components/lab/runtime-config.jsx +124 -127
- package/packages/gui/src/components/lab/system-prompt-editor.jsx +10 -8
- package/packages/gui/src/components/layout/app-shell.jsx +2 -0
- package/packages/gui/src/components/layout/status-bar.jsx +24 -1
- package/packages/gui/src/components/ui/question-modal.jsx +107 -0
- package/packages/gui/src/components/ui/sheet.jsx +2 -2
- package/packages/gui/src/components/ui/slider.jsx +8 -8
- package/packages/gui/src/lib/status.js +1 -0
- package/packages/gui/src/stores/groove.js +49 -2
- package/packages/gui/src/stores/slices/agents-slice.js +18 -2
- package/packages/gui/src/stores/slices/chat-slice.js +14 -14
- package/packages/gui/src/views/model-lab.jsx +68 -32
- package/packages/gui/src/views/models.jsx +57 -36
- package/node_modules/@groove-dev/gui/dist/assets/index-BcoF6_eF.js +0 -1012
- package/node_modules/@groove-dev/gui/dist/assets/index-Dd7qhiEd.css +0 -1
- package/packages/gui/dist/assets/index-BcoF6_eF.js +0 -1012
- package/packages/gui/dist/assets/index-Dd7qhiEd.css +0 -1
|
@@ -5,7 +5,7 @@ import { ScrollArea } from '../ui/scroll-area';
|
|
|
5
5
|
import { Button } from '../ui/button';
|
|
6
6
|
import { Tooltip } from '../ui/tooltip';
|
|
7
7
|
import { cn } from '../../lib/cn';
|
|
8
|
-
import {
|
|
8
|
+
import { SendHorizontal, Plus, ChevronDown, Clock, Zap, Bot } from 'lucide-react';
|
|
9
9
|
|
|
10
10
|
function MessageMetrics({ metrics }) {
|
|
11
11
|
if (!metrics) return null;
|
|
@@ -40,7 +40,7 @@ function UserMessage({ msg }) {
|
|
|
40
40
|
<div className="flex justify-end animate-chat-fade-in">
|
|
41
41
|
<div className="max-w-[80%]">
|
|
42
42
|
<div className="px-3.5 py-2 bg-accent/8 rounded rounded-br-none">
|
|
43
|
-
<p className="text-
|
|
43
|
+
<p className="text-sm text-text-0 font-sans whitespace-pre-wrap break-words leading-relaxed">{msg.content}</p>
|
|
44
44
|
</div>
|
|
45
45
|
</div>
|
|
46
46
|
</div>
|
|
@@ -60,7 +60,7 @@ function AssistantMessage({ msg, streaming }) {
|
|
|
60
60
|
</div>
|
|
61
61
|
{msg.reasoning && (
|
|
62
62
|
<div className="ml-5 mb-1.5 pl-3 border-l border-text-4/20 py-1">
|
|
63
|
-
<div className="text-
|
|
63
|
+
<div className="text-xs font-sans text-text-4 italic whitespace-pre-wrap break-words leading-relaxed">
|
|
64
64
|
{msg.reasoning}
|
|
65
65
|
{isReasoning && <span className="inline-block w-1 h-3 bg-text-4/40 ml-0.5 animate-pulse" />}
|
|
66
66
|
</div>
|
|
@@ -69,7 +69,7 @@ function AssistantMessage({ msg, streaming }) {
|
|
|
69
69
|
<div className="ml-5">
|
|
70
70
|
{msg.content ? (
|
|
71
71
|
<div className={cn(
|
|
72
|
-
'text-
|
|
72
|
+
'text-sm font-sans whitespace-pre-wrap break-words leading-relaxed',
|
|
73
73
|
msg.error ? 'text-danger' : 'text-text-1',
|
|
74
74
|
)}>
|
|
75
75
|
{msg.content}
|
|
@@ -217,44 +217,52 @@ export function ChatPlayground() {
|
|
|
217
217
|
|
|
218
218
|
{/* Input */}
|
|
219
219
|
<div className="flex-shrink-0 px-4 py-3">
|
|
220
|
-
<div className="flex
|
|
221
|
-
<
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
220
|
+
<div className="flex flex-col rounded-lg border border-border-subtle bg-surface-0 transition-colors overflow-hidden focus-within:border-text-4/40">
|
|
221
|
+
<div className="px-1">
|
|
222
|
+
<textarea
|
|
223
|
+
ref={inputRef}
|
|
224
|
+
value={input}
|
|
225
|
+
onChange={(e) => setInput(e.target.value)}
|
|
226
|
+
onKeyDown={handleKeyDown}
|
|
227
|
+
placeholder={!activeRuntime ? 'Select a runtime first' : !activeModel ? 'Select a model first' : 'Type a message...'}
|
|
228
|
+
disabled={!activeRuntime || !activeModel}
|
|
229
|
+
rows={1}
|
|
230
|
+
className={cn(
|
|
231
|
+
'w-full resize-none px-3 py-2.5 text-[13px]',
|
|
232
|
+
'bg-transparent font-sans text-text-0',
|
|
233
|
+
'placeholder:text-text-4',
|
|
234
|
+
'focus:outline-none',
|
|
235
|
+
'disabled:opacity-40 disabled:cursor-not-allowed',
|
|
236
|
+
)}
|
|
237
|
+
style={{ height: 88 }}
|
|
238
|
+
/>
|
|
239
|
+
</div>
|
|
240
|
+
<div className="flex items-center gap-1 px-1.5 pb-1.5 pt-0.5">
|
|
241
|
+
<div className="flex-1" />
|
|
242
|
+
{streaming && (
|
|
243
|
+
<button
|
|
244
|
+
onClick={() => useGrooveStore.getState().stopLabInference()}
|
|
245
|
+
title="Stop generation"
|
|
246
|
+
className="group w-7 h-7 flex items-center justify-center rounded-md transition-colors cursor-pointer"
|
|
247
|
+
>
|
|
248
|
+
<span className="relative flex items-center justify-center w-3.5 h-3.5">
|
|
249
|
+
<span className="absolute inset-0 rounded-full bg-accent/30 group-hover:bg-red-500/30 animate-ping [animation-duration:2s] transition-colors" />
|
|
250
|
+
<span className="relative w-2.5 h-2.5 rounded-full bg-accent group-hover:bg-red-500 transition-colors" />
|
|
251
|
+
</span>
|
|
252
|
+
</button>
|
|
235
253
|
)}
|
|
236
|
-
style={{ height: 'auto', overflowY: input.split('\n').length > 4 ? 'auto' : 'hidden' }}
|
|
237
|
-
onInput={(e) => { e.target.style.height = 'auto'; e.target.style.height = `${Math.min(e.target.scrollHeight, 128)}px`; }}
|
|
238
|
-
/>
|
|
239
|
-
{streaming ? (
|
|
240
|
-
<button
|
|
241
|
-
onClick={() => useGrooveStore.getState().stopLabInference()}
|
|
242
|
-
className="flex-shrink-0 w-7 h-7 flex items-center justify-center rounded-sm bg-danger/15 text-danger hover:bg-danger/25 transition-colors cursor-pointer"
|
|
243
|
-
>
|
|
244
|
-
<Square size={12} />
|
|
245
|
-
</button>
|
|
246
|
-
) : (
|
|
247
254
|
<button
|
|
248
255
|
disabled={!canSend}
|
|
249
256
|
onClick={handleSend}
|
|
250
257
|
className={cn(
|
|
251
|
-
'
|
|
252
|
-
|
|
258
|
+
'w-7 h-7 flex items-center justify-center rounded-md transition-colors cursor-pointer',
|
|
259
|
+
'disabled:opacity-15 disabled:cursor-not-allowed',
|
|
260
|
+
canSend ? 'text-text-0 hover:text-text-1' : 'text-text-4',
|
|
253
261
|
)}
|
|
254
262
|
>
|
|
255
|
-
<
|
|
263
|
+
<SendHorizontal size={15} />
|
|
256
264
|
</button>
|
|
257
|
-
|
|
265
|
+
</div>
|
|
258
266
|
</div>
|
|
259
267
|
</div>
|
|
260
268
|
</div>
|
|
@@ -307,7 +307,7 @@ export function LabAssistant() {
|
|
|
307
307
|
<span className="relative w-1.5 h-1.5 rounded-full bg-accent" />
|
|
308
308
|
</div>
|
|
309
309
|
<span className="text-2xs font-sans text-text-2">
|
|
310
|
-
Lab Assistant is setting up <span className="font-medium text-text-1">{backend?.toUpperCase()}</span
|
|
310
|
+
Lab Assistant {backend === 'lab-general' ? 'is active' : <>is setting up <span className="font-medium text-text-1">{backend?.toUpperCase()}</span></>}
|
|
311
311
|
</span>
|
|
312
312
|
<div className="flex-1" />
|
|
313
313
|
<Badge variant="success" className="text-2xs">running</Badge>
|
|
@@ -322,8 +322,14 @@ export function LabAssistant() {
|
|
|
322
322
|
<div className="w-12 h-12 rounded-lg bg-accent/10 flex items-center justify-center mb-3">
|
|
323
323
|
<FlaskConical size={22} className="text-accent" />
|
|
324
324
|
</div>
|
|
325
|
-
<p className="text-sm text-text-1 font-sans font-medium">
|
|
326
|
-
|
|
325
|
+
<p className="text-sm text-text-1 font-sans font-medium">
|
|
326
|
+
{backend === 'lab-general' ? 'Lab Assistant' : `Setting up ${backend?.toUpperCase()}`}
|
|
327
|
+
</p>
|
|
328
|
+
<p className="text-[13px] text-text-3 font-sans mt-1.5">
|
|
329
|
+
{backend === 'lab-general'
|
|
330
|
+
? 'Ask about runtime setup, model configs, context windows, prompts, or anything else...'
|
|
331
|
+
: 'The assistant is starting up and will begin configuring your runtime...'}
|
|
332
|
+
</p>
|
|
327
333
|
</div>
|
|
328
334
|
) : (
|
|
329
335
|
messages.map((msg, i) =>
|
|
@@ -115,6 +115,7 @@ function SparklineSection({ icon: Icon, label, value, unit, data, color = HEX.ac
|
|
|
115
115
|
export function MetricsPanel() {
|
|
116
116
|
const metrics = useGrooveStore((s) => s.labMetrics);
|
|
117
117
|
const activeRuntime = useGrooveStore((s) => s.labActiveRuntime);
|
|
118
|
+
const activeModel = useGrooveStore((s) => s.labActiveModel);
|
|
118
119
|
const activeSession = useGrooveStore((s) => s.labActiveSession);
|
|
119
120
|
const sessions = useGrooveStore((s) => s.labSessions);
|
|
120
121
|
|
|
@@ -276,11 +277,20 @@ export function MetricsPanel() {
|
|
|
276
277
|
</div>
|
|
277
278
|
|
|
278
279
|
{/* Attach to agent */}
|
|
279
|
-
{activeRuntime && (
|
|
280
|
+
{activeRuntime && activeModel && (
|
|
280
281
|
<>
|
|
281
282
|
<div className="h-px bg-border-subtle" />
|
|
282
|
-
<Tooltip content="
|
|
283
|
-
<button
|
|
283
|
+
<Tooltip content="Spawn a new agent using this runtime and model">
|
|
284
|
+
<button
|
|
285
|
+
onClick={() => {
|
|
286
|
+
useGrooveStore.getState().openDetail({
|
|
287
|
+
type: 'spawn',
|
|
288
|
+
presetProvider: 'local',
|
|
289
|
+
presetModel: `runtime:${activeRuntime}:${activeModel}`,
|
|
290
|
+
});
|
|
291
|
+
}}
|
|
292
|
+
className="w-full flex items-center justify-center gap-1.5 px-3 py-2 text-2xs font-sans text-text-3 hover:text-text-1 border border-border-subtle rounded-sm hover:border-border transition-colors cursor-pointer"
|
|
293
|
+
>
|
|
284
294
|
<Link size={11} /> Attach to Agent
|
|
285
295
|
</button>
|
|
286
296
|
</Tooltip>
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// FSL-1.1-Apache-2.0 — see LICENSE
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { useGrooveStore } from '../../stores/groove';
|
|
4
|
+
import { SidebarSection } from '../../views/model-lab';
|
|
4
5
|
import { TuningSlider } from '../ui/slider';
|
|
5
6
|
import { Tooltip } from '../ui/tooltip';
|
|
6
|
-
import { RotateCcw,
|
|
7
|
+
import { RotateCcw, ChevronRight, Dices, X, Plus } from 'lucide-react';
|
|
7
8
|
import { cn } from '../../lib/cn';
|
|
8
9
|
|
|
9
10
|
const DEFAULTS = {
|
|
@@ -25,40 +26,42 @@ const PENALTY_SLIDERS = [
|
|
|
25
26
|
{ key: 'presencePenalty', label: 'Pres Penalty', min: 0, max: 2, step: 0.01 },
|
|
26
27
|
];
|
|
27
28
|
|
|
28
|
-
function ParamGroup({ title, defaultOpen =
|
|
29
|
+
function ParamGroup({ title, defaultOpen = false, children }) {
|
|
29
30
|
const [open, setOpen] = useState(defaultOpen);
|
|
30
31
|
return (
|
|
31
32
|
<div>
|
|
32
33
|
<button
|
|
33
34
|
onClick={() => setOpen(!open)}
|
|
34
|
-
className="w-full flex items-center gap-1.5
|
|
35
|
+
className="w-full flex items-center gap-1.5 h-7 text-left cursor-pointer group"
|
|
35
36
|
>
|
|
36
37
|
<ChevronRight
|
|
37
38
|
size={10}
|
|
38
39
|
className={cn('text-text-4 transition-transform duration-150 flex-shrink-0', open && 'rotate-90')}
|
|
39
40
|
/>
|
|
40
|
-
<span className="text-
|
|
41
|
+
<span className="text-[10px] font-semibold text-text-4 font-sans uppercase tracking-widest">{title}</span>
|
|
41
42
|
</button>
|
|
42
|
-
{open && <div className="space-y-0.5
|
|
43
|
+
{open && <div className="space-y-1 pl-0.5 pt-1">{children}</div>}
|
|
43
44
|
</div>
|
|
44
45
|
);
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
function
|
|
48
|
+
function ToggleSwitch({ label, active, onClick, description }) {
|
|
48
49
|
return (
|
|
49
50
|
<Tooltip content={description} side="right">
|
|
50
51
|
<button
|
|
51
52
|
onClick={onClick}
|
|
52
|
-
className=
|
|
53
|
-
'w-full flex items-center gap-2 px-2 py-1.5 rounded-sm transition-colors cursor-pointer text-left',
|
|
54
|
-
active ? 'bg-accent/8' : 'hover:bg-surface-3',
|
|
55
|
-
)}
|
|
53
|
+
className="w-full flex items-center gap-2.5 h-9 text-left cursor-pointer group"
|
|
56
54
|
>
|
|
57
|
-
<
|
|
58
|
-
<
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
<span className="text-[11px] font-sans text-text-2 flex-1">{label}</span>
|
|
56
|
+
<div className={cn(
|
|
57
|
+
'w-7 h-[16px] rounded-full transition-colors relative flex-shrink-0',
|
|
58
|
+
active ? 'bg-accent' : 'bg-surface-5',
|
|
59
|
+
)}>
|
|
60
|
+
<div className={cn(
|
|
61
|
+
'absolute top-[2px] w-3 h-3 rounded-full bg-white shadow-sm transition-all',
|
|
62
|
+
active ? 'left-[14px]' : 'left-[2px]',
|
|
63
|
+
)} />
|
|
64
|
+
</div>
|
|
62
65
|
</button>
|
|
63
66
|
</Tooltip>
|
|
64
67
|
);
|
|
@@ -69,26 +72,28 @@ function SeedInput({ value, onChange }) {
|
|
|
69
72
|
onChange(Math.floor(Math.random() * 2147483647));
|
|
70
73
|
}
|
|
71
74
|
return (
|
|
72
|
-
<div className="
|
|
73
|
-
<span className="text-
|
|
74
|
-
<
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
<
|
|
84
|
-
<
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
<
|
|
90
|
-
|
|
91
|
-
|
|
75
|
+
<div className="pt-2">
|
|
76
|
+
<span className="text-[11px] text-text-2 font-sans block mb-2.5">Seed</span>
|
|
77
|
+
<div className="flex items-center gap-1.5">
|
|
78
|
+
<input
|
|
79
|
+
type="number"
|
|
80
|
+
min={0}
|
|
81
|
+
value={value ?? ''}
|
|
82
|
+
onChange={(e) => onChange(e.target.value === '' ? null : parseInt(e.target.value, 10))}
|
|
83
|
+
placeholder="Random"
|
|
84
|
+
className="flex-1 min-w-0 h-7 px-2.5 text-[11px] font-mono bg-surface-1 border border-border rounded text-text-1 placeholder:text-text-4 focus:outline-none focus:ring-1 focus:ring-accent/50 focus:border-accent/50 tabular-nums"
|
|
85
|
+
/>
|
|
86
|
+
<Tooltip content="Randomize seed">
|
|
87
|
+
<button onClick={handleRandomize} className="p-0.5 text-text-4 hover:text-accent transition-colors cursor-pointer">
|
|
88
|
+
<Dices size={12} />
|
|
89
|
+
</button>
|
|
90
|
+
</Tooltip>
|
|
91
|
+
{value != null && (
|
|
92
|
+
<button onClick={() => onChange(null)} className="p-0.5 text-text-4 hover:text-danger transition-colors cursor-pointer">
|
|
93
|
+
<X size={10} />
|
|
94
|
+
</button>
|
|
95
|
+
)}
|
|
96
|
+
</div>
|
|
92
97
|
</div>
|
|
93
98
|
);
|
|
94
99
|
}
|
|
@@ -113,35 +118,35 @@ function StopSequenceInput({ sequences, onChange }) {
|
|
|
113
118
|
}
|
|
114
119
|
|
|
115
120
|
return (
|
|
116
|
-
<div className="
|
|
117
|
-
<span className="text-
|
|
118
|
-
|
|
119
|
-
<div className="flex flex-wrap gap-1">
|
|
120
|
-
{sequences.map((s, i) => (
|
|
121
|
-
<span key={i} className="inline-flex items-center gap-0.5 px-1.5 py-0.5 bg-surface-3 rounded text-2xs font-mono text-text-2">
|
|
122
|
-
{s.length > 12 ? s.slice(0, 12) + '...' : s}
|
|
123
|
-
<button onClick={() => handleRemove(i)} className="text-text-4 hover:text-danger cursor-pointer"><X size={8} /></button>
|
|
124
|
-
</span>
|
|
125
|
-
))}
|
|
126
|
-
</div>
|
|
127
|
-
)}
|
|
128
|
-
<div className="flex gap-1">
|
|
121
|
+
<div className="pt-2">
|
|
122
|
+
<span className="text-[11px] text-text-2 font-sans block mb-2.5">Stop Sequences</span>
|
|
123
|
+
<div className="flex items-center gap-1.5">
|
|
129
124
|
<input
|
|
130
125
|
value={input}
|
|
131
126
|
onChange={(e) => setInput(e.target.value)}
|
|
132
127
|
onKeyDown={handleKeyDown}
|
|
133
128
|
placeholder="Add sequence..."
|
|
134
129
|
maxLength={100}
|
|
135
|
-
className="flex-1 min-w-0 h-
|
|
130
|
+
className="flex-1 min-w-0 h-7 px-2.5 text-[11px] font-mono bg-surface-1 border border-border rounded text-text-1 placeholder:text-text-4 focus:outline-none focus:ring-1 focus:ring-accent/50 focus:border-accent/50"
|
|
136
131
|
/>
|
|
137
132
|
<button
|
|
138
133
|
onClick={handleAdd}
|
|
139
134
|
disabled={!input.trim() || sequences.length >= 10}
|
|
140
|
-
className="p-
|
|
135
|
+
className="p-0.5 text-text-4 hover:text-accent disabled:opacity-30 transition-colors cursor-pointer"
|
|
141
136
|
>
|
|
142
137
|
<Plus size={12} />
|
|
143
138
|
</button>
|
|
144
139
|
</div>
|
|
140
|
+
{sequences.length > 0 && (
|
|
141
|
+
<div className="flex flex-wrap gap-1.5 mt-2.5">
|
|
142
|
+
{sequences.map((s, i) => (
|
|
143
|
+
<span key={i} className="inline-flex items-center gap-1 px-1.5 py-0.5 bg-surface-2 border border-border-subtle rounded text-[10px] font-mono text-text-2">
|
|
144
|
+
{s.length > 12 ? s.slice(0, 12) + '...' : s}
|
|
145
|
+
<button onClick={() => handleRemove(i)} className="text-text-4 hover:text-danger cursor-pointer"><X size={8} /></button>
|
|
146
|
+
</span>
|
|
147
|
+
))}
|
|
148
|
+
</div>
|
|
149
|
+
)}
|
|
145
150
|
</div>
|
|
146
151
|
);
|
|
147
152
|
}
|
|
@@ -157,9 +162,11 @@ export function ParameterPanel() {
|
|
|
157
162
|
}
|
|
158
163
|
|
|
159
164
|
return (
|
|
160
|
-
<
|
|
161
|
-
|
|
162
|
-
|
|
165
|
+
<SidebarSection
|
|
166
|
+
label="Parameters"
|
|
167
|
+
collapsible
|
|
168
|
+
defaultOpen={false}
|
|
169
|
+
action={
|
|
163
170
|
<Tooltip content="Reset to defaults">
|
|
164
171
|
<button
|
|
165
172
|
onClick={handleReset}
|
|
@@ -168,19 +175,16 @@ export function ParameterPanel() {
|
|
|
168
175
|
<RotateCcw size={11} />
|
|
169
176
|
</button>
|
|
170
177
|
</Tooltip>
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
<ToggleRow
|
|
176
|
-
icon={Brain}
|
|
178
|
+
}
|
|
179
|
+
>
|
|
180
|
+
<div className="space-y-0.5 rounded-md bg-surface-1/50 border border-border-subtle px-3 py-2">
|
|
181
|
+
<ToggleSwitch
|
|
177
182
|
label="Thinking"
|
|
178
183
|
active={parameters.thinking}
|
|
179
184
|
onClick={() => setParameter('thinking', !parameters.thinking)}
|
|
180
185
|
description="Chain-of-thought for supported models (Qwen3, etc.)"
|
|
181
186
|
/>
|
|
182
|
-
<
|
|
183
|
-
icon={Braces}
|
|
187
|
+
<ToggleSwitch
|
|
184
188
|
label="JSON Mode"
|
|
185
189
|
active={parameters.jsonMode}
|
|
186
190
|
onClick={() => setParameter('jsonMode', !parameters.jsonMode)}
|
|
@@ -188,7 +192,6 @@ export function ParameterPanel() {
|
|
|
188
192
|
/>
|
|
189
193
|
</div>
|
|
190
194
|
|
|
191
|
-
{/* Sampling group */}
|
|
192
195
|
<ParamGroup title="Sampling">
|
|
193
196
|
{SAMPLING_SLIDERS.map((s) => (
|
|
194
197
|
<TuningSlider
|
|
@@ -203,7 +206,6 @@ export function ParameterPanel() {
|
|
|
203
206
|
))}
|
|
204
207
|
</ParamGroup>
|
|
205
208
|
|
|
206
|
-
{/* Generation group */}
|
|
207
209
|
<ParamGroup title="Generation">
|
|
208
210
|
<TuningSlider
|
|
209
211
|
label="Max Tokens"
|
|
@@ -221,7 +223,6 @@ export function ParameterPanel() {
|
|
|
221
223
|
/>
|
|
222
224
|
</ParamGroup>
|
|
223
225
|
|
|
224
|
-
{/* Penalties group — collapsed by default */}
|
|
225
226
|
<ParamGroup title="Penalties" defaultOpen={false}>
|
|
226
227
|
{PENALTY_SLIDERS.map((s) => (
|
|
227
228
|
<TuningSlider
|
|
@@ -235,6 +236,6 @@ export function ParameterPanel() {
|
|
|
235
236
|
/>
|
|
236
237
|
))}
|
|
237
238
|
</ParamGroup>
|
|
238
|
-
</
|
|
239
|
+
</SidebarSection>
|
|
239
240
|
);
|
|
240
241
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// FSL-1.1-Apache-2.0 — see LICENSE
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { useGrooveStore } from '../../stores/groove';
|
|
4
|
+
import { SidebarSection } from '../../views/model-lab';
|
|
4
5
|
import { Button } from '../ui/button';
|
|
5
6
|
import { Input } from '../ui/input';
|
|
6
7
|
import { Dialog, DialogContent } from '../ui/dialog';
|
|
@@ -54,33 +55,35 @@ export function PresetManager() {
|
|
|
54
55
|
const [saveOpen, setSaveOpen] = useState(false);
|
|
55
56
|
|
|
56
57
|
return (
|
|
57
|
-
<
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
<SidebarSection
|
|
59
|
+
label="Presets"
|
|
60
|
+
collapsible
|
|
61
|
+
defaultOpen={false}
|
|
62
|
+
action={
|
|
60
63
|
<Tooltip content="Save current settings as preset">
|
|
61
64
|
<button
|
|
62
65
|
onClick={() => setSaveOpen(true)}
|
|
63
66
|
className="p-1 text-text-4 hover:text-accent transition-colors cursor-pointer"
|
|
64
67
|
>
|
|
65
|
-
<Save size={
|
|
68
|
+
<Save size={12} />
|
|
66
69
|
</button>
|
|
67
70
|
</Tooltip>
|
|
68
|
-
|
|
69
|
-
|
|
71
|
+
}
|
|
72
|
+
>
|
|
70
73
|
{presets.length === 0 ? (
|
|
71
|
-
<div className="py-
|
|
72
|
-
<BookmarkCheck size={14} className="mx-auto text-text-4 mb-1" />
|
|
73
|
-
<p className="text-
|
|
74
|
+
<div className="py-5 text-center rounded-md bg-surface-1/50 border border-border-subtle">
|
|
75
|
+
<BookmarkCheck size={14} className="mx-auto text-text-4 mb-1.5" />
|
|
76
|
+
<p className="text-[10px] text-text-4 font-sans">No presets saved</p>
|
|
74
77
|
</div>
|
|
75
78
|
) : (
|
|
76
79
|
<ScrollArea className="max-h-32">
|
|
77
|
-
<div className="space-y-
|
|
80
|
+
<div className="space-y-1 rounded-md bg-surface-1/50 border border-border-subtle p-2">
|
|
78
81
|
{presets.map((preset) => (
|
|
79
82
|
<div
|
|
80
83
|
key={preset.id}
|
|
81
84
|
className={cn(
|
|
82
|
-
'flex items-center gap-2 px-2.5 py-
|
|
83
|
-
activePreset === preset.id ? 'bg-accent/
|
|
85
|
+
'flex items-center gap-2.5 px-2.5 py-2 rounded transition-colors',
|
|
86
|
+
activePreset === preset.id ? 'bg-accent/10' : 'hover:bg-surface-3',
|
|
84
87
|
)}
|
|
85
88
|
>
|
|
86
89
|
<button
|
|
@@ -88,7 +91,7 @@ export function PresetManager() {
|
|
|
88
91
|
className="flex-1 text-left min-w-0 cursor-pointer"
|
|
89
92
|
>
|
|
90
93
|
<div className={cn(
|
|
91
|
-
'text-
|
|
94
|
+
'text-[11px] font-sans truncate',
|
|
92
95
|
activePreset === preset.id ? 'text-accent font-medium' : 'text-text-2',
|
|
93
96
|
)}>
|
|
94
97
|
{preset.name}
|
|
@@ -109,6 +112,6 @@ export function PresetManager() {
|
|
|
109
112
|
)}
|
|
110
113
|
|
|
111
114
|
<SavePresetDialog open={saveOpen} onOpenChange={setSaveOpen} />
|
|
112
|
-
</
|
|
115
|
+
</SidebarSection>
|
|
113
116
|
);
|
|
114
117
|
}
|