groove-dev 0.27.196 → 0.27.197

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.
Files changed (68) hide show
  1. package/node_modules/@groove-dev/cli/package.json +1 -1
  2. package/node_modules/@groove-dev/daemon/package.json +1 -1
  3. package/node_modules/@groove-dev/daemon/src/api.js +3 -5
  4. package/node_modules/@groove-dev/daemon/src/chatstore.js +104 -0
  5. package/node_modules/@groove-dev/daemon/src/index.js +3 -2
  6. package/node_modules/@groove-dev/daemon/src/process.js +1 -1
  7. package/node_modules/@groove-dev/daemon/src/routes/agents.js +1 -175
  8. package/node_modules/@groove-dev/daemon/src/routes/chat-history.js +34 -0
  9. package/node_modules/@groove-dev/daemon/test/chatstore.test.js +86 -0
  10. package/node_modules/@groove-dev/gui/dist/assets/index-Da2nbd6M.js +1043 -0
  11. package/node_modules/@groove-dev/gui/dist/assets/index-zmrIbwNm.css +1 -0
  12. package/node_modules/@groove-dev/gui/dist/index.html +2 -2
  13. package/node_modules/@groove-dev/gui/package.json +1 -1
  14. package/node_modules/@groove-dev/gui/src/App.jsx +0 -2
  15. package/node_modules/@groove-dev/gui/src/components/agents/agent-config.jsx +2 -2
  16. package/node_modules/@groove-dev/gui/src/components/agents/spawn-wizard.jsx +3 -3
  17. package/node_modules/@groove-dev/gui/src/components/layout/activity-bar.jsx +2 -3
  18. package/node_modules/@groove-dev/gui/src/components/layout/breadcrumb-bar.jsx +1 -1
  19. package/node_modules/@groove-dev/gui/src/components/layout/command-palette.jsx +1 -1
  20. package/node_modules/@groove-dev/gui/src/stores/groove.js +5 -163
  21. package/node_modules/@groove-dev/gui/src/stores/slices/agents-slice.js +52 -2
  22. package/node_modules/@groove-dev/gui/src/views/marketplace.jsx +1 -1
  23. package/node_modules/@groove-dev/gui/src/views/settings.jsx +0 -61
  24. package/package.json +1 -1
  25. package/packages/cli/package.json +1 -1
  26. package/packages/daemon/package.json +1 -1
  27. package/packages/daemon/src/api.js +3 -5
  28. package/packages/daemon/src/chatstore.js +104 -0
  29. package/packages/daemon/src/index.js +3 -2
  30. package/packages/daemon/src/process.js +1 -1
  31. package/packages/daemon/src/routes/agents.js +1 -175
  32. package/packages/daemon/src/routes/chat-history.js +34 -0
  33. package/packages/gui/dist/assets/index-Da2nbd6M.js +1043 -0
  34. package/packages/gui/dist/assets/index-zmrIbwNm.css +1 -0
  35. package/packages/gui/dist/index.html +2 -2
  36. package/packages/gui/package.json +1 -1
  37. package/packages/gui/src/App.jsx +0 -2
  38. package/packages/gui/src/components/agents/agent-config.jsx +2 -2
  39. package/packages/gui/src/components/agents/spawn-wizard.jsx +3 -3
  40. package/packages/gui/src/components/layout/activity-bar.jsx +2 -3
  41. package/packages/gui/src/components/layout/breadcrumb-bar.jsx +1 -1
  42. package/packages/gui/src/components/layout/command-palette.jsx +1 -1
  43. package/packages/gui/src/stores/groove.js +5 -163
  44. package/packages/gui/src/stores/slices/agents-slice.js +52 -2
  45. package/packages/gui/src/views/marketplace.jsx +1 -1
  46. package/packages/gui/src/views/settings.jsx +0 -61
  47. package/node_modules/@groove-dev/daemon/src/conversations.js +0 -576
  48. package/node_modules/@groove-dev/gui/dist/assets/index-Cat5pJUx.css +0 -1
  49. package/node_modules/@groove-dev/gui/dist/assets/index-L8xSnvHj.js +0 -1070
  50. package/node_modules/@groove-dev/gui/src/components/chat/chat-header.jsx +0 -198
  51. package/node_modules/@groove-dev/gui/src/components/chat/chat-input.jsx +0 -367
  52. package/node_modules/@groove-dev/gui/src/components/chat/chat-messages.jsx +0 -527
  53. package/node_modules/@groove-dev/gui/src/components/chat/chat-view.jsx +0 -212
  54. package/node_modules/@groove-dev/gui/src/components/chat/conversation-list.jsx +0 -163
  55. package/node_modules/@groove-dev/gui/src/components/chat/model-picker.jsx +0 -201
  56. package/node_modules/@groove-dev/gui/src/stores/slices/chat-slice.js +0 -227
  57. package/node_modules/@groove-dev/gui/src/views/chat.jsx +0 -6
  58. package/packages/daemon/src/conversations.js +0 -576
  59. package/packages/gui/dist/assets/index-Cat5pJUx.css +0 -1
  60. package/packages/gui/dist/assets/index-L8xSnvHj.js +0 -1070
  61. package/packages/gui/src/components/chat/chat-header.jsx +0 -198
  62. package/packages/gui/src/components/chat/chat-input.jsx +0 -367
  63. package/packages/gui/src/components/chat/chat-messages.jsx +0 -527
  64. package/packages/gui/src/components/chat/chat-view.jsx +0 -212
  65. package/packages/gui/src/components/chat/conversation-list.jsx +0 -163
  66. package/packages/gui/src/components/chat/model-picker.jsx +0 -201
  67. package/packages/gui/src/stores/slices/chat-slice.js +0 -227
  68. package/packages/gui/src/views/chat.jsx +0 -6
@@ -2,9 +2,8 @@
2
2
 
3
3
  import { resolve } from 'path';
4
4
  import { existsSync, readFileSync, readdirSync, statSync, writeFileSync, mkdirSync } from 'fs';
5
- import { validateAgentConfig, validateReasoningEffort, validateVerbosity } from '../validate.js';
5
+ import { validateAgentConfig } from '../validate.js';
6
6
  import { ROLE_INTEGRATIONS, wrapWithRoleReminder } from '../process.js';
7
- import { getProvider } from '../providers/index.js';
8
7
  import { deliverInstruction } from '../deliver.js';
9
8
  import { renameAgent } from '../rename.js';
10
9
 
@@ -218,179 +217,6 @@ export function registerAgentRoutes(app, daemon) {
218
217
  res.json(suggestion);
219
218
  });
220
219
 
221
- // --- Conversations ---
222
-
223
- app.get('/api/conversations', (req, res) => {
224
- res.json({ conversations: daemon.conversations.list() });
225
- });
226
-
227
- app.post('/api/conversations', async (req, res) => {
228
- try {
229
- const { provider, model, title, mode, reasoning_effort, verbosity } = req.body;
230
- if (provider && typeof provider !== 'string') {
231
- return res.status(400).json({ error: 'provider must be a string' });
232
- }
233
- if (mode && mode !== 'api' && mode !== 'agent') {
234
- return res.status(400).json({ error: 'mode must be "api" or "agent"' });
235
- }
236
- const validatedEffort = validateReasoningEffort(reasoning_effort);
237
- const validatedVerbosity = validateVerbosity(verbosity);
238
- const conversation = await daemon.conversations.create(provider, model, title, mode || 'api', {
239
- reasoningEffort: validatedEffort,
240
- verbosity: validatedVerbosity,
241
- });
242
- daemon.audit.log('conversation.create', { id: conversation.id, provider, model, mode: conversation.mode });
243
- res.status(201).json(conversation);
244
- } catch (err) {
245
- res.status(400).json({ error: err.message });
246
- }
247
- });
248
-
249
- app.get('/api/conversations/:id', (req, res) => {
250
- const conversation = daemon.conversations.get(req.params.id);
251
- if (!conversation) return res.status(404).json({ error: 'Conversation not found' });
252
- res.json(conversation);
253
- });
254
-
255
- app.patch('/api/conversations/:id', async (req, res) => {
256
- try {
257
- const conv = daemon.conversations.get(req.params.id);
258
- if (!conv) return res.status(404).json({ error: 'Conversation not found' });
259
- if (req.body.title !== undefined) daemon.conversations.rename(req.params.id, req.body.title);
260
- if (req.body.pinned !== undefined) daemon.conversations.pin(req.params.id, req.body.pinned);
261
- if (req.body.archived !== undefined) daemon.conversations.archive(req.params.id, req.body.archived);
262
- if (req.body.model !== undefined || req.body.provider !== undefined) {
263
- const newProvider = req.body.provider || conv.provider;
264
- const newModel = req.body.model || conv.model;
265
- daemon.conversations.updateModel(req.params.id, newProvider, newModel);
266
- }
267
- if (req.body.mode !== undefined) {
268
- if (req.body.mode !== 'api' && req.body.mode !== 'agent') {
269
- return res.status(400).json({ error: 'mode must be "api" or "agent"' });
270
- }
271
- await daemon.conversations.setMode(req.params.id, req.body.mode);
272
- }
273
- if (req.body.reasoning_effort !== undefined || req.body.verbosity !== undefined) {
274
- const validatedEffort = req.body.reasoning_effort !== undefined ? validateReasoningEffort(req.body.reasoning_effort) : undefined;
275
- const validatedVerbosity = req.body.verbosity !== undefined ? validateVerbosity(req.body.verbosity) : undefined;
276
- daemon.conversations.updateReasoningSettings(req.params.id, validatedEffort, validatedVerbosity);
277
- }
278
- daemon.audit.log('conversation.update', { id: req.params.id, provider: req.body.provider, model: req.body.model, mode: req.body.mode });
279
- res.json(daemon.conversations.get(req.params.id));
280
- } catch (err) {
281
- res.status(400).json({ error: err.message });
282
- }
283
- });
284
-
285
- app.delete('/api/conversations/:id', async (req, res) => {
286
- try {
287
- const conv = daemon.conversations.get(req.params.id);
288
- if (!conv) return res.status(404).json({ error: 'Conversation not found' });
289
- await daemon.conversations.delete(req.params.id);
290
- daemon.audit.log('conversation.delete', { id: req.params.id });
291
- res.json({ ok: true });
292
- } catch (err) {
293
- res.status(400).json({ error: err.message });
294
- }
295
- });
296
-
297
- app.post('/api/conversations/:id/message', async (req, res) => {
298
- try {
299
- const { message, history, reasoning_effort, verbosity } = req.body;
300
- if (!message || typeof message !== 'string' || !message.trim()) {
301
- return res.status(400).json({ error: 'message is required' });
302
- }
303
- const validatedEffort = validateReasoningEffort(reasoning_effort);
304
- const validatedVerbosity = validateVerbosity(verbosity);
305
-
306
- const conv = daemon.conversations.get(req.params.id);
307
- if (!conv) return res.status(404).json({ error: 'Conversation not found' });
308
-
309
- daemon.conversations.autoTitle(req.params.id, message.trim());
310
- daemon.conversations.touchUpdatedAt(req.params.id);
311
-
312
- await daemon.conversations.sendMessage(req.params.id, message.trim(), history || [], {
313
- reasoningEffort: validatedEffort,
314
- verbosity: validatedVerbosity,
315
- });
316
- daemon.audit.log('conversation.message', { id: req.params.id, mode: conv.mode || 'api' });
317
- res.json({ status: 'streaming', mode: conv.mode || 'api' });
318
- } catch (err) {
319
- res.status(400).json({ error: err.message });
320
- }
321
- });
322
-
323
- app.post('/api/conversations/:id/stop', (req, res) => {
324
- try {
325
- const conv = daemon.conversations.get(req.params.id);
326
- if (!conv) return res.status(404).json({ error: 'Conversation not found' });
327
- daemon.conversations.stopStreaming(req.params.id);
328
- res.json({ ok: true });
329
- } catch (err) {
330
- res.status(400).json({ error: err.message });
331
- }
332
- });
333
-
334
- // --- Image Generation ---
335
-
336
- app.post('/api/conversations/:id/generate-image', async (req, res) => {
337
- try {
338
- const { prompt, model, size, quality } = req.body;
339
- if (!prompt || typeof prompt !== 'string' || !prompt.trim()) {
340
- return res.status(400).json({ error: 'prompt is required' });
341
- }
342
- const conv = daemon.conversations.get(req.params.id);
343
- if (!conv) return res.status(404).json({ error: 'Conversation not found' });
344
-
345
- let providerName = conv.provider;
346
- let provider = getProvider(providerName);
347
-
348
- // If a specific image model was requested, find the right provider
349
- if (model) {
350
- const imageProviders = ['codex', 'grok', 'nano-banana'];
351
- for (const pid of imageProviders) {
352
- const p = getProvider(pid);
353
- if (p?.constructor.models.some((m) => m.id === model)) {
354
- provider = p;
355
- providerName = pid;
356
- break;
357
- }
358
- }
359
- }
360
-
361
- if (!provider?.generateImage) {
362
- return res.status(400).json({ error: 'Provider does not support image generation' });
363
- }
364
-
365
- const apiKey = daemon.conversations._getApiKey(providerName);
366
- if (!apiKey) {
367
- return res.status(400).json({ error: `No API key configured for ${providerName}` });
368
- }
369
-
370
- daemon.broadcast({
371
- type: 'conversation:image-progress',
372
- data: { conversationId: req.params.id, status: 'generating', prompt: prompt.trim() },
373
- });
374
-
375
- const result = await provider.generateImage(prompt.trim(), { model, size, quality, apiKey });
376
-
377
- daemon.broadcast({
378
- type: 'conversation:image',
379
- data: { conversationId: req.params.id, ...result, prompt: prompt.trim() },
380
- });
381
-
382
- daemon.conversations.touchUpdatedAt(req.params.id);
383
- daemon.audit.log('conversation.image', { id: req.params.id, model: result.model, provider: result.provider });
384
- res.json(result);
385
- } catch (err) {
386
- daemon.broadcast({
387
- type: 'conversation:image-progress',
388
- data: { conversationId: req.params.id, status: 'error', error: err.message },
389
- });
390
- res.status(500).json({ error: err.message });
391
- }
392
- });
393
-
394
220
  // Stop an agent's current work without killing the agent
395
221
  app.post('/api/agents/:id/stop', async (req, res) => {
396
222
  try {
@@ -0,0 +1,34 @@
1
+ // FSL-1.1-Apache-2.0 — see LICENSE
2
+
3
+ export function registerChatHistoryRoutes(app, daemon) {
4
+ // Full history for all agents — the GUI loads this on connect so chats are
5
+ // present regardless of which origin/port the tunnel came up on.
6
+ app.get('/api/chat-history', (req, res) => {
7
+ res.json({ history: daemon.chatStore.getAll() });
8
+ });
9
+
10
+ // Append a single message for an agent.
11
+ app.post('/api/chat-history/:agentId', (req, res) => {
12
+ const { message } = req.body || {};
13
+ if (!message || typeof message !== 'object') {
14
+ return res.status(400).json({ error: 'message object required' });
15
+ }
16
+ daemon.chatStore.append(req.params.agentId, message);
17
+ res.json({ ok: true });
18
+ });
19
+
20
+ // Replace an agent's whole history (batch sync).
21
+ app.put('/api/chat-history/:agentId', (req, res) => {
22
+ const { messages } = req.body || {};
23
+ if (!Array.isArray(messages)) {
24
+ return res.status(400).json({ error: 'messages array required' });
25
+ }
26
+ daemon.chatStore.replace(req.params.agentId, messages);
27
+ res.json({ ok: true });
28
+ });
29
+
30
+ app.delete('/api/chat-history/:agentId', (req, res) => {
31
+ daemon.chatStore.remove(req.params.agentId);
32
+ res.json({ ok: true });
33
+ });
34
+ }