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.
- 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 +3 -5
- package/node_modules/@groove-dev/daemon/src/chatstore.js +104 -0
- package/node_modules/@groove-dev/daemon/src/index.js +3 -2
- package/node_modules/@groove-dev/daemon/src/process.js +1 -1
- package/node_modules/@groove-dev/daemon/src/routes/agents.js +1 -175
- package/node_modules/@groove-dev/daemon/src/routes/chat-history.js +34 -0
- package/node_modules/@groove-dev/daemon/test/chatstore.test.js +86 -0
- package/node_modules/@groove-dev/gui/dist/assets/index-Da2nbd6M.js +1043 -0
- package/node_modules/@groove-dev/gui/dist/assets/index-zmrIbwNm.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/App.jsx +0 -2
- package/node_modules/@groove-dev/gui/src/components/agents/agent-config.jsx +2 -2
- package/node_modules/@groove-dev/gui/src/components/agents/spawn-wizard.jsx +3 -3
- package/node_modules/@groove-dev/gui/src/components/layout/activity-bar.jsx +2 -3
- package/node_modules/@groove-dev/gui/src/components/layout/breadcrumb-bar.jsx +1 -1
- package/node_modules/@groove-dev/gui/src/components/layout/command-palette.jsx +1 -1
- package/node_modules/@groove-dev/gui/src/stores/groove.js +5 -163
- package/node_modules/@groove-dev/gui/src/stores/slices/agents-slice.js +52 -2
- package/node_modules/@groove-dev/gui/src/views/marketplace.jsx +1 -1
- package/node_modules/@groove-dev/gui/src/views/settings.jsx +0 -61
- 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 +3 -5
- package/packages/daemon/src/chatstore.js +104 -0
- package/packages/daemon/src/index.js +3 -2
- package/packages/daemon/src/process.js +1 -1
- package/packages/daemon/src/routes/agents.js +1 -175
- package/packages/daemon/src/routes/chat-history.js +34 -0
- package/packages/gui/dist/assets/index-Da2nbd6M.js +1043 -0
- package/packages/gui/dist/assets/index-zmrIbwNm.css +1 -0
- package/packages/gui/dist/index.html +2 -2
- package/packages/gui/package.json +1 -1
- package/packages/gui/src/App.jsx +0 -2
- package/packages/gui/src/components/agents/agent-config.jsx +2 -2
- package/packages/gui/src/components/agents/spawn-wizard.jsx +3 -3
- package/packages/gui/src/components/layout/activity-bar.jsx +2 -3
- package/packages/gui/src/components/layout/breadcrumb-bar.jsx +1 -1
- package/packages/gui/src/components/layout/command-palette.jsx +1 -1
- package/packages/gui/src/stores/groove.js +5 -163
- package/packages/gui/src/stores/slices/agents-slice.js +52 -2
- package/packages/gui/src/views/marketplace.jsx +1 -1
- package/packages/gui/src/views/settings.jsx +0 -61
- package/node_modules/@groove-dev/daemon/src/conversations.js +0 -576
- package/node_modules/@groove-dev/gui/dist/assets/index-Cat5pJUx.css +0 -1
- package/node_modules/@groove-dev/gui/dist/assets/index-L8xSnvHj.js +0 -1070
- package/node_modules/@groove-dev/gui/src/components/chat/chat-header.jsx +0 -198
- package/node_modules/@groove-dev/gui/src/components/chat/chat-input.jsx +0 -367
- package/node_modules/@groove-dev/gui/src/components/chat/chat-messages.jsx +0 -527
- package/node_modules/@groove-dev/gui/src/components/chat/chat-view.jsx +0 -212
- package/node_modules/@groove-dev/gui/src/components/chat/conversation-list.jsx +0 -163
- package/node_modules/@groove-dev/gui/src/components/chat/model-picker.jsx +0 -201
- package/node_modules/@groove-dev/gui/src/stores/slices/chat-slice.js +0 -227
- package/node_modules/@groove-dev/gui/src/views/chat.jsx +0 -6
- package/packages/daemon/src/conversations.js +0 -576
- package/packages/gui/dist/assets/index-Cat5pJUx.css +0 -1
- package/packages/gui/dist/assets/index-L8xSnvHj.js +0 -1070
- package/packages/gui/src/components/chat/chat-header.jsx +0 -198
- package/packages/gui/src/components/chat/chat-input.jsx +0 -367
- package/packages/gui/src/components/chat/chat-messages.jsx +0 -527
- package/packages/gui/src/components/chat/chat-view.jsx +0 -212
- package/packages/gui/src/components/chat/conversation-list.jsx +0 -163
- package/packages/gui/src/components/chat/model-picker.jsx +0 -201
- package/packages/gui/src/stores/slices/chat-slice.js +0 -227
- package/packages/gui/src/views/chat.jsx +0 -6
|
@@ -7,7 +7,6 @@ import { persistJSON, persistChatHistory } from './helpers.js';
|
|
|
7
7
|
import { createUiSlice } from './slices/ui-slice.js';
|
|
8
8
|
import { createAgentsSlice } from './slices/agents-slice.js';
|
|
9
9
|
import { createTeamsSlice } from './slices/teams-slice.js';
|
|
10
|
-
import { createChatSlice } from './slices/chat-slice.js';
|
|
11
10
|
import { createEditorSlice } from './slices/editor-slice.js';
|
|
12
11
|
import { createProvidersSlice } from './slices/providers-slice.js';
|
|
13
12
|
import { createNetworkSlice } from './slices/network-slice.js';
|
|
@@ -33,7 +32,6 @@ export const useGrooveStore = create((set, get) => ({
|
|
|
33
32
|
...createUiSlice(set, get),
|
|
34
33
|
...createAgentsSlice(set, get),
|
|
35
34
|
...createTeamsSlice(set, get),
|
|
36
|
-
...createChatSlice(set, get),
|
|
37
35
|
...createEditorSlice(set, get),
|
|
38
36
|
...createProvidersSlice(set, get),
|
|
39
37
|
...createNetworkSlice(set, get),
|
|
@@ -69,7 +67,7 @@ export const useGrooveStore = create((set, get) => ({
|
|
|
69
67
|
if (isTunneled) get().fetchProjectDir();
|
|
70
68
|
}).catch(() => {});
|
|
71
69
|
get().fetchTeams();
|
|
72
|
-
get().
|
|
70
|
+
get().fetchChatHistory();
|
|
73
71
|
get().fetchApprovals();
|
|
74
72
|
get().checkMarketplaceAuth();
|
|
75
73
|
get().fetchTunnels();
|
|
@@ -266,27 +264,6 @@ export const useGrooveStore = create((set, get) => ({
|
|
|
266
264
|
set({ chatHistory: history });
|
|
267
265
|
persistChatHistory(history);
|
|
268
266
|
}
|
|
269
|
-
|
|
270
|
-
const conv = get().conversations.find((c) => c.agentId === agentId);
|
|
271
|
-
if (conv) {
|
|
272
|
-
const convMsgs = { ...get().conversationMessages };
|
|
273
|
-
if (!convMsgs[conv.id]) convMsgs[conv.id] = [];
|
|
274
|
-
const convArr = [...convMsgs[conv.id]];
|
|
275
|
-
const lastConv = convArr[convArr.length - 1];
|
|
276
|
-
const isRecentConv = lastConv && lastConv.from === 'assistant' && (Date.now() - lastConv.timestamp) < 8000;
|
|
277
|
-
const isConvDupe = isRecentConv && (lastConv.text === trimmed || lastConv.text.endsWith(trimmed));
|
|
278
|
-
if (!isConvDupe) {
|
|
279
|
-
if (isRecentConv) {
|
|
280
|
-
const sep = data.subtype === 'assistant' ? '\n\n' : ' ';
|
|
281
|
-
convArr[convArr.length - 1] = { ...lastConv, text: lastConv.text + sep + trimmed, timestamp: Date.now() };
|
|
282
|
-
} else {
|
|
283
|
-
convArr.push({ from: 'assistant', text: trimmed, timestamp: Date.now() });
|
|
284
|
-
}
|
|
285
|
-
convMsgs[conv.id] = convArr.slice(-200);
|
|
286
|
-
set({ conversationMessages: convMsgs, streamingConversationId: conv.id });
|
|
287
|
-
persistJSON('groove:conversationMessages', convMsgs);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
267
|
}
|
|
291
268
|
|
|
292
269
|
if (activityText && activityText.trim()) {
|
|
@@ -347,11 +324,6 @@ export const useGrooveStore = create((set, get) => ({
|
|
|
347
324
|
});
|
|
348
325
|
}
|
|
349
326
|
|
|
350
|
-
const exitConv = get().conversations.find((c) => c.agentId === msg.agentId);
|
|
351
|
-
if (exitConv && get().streamingConversationId === exitConv.id) {
|
|
352
|
-
set({ sendingMessage: false, streamingConversationId: null });
|
|
353
|
-
}
|
|
354
|
-
|
|
355
327
|
if (msg.error && msg.agentId) {
|
|
356
328
|
get().addChatMessage(msg.agentId, 'system', `Crashed: ${msg.error}`);
|
|
357
329
|
}
|
|
@@ -385,8 +357,10 @@ export const useGrooveStore = create((set, get) => ({
|
|
|
385
357
|
isQuery: false,
|
|
386
358
|
innerchat: { turnId: turn.id, threadId: thread.id, kind: turn.kind, peer, direction },
|
|
387
359
|
});
|
|
360
|
+
const pushed = [];
|
|
388
361
|
const push = (agentId, item) => {
|
|
389
362
|
history[agentId] = [...(history[agentId] || []), item].slice(-100);
|
|
363
|
+
pushed.push([agentId, item]);
|
|
390
364
|
};
|
|
391
365
|
|
|
392
366
|
if (turn.kind === 'ask') {
|
|
@@ -403,6 +377,8 @@ export const useGrooveStore = create((set, get) => ({
|
|
|
403
377
|
}
|
|
404
378
|
|
|
405
379
|
persistChatHistory(history);
|
|
380
|
+
// Mirror to the daemon so these survive an origin/port change too.
|
|
381
|
+
for (const [agentId, item] of pushed) get().persistMessageRemote(agentId, item);
|
|
406
382
|
|
|
407
383
|
const answers = { ...s.innerchatAnswers };
|
|
408
384
|
if (turn.kind === 'answer') {
|
|
@@ -967,140 +943,6 @@ export const useGrooveStore = create((set, get) => ({
|
|
|
967
943
|
get().fetchNetworkInstallStatus();
|
|
968
944
|
break;
|
|
969
945
|
|
|
970
|
-
case 'conversation:created': {
|
|
971
|
-
const conv = msg.data;
|
|
972
|
-
if (conv) set((s) => ({ conversations: [conv, ...s.conversations.filter((c) => c.id !== conv.id)] }));
|
|
973
|
-
break;
|
|
974
|
-
}
|
|
975
|
-
|
|
976
|
-
case 'conversation:updated': {
|
|
977
|
-
const conv = msg.data;
|
|
978
|
-
if (conv) set((s) => ({ conversations: s.conversations.map((c) => c.id === conv.id ? { ...c, ...conv } : c) }));
|
|
979
|
-
break;
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
case 'conversation:deleted': {
|
|
983
|
-
const id = msg.data?.id || msg.id;
|
|
984
|
-
if (id) {
|
|
985
|
-
set((s) => {
|
|
986
|
-
const conversations = s.conversations.filter((c) => c.id !== id);
|
|
987
|
-
const conversationMessages = { ...s.conversationMessages };
|
|
988
|
-
delete conversationMessages[id];
|
|
989
|
-
const activeConversationId = s.activeConversationId === id ? null : s.activeConversationId;
|
|
990
|
-
if (activeConversationId !== s.activeConversationId) localStorage.setItem('groove:activeConversationId', '');
|
|
991
|
-
return { conversations, conversationMessages, activeConversationId };
|
|
992
|
-
});
|
|
993
|
-
}
|
|
994
|
-
break;
|
|
995
|
-
}
|
|
996
|
-
|
|
997
|
-
case 'conversation:tool': {
|
|
998
|
-
const { conversationId, name, summary } = msg.data || msg;
|
|
999
|
-
if (!conversationId) break;
|
|
1000
|
-
set((s) => {
|
|
1001
|
-
const tools = { ...s.conversationActiveTools };
|
|
1002
|
-
tools[conversationId] = { name: name || 'Tool', summary: summary || null, timestamp: Date.now() };
|
|
1003
|
-
return { conversationActiveTools: tools };
|
|
1004
|
-
});
|
|
1005
|
-
break;
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
case 'conversation:chunk': {
|
|
1009
|
-
const { conversationId, text } = msg.data || msg;
|
|
1010
|
-
if (!conversationId || !text) break;
|
|
1011
|
-
set((s) => {
|
|
1012
|
-
const msgs = { ...s.conversationMessages };
|
|
1013
|
-
if (!msgs[conversationId]) msgs[conversationId] = [];
|
|
1014
|
-
const arr = [...msgs[conversationId]];
|
|
1015
|
-
const last = arr[arr.length - 1];
|
|
1016
|
-
if (last && last.from === 'assistant' && (Date.now() - last.timestamp) < 30000) {
|
|
1017
|
-
arr[arr.length - 1] = { ...last, text: last.text + text, timestamp: Date.now() };
|
|
1018
|
-
} else {
|
|
1019
|
-
arr.push({ from: 'assistant', text, timestamp: Date.now() });
|
|
1020
|
-
}
|
|
1021
|
-
msgs[conversationId] = arr.slice(-200);
|
|
1022
|
-
const tools = { ...s.conversationActiveTools };
|
|
1023
|
-
delete tools[conversationId];
|
|
1024
|
-
return { conversationMessages: msgs, streamingConversationId: conversationId, conversationActiveTools: tools };
|
|
1025
|
-
});
|
|
1026
|
-
break;
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1029
|
-
case 'conversation:complete': {
|
|
1030
|
-
const { conversationId } = msg.data || msg;
|
|
1031
|
-
if (conversationId && get().streamingConversationId === conversationId) {
|
|
1032
|
-
const tools = { ...get().conversationActiveTools };
|
|
1033
|
-
delete tools[conversationId];
|
|
1034
|
-
set({ sendingMessage: false, streamingConversationId: null, conversationActiveTools: tools });
|
|
1035
|
-
}
|
|
1036
|
-
if (conversationId) persistJSON('groove:conversationMessages', get().conversationMessages);
|
|
1037
|
-
break;
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1040
|
-
case 'conversation:image': {
|
|
1041
|
-
const { conversationId, prompt, url, b64_json, mimeType, model: imgModel, provider: imgProvider } = msg.data || msg;
|
|
1042
|
-
if (!conversationId) break;
|
|
1043
|
-
const imageUrl = url || (b64_json ? `data:${mimeType || 'image/png'};base64,${b64_json}` : null);
|
|
1044
|
-
set((s) => {
|
|
1045
|
-
const msgs = { ...s.conversationMessages };
|
|
1046
|
-
if (!msgs[conversationId]) msgs[conversationId] = [];
|
|
1047
|
-
const arr = [...msgs[conversationId]];
|
|
1048
|
-
const loadingIdx = arr.findLastIndex((m) => m.type === 'image-loading' && m.prompt === prompt);
|
|
1049
|
-
if (loadingIdx >= 0) {
|
|
1050
|
-
arr[loadingIdx] = { from: 'assistant', type: 'image', imageUrl, prompt, model: imgModel, provider: imgProvider, timestamp: Date.now() };
|
|
1051
|
-
} else {
|
|
1052
|
-
arr.push({ from: 'assistant', type: 'image', imageUrl, prompt, model: imgModel, provider: imgProvider, timestamp: Date.now() });
|
|
1053
|
-
}
|
|
1054
|
-
msgs[conversationId] = arr.slice(-200);
|
|
1055
|
-
persistJSON('groove:conversationMessages', msgs);
|
|
1056
|
-
const isActive = s.streamingConversationId === conversationId;
|
|
1057
|
-
return { conversationMessages: msgs, sendingMessage: isActive ? false : s.sendingMessage, streamingConversationId: isActive ? null : s.streamingConversationId };
|
|
1058
|
-
});
|
|
1059
|
-
break;
|
|
1060
|
-
}
|
|
1061
|
-
|
|
1062
|
-
case 'conversation:image-progress': {
|
|
1063
|
-
const { conversationId, status, prompt: imgPrompt, error: imgError } = msg.data || msg;
|
|
1064
|
-
if (!conversationId) break;
|
|
1065
|
-
if (status === 'generating') {
|
|
1066
|
-
set((s) => {
|
|
1067
|
-
const msgs = { ...s.conversationMessages };
|
|
1068
|
-
if (!msgs[conversationId]) msgs[conversationId] = [];
|
|
1069
|
-
msgs[conversationId] = [...msgs[conversationId], { from: 'assistant', type: 'image-loading', prompt: imgPrompt, timestamp: Date.now() }];
|
|
1070
|
-
return { conversationMessages: msgs, streamingConversationId: conversationId };
|
|
1071
|
-
});
|
|
1072
|
-
} else if (status === 'error') {
|
|
1073
|
-
set((s) => {
|
|
1074
|
-
const msgs = { ...s.conversationMessages };
|
|
1075
|
-
if (!msgs[conversationId]) msgs[conversationId] = [];
|
|
1076
|
-
const arr = [...msgs[conversationId]];
|
|
1077
|
-
const loadingIdx = arr.findLastIndex((m) => m.type === 'image-loading');
|
|
1078
|
-
if (loadingIdx >= 0) arr.splice(loadingIdx, 1);
|
|
1079
|
-
arr.push({ from: 'system', text: `Image generation failed: ${imgError || 'Unknown error'}`, timestamp: Date.now() });
|
|
1080
|
-
msgs[conversationId] = arr;
|
|
1081
|
-
persistJSON('groove:conversationMessages', msgs);
|
|
1082
|
-
const isActive = s.streamingConversationId === conversationId;
|
|
1083
|
-
return { conversationMessages: msgs, sendingMessage: isActive ? false : s.sendingMessage, streamingConversationId: isActive ? null : s.streamingConversationId };
|
|
1084
|
-
});
|
|
1085
|
-
}
|
|
1086
|
-
break;
|
|
1087
|
-
}
|
|
1088
|
-
|
|
1089
|
-
case 'conversation:error': {
|
|
1090
|
-
const { conversationId, error } = msg.data || msg;
|
|
1091
|
-
if (conversationId) {
|
|
1092
|
-
set((s) => {
|
|
1093
|
-
const msgs = { ...s.conversationMessages };
|
|
1094
|
-
if (!msgs[conversationId]) msgs[conversationId] = [];
|
|
1095
|
-
msgs[conversationId] = [...msgs[conversationId], { from: 'system', text: `Error: ${error || 'Unknown error'}`, timestamp: Date.now() }];
|
|
1096
|
-
persistJSON('groove:conversationMessages', msgs);
|
|
1097
|
-
const isActive = s.streamingConversationId === conversationId;
|
|
1098
|
-
return { conversationMessages: msgs, sendingMessage: isActive ? false : s.sendingMessage, streamingConversationId: isActive ? null : s.streamingConversationId };
|
|
1099
|
-
});
|
|
1100
|
-
}
|
|
1101
|
-
break;
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
946
|
case 'network:token:timing': {
|
|
1105
947
|
const { __proto__: _a, constructor: _b, prototype: _c, ...td } = msg.data || {};
|
|
1106
948
|
const updates = {
|
|
@@ -89,6 +89,7 @@ export const createAgentsSlice = (set, get) => ({
|
|
|
89
89
|
persistJSON('groove:activityLog', activityLog);
|
|
90
90
|
return { chatHistory, activityLog, tokenTimeline };
|
|
91
91
|
});
|
|
92
|
+
api.delete(`/chat-history/${encodeURIComponent(id)}`).catch(() => {});
|
|
92
93
|
}
|
|
93
94
|
} catch (err) {
|
|
94
95
|
get().addToast('error', 'Kill failed', err.message);
|
|
@@ -166,15 +167,64 @@ export const createAgentsSlice = (set, get) => ({
|
|
|
166
167
|
// ── Chat ──────────────────────────────────────────────────
|
|
167
168
|
|
|
168
169
|
addChatMessage(agentId, from, text, isQuery = false, attachments = undefined) {
|
|
170
|
+
const msg = { from, text, timestamp: Date.now(), isQuery };
|
|
171
|
+
if (attachments?.length) msg.attachments = attachments;
|
|
169
172
|
set((s) => {
|
|
170
173
|
const history = { ...s.chatHistory };
|
|
171
174
|
if (!history[agentId]) history[agentId] = [];
|
|
172
|
-
const msg = { from, text, timestamp: Date.now(), isQuery };
|
|
173
|
-
if (attachments?.length) msg.attachments = attachments;
|
|
174
175
|
history[agentId] = [...history[agentId].slice(-100), msg];
|
|
175
176
|
persistChatHistory(history);
|
|
176
177
|
return { chatHistory: history };
|
|
177
178
|
});
|
|
179
|
+
get().persistMessageRemote(agentId, msg);
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
// Persist one message to the daemon so history survives on the server, not
|
|
183
|
+
// just in this browser's per-origin localStorage. Attachment payloads are
|
|
184
|
+
// stripped; the daemon keeps metadata only.
|
|
185
|
+
persistMessageRemote(agentId, msg) {
|
|
186
|
+
if (!agentId || !msg) return;
|
|
187
|
+
const clean = msg.attachments?.length
|
|
188
|
+
? { ...msg, attachments: msg.attachments.map(({ dataUrl, ...rest }) => rest) }
|
|
189
|
+
: msg;
|
|
190
|
+
api.post(`/chat-history/${encodeURIComponent(agentId)}`, { message: clean }).catch(() => {});
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
// Load server-side history on (re)connect and merge it in — the daemon is the
|
|
194
|
+
// source of truth, so this restores chats regardless of which tunnel port
|
|
195
|
+
// (and thus browser origin) we came up on.
|
|
196
|
+
//
|
|
197
|
+
// Also runs a ONE-TIME, per-origin seed: whatever chat history is stranded in
|
|
198
|
+
// THIS origin's localStorage gets pushed to the daemon for any agent the
|
|
199
|
+
// daemon doesn't yet know. Visiting each old origin once migrates its history
|
|
200
|
+
// server-side without clobbering anything already there.
|
|
201
|
+
async fetchChatHistory() {
|
|
202
|
+
try {
|
|
203
|
+
const { history } = await api.get('/chat-history');
|
|
204
|
+
const remote = (history && typeof history === 'object') ? history : {};
|
|
205
|
+
|
|
206
|
+
if (localStorage.getItem('groove:chatImported') !== '1') {
|
|
207
|
+
const local = get().chatHistory;
|
|
208
|
+
for (const [agentId, msgs] of Object.entries(local)) {
|
|
209
|
+
// Only seed agents the daemon has nothing for — never overwrite
|
|
210
|
+
// server history with an older local copy.
|
|
211
|
+
if (Array.isArray(msgs) && msgs.length && !(remote[agentId]?.length)) {
|
|
212
|
+
api.put(`/chat-history/${encodeURIComponent(agentId)}`, { messages: msgs }).catch(() => {});
|
|
213
|
+
remote[agentId] = msgs; // reflect so the merge below keeps it
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
localStorage.setItem('groove:chatImported', '1');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
set((s) => {
|
|
220
|
+
const merged = { ...s.chatHistory };
|
|
221
|
+
for (const [agentId, msgs] of Object.entries(remote)) {
|
|
222
|
+
if (Array.isArray(msgs) && msgs.length) merged[agentId] = msgs;
|
|
223
|
+
}
|
|
224
|
+
persistChatHistory(merged);
|
|
225
|
+
return { chatHistory: merged };
|
|
226
|
+
});
|
|
227
|
+
} catch { /* offline or old daemon without the endpoint — keep local */ }
|
|
178
228
|
},
|
|
179
229
|
|
|
180
230
|
async stopAgent(id) {
|
|
@@ -581,7 +581,7 @@ function MyLibrary() {
|
|
|
581
581
|
];
|
|
582
582
|
|
|
583
583
|
const emptyMessages = {
|
|
584
|
-
all: 'No skills or integrations installed yet.
|
|
584
|
+
all: 'No skills or integrations installed yet. Browse the Integrations tab to get started.',
|
|
585
585
|
skills: 'No skills installed.',
|
|
586
586
|
integrations: 'No integrations installed.',
|
|
587
587
|
};
|
|
@@ -1787,67 +1787,6 @@ export default function SettingsView() {
|
|
|
1787
1787
|
</div>
|
|
1788
1788
|
</ConfigCard>
|
|
1789
1789
|
|
|
1790
|
-
<ConfigCard icon={MessageSquare} label="Default Chat Model" description="Provider and model for new chat conversations.">
|
|
1791
|
-
<div className="space-y-2">
|
|
1792
|
-
<select
|
|
1793
|
-
value={config.defaultChatProvider || config.defaultProvider || 'claude-code'}
|
|
1794
|
-
onChange={(e) => {
|
|
1795
|
-
updateConfig('defaultChatProvider', e.target.value);
|
|
1796
|
-
const prov = providers.find((p) => p.id === e.target.value);
|
|
1797
|
-
const chatModels = (prov?.models || []).filter((m) => {
|
|
1798
|
-
const id = (typeof m === 'string' ? m : m.id || '').toLowerCase();
|
|
1799
|
-
return !id.includes('dall-e') && !id.includes('imagen') && !id.includes('image');
|
|
1800
|
-
});
|
|
1801
|
-
if (chatModels.length > 0) {
|
|
1802
|
-
const first = typeof chatModels[0] === 'string' ? chatModels[0] : chatModels[0].id;
|
|
1803
|
-
updateConfig('defaultChatModel', first);
|
|
1804
|
-
}
|
|
1805
|
-
}}
|
|
1806
|
-
className="w-full h-8 px-2.5 text-xs bg-surface-0 border border-border-subtle rounded-md text-text-0 font-mono focus:outline-none focus:ring-1 focus:ring-accent cursor-pointer"
|
|
1807
|
-
>
|
|
1808
|
-
{visibleProviders.filter((p) => p.installed && (p.authType === 'local' || (p.authType === 'subscription' && p.authStatus?.authenticated) || p.hasKey)).map((p) => (
|
|
1809
|
-
<option key={p.id} value={p.id}>{p.name}</option>
|
|
1810
|
-
))}
|
|
1811
|
-
</select>
|
|
1812
|
-
{(() => {
|
|
1813
|
-
const chatProv = providers.find((p) => p.id === (config.defaultChatProvider || config.defaultProvider || 'claude-code'));
|
|
1814
|
-
const chatModels = (chatProv?.models || []).filter((m) => {
|
|
1815
|
-
const id = (typeof m === 'string' ? m : m.id || '').toLowerCase();
|
|
1816
|
-
return !id.includes('dall-e') && !id.includes('imagen') && !id.includes('image');
|
|
1817
|
-
});
|
|
1818
|
-
const isChatLocal = (config.defaultChatProvider || config.defaultProvider || 'claude-code') === 'local';
|
|
1819
|
-
return (
|
|
1820
|
-
<select
|
|
1821
|
-
value={config.defaultChatModel || ''}
|
|
1822
|
-
onChange={(e) => updateConfig('defaultChatModel', e.target.value || null)}
|
|
1823
|
-
className="w-full h-8 px-2.5 text-xs bg-surface-0 border border-border-subtle rounded-md text-text-0 font-mono focus:outline-none focus:ring-1 focus:ring-accent cursor-pointer"
|
|
1824
|
-
>
|
|
1825
|
-
<option value="">Auto (Sonnet)</option>
|
|
1826
|
-
{isChatLocal ? (
|
|
1827
|
-
<>
|
|
1828
|
-
{chatModels.filter(m => m.source === 'ollama').length > 0 && (
|
|
1829
|
-
<optgroup label="Ollama">{chatModels.filter(m => m.source === 'ollama').map(m => <option key={m.id} value={m.id}>{m.name}</option>)}</optgroup>
|
|
1830
|
-
)}
|
|
1831
|
-
{chatModels.filter(m => m.source === 'gguf').length > 0 && (
|
|
1832
|
-
<optgroup label="Downloaded GGUFs">{chatModels.filter(m => m.source === 'gguf').map(m => <option key={m.id} value={m.id}>{m.name}{m.hasRuntime ? '' : ' (no runtime)'}</option>)}</optgroup>
|
|
1833
|
-
)}
|
|
1834
|
-
{chatModels.filter(m => m.source === 'runtime').length > 0 && (
|
|
1835
|
-
<optgroup label="Runtime Models">{chatModels.filter(m => m.source === 'runtime').map(m => <option key={m.id} value={m.id}>{m.name}</option>)}</optgroup>
|
|
1836
|
-
)}
|
|
1837
|
-
</>
|
|
1838
|
-
) : (
|
|
1839
|
-
chatModels.map((m) => {
|
|
1840
|
-
const id = typeof m === 'string' ? m : m.id;
|
|
1841
|
-
const name = typeof m === 'string' ? m : m.name || m.id;
|
|
1842
|
-
return <option key={id} value={id}>{name}</option>;
|
|
1843
|
-
})
|
|
1844
|
-
)}
|
|
1845
|
-
</select>
|
|
1846
|
-
);
|
|
1847
|
-
})()}
|
|
1848
|
-
</div>
|
|
1849
|
-
</ConfigCard>
|
|
1850
|
-
|
|
1851
1790
|
</div>
|
|
1852
1791
|
</div>
|
|
1853
1792
|
)}
|