groove-dev 0.27.89 → 0.27.91
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/parsers/claude-code.js +0 -2
- package/moe-training/client/session-attestation.js +2 -1
- package/moe-training/client/trajectory-capture.js +6 -0
- package/moe-training/test/client/parsers/claude-code.test.js +2 -2
- 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 +16 -9
- package/node_modules/@groove-dev/daemon/src/conversations.js +32 -6
- package/node_modules/@groove-dev/daemon/src/providers/claude-code.js +1 -1
- package/node_modules/@groove-dev/daemon/src/providers/codex.js +1 -1
- package/node_modules/@groove-dev/daemon/src/providers/gemini.js +1 -1
- package/node_modules/@groove-dev/daemon/src/providers/grok.js +2 -2
- package/node_modules/@groove-dev/gui/dist/assets/{index-BKD8JAsV.js → index-MLIZRMj1.js} +1 -1
- package/node_modules/@groove-dev/gui/dist/index.html +1 -1
- package/node_modules/@groove-dev/gui/package.json +1 -1
- package/node_modules/@groove-dev/gui/src/components/chat/chat-view.jsx +1 -3
- 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 +16 -9
- package/packages/daemon/src/conversations.js +32 -6
- package/packages/daemon/src/providers/claude-code.js +1 -1
- package/packages/daemon/src/providers/codex.js +1 -1
- package/packages/daemon/src/providers/gemini.js +1 -1
- package/packages/daemon/src/providers/grok.js +2 -2
- package/packages/gui/dist/assets/{index-BKD8JAsV.js → index-MLIZRMj1.js} +1 -1
- package/packages/gui/dist/index.html +1 -1
- package/packages/gui/package.json +1 -1
- package/packages/gui/src/components/chat/chat-view.jsx +1 -3
|
@@ -30,7 +30,6 @@ export class ClaudeCodeParser {
|
|
|
30
30
|
results.push({
|
|
31
31
|
type: 'thought',
|
|
32
32
|
content: block.text || '',
|
|
33
|
-
token_count: jsonEvent.message?.usage?.output_tokens || 0,
|
|
34
33
|
});
|
|
35
34
|
} else if (block.type === 'tool_use') {
|
|
36
35
|
this._pendingToolUse.set(block.id, block);
|
|
@@ -67,7 +66,6 @@ export class ClaudeCodeParser {
|
|
|
67
66
|
return {
|
|
68
67
|
type: 'resolution',
|
|
69
68
|
content: typeof jsonEvent.result === 'string' ? jsonEvent.result : JSON.stringify(jsonEvent.result),
|
|
70
|
-
token_count: jsonEvent.total_tokens_used || 0,
|
|
71
69
|
};
|
|
72
70
|
}
|
|
73
71
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { platform, arch, cpus, totalmem, hostname, release, endianness } from 'node:os';
|
|
4
4
|
import { createHash } from 'node:crypto';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
5
6
|
import { generateECDHKeypair, deriveSharedSecret, signEnvelope, computeAppHash } from '../shared/crypto.js';
|
|
6
7
|
|
|
7
8
|
export class SessionAttestation {
|
|
@@ -14,7 +15,7 @@ export class SessionAttestation {
|
|
|
14
15
|
const keypair = generateECDHKeypair();
|
|
15
16
|
let appVersionHash = '';
|
|
16
17
|
try {
|
|
17
|
-
appVersionHash = computeAppHash(
|
|
18
|
+
appVersionHash = computeAppHash(fileURLToPath(import.meta.url));
|
|
18
19
|
} catch {
|
|
19
20
|
appVersionHash = 'unknown';
|
|
20
21
|
}
|
|
@@ -172,6 +172,12 @@ export class TrajectoryCapture {
|
|
|
172
172
|
ev.arguments = this._scrubObject(ev.arguments);
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
+
if (!ev.token_count || ev.token_count < 2) {
|
|
176
|
+
const text = ev.content || '';
|
|
177
|
+
const argsLen = ev.arguments ? JSON.stringify(ev.arguments).length : 0;
|
|
178
|
+
ev.token_count = Math.max(1, Math.ceil((text.length + argsLen) / 4));
|
|
179
|
+
}
|
|
180
|
+
|
|
175
181
|
const step = {
|
|
176
182
|
step: ++ctx.stepCount,
|
|
177
183
|
type: ev.type,
|
|
@@ -17,7 +17,7 @@ describe('ClaudeCodeParser', () => {
|
|
|
17
17
|
const result = parser.parseEvent(event);
|
|
18
18
|
assert.equal(result.type, 'thought');
|
|
19
19
|
assert.equal(result.content, 'I need to fix the bug');
|
|
20
|
-
assert.equal(result.token_count,
|
|
20
|
+
assert.equal(result.token_count, undefined);
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
it('parses tool_use block as action', () => {
|
|
@@ -79,7 +79,7 @@ describe('ClaudeCodeParser', () => {
|
|
|
79
79
|
const result = parser.parseEvent(event);
|
|
80
80
|
assert.equal(result.type, 'resolution');
|
|
81
81
|
assert.equal(result.content, 'Task completed successfully');
|
|
82
|
-
assert.equal(result.token_count,
|
|
82
|
+
assert.equal(result.token_count, undefined);
|
|
83
83
|
});
|
|
84
84
|
|
|
85
85
|
it('extracts tokens from assistant event', () => {
|
|
@@ -1115,8 +1115,8 @@ export function createApi(app, daemon) {
|
|
|
1115
1115
|
app.post('/api/conversations', async (req, res) => {
|
|
1116
1116
|
try {
|
|
1117
1117
|
const { provider, model, title, mode, reasoning_effort, verbosity } = req.body;
|
|
1118
|
-
if (
|
|
1119
|
-
return res.status(400).json({ error: 'provider
|
|
1118
|
+
if (provider && typeof provider !== 'string') {
|
|
1119
|
+
return res.status(400).json({ error: 'provider must be a string' });
|
|
1120
1120
|
}
|
|
1121
1121
|
if (mode && mode !== 'api' && mode !== 'agent') {
|
|
1122
1122
|
return res.status(400).json({ error: 'mode must be "api" or "agent"' });
|
|
@@ -4504,8 +4504,10 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4504
4504
|
}
|
|
4505
4505
|
|
|
4506
4506
|
daemon.config.defaultProvider = provider;
|
|
4507
|
+
daemon.config.defaultChatProvider = provider;
|
|
4507
4508
|
if (model && typeof model === 'string' && model.length <= 100) {
|
|
4508
4509
|
daemon.config.defaultModel = model.trim();
|
|
4510
|
+
daemon.config.defaultChatModel = model.trim();
|
|
4509
4511
|
}
|
|
4510
4512
|
const { saveConfig } = await import('./firstrun.js');
|
|
4511
4513
|
saveConfig(daemon.grooveDir, daemon.config);
|
|
@@ -4537,15 +4539,20 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4537
4539
|
saveConfig(daemon.grooveDir, daemon.config);
|
|
4538
4540
|
|
|
4539
4541
|
if (enabled) {
|
|
4540
|
-
const userId = ConsentManager.getOrCreateUserId();
|
|
4541
|
-
const consent = new ConsentManager();
|
|
4542
4542
|
try {
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4543
|
+
const userId = ConsentManager.getOrCreateUserId();
|
|
4544
|
+
const consent = new ConsentManager();
|
|
4545
|
+
try {
|
|
4546
|
+
consent.recordConsent(userId, true, '1.0');
|
|
4547
|
+
} finally {
|
|
4548
|
+
consent.close();
|
|
4549
|
+
}
|
|
4550
|
+
await daemon._initTrajectoryCapture();
|
|
4551
|
+
daemon.state.set('training_enrolled_at', new Date().toISOString());
|
|
4552
|
+
} catch (e) {
|
|
4553
|
+
daemon.config.training_opt_in = false;
|
|
4554
|
+
return res.status(500).json({ error: 'Failed to enable data sharing', detail: e.message });
|
|
4546
4555
|
}
|
|
4547
|
-
await daemon._initTrajectoryCapture();
|
|
4548
|
-
daemon.state.set('training_enrolled_at', new Date().toISOString());
|
|
4549
4556
|
} else {
|
|
4550
4557
|
if (daemon.trajectoryCapture) {
|
|
4551
4558
|
try { await daemon.trajectoryCapture.shutdown(); } catch (e) { /* */ }
|
|
@@ -55,6 +55,22 @@ export class ConversationManager {
|
|
|
55
55
|
return null;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
_resolveAutoProviderModel(preferredProvider) {
|
|
59
|
+
const priority = ['claude-code', 'codex', 'gemini', 'grok', 'ollama'];
|
|
60
|
+
const candidates = preferredProvider ? [preferredProvider] : priority;
|
|
61
|
+
|
|
62
|
+
for (const pid of candidates) {
|
|
63
|
+
if (!isProviderInstalled(pid)) continue;
|
|
64
|
+
const p = getProvider(pid);
|
|
65
|
+
if (!p) continue;
|
|
66
|
+
const models = p.constructor.models || [];
|
|
67
|
+
const chatModel = models.find((m) => m.type !== 'image') || models[0];
|
|
68
|
+
if (chatModel) return { provider: pid, model: chatModel.id };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return { provider: 'claude-code', model: 'claude-sonnet-4-6' };
|
|
72
|
+
}
|
|
73
|
+
|
|
58
74
|
async create(provider, model, title, mode = 'api', options = {}) {
|
|
59
75
|
if (!provider && this.daemon.config?.defaultChatProvider) {
|
|
60
76
|
provider = this.daemon.config.defaultChatProvider;
|
|
@@ -63,6 +79,12 @@ export class ConversationManager {
|
|
|
63
79
|
model = this.daemon.config.defaultChatModel;
|
|
64
80
|
}
|
|
65
81
|
|
|
82
|
+
if (!provider || !model) {
|
|
83
|
+
const resolved = this._resolveAutoProviderModel(provider);
|
|
84
|
+
if (!provider) provider = resolved.provider;
|
|
85
|
+
if (!model) model = resolved.model;
|
|
86
|
+
}
|
|
87
|
+
|
|
66
88
|
const id = randomUUID().slice(0, 12);
|
|
67
89
|
const now = new Date().toISOString();
|
|
68
90
|
|
|
@@ -328,12 +350,16 @@ export class ConversationManager {
|
|
|
328
350
|
let providerName = conv.provider;
|
|
329
351
|
|
|
330
352
|
if (!provider || !isProviderInstalled(conv.provider)) {
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
if (!
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
353
|
+
const resolved = this._resolveAutoProviderModel(null);
|
|
354
|
+
provider = getProvider(resolved.provider);
|
|
355
|
+
if (!provider) throw new Error('No provider available for chat');
|
|
356
|
+
providerName = resolved.provider;
|
|
357
|
+
modelId = resolved.model;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (!modelId) {
|
|
361
|
+
const resolved = this._resolveAutoProviderModel(providerName);
|
|
362
|
+
modelId = resolved.model;
|
|
337
363
|
}
|
|
338
364
|
|
|
339
365
|
// Build messages array for direct API call
|
|
@@ -282,7 +282,7 @@ export class ClaudeCodeProvider extends Provider {
|
|
|
282
282
|
let finished = false;
|
|
283
283
|
const finish = () => { if (!finished) { finished = true; onDone(); } };
|
|
284
284
|
const body = JSON.stringify({
|
|
285
|
-
model
|
|
285
|
+
model,
|
|
286
286
|
messages,
|
|
287
287
|
max_tokens: 8192,
|
|
288
288
|
stream: true,
|
|
@@ -163,7 +163,7 @@ export class CodexProvider extends Provider {
|
|
|
163
163
|
const effort = reasoningEffort || 'medium';
|
|
164
164
|
const verb = verbosity || 'medium';
|
|
165
165
|
const body = {
|
|
166
|
-
model
|
|
166
|
+
model,
|
|
167
167
|
input: previousResponseId ? [messages[messages.length - 1]] : messages,
|
|
168
168
|
stream: true,
|
|
169
169
|
reasoning: { effort },
|
|
@@ -94,7 +94,7 @@ export class GeminiProvider extends Provider {
|
|
|
94
94
|
const controller = new AbortController();
|
|
95
95
|
let finished = false;
|
|
96
96
|
const finish = () => { if (!finished) { finished = true; onDone(); } };
|
|
97
|
-
const m = model
|
|
97
|
+
const m = model;
|
|
98
98
|
const contents = messages.map((msg) => ({
|
|
99
99
|
role: msg.role === 'assistant' ? 'model' : 'user',
|
|
100
100
|
parts: [{ text: msg.content }],
|
|
@@ -58,7 +58,7 @@ export class GrokProvider extends Provider {
|
|
|
58
58
|
getLoopConfig(agent) {
|
|
59
59
|
return {
|
|
60
60
|
apiBase: 'https://api.x.ai/v1',
|
|
61
|
-
model: agent.model
|
|
61
|
+
model: agent.model,
|
|
62
62
|
contextWindow: 131072,
|
|
63
63
|
temperature: 0.1,
|
|
64
64
|
maxResponseTokens: 16384,
|
|
@@ -97,7 +97,7 @@ export class GrokProvider extends Provider {
|
|
|
97
97
|
'Content-Type': 'application/json',
|
|
98
98
|
},
|
|
99
99
|
body: JSON.stringify({
|
|
100
|
-
model
|
|
100
|
+
model,
|
|
101
101
|
messages,
|
|
102
102
|
stream: true,
|
|
103
103
|
}),
|