groove-dev 0.27.134 → 0.27.136
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/moe-training/client/domain-tagger.js +1 -1
- package/moe-training/scripts/retag-delegate-yield.js +303 -0
- package/moe-training/test/shared/envelope-schema.test.js +3 -3
- 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/adaptive.js +77 -0
- package/node_modules/@groove-dev/daemon/src/api.js +35 -5
- package/node_modules/@groove-dev/daemon/src/journalist.js +28 -12
- package/node_modules/@groove-dev/daemon/src/model-lab.js +53 -76
- package/node_modules/@groove-dev/daemon/src/process.js +91 -2
- package/node_modules/@groove-dev/daemon/src/rotator.js +45 -3
- package/node_modules/@groove-dev/gui/dist/assets/{index-Dozp69tK.js → index-BrZHF7pK.js} +1770 -1766
- package/node_modules/@groove-dev/gui/dist/assets/index-DIfiwdKl.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-chat.jsx +60 -18
- package/node_modules/@groove-dev/gui/src/components/agents/agent-feed.jsx +42 -20
- package/node_modules/@groove-dev/gui/src/components/agents/agent-file-tree.jsx +1 -1
- package/node_modules/@groove-dev/gui/src/components/agents/workspace-mode.jsx +1 -1
- package/node_modules/@groove-dev/gui/src/components/chat/chat-messages.jsx +2 -22
- package/node_modules/@groove-dev/gui/src/components/editor/code-editor.jsx +9 -9
- package/node_modules/@groove-dev/gui/src/components/editor/file-tree.jsx +1 -1
- package/node_modules/@groove-dev/gui/src/components/editor/terminal.jsx +7 -0
- package/node_modules/@groove-dev/gui/src/components/lab/chat-playground.jsx +59 -51
- package/node_modules/@groove-dev/gui/src/components/lab/lab-assistant.jsx +48 -48
- package/node_modules/@groove-dev/gui/src/components/lab/metrics-panel.jsx +39 -38
- package/node_modules/@groove-dev/gui/src/components/lab/parameter-panel.jsx +4 -5
- package/node_modules/@groove-dev/gui/src/components/lab/preset-manager.jsx +11 -11
- package/node_modules/@groove-dev/gui/src/components/lab/runtime-config.jsx +66 -62
- package/node_modules/@groove-dev/gui/src/components/lab/system-prompt-editor.jsx +13 -13
- package/node_modules/@groove-dev/gui/src/components/layout/breadcrumb-bar.jsx +1 -1
- package/node_modules/@groove-dev/gui/src/components/preview/preview-workspace.jsx +62 -22
- package/node_modules/@groove-dev/gui/src/components/ui/slider.jsx +16 -17
- package/node_modules/@groove-dev/gui/src/components/ui/table-tree.jsx +38 -0
- package/node_modules/@groove-dev/gui/src/stores/groove.js +23 -9
- package/node_modules/@groove-dev/gui/src/views/editor.jsx +1 -1
- package/node_modules/@groove-dev/gui/src/views/model-lab.jsx +101 -87
- package/node_modules/moe-training/client/domain-tagger.js +1 -1
- package/node_modules/moe-training/scripts/retag-delegate-yield.js +303 -0
- package/node_modules/moe-training/test/shared/envelope-schema.test.js +3 -3
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/daemon/package.json +1 -1
- package/packages/daemon/src/adaptive.js +77 -0
- package/packages/daemon/src/api.js +35 -5
- package/packages/daemon/src/journalist.js +28 -12
- package/packages/daemon/src/model-lab.js +53 -76
- package/packages/daemon/src/process.js +91 -2
- package/packages/daemon/src/rotator.js +45 -3
- package/packages/gui/dist/assets/{index-Dozp69tK.js → index-BrZHF7pK.js} +1770 -1766
- package/packages/gui/dist/assets/index-DIfiwdKl.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-chat.jsx +60 -18
- package/packages/gui/src/components/agents/agent-feed.jsx +42 -20
- package/packages/gui/src/components/agents/agent-file-tree.jsx +1 -1
- package/packages/gui/src/components/agents/workspace-mode.jsx +1 -1
- package/packages/gui/src/components/chat/chat-messages.jsx +2 -22
- package/packages/gui/src/components/editor/code-editor.jsx +9 -9
- package/packages/gui/src/components/editor/file-tree.jsx +1 -1
- package/packages/gui/src/components/editor/terminal.jsx +7 -0
- package/packages/gui/src/components/lab/chat-playground.jsx +59 -51
- package/packages/gui/src/components/lab/lab-assistant.jsx +48 -48
- package/packages/gui/src/components/lab/metrics-panel.jsx +39 -38
- package/packages/gui/src/components/lab/parameter-panel.jsx +4 -5
- package/packages/gui/src/components/lab/preset-manager.jsx +11 -11
- package/packages/gui/src/components/lab/runtime-config.jsx +66 -62
- package/packages/gui/src/components/lab/system-prompt-editor.jsx +13 -13
- package/packages/gui/src/components/layout/breadcrumb-bar.jsx +1 -1
- package/packages/gui/src/components/preview/preview-workspace.jsx +62 -22
- package/packages/gui/src/components/ui/slider.jsx +16 -17
- package/packages/gui/src/components/ui/table-tree.jsx +38 -0
- package/packages/gui/src/stores/groove.js +23 -9
- package/packages/gui/src/views/editor.jsx +1 -1
- package/packages/gui/src/views/model-lab.jsx +101 -87
- package/plan_files/DELEGATE_YIELD_TRAINING_TAGS.md +135 -0
- package/plan_files/session-quality-rotation-fixes.md +218 -0
- package/test.py +571 -0
- package/node_modules/@groove-dev/gui/dist/assets/index-BgQL4bNl.css +0 -1
- package/packages/gui/dist/assets/index-BgQL4bNl.css +0 -1
- /package/{AGENT_ORCHESTRATION.md → plan_files/AGENT_ORCHESTRATION.md} +0 -0
- /package/{DYNAMIC_LEAF_ARCH.md → plan_files/DYNAMIC_LEAF_ARCH.md} +0 -0
- /package/{EMBEDDING_DIAGNOSTIC.md → plan_files/EMBEDDING_DIAGNOSTIC.md} +0 -0
- /package/{EMBEDDING_SERVICE_BUILD_PLAN.md → plan_files/EMBEDDING_SERVICE_BUILD_PLAN.md} +0 -0
- /package/{MOE_TRAINING_PIPELINE.md → plan_files/MOE_TRAINING_PIPELINE.md} +0 -0
|
@@ -220,6 +220,7 @@ export const useGrooveStore = create((set, get) => ({
|
|
|
220
220
|
}),
|
|
221
221
|
labSystemPrompt: localStorage.getItem('groove:labSystemPrompt') || '',
|
|
222
222
|
labStreaming: false,
|
|
223
|
+
labAbortController: null,
|
|
223
224
|
labLocalModels: [],
|
|
224
225
|
labLaunching: null,
|
|
225
226
|
labLlamaInstalled: null,
|
|
@@ -3501,6 +3502,9 @@ export const useGrooveStore = create((set, get) => ({
|
|
|
3501
3502
|
return { labSessions: sessions };
|
|
3502
3503
|
});
|
|
3503
3504
|
|
|
3505
|
+
const abortController = new AbortController();
|
|
3506
|
+
set({ labAbortController: abortController });
|
|
3507
|
+
|
|
3504
3508
|
const startTime = performance.now();
|
|
3505
3509
|
let firstTokenTime = null;
|
|
3506
3510
|
let tokenCount = 0;
|
|
@@ -3536,6 +3540,7 @@ export const useGrooveStore = create((set, get) => ({
|
|
|
3536
3540
|
method: 'POST',
|
|
3537
3541
|
headers: { 'Content-Type': 'application/json' },
|
|
3538
3542
|
body: JSON.stringify(body),
|
|
3543
|
+
signal: abortController.signal,
|
|
3539
3544
|
});
|
|
3540
3545
|
|
|
3541
3546
|
if (!res.ok) {
|
|
@@ -3639,20 +3644,29 @@ export const useGrooveStore = create((set, get) => ({
|
|
|
3639
3644
|
});
|
|
3640
3645
|
}
|
|
3641
3646
|
} catch (err) {
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3647
|
+
if (err.name === 'AbortError') {
|
|
3648
|
+
// User cancelled — keep whatever content was already streamed
|
|
3649
|
+
} else {
|
|
3650
|
+
set((s) => {
|
|
3651
|
+
const sessions = s.labSessions.map((sess) => {
|
|
3652
|
+
if (sess.id !== sessionId) return sess;
|
|
3653
|
+
const msgs = [...sess.messages];
|
|
3654
|
+
msgs[msgs.length - 1] = { ...msgs[msgs.length - 1], content: `Error: ${err.message}`, error: true };
|
|
3655
|
+
return { ...sess, messages: msgs };
|
|
3656
|
+
});
|
|
3657
|
+
return { labSessions: sessions };
|
|
3648
3658
|
});
|
|
3649
|
-
|
|
3650
|
-
});
|
|
3659
|
+
}
|
|
3651
3660
|
} finally {
|
|
3652
|
-
set({ labStreaming: false });
|
|
3661
|
+
set({ labStreaming: false, labAbortController: null });
|
|
3653
3662
|
}
|
|
3654
3663
|
},
|
|
3655
3664
|
|
|
3665
|
+
stopLabInference() {
|
|
3666
|
+
const ctrl = get().labAbortController;
|
|
3667
|
+
if (ctrl) ctrl.abort();
|
|
3668
|
+
},
|
|
3669
|
+
|
|
3656
3670
|
saveLabPreset(name) {
|
|
3657
3671
|
const st = get();
|
|
3658
3672
|
const preset = {
|
|
@@ -121,7 +121,7 @@ export default function EditorView() {
|
|
|
121
121
|
{sidebarCollapsed && (
|
|
122
122
|
<button
|
|
123
123
|
onClick={() => setSidebarCollapsed(false)}
|
|
124
|
-
className="flex-shrink-0 w-6 flex items-
|
|
124
|
+
className="flex-shrink-0 w-6 flex items-start justify-center pt-2 border-r border-border bg-surface-2 text-text-4 hover:text-text-0 hover:bg-surface-3 transition-colors cursor-pointer"
|
|
125
125
|
title="Show sidebar"
|
|
126
126
|
>
|
|
127
127
|
<PanelLeftOpen size={14} />
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import { useState, useCallback, useRef, useEffect } from 'react';
|
|
3
3
|
import { useGrooveStore } from '../stores/groove';
|
|
4
4
|
import { ScrollArea } from '../components/ui/scroll-area';
|
|
5
|
-
import { Badge } from '../components/ui/badge';
|
|
6
5
|
import { Tooltip } from '../components/ui/tooltip';
|
|
7
6
|
import { Combobox } from '../components/ui/combobox';
|
|
8
7
|
import { RuntimeConfig, LaunchModel } from '../components/lab/runtime-config';
|
|
@@ -13,7 +12,7 @@ import { LabAssistant } from '../components/lab/lab-assistant';
|
|
|
13
12
|
import { MetricsPanel } from '../components/lab/metrics-panel';
|
|
14
13
|
import { PresetManager } from '../components/lab/preset-manager';
|
|
15
14
|
import { cn } from '../lib/cn';
|
|
16
|
-
import { FlaskConical, PanelLeftOpen, PanelRightOpen, Box } from 'lucide-react';
|
|
15
|
+
import { FlaskConical, PanelLeftClose, PanelLeftOpen, PanelRightClose, PanelRightOpen, Box } from 'lucide-react';
|
|
17
16
|
|
|
18
17
|
const LEFT_DEFAULT = 280;
|
|
19
18
|
const LEFT_MIN = 220;
|
|
@@ -32,7 +31,7 @@ function ModelSelector() {
|
|
|
32
31
|
|
|
33
32
|
return (
|
|
34
33
|
<div className="space-y-1.5">
|
|
35
|
-
<span className="text-
|
|
34
|
+
<span className="text-2xs font-semibold font-sans text-text-3 uppercase tracking-wider">Model</span>
|
|
36
35
|
<Combobox
|
|
37
36
|
value={activeModel || ''}
|
|
38
37
|
onChange={setActiveModel}
|
|
@@ -53,15 +52,38 @@ function ModelSelector() {
|
|
|
53
52
|
);
|
|
54
53
|
}
|
|
55
54
|
|
|
56
|
-
function ResizeHandle({ onMouseDown
|
|
55
|
+
function ResizeHandle({ onMouseDown }) {
|
|
57
56
|
return (
|
|
58
57
|
<div
|
|
59
58
|
onMouseDown={onMouseDown}
|
|
60
|
-
className=
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
59
|
+
className="flex-shrink-0 w-[3px] cursor-col-resize group relative"
|
|
60
|
+
>
|
|
61
|
+
<div className="absolute inset-y-0 -left-1 -right-1" />
|
|
62
|
+
<div className="absolute inset-y-0 left-[1px] w-px bg-border group-hover:bg-accent/50 transition-colors" />
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function PanelToggle({ collapsed, onClick, side }) {
|
|
68
|
+
const Icon = side === 'left'
|
|
69
|
+
? (collapsed ? PanelLeftOpen : PanelLeftClose)
|
|
70
|
+
: (collapsed ? PanelRightOpen : PanelRightClose);
|
|
71
|
+
const label = side === 'left'
|
|
72
|
+
? (collapsed ? 'Show config' : 'Hide config')
|
|
73
|
+
: (collapsed ? 'Show metrics' : 'Hide metrics');
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<Tooltip content={label}>
|
|
77
|
+
<button
|
|
78
|
+
onClick={onClick}
|
|
79
|
+
className={cn(
|
|
80
|
+
'p-1 transition-colors cursor-pointer',
|
|
81
|
+
collapsed ? 'text-text-4 hover:text-text-1' : 'text-text-3 hover:text-text-1',
|
|
82
|
+
)}
|
|
83
|
+
>
|
|
84
|
+
<Icon size={14} />
|
|
85
|
+
</button>
|
|
86
|
+
</Tooltip>
|
|
65
87
|
);
|
|
66
88
|
}
|
|
67
89
|
|
|
@@ -130,93 +152,79 @@ export default function ModelLabView() {
|
|
|
130
152
|
|
|
131
153
|
return (
|
|
132
154
|
<div className="h-full flex flex-col bg-surface-0">
|
|
133
|
-
{/* Header */}
|
|
134
|
-
<div className="flex-shrink-0 flex items-center justify-between px-5 py-2.5 border-b border-border">
|
|
135
|
-
<div className="flex items-center gap-2.5">
|
|
136
|
-
<FlaskConical size={16} className="text-accent" />
|
|
137
|
-
<h1 className="text-sm font-bold font-sans text-text-0">Model Lab</h1>
|
|
138
|
-
<Badge variant="accent">Beta</Badge>
|
|
139
|
-
</div>
|
|
140
|
-
<div className="flex items-center gap-1">
|
|
141
|
-
<Tooltip content={leftCollapsed ? 'Show config panel' : 'Hide config panel'}>
|
|
142
|
-
<button
|
|
143
|
-
onClick={() => setLeftCollapsed(!leftCollapsed)}
|
|
144
|
-
className={cn(
|
|
145
|
-
'p-1.5 rounded-md transition-colors cursor-pointer',
|
|
146
|
-
leftCollapsed ? 'text-text-3 hover:text-accent hover:bg-accent/10' : 'text-accent bg-accent/10',
|
|
147
|
-
)}
|
|
148
|
-
>
|
|
149
|
-
<PanelLeftOpen size={14} />
|
|
150
|
-
</button>
|
|
151
|
-
</Tooltip>
|
|
152
|
-
<Tooltip content={rightCollapsed ? 'Show metrics panel' : 'Hide metrics panel'}>
|
|
153
|
-
<button
|
|
154
|
-
onClick={() => setRightCollapsed(!rightCollapsed)}
|
|
155
|
-
className={cn(
|
|
156
|
-
'p-1.5 rounded-md transition-colors cursor-pointer',
|
|
157
|
-
rightCollapsed ? 'text-text-3 hover:text-accent hover:bg-accent/10' : 'text-accent bg-accent/10',
|
|
158
|
-
)}
|
|
159
|
-
>
|
|
160
|
-
<PanelRightOpen size={14} />
|
|
161
|
-
</button>
|
|
162
|
-
</Tooltip>
|
|
163
|
-
</div>
|
|
164
|
-
</div>
|
|
165
|
-
|
|
166
155
|
{/* 3-panel layout */}
|
|
167
156
|
<div className="flex-1 flex min-h-0">
|
|
168
157
|
{/* Left panel — config */}
|
|
169
158
|
<div
|
|
170
159
|
className={cn(
|
|
171
|
-
'flex-shrink-0
|
|
172
|
-
leftCollapsed && 'w-0
|
|
160
|
+
'flex-shrink-0 transition-all duration-200 overflow-hidden',
|
|
161
|
+
leftCollapsed && 'w-0',
|
|
173
162
|
)}
|
|
174
163
|
style={leftCollapsed ? undefined : { width: leftWidth }}
|
|
175
164
|
>
|
|
176
|
-
<
|
|
177
|
-
<div className="
|
|
178
|
-
<
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
<
|
|
183
|
-
<div className="border-t border-border-subtle" />
|
|
184
|
-
<ParameterPanel />
|
|
185
|
-
<div className="border-t border-border-subtle" />
|
|
186
|
-
<PresetManager />
|
|
187
|
-
<div className="border-t border-border-subtle" />
|
|
188
|
-
<SystemPromptEditor />
|
|
165
|
+
<div className="h-full flex flex-col">
|
|
166
|
+
<div className="flex-shrink-0 flex items-center justify-between px-4 h-10">
|
|
167
|
+
<div className="flex items-center gap-2">
|
|
168
|
+
<FlaskConical size={13} className="text-accent" />
|
|
169
|
+
<span className="text-xs font-semibold font-sans text-text-1">Model Lab</span>
|
|
170
|
+
</div>
|
|
171
|
+
<PanelToggle collapsed={false} onClick={() => setLeftCollapsed(true)} side="left" />
|
|
189
172
|
</div>
|
|
190
|
-
|
|
173
|
+
<ScrollArea className="flex-1 min-h-0">
|
|
174
|
+
<div className="px-4 pb-4 space-y-5">
|
|
175
|
+
<LaunchModel />
|
|
176
|
+
<div className="h-px bg-border-subtle" />
|
|
177
|
+
<RuntimeConfig />
|
|
178
|
+
<div className="h-px bg-border-subtle" />
|
|
179
|
+
<ModelSelector />
|
|
180
|
+
<div className="h-px bg-border-subtle" />
|
|
181
|
+
<ParameterPanel />
|
|
182
|
+
<div className="h-px bg-border-subtle" />
|
|
183
|
+
<PresetManager />
|
|
184
|
+
<div className="h-px bg-border-subtle" />
|
|
185
|
+
<SystemPromptEditor />
|
|
186
|
+
</div>
|
|
187
|
+
</ScrollArea>
|
|
188
|
+
</div>
|
|
191
189
|
</div>
|
|
192
190
|
|
|
193
191
|
{!leftCollapsed && <ResizeHandle onMouseDown={onLeftMouseDown} />}
|
|
194
192
|
|
|
195
193
|
{/* Center panel — chat playground / assistant */}
|
|
196
194
|
<div className="flex-1 min-w-0 flex flex-col">
|
|
197
|
-
{
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
195
|
+
{/* Center header bar */}
|
|
196
|
+
<div className="flex-shrink-0 flex items-center h-10 px-3 gap-2">
|
|
197
|
+
{leftCollapsed && (
|
|
198
|
+
<PanelToggle collapsed onClick={() => setLeftCollapsed(false)} side="left" />
|
|
199
|
+
)}
|
|
200
|
+
{labAssistantAgentId && (
|
|
201
|
+
<div className="flex items-center gap-px bg-surface-2 rounded p-px">
|
|
202
|
+
<button
|
|
203
|
+
onClick={() => setLabAssistantMode(false)}
|
|
204
|
+
className={cn(
|
|
205
|
+
'px-3 py-1 text-2xs font-sans font-medium rounded-sm transition-colors cursor-pointer',
|
|
206
|
+
!labAssistantMode ? 'text-text-0 bg-surface-4' : 'text-text-3 hover:text-text-1',
|
|
207
|
+
)}
|
|
208
|
+
>
|
|
209
|
+
Playground
|
|
210
|
+
</button>
|
|
211
|
+
<button
|
|
212
|
+
onClick={() => setLabAssistantMode(true)}
|
|
213
|
+
className={cn(
|
|
214
|
+
'px-3 py-1 text-2xs font-sans font-medium rounded-sm transition-colors cursor-pointer',
|
|
215
|
+
labAssistantMode ? 'text-text-0 bg-surface-4' : 'text-text-3 hover:text-text-1',
|
|
216
|
+
)}
|
|
217
|
+
>
|
|
218
|
+
Assistant
|
|
219
|
+
</button>
|
|
220
|
+
</div>
|
|
221
|
+
)}
|
|
222
|
+
<div className="flex-1" />
|
|
223
|
+
{rightCollapsed && (
|
|
224
|
+
<PanelToggle collapsed onClick={() => setRightCollapsed(false)} side="right" />
|
|
225
|
+
)}
|
|
226
|
+
</div>
|
|
227
|
+
<div className="flex-1 min-h-0">
|
|
220
228
|
{labAssistantMode && labAssistantAgentId ? <LabAssistant /> : <ChatPlayground />}
|
|
221
229
|
</div>
|
|
222
230
|
</div>
|
|
@@ -226,16 +234,22 @@ export default function ModelLabView() {
|
|
|
226
234
|
{/* Right panel — metrics */}
|
|
227
235
|
<div
|
|
228
236
|
className={cn(
|
|
229
|
-
'flex-shrink-0
|
|
230
|
-
rightCollapsed && 'w-0
|
|
237
|
+
'flex-shrink-0 transition-all duration-200 overflow-hidden',
|
|
238
|
+
rightCollapsed && 'w-0',
|
|
231
239
|
)}
|
|
232
240
|
style={rightCollapsed ? undefined : { width: rightWidth }}
|
|
233
241
|
>
|
|
234
|
-
<
|
|
235
|
-
<div className="px-4
|
|
236
|
-
<
|
|
242
|
+
<div className="h-full flex flex-col">
|
|
243
|
+
<div className="flex-shrink-0 flex items-center justify-between px-4 h-10">
|
|
244
|
+
<span className="text-2xs font-semibold font-sans text-text-3 uppercase tracking-wider">Metrics</span>
|
|
245
|
+
<PanelToggle collapsed={false} onClick={() => setRightCollapsed(true)} side="right" />
|
|
237
246
|
</div>
|
|
238
|
-
|
|
247
|
+
<ScrollArea className="flex-1 min-h-0">
|
|
248
|
+
<div className="px-4 pb-4">
|
|
249
|
+
<MetricsPanel />
|
|
250
|
+
</div>
|
|
251
|
+
</ScrollArea>
|
|
252
|
+
</div>
|
|
239
253
|
</div>
|
|
240
254
|
</div>
|
|
241
255
|
</div>
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Groove Team: Delegate/Yield Tag Extraction from Planner Telemetry
|
|
2
|
+
|
|
3
|
+
## Context
|
|
4
|
+
|
|
5
|
+
The Hummingbird chassis is being trained on Groove planner telemetry data to learn orchestration — decomposing tasks, sequencing work, dispatching to specialists. The chassis already learns this well from the existing ReAct tag format (thought, action, observation, resolution).
|
|
6
|
+
|
|
7
|
+
We're adding two new coordination tags to the protocol:
|
|
8
|
+
|
|
9
|
+
| Tag | Purpose | Example |
|
|
10
|
+
|-----|---------|---------|
|
|
11
|
+
| `<delegate>` | "This needs a different specialist — re-route" | `<delegate>Create a PostgreSQL schema for user auth with sessions table</delegate>` |
|
|
12
|
+
| `<yield>` | "My part is done, here's my artifact for the next agent" | `<yield path="phase_01/api.py">Flask REST API with auth endpoints</yield>` |
|
|
13
|
+
|
|
14
|
+
The delegation behavior already exists in Groove planner sessions — it just isn't captured with these tags. Every time a planner agent reads `recommended-team.json` and dispatches work to a specialist agent, that's a delegation. Every time an agent produces an artifact that the next agent consumes, that's a yield.
|
|
15
|
+
|
|
16
|
+
## What We Need
|
|
17
|
+
|
|
18
|
+
### 1. Retroactive Tagging of Existing Planner Telemetry
|
|
19
|
+
|
|
20
|
+
Go through existing planner session trajectory_logs and identify two patterns:
|
|
21
|
+
|
|
22
|
+
**Pattern A — Delegation (dispatch to specialist):**
|
|
23
|
+
|
|
24
|
+
Look for sequences where the planner:
|
|
25
|
+
1. Reads `recommended-team.json` or `AGENTS_REGISTRY.md`
|
|
26
|
+
2. Reasons about which specialist to use (in a thought step)
|
|
27
|
+
3. Dispatches work to a specialist agent
|
|
28
|
+
|
|
29
|
+
The dispatch moment should become a `<delegate>` step. The content is the rewritten task — what the planner told the specialist to do.
|
|
30
|
+
|
|
31
|
+
Before (current format):
|
|
32
|
+
```json
|
|
33
|
+
{"step": 4, "type": "thought", "content": "This needs a backend specialist to implement the API endpoints..."}
|
|
34
|
+
{"step": 5, "type": "action", "tool": "Agent", "content": "Dispatch to backend-2: Implement REST endpoints for user authentication with JWT tokens and session management"}
|
|
35
|
+
{"step": 6, "type": "observation", "content": "Agent dispatched to backend-2"}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
After (with delegate tag):
|
|
39
|
+
```json
|
|
40
|
+
{"step": 4, "type": "thought", "content": "This needs a backend specialist to implement the API endpoints..."}
|
|
41
|
+
{"step": 5, "type": "delegate", "content": "Implement REST endpoints for user authentication with JWT tokens and session management"}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Key rules:
|
|
45
|
+
- The delegate content is the TASK, not "dispatch to backend-2." The delegating agent doesn't choose the target — the router does.
|
|
46
|
+
- Strip any agent ID references (backend-2, fullstack-7, etc.) from the content — just the task description.
|
|
47
|
+
- The thought step before the delegate should contain the reasoning about WHY this needs a different specialist.
|
|
48
|
+
- A delegate is a terminal step — it replaces resolution. Nothing comes after it in that firing.
|
|
49
|
+
|
|
50
|
+
**Pattern B — Yield (artifact handoff):**
|
|
51
|
+
|
|
52
|
+
Look for sequences where an agent:
|
|
53
|
+
1. Produces a file or artifact (Write, Edit)
|
|
54
|
+
2. That artifact is subsequently read by a different agent in the same pipeline
|
|
55
|
+
|
|
56
|
+
The artifact production should become a `<yield>` step.
|
|
57
|
+
|
|
58
|
+
Before (current format):
|
|
59
|
+
```json
|
|
60
|
+
{"step": 7, "type": "action", "tool": "Write", "content": "Writing api.py with Flask endpoints..."}
|
|
61
|
+
{"step": 8, "type": "observation", "content": "File written successfully"}
|
|
62
|
+
{"step": 9, "type": "resolution", "content": "API endpoints implemented. The backend agent can now build on this."}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
After (with yield tag):
|
|
66
|
+
```json
|
|
67
|
+
{"step": 7, "type": "action", "tool": "Write", "content": "Writing api.py with Flask endpoints..."}
|
|
68
|
+
{"step": 8, "type": "observation", "content": "File written successfully"}
|
|
69
|
+
{"step": 9, "type": "yield", "content": "Flask REST API with auth endpoints", "path": "api.py"}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Key rules:
|
|
73
|
+
- The yield content is a SHORT summary (~10-20 tokens) of what the artifact is — enough for the next agent's prompt.
|
|
74
|
+
- The path field is the file path of the artifact.
|
|
75
|
+
- A yield is a terminal step — it replaces resolution. The agent's work is done; the next agent picks up.
|
|
76
|
+
- Only tag as yield if another agent actually consumed the artifact. If the agent resolved directly to the user, keep it as resolution.
|
|
77
|
+
|
|
78
|
+
### 2. Step Format
|
|
79
|
+
|
|
80
|
+
Both new step types follow the same shape as existing steps:
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"step": 5,
|
|
85
|
+
"type": "delegate",
|
|
86
|
+
"content": "The rewritten task for the next specialist",
|
|
87
|
+
"timestamp": 1777412000.5,
|
|
88
|
+
"token_count": 15
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"step": 9,
|
|
95
|
+
"type": "yield",
|
|
96
|
+
"content": "Short artifact summary",
|
|
97
|
+
"path": "phase_01/output_file.py",
|
|
98
|
+
"timestamp": 1777412001.2,
|
|
99
|
+
"token_count": 8
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
They flow through the same `_processStep -> EnvelopeBuilder.addStep -> envelope -> Central Command` path as all other steps.
|
|
104
|
+
|
|
105
|
+
### 3. Future Telemetry Capture
|
|
106
|
+
|
|
107
|
+
Once nano agents are running and producing `<delegate>` and `<yield>` tags in their output, the chassis parser should emit these as step objects into the trajectory capture:
|
|
108
|
+
|
|
109
|
+
- When parser sees `<delegate>task</delegate>` → emit `{"type": "delegate", "content": "task"}`
|
|
110
|
+
- When parser sees `<yield path="...">summary</yield>` → emit `{"type": "yield", "content": "summary", "path": "..."}`
|
|
111
|
+
|
|
112
|
+
Same as how the current parser emits thought/action/observation/resolution steps.
|
|
113
|
+
|
|
114
|
+
### 4. What NOT to Do
|
|
115
|
+
|
|
116
|
+
- Do NOT add empty delegate/yield steps to sessions where they don't occur. If a session resolves normally, it ends with resolution. The absence of delegate/yield is correct.
|
|
117
|
+
- Do NOT change the thought or resolution content. Only add/modify the terminal step (replacing resolution with delegate or yield where the pattern matches).
|
|
118
|
+
- Do NOT invent delegation where it didn't happen. Only tag real dispatch-to-specialist moments.
|
|
119
|
+
|
|
120
|
+
### 5. Output
|
|
121
|
+
|
|
122
|
+
Deliver the retroactively tagged sessions as:
|
|
123
|
+
- Same JSONL format as current planner telemetry
|
|
124
|
+
- Same file location (ingestion/ directory)
|
|
125
|
+
- Filename convention: `2026-05-09-planner-delegated-{hash}.jsonl` or similar
|
|
126
|
+
|
|
127
|
+
We'll run these through the standard `build_production_data.py` pipeline.
|
|
128
|
+
|
|
129
|
+
### 6. Estimated Yield
|
|
130
|
+
|
|
131
|
+
From the 139 organic planner sessions currently in the training set:
|
|
132
|
+
- Most sessions involve at least one specialist dispatch → expect 80-120 delegate examples
|
|
133
|
+
- Many multi-agent sessions involve artifact handoffs → expect 40-80 yield examples
|
|
134
|
+
|
|
135
|
+
This organic data is highest quality — real frontier model orchestration decisions. It sets the standard that our synthetic generation will match.
|