@lobehub/lobehub 2.0.0-next.104 → 2.0.0-next.106
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/CHANGELOG.md +50 -0
- package/apps/desktop/package.json +2 -2
- package/changelog/v1.json +14 -0
- package/locales/ar/image.json +8 -0
- package/locales/ar/models.json +110 -64
- package/locales/ar/providers.json +3 -0
- package/locales/bg-BG/image.json +8 -0
- package/locales/bg-BG/models.json +98 -68
- package/locales/bg-BG/providers.json +3 -0
- package/locales/de-DE/image.json +8 -0
- package/locales/de-DE/models.json +176 -38
- package/locales/de-DE/providers.json +3 -0
- package/locales/en-US/image.json +8 -0
- package/locales/en-US/models.json +176 -38
- package/locales/en-US/providers.json +3 -0
- package/locales/es-ES/image.json +8 -0
- package/locales/es-ES/models.json +176 -38
- package/locales/es-ES/providers.json +3 -0
- package/locales/fa-IR/image.json +8 -0
- package/locales/fa-IR/models.json +110 -64
- package/locales/fa-IR/providers.json +3 -0
- package/locales/fr-FR/image.json +8 -0
- package/locales/fr-FR/models.json +110 -64
- package/locales/fr-FR/providers.json +3 -0
- package/locales/it-IT/image.json +8 -0
- package/locales/it-IT/models.json +176 -38
- package/locales/it-IT/providers.json +3 -0
- package/locales/ja-JP/image.json +8 -0
- package/locales/ja-JP/models.json +110 -64
- package/locales/ja-JP/providers.json +3 -0
- package/locales/ko-KR/image.json +8 -0
- package/locales/ko-KR/models.json +110 -64
- package/locales/ko-KR/providers.json +3 -0
- package/locales/nl-NL/image.json +8 -0
- package/locales/nl-NL/models.json +176 -38
- package/locales/nl-NL/providers.json +3 -0
- package/locales/pl-PL/image.json +8 -0
- package/locales/pl-PL/models.json +110 -64
- package/locales/pl-PL/providers.json +3 -0
- package/locales/pt-BR/image.json +8 -0
- package/locales/pt-BR/models.json +176 -38
- package/locales/pt-BR/providers.json +3 -0
- package/locales/ru-RU/image.json +8 -0
- package/locales/ru-RU/models.json +98 -68
- package/locales/ru-RU/providers.json +3 -0
- package/locales/tr-TR/image.json +8 -0
- package/locales/tr-TR/models.json +110 -64
- package/locales/tr-TR/providers.json +3 -0
- package/locales/vi-VN/image.json +8 -0
- package/locales/vi-VN/models.json +176 -38
- package/locales/vi-VN/providers.json +3 -0
- package/locales/zh-CN/image.json +8 -0
- package/locales/zh-CN/models.json +179 -38
- package/locales/zh-CN/providers.json +3 -0
- package/locales/zh-TW/image.json +8 -0
- package/locales/zh-TW/models.json +176 -38
- package/locales/zh-TW/providers.json +3 -0
- package/package.json +9 -3
- package/packages/database/src/repositories/knowledge/index.ts +5 -8
- package/packages/model-bank/src/aiModels/moonshot.ts +46 -0
- package/packages/model-runtime/src/core/contextBuilders/openai.ts +1 -1
- package/packages/model-runtime/src/providers/moonshot/index.ts +17 -4
- package/packages/model-runtime/src/utils/postProcessModelList.ts +15 -13
- package/packages/types/src/user/settings/keyVaults.ts +0 -68
- package/packages/utils/src/client/parserPlaceholder.ts +1 -1
- package/src/services/__tests__/_auth.test.ts +1 -4
- package/src/services/_auth.ts +2 -3
- package/src/services/_header.ts +1 -8
- package/src/store/chat/agents/__tests__/createAgentExecutors/call-llm.test.ts +18 -0
- package/src/store/chat/agents/__tests__/createAgentExecutors/call-tool.test.ts +40 -11
- package/src/store/chat/agents/__tests__/createAgentExecutors/helpers/assertions.ts +3 -0
- package/src/store/chat/agents/__tests__/createAgentExecutors/request-human-approve.test.ts +15 -0
- package/src/store/chat/agents/__tests__/createAgentExecutors/resolve-aborted-tools.test.ts +37 -11
- package/src/store/chat/agents/createAgentExecutors.ts +22 -13
- package/src/store/chat/slices/aiChat/actions/conversationLifecycle.ts +4 -8
- package/src/store/chat/slices/builtinTool/actions/__tests__/search.test.ts +16 -2
- package/src/store/chat/slices/builtinTool/actions/localSystem.ts +5 -1
- package/src/store/chat/slices/builtinTool/actions/search.ts +5 -1
- package/src/store/chat/slices/message/actions/publicApi.ts +10 -2
- package/src/store/chat/slices/message/actions/query.ts +17 -4
- package/src/store/chat/slices/operation/__tests__/selectors.test.ts +93 -5
- package/src/store/chat/slices/operation/selectors.ts +16 -3
- package/src/store/chat/slices/plugin/actions/optimisticUpdate.ts +24 -18
- package/src/store/user/slices/settings/selectors/keyVaults.ts +0 -5
- package/src/features/ChatList/Error/AccessCodeForm.tsx +0 -63
- package/src/services/__tests__/share.test.ts +0 -61
|
@@ -108,7 +108,11 @@ export const localSystemSlice: StateCreator<
|
|
|
108
108
|
},
|
|
109
109
|
|
|
110
110
|
reSearchLocalFiles: async (id, params) => {
|
|
111
|
-
|
|
111
|
+
// Get operationId from messageOperationMap to ensure proper context isolation
|
|
112
|
+
const operationId = get().messageOperationMap[id];
|
|
113
|
+
const context = operationId ? { operationId } : undefined;
|
|
114
|
+
|
|
115
|
+
await get().optimisticUpdatePluginArguments(id, params, false, context);
|
|
112
116
|
|
|
113
117
|
return get().searchLocalFiles(id, params);
|
|
114
118
|
},
|
|
@@ -276,7 +276,11 @@ export const searchSlice: StateCreator<
|
|
|
276
276
|
},
|
|
277
277
|
|
|
278
278
|
triggerSearchAgain: async (id, data, options) => {
|
|
279
|
-
|
|
279
|
+
// Get operationId from messageOperationMap to ensure proper context isolation
|
|
280
|
+
const operationId = get().messageOperationMap[id];
|
|
281
|
+
const context = operationId ? { operationId } : undefined;
|
|
282
|
+
|
|
283
|
+
await get().optimisticUpdatePluginArguments(id, data, false, context);
|
|
280
284
|
|
|
281
285
|
await get().search(id, data, options?.aiSummary);
|
|
282
286
|
},
|
|
@@ -167,14 +167,22 @@ export const messagePublicApi: StateCreator<
|
|
|
167
167
|
const message = dbMessageSelectors.getDbMessageById(id)(get());
|
|
168
168
|
if (!message || message.role !== 'tool') return;
|
|
169
169
|
|
|
170
|
+
// Get operationId from messageOperationMap to ensure proper context isolation
|
|
171
|
+
const operationId = get().messageOperationMap[id];
|
|
172
|
+
const context = operationId ? { operationId } : undefined;
|
|
173
|
+
|
|
170
174
|
const removeToolInAssistantMessage = async () => {
|
|
171
175
|
if (!message.parentId) return;
|
|
172
|
-
await get().optimisticRemoveToolFromAssistantMessage(
|
|
176
|
+
await get().optimisticRemoveToolFromAssistantMessage(
|
|
177
|
+
message.parentId,
|
|
178
|
+
message.tool_call_id,
|
|
179
|
+
context,
|
|
180
|
+
);
|
|
173
181
|
};
|
|
174
182
|
|
|
175
183
|
await Promise.all([
|
|
176
184
|
// 1. remove tool message
|
|
177
|
-
get().optimisticDeleteMessage(id),
|
|
185
|
+
get().optimisticDeleteMessage(id, context),
|
|
178
186
|
// 2. remove the tool item in the assistant tools
|
|
179
187
|
removeToolInAssistantMessage(),
|
|
180
188
|
]);
|
|
@@ -32,6 +32,7 @@ export interface MessageQueryAction {
|
|
|
32
32
|
messages: UIChatMessage[],
|
|
33
33
|
params?: {
|
|
34
34
|
action?: any;
|
|
35
|
+
operationId?: string;
|
|
35
36
|
sessionId?: string;
|
|
36
37
|
topicId?: string | null;
|
|
37
38
|
},
|
|
@@ -66,10 +67,22 @@ export const messageQuery: StateCreator<
|
|
|
66
67
|
},
|
|
67
68
|
|
|
68
69
|
replaceMessages: (messages, params) => {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
let sessionId: string;
|
|
71
|
+
let topicId: string | null | undefined;
|
|
72
|
+
|
|
73
|
+
// Priority 1: Get context from operation if operationId is provided
|
|
74
|
+
if (params?.operationId) {
|
|
75
|
+
const { sessionId: opSessionId, topicId: opTopicId } =
|
|
76
|
+
get().internal_getSessionContext(params);
|
|
77
|
+
sessionId = opSessionId;
|
|
78
|
+
topicId = opTopicId;
|
|
79
|
+
} else {
|
|
80
|
+
// Priority 2: Use explicit sessionId/topicId or fallback to global state
|
|
81
|
+
sessionId = params?.sessionId ?? get().activeId;
|
|
82
|
+
topicId = params?.topicId ?? get().activeTopicId;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const messagesKey = messageMapKey(sessionId, topicId);
|
|
73
86
|
|
|
74
87
|
// Get raw messages from dbMessagesMap and apply reducer
|
|
75
88
|
const nextDbMap = { ...get().dbMessagesMap, [messagesKey]: messages };
|
|
@@ -393,6 +393,11 @@ describe('Operation Selectors', () => {
|
|
|
393
393
|
it('isMainWindowAgentRuntimeRunning should only detect main window operations', () => {
|
|
394
394
|
const { result } = renderHook(() => useChatStore());
|
|
395
395
|
|
|
396
|
+
// Set active context
|
|
397
|
+
act(() => {
|
|
398
|
+
useChatStore.setState({ activeId: 'session1', activeTopicId: undefined });
|
|
399
|
+
});
|
|
400
|
+
|
|
396
401
|
expect(operationSelectors.isMainWindowAgentRuntimeRunning(result.current)).toBe(false);
|
|
397
402
|
|
|
398
403
|
// Start a main window operation (inThread: false)
|
|
@@ -400,7 +405,7 @@ describe('Operation Selectors', () => {
|
|
|
400
405
|
act(() => {
|
|
401
406
|
mainOpId = result.current.startOperation({
|
|
402
407
|
type: 'execAgentRuntime',
|
|
403
|
-
context: { sessionId: 'session1' },
|
|
408
|
+
context: { sessionId: 'session1', topicId: null },
|
|
404
409
|
metadata: { inThread: false },
|
|
405
410
|
}).operationId;
|
|
406
411
|
});
|
|
@@ -420,12 +425,17 @@ describe('Operation Selectors', () => {
|
|
|
420
425
|
it('isMainWindowAgentRuntimeRunning should exclude thread operations', () => {
|
|
421
426
|
const { result } = renderHook(() => useChatStore());
|
|
422
427
|
|
|
428
|
+
// Set active context
|
|
429
|
+
act(() => {
|
|
430
|
+
useChatStore.setState({ activeId: 'session1', activeTopicId: undefined });
|
|
431
|
+
});
|
|
432
|
+
|
|
423
433
|
// Start a thread operation (inThread: true)
|
|
424
434
|
let threadOpId: string;
|
|
425
435
|
act(() => {
|
|
426
436
|
threadOpId = result.current.startOperation({
|
|
427
437
|
type: 'execAgentRuntime',
|
|
428
|
-
context: { sessionId: 'session1', threadId: 'thread1' },
|
|
438
|
+
context: { sessionId: 'session1', topicId: null, threadId: 'thread1' },
|
|
429
439
|
metadata: { inThread: true },
|
|
430
440
|
}).operationId;
|
|
431
441
|
});
|
|
@@ -447,6 +457,11 @@ describe('Operation Selectors', () => {
|
|
|
447
457
|
it('isMainWindowAgentRuntimeRunning should distinguish between main and thread operations', () => {
|
|
448
458
|
const { result } = renderHook(() => useChatStore());
|
|
449
459
|
|
|
460
|
+
// Set active context
|
|
461
|
+
act(() => {
|
|
462
|
+
useChatStore.setState({ activeId: 'session1', activeTopicId: undefined });
|
|
463
|
+
});
|
|
464
|
+
|
|
450
465
|
let mainOpId: string;
|
|
451
466
|
let threadOpId: string;
|
|
452
467
|
|
|
@@ -454,13 +469,13 @@ describe('Operation Selectors', () => {
|
|
|
454
469
|
act(() => {
|
|
455
470
|
mainOpId = result.current.startOperation({
|
|
456
471
|
type: 'execAgentRuntime',
|
|
457
|
-
context: { sessionId: 'session1' },
|
|
472
|
+
context: { sessionId: 'session1', topicId: null },
|
|
458
473
|
metadata: { inThread: false },
|
|
459
474
|
}).operationId;
|
|
460
475
|
|
|
461
476
|
threadOpId = result.current.startOperation({
|
|
462
477
|
type: 'execAgentRuntime',
|
|
463
|
-
context: { sessionId: 'session1', threadId: 'thread1' },
|
|
478
|
+
context: { sessionId: 'session1', topicId: null, threadId: 'thread1' },
|
|
464
479
|
metadata: { inThread: true },
|
|
465
480
|
}).operationId;
|
|
466
481
|
});
|
|
@@ -489,11 +504,16 @@ describe('Operation Selectors', () => {
|
|
|
489
504
|
it('isMainWindowAgentRuntimeRunning should exclude aborting operations', () => {
|
|
490
505
|
const { result } = renderHook(() => useChatStore());
|
|
491
506
|
|
|
507
|
+
// Set active context
|
|
508
|
+
act(() => {
|
|
509
|
+
useChatStore.setState({ activeId: 'session1', activeTopicId: undefined });
|
|
510
|
+
});
|
|
511
|
+
|
|
492
512
|
let opId: string;
|
|
493
513
|
act(() => {
|
|
494
514
|
opId = result.current.startOperation({
|
|
495
515
|
type: 'execAgentRuntime',
|
|
496
|
-
context: { sessionId: 'session1' },
|
|
516
|
+
context: { sessionId: 'session1', topicId: null },
|
|
497
517
|
metadata: { inThread: false },
|
|
498
518
|
}).operationId;
|
|
499
519
|
});
|
|
@@ -509,5 +529,73 @@ describe('Operation Selectors', () => {
|
|
|
509
529
|
expect(operationSelectors.isMainWindowAgentRuntimeRunning(result.current)).toBe(false);
|
|
510
530
|
expect(operationSelectors.isAgentRuntimeRunning(result.current)).toBe(false);
|
|
511
531
|
});
|
|
532
|
+
|
|
533
|
+
it('isMainWindowAgentRuntimeRunning should only detect operations in current active topic', () => {
|
|
534
|
+
const { result } = renderHook(() => useChatStore());
|
|
535
|
+
|
|
536
|
+
// Set active session and topic
|
|
537
|
+
act(() => {
|
|
538
|
+
useChatStore.setState({ activeId: 'session1', activeTopicId: 'topic1' });
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
let topic1OpId: string;
|
|
542
|
+
let topic2OpId: string;
|
|
543
|
+
|
|
544
|
+
// Start operation in topic1 (current active topic)
|
|
545
|
+
act(() => {
|
|
546
|
+
topic1OpId = result.current.startOperation({
|
|
547
|
+
type: 'execAgentRuntime',
|
|
548
|
+
context: { sessionId: 'session1', topicId: 'topic1' },
|
|
549
|
+
metadata: { inThread: false },
|
|
550
|
+
}).operationId;
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
// Should detect operation in current topic
|
|
554
|
+
expect(operationSelectors.isMainWindowAgentRuntimeRunning(result.current)).toBe(true);
|
|
555
|
+
|
|
556
|
+
// Start operation in topic2 (different topic)
|
|
557
|
+
act(() => {
|
|
558
|
+
topic2OpId = result.current.startOperation({
|
|
559
|
+
type: 'execAgentRuntime',
|
|
560
|
+
context: { sessionId: 'session1', topicId: 'topic2' },
|
|
561
|
+
metadata: { inThread: false },
|
|
562
|
+
}).operationId;
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
// Should still only detect topic1 operation (current active topic)
|
|
566
|
+
expect(operationSelectors.isMainWindowAgentRuntimeRunning(result.current)).toBe(true);
|
|
567
|
+
|
|
568
|
+
// Switch to topic2
|
|
569
|
+
act(() => {
|
|
570
|
+
useChatStore.setState({ activeTopicId: 'topic2' });
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
// Should now detect topic2 operation
|
|
574
|
+
expect(operationSelectors.isMainWindowAgentRuntimeRunning(result.current)).toBe(true);
|
|
575
|
+
|
|
576
|
+
// Complete topic2 operation
|
|
577
|
+
act(() => {
|
|
578
|
+
result.current.completeOperation(topic2OpId!);
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
// Should not detect any operation in topic2 now
|
|
582
|
+
expect(operationSelectors.isMainWindowAgentRuntimeRunning(result.current)).toBe(false);
|
|
583
|
+
|
|
584
|
+
// Switch back to topic1
|
|
585
|
+
act(() => {
|
|
586
|
+
useChatStore.setState({ activeTopicId: 'topic1' });
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
// Should detect topic1 operation again
|
|
590
|
+
expect(operationSelectors.isMainWindowAgentRuntimeRunning(result.current)).toBe(true);
|
|
591
|
+
|
|
592
|
+
// Complete topic1 operation
|
|
593
|
+
act(() => {
|
|
594
|
+
result.current.completeOperation(topic1OpId!);
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
// Should not detect any operation now
|
|
598
|
+
expect(operationSelectors.isMainWindowAgentRuntimeRunning(result.current)).toBe(false);
|
|
599
|
+
});
|
|
512
600
|
});
|
|
513
601
|
});
|
|
@@ -180,14 +180,27 @@ const isAgentRuntimeRunning = (s: ChatStoreState): boolean => {
|
|
|
180
180
|
/**
|
|
181
181
|
* Check if agent runtime is running in main window only
|
|
182
182
|
* Used for main window UI state (e.g., send button loading)
|
|
183
|
-
* Excludes thread operations to prevent cross-contamination
|
|
183
|
+
* Excludes thread operations and operations from other topics to prevent cross-contamination
|
|
184
184
|
*/
|
|
185
185
|
const isMainWindowAgentRuntimeRunning = (s: ChatStoreState): boolean => {
|
|
186
186
|
const operationIds = s.operationsByType['execAgentRuntime'] || [];
|
|
187
|
+
|
|
187
188
|
return operationIds.some((id) => {
|
|
188
189
|
const op = s.operations[id];
|
|
189
|
-
|
|
190
|
-
|
|
190
|
+
if (!op || op.status !== 'running' || op.metadata.isAborting || op.metadata.inThread) {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Session must match
|
|
195
|
+
if (s.activeId !== op.context.sessionId) return false;
|
|
196
|
+
|
|
197
|
+
// Topic comparison: normalize null/undefined (both mean "default topic")
|
|
198
|
+
// activeTopicId can be null (initial state) or undefined (after topic operations)
|
|
199
|
+
// Operation context topicId can also be null or undefined
|
|
200
|
+
const activeTopicId = s.activeTopicId ?? null;
|
|
201
|
+
const opTopicId = op.context.topicId ?? null;
|
|
202
|
+
|
|
203
|
+
return activeTopicId === opTopicId;
|
|
191
204
|
});
|
|
192
205
|
};
|
|
193
206
|
|
|
@@ -32,6 +32,7 @@ export interface PluginOptimisticUpdateAction {
|
|
|
32
32
|
id: string,
|
|
33
33
|
value: T,
|
|
34
34
|
replace?: boolean,
|
|
35
|
+
context?: OptimisticUpdateContext,
|
|
35
36
|
) => Promise<void>;
|
|
36
37
|
|
|
37
38
|
/**
|
|
@@ -106,7 +107,7 @@ export const pluginOptimisticUpdate: StateCreator<
|
|
|
106
107
|
}
|
|
107
108
|
},
|
|
108
109
|
|
|
109
|
-
optimisticUpdatePluginArguments: async (id, value, replace = false) => {
|
|
110
|
+
optimisticUpdatePluginArguments: async (id, value, replace = false, context) => {
|
|
110
111
|
const { refreshMessages } = get();
|
|
111
112
|
const toolMessage = displayMessageSelectors.getDisplayMessageById(id)(get());
|
|
112
113
|
if (!toolMessage || !toolMessage?.tool_call_id) return;
|
|
@@ -121,20 +122,22 @@ export const pluginOptimisticUpdate: StateCreator<
|
|
|
121
122
|
if (isEqual(prevJson, nextValue)) return;
|
|
122
123
|
|
|
123
124
|
// optimistic update
|
|
124
|
-
get().internal_dispatchMessage(
|
|
125
|
-
id,
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
});
|
|
125
|
+
get().internal_dispatchMessage(
|
|
126
|
+
{ id, type: 'updateMessagePlugin', value: { arguments: JSON.stringify(nextValue) } },
|
|
127
|
+
context,
|
|
128
|
+
);
|
|
129
129
|
|
|
130
130
|
// 同样需要更新 assistantMessage 的 pluginArguments
|
|
131
131
|
if (assistantMessage) {
|
|
132
|
-
get().internal_dispatchMessage(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
132
|
+
get().internal_dispatchMessage(
|
|
133
|
+
{
|
|
134
|
+
id: assistantMessage.id,
|
|
135
|
+
type: 'updateMessageTools',
|
|
136
|
+
tool_call_id: toolMessage?.tool_call_id,
|
|
137
|
+
value: { arguments: JSON.stringify(nextValue) },
|
|
138
|
+
},
|
|
139
|
+
context,
|
|
140
|
+
);
|
|
138
141
|
assistantMessage = displayMessageSelectors.getDisplayMessageById(assistantMessage?.id)(get());
|
|
139
142
|
}
|
|
140
143
|
|
|
@@ -183,11 +186,14 @@ export const pluginOptimisticUpdate: StateCreator<
|
|
|
183
186
|
if (!assistantMessage) return;
|
|
184
187
|
|
|
185
188
|
const { internal_dispatchMessage, internal_refreshToUpdateMessageTools } = get();
|
|
186
|
-
internal_dispatchMessage(
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
189
|
+
internal_dispatchMessage(
|
|
190
|
+
{
|
|
191
|
+
type: 'addMessageTool',
|
|
192
|
+
value: tool,
|
|
193
|
+
id: assistantMessage.id,
|
|
194
|
+
},
|
|
195
|
+
context,
|
|
196
|
+
);
|
|
191
197
|
|
|
192
198
|
await internal_refreshToUpdateMessageTools(id, context);
|
|
193
199
|
},
|
|
@@ -199,7 +205,7 @@ export const pluginOptimisticUpdate: StateCreator<
|
|
|
199
205
|
const { internal_dispatchMessage, internal_refreshToUpdateMessageTools } = get();
|
|
200
206
|
|
|
201
207
|
// optimistic update
|
|
202
|
-
internal_dispatchMessage({ type: 'deleteMessageTool', tool_call_id, id: message.id });
|
|
208
|
+
internal_dispatchMessage({ type: 'deleteMessageTool', tool_call_id, id: message.id }, context);
|
|
203
209
|
|
|
204
210
|
// update the message tools
|
|
205
211
|
await internal_refreshToUpdateMessageTools(id, context);
|
|
@@ -10,12 +10,7 @@ const getVaultByProvider = (provider: string) => (s: UserStore) =>
|
|
|
10
10
|
// @ts-ignore
|
|
11
11
|
(keyVaultsSettings(s)[provider] || {}) as any;
|
|
12
12
|
|
|
13
|
-
const password = (s: UserStore) => keyVaultsSettings(s).password || '';
|
|
14
|
-
|
|
15
13
|
export const keyVaultsConfigSelectors = {
|
|
16
14
|
getVaultByProvider,
|
|
17
|
-
|
|
18
15
|
keyVaultsSettings,
|
|
19
|
-
|
|
20
|
-
password,
|
|
21
16
|
};
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { Button, InputPassword } from '@lobehub/ui';
|
|
2
|
-
import { memo } from 'react';
|
|
3
|
-
import { useTranslation } from 'react-i18next';
|
|
4
|
-
import { Flexbox } from 'react-layout-kit';
|
|
5
|
-
|
|
6
|
-
import { useChatStore } from '@/store/chat';
|
|
7
|
-
import { useUserStore } from '@/store/user';
|
|
8
|
-
import { keyVaultsConfigSelectors } from '@/store/user/selectors';
|
|
9
|
-
|
|
10
|
-
import { FormAction } from './style';
|
|
11
|
-
|
|
12
|
-
interface AccessCodeFormProps {
|
|
13
|
-
id: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const AccessCodeForm = memo<AccessCodeFormProps>(({ id }) => {
|
|
17
|
-
const { t } = useTranslation('error');
|
|
18
|
-
const [password, updateKeyVaults] = useUserStore((s) => [
|
|
19
|
-
keyVaultsConfigSelectors.password(s),
|
|
20
|
-
s.updateKeyVaults,
|
|
21
|
-
]);
|
|
22
|
-
const [resend, deleteMessage] = useChatStore((s) => [s.delAndRegenerateMessage, s.deleteMessage]);
|
|
23
|
-
|
|
24
|
-
return (
|
|
25
|
-
<>
|
|
26
|
-
<FormAction
|
|
27
|
-
avatar={'🗳'}
|
|
28
|
-
description={t('unlock.password.description')}
|
|
29
|
-
title={t('unlock.password.title')}
|
|
30
|
-
>
|
|
31
|
-
<InputPassword
|
|
32
|
-
autoComplete={'new-password'}
|
|
33
|
-
onChange={(e) => {
|
|
34
|
-
updateKeyVaults({ password: e.target.value });
|
|
35
|
-
}}
|
|
36
|
-
placeholder={t('unlock.password.placeholder')}
|
|
37
|
-
value={password}
|
|
38
|
-
variant={'filled'}
|
|
39
|
-
/>
|
|
40
|
-
</FormAction>
|
|
41
|
-
<Flexbox gap={12}>
|
|
42
|
-
<Button
|
|
43
|
-
onClick={() => {
|
|
44
|
-
resend(id);
|
|
45
|
-
deleteMessage(id);
|
|
46
|
-
}}
|
|
47
|
-
type={'primary'}
|
|
48
|
-
>
|
|
49
|
-
{t('unlock.confirm')}
|
|
50
|
-
</Button>
|
|
51
|
-
<Button
|
|
52
|
-
onClick={() => {
|
|
53
|
-
deleteMessage(id);
|
|
54
|
-
}}
|
|
55
|
-
>
|
|
56
|
-
{t('unlock.closeMessage')}
|
|
57
|
-
</Button>
|
|
58
|
-
</Flexbox>
|
|
59
|
-
</>
|
|
60
|
-
);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
export default AccessCodeForm;
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import type { PartialDeep } from 'type-fest';
|
|
2
|
-
import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
-
|
|
4
|
-
import { LOBE_URL_IMPORT_NAME } from '@/const/url';
|
|
5
|
-
import { UserSettings } from '@/types/user/settings';
|
|
6
|
-
|
|
7
|
-
import { shareService } from '../share';
|
|
8
|
-
|
|
9
|
-
// Mock dependencies
|
|
10
|
-
vi.mock('@/utils/parseMarkdown', () => ({
|
|
11
|
-
parseMarkdown: vi.fn(),
|
|
12
|
-
}));
|
|
13
|
-
|
|
14
|
-
global.fetch = vi.fn();
|
|
15
|
-
|
|
16
|
-
beforeEach(() => {
|
|
17
|
-
vi.clearAllMocks();
|
|
18
|
-
});
|
|
19
|
-
describe('ShareGPTService', () => {
|
|
20
|
-
describe('ShareViaUrl', () => {
|
|
21
|
-
describe('createShareSettingsUrl', () => {
|
|
22
|
-
it('should create a share settings URL with the provided settings', () => {
|
|
23
|
-
const settings: PartialDeep<UserSettings> = {
|
|
24
|
-
keyVaults: {
|
|
25
|
-
openai: {
|
|
26
|
-
apiKey: 'user-key',
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
};
|
|
30
|
-
const url = shareService.createShareSettingsUrl(settings);
|
|
31
|
-
expect(url).toBe(
|
|
32
|
-
`/?${LOBE_URL_IMPORT_NAME}=%7B%22keyVaults%22:%7B%22openai%22:%7B%22apiKey%22:%22user-key%22%7D%7D%7D`,
|
|
33
|
-
);
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
describe('decodeShareSettings', () => {
|
|
38
|
-
it('should decode share settings from search params', () => {
|
|
39
|
-
const settings = '{"languageModel":{"openai":{"apiKey":"user-key"}}}';
|
|
40
|
-
const decodedSettings = shareService.decodeShareSettings(settings);
|
|
41
|
-
expect(decodedSettings).toEqual({
|
|
42
|
-
data: {
|
|
43
|
-
languageModel: {
|
|
44
|
-
openai: {
|
|
45
|
-
apiKey: 'user-key',
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('should return an error message if decoding fails', () => {
|
|
53
|
-
const settings = '%7B%22theme%22%3A%22dark%22%2C%22fontSize%22%3A16%';
|
|
54
|
-
const decodedSettings = shareService.decodeShareSettings(settings);
|
|
55
|
-
expect(decodedSettings).toEqual({
|
|
56
|
-
message: expect.any(String),
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
});
|