@lobehub/lobehub 2.0.0-next.1 → 2.0.0-next.11
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/.github/workflows/desktop-pr-build.yml +12 -10
- package/.github/workflows/docker.yml +25 -20
- package/.github/workflows/e2e.yml +3 -3
- package/.github/workflows/release-desktop-beta.yml +8 -8
- package/.github/workflows/release.yml +1 -1
- package/.github/workflows/test.yml +4 -4
- package/CHANGELOG.md +261 -0
- package/apps/desktop/src/main/utils/next-electron-rsc.ts +7 -5
- package/changelog/v1.json +82 -0
- package/docs/development/database-schema.dbml +11 -1
- package/docs/self-hosting/advanced/auth/next-auth/auth0.mdx +2 -2
- package/docs/self-hosting/advanced/auth/next-auth/auth0.zh-CN.mdx +2 -2
- package/docs/self-hosting/advanced/auth/next-auth/authelia.mdx +2 -2
- package/docs/self-hosting/advanced/auth/next-auth/authelia.zh-CN.mdx +2 -2
- package/docs/self-hosting/advanced/auth/next-auth/authentik.mdx +2 -2
- package/docs/self-hosting/advanced/auth/next-auth/authentik.zh-CN.mdx +2 -2
- package/docs/self-hosting/advanced/auth/next-auth/casdoor.mdx +2 -2
- package/docs/self-hosting/advanced/auth/next-auth/casdoor.zh-CN.mdx +2 -2
- package/docs/self-hosting/advanced/auth/next-auth/cloudflare-zero-trust.mdx +2 -2
- package/docs/self-hosting/advanced/auth/next-auth/cloudflare-zero-trust.zh-CN.mdx +2 -2
- package/docs/self-hosting/advanced/auth/next-auth/github.mdx +2 -2
- package/docs/self-hosting/advanced/auth/next-auth/github.zh-CN.mdx +2 -2
- package/docs/self-hosting/advanced/auth/next-auth/google.mdx +32 -29
- package/docs/self-hosting/advanced/auth/next-auth/keycloak.mdx +2 -2
- package/docs/self-hosting/advanced/auth/next-auth/keycloak.zh-CN.mdx +2 -2
- package/docs/self-hosting/advanced/auth/next-auth/logto.mdx +5 -3
- package/docs/self-hosting/advanced/auth/next-auth/logto.zh-CN.mdx +5 -3
- package/docs/self-hosting/advanced/auth/next-auth/microsoft-entra-id.mdx +2 -2
- package/docs/self-hosting/advanced/auth/next-auth/microsoft-entra-id.zh-CN.mdx +2 -2
- package/docs/self-hosting/advanced/auth/next-auth/okta.mdx +2 -2
- package/docs/self-hosting/advanced/auth/next-auth/okta.zh-CN.mdx +2 -2
- package/docs/self-hosting/advanced/auth/next-auth/wechat.mdx +2 -2
- package/docs/self-hosting/advanced/auth/next-auth/wechat.zh-CN.mdx +2 -2
- package/docs/self-hosting/advanced/auth/next-auth/zitadel.mdx +2 -2
- package/docs/self-hosting/advanced/auth/next-auth/zitadel.zh-CN.mdx +2 -2
- package/docs/self-hosting/advanced/auth.mdx +32 -21
- package/docs/self-hosting/advanced/auth.zh-CN.mdx +30 -19
- package/docs/self-hosting/advanced/online-search.mdx +30 -25
- package/docs/self-hosting/advanced/online-search.zh-CN.mdx +25 -23
- package/locales/ar/models.json +15 -6
- package/locales/bg-BG/models.json +15 -6
- package/locales/de-DE/models.json +15 -6
- package/locales/en-US/models.json +15 -6
- package/locales/es-ES/models.json +15 -6
- package/locales/fa-IR/models.json +15 -6
- package/locales/fr-FR/models.json +15 -6
- package/locales/it-IT/models.json +15 -6
- package/locales/ja-JP/models.json +15 -6
- package/locales/ko-KR/models.json +21 -12
- package/locales/nl-NL/models.json +15 -6
- package/locales/pl-PL/models.json +15 -6
- package/locales/pt-BR/models.json +15 -6
- package/locales/ru-RU/models.json +15 -6
- package/locales/tr-TR/models.json +15 -6
- package/locales/vi-VN/models.json +15 -6
- package/locales/zh-CN/models.json +15 -6
- package/locales/zh-TW/models.json +15 -6
- package/next.config.ts +2 -3
- package/package.json +17 -23
- package/packages/const/src/index.ts +0 -1
- package/packages/const/src/models.ts +13 -0
- package/packages/const/src/url.ts +1 -4
- package/packages/context-engine/src/index.ts +1 -6
- package/packages/context-engine/src/processors/GroupMessageFlatten.ts +12 -2
- package/packages/context-engine/src/processors/__tests__/GroupMessageFlatten.test.ts +73 -9
- package/packages/context-engine/src/providers/index.ts +0 -2
- package/packages/database/migrations/0041_improve_index.sql +10 -0
- package/packages/database/migrations/meta/0041_snapshot.json +7784 -0
- package/packages/database/migrations/meta/_journal.json +7 -0
- package/packages/database/package.json +1 -1
- package/packages/database/src/core/migrations.json +17 -0
- package/packages/database/src/models/__tests__/message.grouping.test.ts +812 -0
- package/packages/database/src/models/__tests__/message.test.ts +322 -170
- package/packages/database/src/models/message.ts +62 -24
- package/packages/database/src/models/session.ts +60 -19
- package/packages/database/src/schemas/agent.ts +10 -11
- package/packages/database/src/schemas/message.ts +5 -1
- package/packages/database/src/schemas/relations.ts +6 -4
- package/packages/database/src/schemas/session.ts +2 -0
- package/packages/database/src/schemas/topic.ts +6 -1
- package/packages/database/src/utils/__tests__/groupMessages.test.ts +145 -2
- package/packages/database/src/utils/groupMessages.ts +7 -5
- package/packages/electron-client-ipc/package.json +4 -1
- package/packages/file-loaders/package.json +1 -0
- package/packages/model-bank/src/aiModels/anthropic.ts +0 -63
- package/packages/model-bank/src/aiModels/azure.ts +155 -0
- package/packages/model-bank/src/aiModels/bedrock.ts +44 -0
- package/packages/model-bank/src/aiModels/higress.ts +0 -55
- package/packages/model-bank/src/aiModels/infiniai.ts +21 -0
- package/packages/model-bank/src/aiModels/ollamacloud.ts +13 -0
- package/packages/model-bank/src/aiModels/siliconcloud.ts +19 -0
- package/packages/model-runtime/src/core/openaiCompatibleFactory/createImage.ts +1 -1
- package/packages/model-runtime/src/core/openaiCompatibleFactory/index.test.ts +33 -3
- package/packages/model-runtime/src/core/parameterResolver.ts +3 -0
- package/packages/model-runtime/src/core/streams/openai/__snapshots__/responsesStream.test.ts.snap +0 -38
- package/packages/model-runtime/src/providers/azureOpenai/index.ts +2 -1
- package/packages/model-runtime/src/providers/minimax/index.ts +5 -5
- package/packages/model-runtime/src/providers/search1api/index.test.ts +2 -2
- package/packages/types/src/message/common/base.ts +13 -0
- package/packages/types/src/message/common/image.ts +8 -0
- package/packages/types/src/message/common/metadata.ts +39 -0
- package/packages/types/src/message/common/tools.ts +10 -0
- package/packages/types/src/message/db/params.ts +47 -1
- package/packages/types/src/message/ui/chat.ts +4 -1
- package/packages/types/src/search.ts +16 -0
- package/packages/web-crawler/src/crawImpl/firecrawl.ts +39 -12
- package/scripts/migrateServerDB/index.ts +2 -1
- package/src/app/(backend)/oidc/consent/route.ts +0 -1
- package/src/app/(backend)/webapi/revalidate/route.ts +1 -1
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/V1Mobile/index.tsx +2 -2
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/V1Mobile/useSend.ts +6 -4
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/useSend.ts +15 -10
- package/src/app/[variants]/(main)/chat/@session/features/SessionListContent/List/Item/index.tsx +4 -2
- package/src/app/[variants]/(main)/settings/_layout/SettingsContent.tsx +0 -3
- package/src/app/[variants]/layout.tsx +1 -0
- package/src/app/sitemap.tsx +7 -1
- package/src/components/Thinking/index.tsx +4 -3
- package/src/config/modelProviders/anthropic.ts +0 -23
- package/src/config/modelProviders/higress.ts +0 -23
- package/src/config/modelProviders/minimax.ts +1 -1
- package/src/config/modelProviders/qiniu.ts +1 -1
- package/src/envs/auth.ts +0 -179
- package/src/features/AgentSetting/AgentPlugin/index.tsx +21 -13
- package/src/features/ChatInput/ActionBar/STT/browser.tsx +2 -2
- package/src/features/ChatInput/ActionBar/STT/openai.tsx +2 -2
- package/src/features/ChatInput/ActionBar/Tools/useControls.tsx +1 -3
- package/src/features/Conversation/Error/ErrorJsonViewer.tsx +4 -3
- package/src/features/Conversation/Error/OllamaBizError/index.tsx +7 -2
- package/src/features/Conversation/Error/index.tsx +15 -5
- package/src/features/Conversation/MarkdownElements/LobeArtifact/Render/index.tsx +2 -2
- package/src/features/Conversation/Messages/Assistant/Extra/index.tsx +2 -2
- package/src/features/Conversation/Messages/Assistant/MessageContent.tsx +5 -3
- package/src/features/Conversation/Messages/Assistant/Tool/Inspector/BuiltinPluginTitle.tsx +2 -2
- package/src/features/Conversation/Messages/Assistant/Tool/Inspector/ToolTitle.tsx +4 -2
- package/src/features/Conversation/Messages/Assistant/Tool/Render/CustomRender.tsx +2 -2
- package/src/features/Conversation/Messages/Assistant/Tool/Render/index.tsx +2 -2
- package/src/features/Conversation/Messages/Assistant/Tool/index.tsx +2 -2
- package/src/features/Conversation/Messages/Assistant/index.tsx +4 -4
- package/src/features/Conversation/Messages/Default.tsx +2 -2
- package/src/features/Conversation/Messages/User/Extra.tsx +2 -2
- package/src/features/Conversation/Messages/User/index.tsx +4 -4
- package/src/features/Conversation/Messages/index.tsx +3 -3
- package/src/features/Conversation/components/AutoScroll.tsx +2 -2
- package/src/features/Conversation/components/Extras/Usage/UsageDetail/index.tsx +9 -6
- package/src/features/PluginTag/index.tsx +1 -3
- package/src/features/PluginsUI/Render/BuiltinType/index.test.tsx +37 -28
- package/src/features/Portal/Artifacts/Body/index.tsx +2 -2
- package/src/libs/next-auth/auth.config.ts +1 -1
- package/src/libs/next-auth/sso-providers/auth0.ts +0 -7
- package/src/libs/next-auth/sso-providers/authelia.ts +3 -5
- package/src/libs/next-auth/sso-providers/authentik.ts +0 -7
- package/src/libs/next-auth/sso-providers/cloudflare-zero-trust.ts +3 -6
- package/src/libs/next-auth/sso-providers/cognito.ts +1 -5
- package/src/libs/next-auth/sso-providers/generic-oidc.ts +3 -5
- package/src/libs/next-auth/sso-providers/github.ts +0 -6
- package/src/libs/next-auth/sso-providers/google.ts +0 -2
- package/src/libs/next-auth/sso-providers/index.ts +0 -2
- package/src/libs/next-auth/sso-providers/keycloak.ts +0 -3
- package/src/libs/next-auth/sso-providers/logto.ts +3 -5
- package/src/libs/next-auth/sso-providers/okta.ts +0 -4
- package/src/libs/next-auth/sso-providers/zitadel.ts +0 -7
- package/src/libs/oidc-provider/provider.ts +1 -1
- package/src/server/modules/AssistantStore/index.ts +1 -1
- package/src/server/modules/ModelRuntime/trace.ts +11 -4
- package/src/server/routers/lambda/message.ts +14 -3
- package/src/server/routers/lambda/session.ts +8 -5
- package/src/server/services/search/impls/firecrawl/index.ts +51 -11
- package/src/server/services/search/impls/firecrawl/type.ts +60 -9
- package/src/services/chat/chat.test.ts +1 -40
- package/src/services/chat/contextEngineering.test.ts +0 -30
- package/src/services/chat/contextEngineering.ts +1 -12
- package/src/services/chat/index.ts +2 -7
- package/src/services/chat/types.ts +1 -1
- package/src/services/message/_deprecated.ts +1 -1
- package/src/services/message/client.ts +8 -2
- package/src/services/message/server.ts +7 -2
- package/src/services/message/type.ts +6 -1
- package/src/services/user/client.test.ts +4 -1
- package/src/store/chat/helpers.test.ts +99 -0
- package/src/store/chat/helpers.ts +21 -2
- package/src/store/chat/selectors.ts +1 -1
- package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +3 -3
- package/src/store/chat/slices/builtinTool/actions/index.ts +1 -4
- package/src/store/chat/slices/message/action.test.ts +5 -1
- package/src/store/chat/slices/message/action.ts +102 -14
- package/src/store/chat/slices/message/reducer.test.ts +363 -5
- package/src/store/chat/slices/message/reducer.ts +87 -3
- package/src/store/chat/slices/message/{selectors.test.ts → selectors/chat.test.ts} +266 -30
- package/src/store/chat/slices/message/{selectors.ts → selectors/chat.ts} +29 -79
- package/src/store/chat/slices/message/selectors/index.ts +2 -0
- package/src/store/chat/slices/message/selectors/messageState.test.ts +36 -0
- package/src/store/chat/slices/message/selectors/messageState.ts +80 -0
- package/src/store/chat/slices/plugin/action.test.ts +34 -132
- package/src/store/chat/slices/plugin/action.ts +1 -44
- package/src/store/tool/selectors/tool.test.ts +1 -1
- package/src/store/tool/selectors/tool.ts +6 -8
- package/src/store/tool/slices/builtin/action.test.ts +83 -35
- package/src/store/tool/slices/builtin/action.ts +0 -9
- package/src/store/tool/slices/builtin/selectors.test.ts +4 -30
- package/src/store/tool/slices/builtin/selectors.ts +15 -21
- package/src/tools/index.ts +0 -6
- package/src/tools/renders.ts +0 -3
- package/src/tools/web-browsing/Portal/Search/Footer.tsx +2 -2
- package/tsconfig.json +9 -2
- package/packages/const/src/guide.ts +0 -89
- package/packages/context-engine/src/providers/InboxGuide.ts +0 -102
- package/packages/context-engine/src/providers/__tests__/InboxGuideProvider.test.ts +0 -121
- package/src/app/[variants]/(main)/settings/llm/ProviderList/Azure/index.tsx +0 -93
- package/src/app/[variants]/(main)/settings/llm/ProviderList/Bedrock/index.tsx +0 -70
- package/src/app/[variants]/(main)/settings/llm/ProviderList/Cloudflare/index.tsx +0 -39
- package/src/app/[variants]/(main)/settings/llm/ProviderList/Github/index.tsx +0 -52
- package/src/app/[variants]/(main)/settings/llm/ProviderList/HuggingFace/index.tsx +0 -52
- package/src/app/[variants]/(main)/settings/llm/ProviderList/Ollama/index.tsx +0 -20
- package/src/app/[variants]/(main)/settings/llm/ProviderList/OpenAI/index.tsx +0 -17
- package/src/app/[variants]/(main)/settings/llm/ProviderList/providers.tsx +0 -132
- package/src/app/[variants]/(main)/settings/llm/components/Checker.tsx +0 -118
- package/src/app/[variants]/(main)/settings/llm/components/ProviderConfig/index.tsx +0 -303
- package/src/app/[variants]/(main)/settings/llm/components/ProviderModelList/CustomModelOption.tsx +0 -98
- package/src/app/[variants]/(main)/settings/llm/components/ProviderModelList/ModelConfigModal/Form.tsx +0 -104
- package/src/app/[variants]/(main)/settings/llm/components/ProviderModelList/ModelConfigModal/index.tsx +0 -77
- package/src/app/[variants]/(main)/settings/llm/components/ProviderModelList/ModelFetcher.tsx +0 -105
- package/src/app/[variants]/(main)/settings/llm/components/ProviderModelList/Option.tsx +0 -68
- package/src/app/[variants]/(main)/settings/llm/components/ProviderModelList/index.tsx +0 -146
- package/src/app/[variants]/(main)/settings/llm/const.ts +0 -20
- package/src/app/[variants]/(main)/settings/llm/features/Footer.tsx +0 -35
- package/src/app/[variants]/(main)/settings/llm/index.tsx +0 -30
- package/src/app/[variants]/(main)/settings/llm/type.ts +0 -5
- package/src/envs/__tests__/auth.test.ts +0 -200
- package/src/libs/next-auth/sso-providers/azure-ad.ts +0 -33
- package/src/services/chat/__snapshots__/chat.test.ts.snap +0 -110
- package/src/store/chat/slices/builtinTool/actions/__tests__/dalle.test.ts +0 -121
- package/src/store/chat/slices/builtinTool/actions/dalle.ts +0 -124
- package/src/tools/dalle/Render/GalleyGrid.tsx +0 -60
- package/src/tools/dalle/Render/Item/EditMode.tsx +0 -66
- package/src/tools/dalle/Render/Item/Error.tsx +0 -49
- package/src/tools/dalle/Render/Item/Image.tsx +0 -44
- package/src/tools/dalle/Render/Item/ImageFileItem.tsx +0 -57
- package/src/tools/dalle/Render/Item/index.tsx +0 -88
- package/src/tools/dalle/Render/ToolBar.tsx +0 -56
- package/src/tools/dalle/Render/index.tsx +0 -52
- package/src/tools/dalle/index.ts +0 -92
- /package/src/{middleware.ts → proxy.ts} +0 -0
|
@@ -471,7 +471,11 @@ describe('chatMessage actions', () => {
|
|
|
471
471
|
await result.current.internal_updateMessageContent(messageId, newContent);
|
|
472
472
|
});
|
|
473
473
|
|
|
474
|
-
expect(spy).toHaveBeenCalledWith(
|
|
474
|
+
expect(spy).toHaveBeenCalledWith(
|
|
475
|
+
messageId,
|
|
476
|
+
{ content: newContent },
|
|
477
|
+
{ sessionId: 'session-id', topicId: 'topic-id' },
|
|
478
|
+
);
|
|
475
479
|
});
|
|
476
480
|
|
|
477
481
|
it('should dispatch message update action', async () => {
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
ChatMessageError,
|
|
7
7
|
ChatMessagePluginError,
|
|
8
8
|
CreateMessageParams,
|
|
9
|
+
CreateNewMessageParams,
|
|
9
10
|
GroundingSearch,
|
|
10
11
|
MessageMetadata,
|
|
11
12
|
MessageToolCall,
|
|
@@ -117,6 +118,14 @@ export interface ChatMessageAction {
|
|
|
117
118
|
* otherwise the message will be too slow to show
|
|
118
119
|
*/
|
|
119
120
|
internal_createTmpMessage: (params: CreateMessageParams) => string;
|
|
121
|
+
/**
|
|
122
|
+
* create a new message using createNewMessage API and return full message list
|
|
123
|
+
* used for group message scenarios to reduce network requests
|
|
124
|
+
*/
|
|
125
|
+
internal_createNewMessage: (
|
|
126
|
+
params: CreateNewMessageParams,
|
|
127
|
+
context?: { tempMessageId?: string; groupMessageId?: string },
|
|
128
|
+
) => Promise<{ id: string; messages: UIChatMessage[] } | undefined>;
|
|
120
129
|
/**
|
|
121
130
|
* delete the message content with optimistic update
|
|
122
131
|
*/
|
|
@@ -374,8 +383,16 @@ export const chatMessage: StateCreator<
|
|
|
374
383
|
|
|
375
384
|
internal_updateMessageError: async (id, error) => {
|
|
376
385
|
get().internal_dispatchMessage({ id, type: 'updateMessage', value: { error } });
|
|
377
|
-
await messageService.updateMessage(
|
|
378
|
-
|
|
386
|
+
const result = await messageService.updateMessage(
|
|
387
|
+
id,
|
|
388
|
+
{ error },
|
|
389
|
+
{ topicId: get().activeTopicId, sessionId: get().activeId },
|
|
390
|
+
);
|
|
391
|
+
if (result?.success && result.messages) {
|
|
392
|
+
get().replaceMessages(result.messages);
|
|
393
|
+
} else {
|
|
394
|
+
await get().refreshMessages();
|
|
395
|
+
}
|
|
379
396
|
},
|
|
380
397
|
|
|
381
398
|
internal_updateMessagePluginError: async (id, error) => {
|
|
@@ -384,7 +401,12 @@ export const chatMessage: StateCreator<
|
|
|
384
401
|
},
|
|
385
402
|
|
|
386
403
|
internal_updateMessageContent: async (id, content, extra) => {
|
|
387
|
-
const {
|
|
404
|
+
const {
|
|
405
|
+
internal_dispatchMessage,
|
|
406
|
+
refreshMessages,
|
|
407
|
+
internal_transformToolCalls,
|
|
408
|
+
replaceMessages,
|
|
409
|
+
} = get();
|
|
388
410
|
|
|
389
411
|
// Due to the async update method and refresh need about 100ms
|
|
390
412
|
// we need to update the message content at the frontend to avoid the update flick
|
|
@@ -403,17 +425,26 @@ export const chatMessage: StateCreator<
|
|
|
403
425
|
});
|
|
404
426
|
}
|
|
405
427
|
|
|
406
|
-
await messageService.updateMessage(
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
428
|
+
const result = await messageService.updateMessage(
|
|
429
|
+
id,
|
|
430
|
+
{
|
|
431
|
+
content,
|
|
432
|
+
tools: extra?.toolCalls ? internal_transformToolCalls(extra?.toolCalls) : undefined,
|
|
433
|
+
reasoning: extra?.reasoning,
|
|
434
|
+
search: extra?.search,
|
|
435
|
+
metadata: extra?.metadata,
|
|
436
|
+
model: extra?.model,
|
|
437
|
+
provider: extra?.provider,
|
|
438
|
+
imageList: extra?.imageList,
|
|
439
|
+
},
|
|
440
|
+
{ topicId: get().activeTopicId, sessionId: get().activeId },
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
if (result && result.success && result.messages) {
|
|
444
|
+
replaceMessages(result.messages);
|
|
445
|
+
} else {
|
|
446
|
+
await refreshMessages();
|
|
447
|
+
}
|
|
417
448
|
},
|
|
418
449
|
|
|
419
450
|
internal_createMessage: async (message, context) => {
|
|
@@ -473,6 +504,63 @@ export const chatMessage: StateCreator<
|
|
|
473
504
|
|
|
474
505
|
return tempId;
|
|
475
506
|
},
|
|
507
|
+
|
|
508
|
+
internal_createNewMessage: async (message, context) => {
|
|
509
|
+
const {
|
|
510
|
+
internal_createTmpMessage,
|
|
511
|
+
internal_toggleMessageLoading,
|
|
512
|
+
internal_dispatchMessage,
|
|
513
|
+
replaceMessages,
|
|
514
|
+
} = get();
|
|
515
|
+
|
|
516
|
+
let tempId = context?.tempMessageId;
|
|
517
|
+
if (!tempId) {
|
|
518
|
+
tempId = 'tmp_' + nanoid();
|
|
519
|
+
|
|
520
|
+
// Check if should add as group block (explicitly controlled by caller)
|
|
521
|
+
if (context?.groupMessageId) {
|
|
522
|
+
internal_dispatchMessage({
|
|
523
|
+
type: 'addGroupBlock',
|
|
524
|
+
groupMessageId: context.groupMessageId,
|
|
525
|
+
blockId: tempId,
|
|
526
|
+
value: {
|
|
527
|
+
id: tempId,
|
|
528
|
+
content: message.content,
|
|
529
|
+
},
|
|
530
|
+
});
|
|
531
|
+
internal_toggleMessageLoading(true, tempId);
|
|
532
|
+
} else {
|
|
533
|
+
// Regular message creation at top level
|
|
534
|
+
tempId = internal_createTmpMessage(message as any);
|
|
535
|
+
internal_toggleMessageLoading(true, tempId);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
try {
|
|
540
|
+
// 使用 createNewMessage API
|
|
541
|
+
const result = await messageService.createNewMessage(message);
|
|
542
|
+
|
|
543
|
+
// 直接用返回的 messages 更新 store(已包含 group 结构)
|
|
544
|
+
replaceMessages(result.messages);
|
|
545
|
+
|
|
546
|
+
internal_toggleMessageLoading(false, tempId);
|
|
547
|
+
return result;
|
|
548
|
+
} catch (e) {
|
|
549
|
+
internal_toggleMessageLoading(false, tempId);
|
|
550
|
+
internal_dispatchMessage({
|
|
551
|
+
id: tempId,
|
|
552
|
+
type: 'updateMessage',
|
|
553
|
+
value: {
|
|
554
|
+
error: {
|
|
555
|
+
type: ChatErrorType.CreateMessageError,
|
|
556
|
+
message: (e as Error).message,
|
|
557
|
+
body: e,
|
|
558
|
+
},
|
|
559
|
+
},
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
},
|
|
563
|
+
|
|
476
564
|
internal_deleteMessage: async (id: string) => {
|
|
477
565
|
get().internal_dispatchMessage({ type: 'deleteMessage', id });
|
|
478
566
|
await messageService.removeMessage(id);
|
|
@@ -57,16 +57,131 @@ describe('messagesReducer', () => {
|
|
|
57
57
|
expect(newState).toEqual(initialState);
|
|
58
58
|
});
|
|
59
59
|
|
|
60
|
-
it('should
|
|
60
|
+
it('should update a block in group message children when id matches a block', () => {
|
|
61
|
+
const stateWithGroup: UIChatMessage[] = [
|
|
62
|
+
...initialState,
|
|
63
|
+
{
|
|
64
|
+
id: 'group1',
|
|
65
|
+
role: 'group',
|
|
66
|
+
content: '',
|
|
67
|
+
createdAt: 1629264000000,
|
|
68
|
+
updatedAt: 1629264000000,
|
|
69
|
+
meta: {},
|
|
70
|
+
children: [
|
|
71
|
+
{
|
|
72
|
+
id: 'block1',
|
|
73
|
+
content: 'Original block content',
|
|
74
|
+
tools: [
|
|
75
|
+
{
|
|
76
|
+
id: 'tool1',
|
|
77
|
+
identifier: 'search',
|
|
78
|
+
apiName: 'search',
|
|
79
|
+
type: 'builtin',
|
|
80
|
+
arguments: '{"query": "test"}',
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
} as UIChatMessage,
|
|
86
|
+
];
|
|
87
|
+
|
|
61
88
|
const payload: MessageDispatch = {
|
|
62
89
|
type: 'updateMessage',
|
|
63
|
-
id: '
|
|
64
|
-
value: { content: 'Updated
|
|
90
|
+
id: 'block1',
|
|
91
|
+
value: { content: 'Updated block content' },
|
|
65
92
|
};
|
|
66
93
|
|
|
67
|
-
const newState = messagesReducer(
|
|
94
|
+
const newState = messagesReducer(stateWithGroup, payload);
|
|
95
|
+
const groupMessage = newState.find((m) => m.id === 'group1');
|
|
96
|
+
const block = groupMessage?.children?.find((b) => b.id === 'block1');
|
|
68
97
|
|
|
69
|
-
expect(
|
|
98
|
+
expect(block?.content).toBe('Updated block content');
|
|
99
|
+
expect(groupMessage?.updatedAt).toBeGreaterThan(1629264000000);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('should update block tools in group message children', () => {
|
|
103
|
+
const stateWithGroup: UIChatMessage[] = [
|
|
104
|
+
...initialState,
|
|
105
|
+
{
|
|
106
|
+
id: 'group1',
|
|
107
|
+
role: 'group',
|
|
108
|
+
content: '',
|
|
109
|
+
createdAt: 1629264000000,
|
|
110
|
+
updatedAt: 1629264000000,
|
|
111
|
+
meta: {},
|
|
112
|
+
children: [
|
|
113
|
+
{
|
|
114
|
+
id: 'block1',
|
|
115
|
+
content: 'Block content',
|
|
116
|
+
tools: [
|
|
117
|
+
{
|
|
118
|
+
id: 'tool1',
|
|
119
|
+
identifier: 'search',
|
|
120
|
+
apiName: 'search',
|
|
121
|
+
type: 'builtin',
|
|
122
|
+
arguments: '{"query": "test"}',
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
} as UIChatMessage,
|
|
128
|
+
];
|
|
129
|
+
|
|
130
|
+
const newTools = [
|
|
131
|
+
{
|
|
132
|
+
id: 'tool1',
|
|
133
|
+
identifier: 'search',
|
|
134
|
+
apiName: 'search',
|
|
135
|
+
type: 'builtin',
|
|
136
|
+
arguments: '{"query": "updated"}',
|
|
137
|
+
result: {
|
|
138
|
+
id: 'result1',
|
|
139
|
+
content: 'Search result',
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
];
|
|
143
|
+
|
|
144
|
+
const payload: MessageDispatch = {
|
|
145
|
+
type: 'updateMessage',
|
|
146
|
+
id: 'block1',
|
|
147
|
+
value: { tools: newTools as any },
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const newState = messagesReducer(stateWithGroup, payload);
|
|
151
|
+
const groupMessage = newState.find((m) => m.id === 'group1');
|
|
152
|
+
const block = groupMessage?.children?.find((b) => b.id === 'block1');
|
|
153
|
+
|
|
154
|
+
expect(block?.tools).toEqual(newTools);
|
|
155
|
+
expect(groupMessage?.updatedAt).toBeGreaterThan(1629264000000);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('should not modify state when updating non-existent block in group message', () => {
|
|
159
|
+
const stateWithGroup: UIChatMessage[] = [
|
|
160
|
+
...initialState,
|
|
161
|
+
{
|
|
162
|
+
id: 'group1',
|
|
163
|
+
role: 'group',
|
|
164
|
+
content: '',
|
|
165
|
+
createdAt: 1629264000000,
|
|
166
|
+
updatedAt: 1629264000000,
|
|
167
|
+
meta: {},
|
|
168
|
+
children: [
|
|
169
|
+
{
|
|
170
|
+
id: 'block1',
|
|
171
|
+
content: 'Block content',
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
} as UIChatMessage,
|
|
175
|
+
];
|
|
176
|
+
|
|
177
|
+
const payload: MessageDispatch = {
|
|
178
|
+
type: 'updateMessage',
|
|
179
|
+
id: 'nonexistentBlock',
|
|
180
|
+
value: { content: 'Updated content' },
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const newState = messagesReducer(stateWithGroup, payload);
|
|
184
|
+
expect(newState).toEqual(stateWithGroup);
|
|
70
185
|
});
|
|
71
186
|
});
|
|
72
187
|
|
|
@@ -502,4 +617,247 @@ describe('messagesReducer', () => {
|
|
|
502
617
|
expect(newState).toEqual(initialState);
|
|
503
618
|
});
|
|
504
619
|
});
|
|
620
|
+
|
|
621
|
+
describe('updateGroupBlockToolResult', () => {
|
|
622
|
+
it('should update a tool result in a group message block', () => {
|
|
623
|
+
const stateWithGroup: UIChatMessage[] = [
|
|
624
|
+
...initialState,
|
|
625
|
+
{
|
|
626
|
+
id: 'group1',
|
|
627
|
+
role: 'group',
|
|
628
|
+
content: '',
|
|
629
|
+
createdAt: 1629264000000,
|
|
630
|
+
updatedAt: 1629264000000,
|
|
631
|
+
meta: {},
|
|
632
|
+
children: [
|
|
633
|
+
{
|
|
634
|
+
id: 'block1',
|
|
635
|
+
content: 'Assistant response',
|
|
636
|
+
tools: [
|
|
637
|
+
{
|
|
638
|
+
id: 'tool1',
|
|
639
|
+
identifier: 'search',
|
|
640
|
+
apiName: 'search',
|
|
641
|
+
type: 'builtin',
|
|
642
|
+
arguments: '{"query": "test"}',
|
|
643
|
+
result: {
|
|
644
|
+
id: 'result1',
|
|
645
|
+
content: 'Initial result',
|
|
646
|
+
},
|
|
647
|
+
},
|
|
648
|
+
],
|
|
649
|
+
},
|
|
650
|
+
],
|
|
651
|
+
} as UIChatMessage,
|
|
652
|
+
];
|
|
653
|
+
|
|
654
|
+
const payload: MessageDispatch = {
|
|
655
|
+
type: 'updateGroupBlockToolResult',
|
|
656
|
+
groupMessageId: 'group1',
|
|
657
|
+
blockId: 'block1',
|
|
658
|
+
toolId: 'tool1',
|
|
659
|
+
toolResult: {
|
|
660
|
+
id: 'result1',
|
|
661
|
+
content: 'Updated result content',
|
|
662
|
+
state: { foo: 'bar' },
|
|
663
|
+
},
|
|
664
|
+
};
|
|
665
|
+
|
|
666
|
+
const newState = messagesReducer(stateWithGroup, payload);
|
|
667
|
+
const groupMessage = newState.find((m) => m.id === 'group1');
|
|
668
|
+
const block = groupMessage?.children?.find((b) => b.id === 'block1');
|
|
669
|
+
const tool = block?.tools?.find((t) => t.id === 'tool1');
|
|
670
|
+
|
|
671
|
+
expect(tool?.result).toEqual({
|
|
672
|
+
id: 'result1',
|
|
673
|
+
content: 'Updated result content',
|
|
674
|
+
state: { foo: 'bar' },
|
|
675
|
+
});
|
|
676
|
+
expect(groupMessage?.updatedAt).toBeGreaterThan(1629264000000);
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
it('should not modify state if group message is not found', () => {
|
|
680
|
+
const payload: MessageDispatch = {
|
|
681
|
+
type: 'updateGroupBlockToolResult',
|
|
682
|
+
groupMessageId: 'nonexistent',
|
|
683
|
+
blockId: 'block1',
|
|
684
|
+
toolId: 'tool1',
|
|
685
|
+
toolResult: {
|
|
686
|
+
id: 'result1',
|
|
687
|
+
content: 'Updated result',
|
|
688
|
+
},
|
|
689
|
+
};
|
|
690
|
+
|
|
691
|
+
const newState = messagesReducer(initialState, payload);
|
|
692
|
+
expect(newState).toEqual(initialState);
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
it('should not modify state if block is not found', () => {
|
|
696
|
+
const stateWithGroup: UIChatMessage[] = [
|
|
697
|
+
...initialState,
|
|
698
|
+
{
|
|
699
|
+
id: 'group1',
|
|
700
|
+
role: 'group',
|
|
701
|
+
content: '',
|
|
702
|
+
createdAt: 1629264000000,
|
|
703
|
+
updatedAt: 1629264000000,
|
|
704
|
+
meta: {},
|
|
705
|
+
children: [
|
|
706
|
+
{
|
|
707
|
+
id: 'block1',
|
|
708
|
+
content: 'Assistant response',
|
|
709
|
+
tools: [],
|
|
710
|
+
},
|
|
711
|
+
],
|
|
712
|
+
} as UIChatMessage,
|
|
713
|
+
];
|
|
714
|
+
|
|
715
|
+
const payload: MessageDispatch = {
|
|
716
|
+
type: 'updateGroupBlockToolResult',
|
|
717
|
+
groupMessageId: 'group1',
|
|
718
|
+
blockId: 'nonexistentBlock',
|
|
719
|
+
toolId: 'tool1',
|
|
720
|
+
toolResult: {
|
|
721
|
+
id: 'result1',
|
|
722
|
+
content: 'Updated result',
|
|
723
|
+
},
|
|
724
|
+
};
|
|
725
|
+
|
|
726
|
+
const newState = messagesReducer(stateWithGroup, payload);
|
|
727
|
+
expect(newState).toEqual(stateWithGroup);
|
|
728
|
+
});
|
|
729
|
+
|
|
730
|
+
it('should not modify state if tool is not found', () => {
|
|
731
|
+
const stateWithGroup: UIChatMessage[] = [
|
|
732
|
+
...initialState,
|
|
733
|
+
{
|
|
734
|
+
id: 'group1',
|
|
735
|
+
role: 'group',
|
|
736
|
+
content: '',
|
|
737
|
+
createdAt: 1629264000000,
|
|
738
|
+
updatedAt: 1629264000000,
|
|
739
|
+
meta: {},
|
|
740
|
+
children: [
|
|
741
|
+
{
|
|
742
|
+
id: 'block1',
|
|
743
|
+
content: 'Assistant response',
|
|
744
|
+
tools: [
|
|
745
|
+
{
|
|
746
|
+
id: 'tool1',
|
|
747
|
+
identifier: 'search',
|
|
748
|
+
apiName: 'search',
|
|
749
|
+
type: 'builtin',
|
|
750
|
+
arguments: '{"query": "test"}',
|
|
751
|
+
},
|
|
752
|
+
],
|
|
753
|
+
},
|
|
754
|
+
],
|
|
755
|
+
} as UIChatMessage,
|
|
756
|
+
];
|
|
757
|
+
|
|
758
|
+
const payload: MessageDispatch = {
|
|
759
|
+
type: 'updateGroupBlockToolResult',
|
|
760
|
+
groupMessageId: 'group1',
|
|
761
|
+
blockId: 'block1',
|
|
762
|
+
toolId: 'nonexistentTool',
|
|
763
|
+
toolResult: {
|
|
764
|
+
id: 'result1',
|
|
765
|
+
content: 'Updated result',
|
|
766
|
+
},
|
|
767
|
+
};
|
|
768
|
+
|
|
769
|
+
const newState = messagesReducer(stateWithGroup, payload);
|
|
770
|
+
expect(newState).toEqual(stateWithGroup);
|
|
771
|
+
});
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
describe('addGroupBlock', () => {
|
|
775
|
+
it('should add a new block to group message children', () => {
|
|
776
|
+
const stateWithGroup: UIChatMessage[] = [
|
|
777
|
+
...initialState,
|
|
778
|
+
{
|
|
779
|
+
id: 'group1',
|
|
780
|
+
role: 'group',
|
|
781
|
+
content: '',
|
|
782
|
+
createdAt: 1629264000000,
|
|
783
|
+
updatedAt: 1629264000000,
|
|
784
|
+
meta: {},
|
|
785
|
+
children: [
|
|
786
|
+
{
|
|
787
|
+
id: 'block1',
|
|
788
|
+
content: 'First block',
|
|
789
|
+
},
|
|
790
|
+
],
|
|
791
|
+
} as UIChatMessage,
|
|
792
|
+
];
|
|
793
|
+
|
|
794
|
+
const payload: MessageDispatch = {
|
|
795
|
+
type: 'addGroupBlock',
|
|
796
|
+
groupMessageId: 'group1',
|
|
797
|
+
blockId: 'block2',
|
|
798
|
+
value: {
|
|
799
|
+
id: 'block2',
|
|
800
|
+
content: 'Second block',
|
|
801
|
+
},
|
|
802
|
+
};
|
|
803
|
+
|
|
804
|
+
const newState = messagesReducer(stateWithGroup, payload);
|
|
805
|
+
const groupMessage = newState.find((m) => m.id === 'group1');
|
|
806
|
+
|
|
807
|
+
expect(groupMessage?.children).toHaveLength(2);
|
|
808
|
+
expect(groupMessage?.children?.[1]).toEqual({
|
|
809
|
+
id: 'block2',
|
|
810
|
+
content: 'Second block',
|
|
811
|
+
});
|
|
812
|
+
expect(groupMessage?.updatedAt).toBeGreaterThan(1629264000000);
|
|
813
|
+
});
|
|
814
|
+
|
|
815
|
+
it('should not modify state if group message is not found', () => {
|
|
816
|
+
const stateWithGroup: UIChatMessage[] = [
|
|
817
|
+
...initialState,
|
|
818
|
+
{
|
|
819
|
+
id: 'group1',
|
|
820
|
+
role: 'group',
|
|
821
|
+
content: '',
|
|
822
|
+
createdAt: 1629264000000,
|
|
823
|
+
updatedAt: 1629264000000,
|
|
824
|
+
meta: {},
|
|
825
|
+
children: [
|
|
826
|
+
{
|
|
827
|
+
id: 'block1',
|
|
828
|
+
content: 'First block',
|
|
829
|
+
},
|
|
830
|
+
],
|
|
831
|
+
} as UIChatMessage,
|
|
832
|
+
];
|
|
833
|
+
|
|
834
|
+
const payload: MessageDispatch = {
|
|
835
|
+
type: 'addGroupBlock',
|
|
836
|
+
groupMessageId: 'nonexistentGroup',
|
|
837
|
+
blockId: 'block2',
|
|
838
|
+
value: {
|
|
839
|
+
id: 'block2',
|
|
840
|
+
content: 'Second block',
|
|
841
|
+
},
|
|
842
|
+
};
|
|
843
|
+
|
|
844
|
+
const newState = messagesReducer(stateWithGroup, payload);
|
|
845
|
+
expect(newState).toEqual(stateWithGroup);
|
|
846
|
+
});
|
|
847
|
+
|
|
848
|
+
it('should not modify state if message is not a group message', () => {
|
|
849
|
+
const payload: MessageDispatch = {
|
|
850
|
+
type: 'addGroupBlock',
|
|
851
|
+
groupMessageId: 'message1',
|
|
852
|
+
blockId: 'block2',
|
|
853
|
+
value: {
|
|
854
|
+
id: 'block2',
|
|
855
|
+
content: 'Second block',
|
|
856
|
+
},
|
|
857
|
+
};
|
|
858
|
+
|
|
859
|
+
const newState = messagesReducer(initialState, payload);
|
|
860
|
+
expect(newState).toEqual(initialState);
|
|
861
|
+
});
|
|
862
|
+
});
|
|
505
863
|
});
|
|
@@ -75,6 +75,29 @@ interface UpdateMessageExtra {
|
|
|
75
75
|
value: any;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
interface UpdateGroupBlockToolResult {
|
|
79
|
+
blockId: string;
|
|
80
|
+
groupMessageId: string;
|
|
81
|
+
toolId: string;
|
|
82
|
+
toolResult: {
|
|
83
|
+
content: string;
|
|
84
|
+
error?: any;
|
|
85
|
+
id: string;
|
|
86
|
+
state?: any;
|
|
87
|
+
};
|
|
88
|
+
type: 'updateGroupBlockToolResult';
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
interface AddGroupBlock {
|
|
92
|
+
blockId: string;
|
|
93
|
+
groupMessageId: string;
|
|
94
|
+
type: 'addGroupBlock';
|
|
95
|
+
value: {
|
|
96
|
+
content: string;
|
|
97
|
+
id: string;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
78
101
|
export type MessageDispatch =
|
|
79
102
|
| CreateMessage
|
|
80
103
|
| UpdateMessage
|
|
@@ -86,7 +109,9 @@ export type MessageDispatch =
|
|
|
86
109
|
| UpdateMessageTools
|
|
87
110
|
| AddMessageTool
|
|
88
111
|
| DeleteMessageTool
|
|
89
|
-
| DeleteMessages
|
|
112
|
+
| DeleteMessages
|
|
113
|
+
| UpdateGroupBlockToolResult
|
|
114
|
+
| AddGroupBlock;
|
|
90
115
|
|
|
91
116
|
export const messagesReducer = (
|
|
92
117
|
state: UIChatMessage[],
|
|
@@ -96,10 +121,27 @@ export const messagesReducer = (
|
|
|
96
121
|
case 'updateMessage': {
|
|
97
122
|
return produce(state, (draftState) => {
|
|
98
123
|
const { id, value } = payload;
|
|
124
|
+
|
|
125
|
+
// First, try to find in top-level messages
|
|
99
126
|
const index = draftState.findIndex((i) => i.id === id);
|
|
100
|
-
if (index
|
|
127
|
+
if (index >= 0) {
|
|
128
|
+
draftState[index] = merge(draftState[index], { ...value, updatedAt: Date.now() });
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
101
131
|
|
|
102
|
-
|
|
132
|
+
// If not found, search in group message children (blocks)
|
|
133
|
+
for (const message of draftState) {
|
|
134
|
+
if (message.role === 'group' && message.children) {
|
|
135
|
+
const blockIndex = message.children.findIndex((block) => block.id === id);
|
|
136
|
+
if (blockIndex >= 0) {
|
|
137
|
+
message.children[blockIndex] = merge(message.children[blockIndex], {
|
|
138
|
+
...value,
|
|
139
|
+
});
|
|
140
|
+
message.updatedAt = Date.now();
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
103
145
|
});
|
|
104
146
|
}
|
|
105
147
|
|
|
@@ -226,6 +268,48 @@ export const messagesReducer = (
|
|
|
226
268
|
});
|
|
227
269
|
});
|
|
228
270
|
}
|
|
271
|
+
|
|
272
|
+
case 'updateGroupBlockToolResult': {
|
|
273
|
+
return produce(state, (draftState) => {
|
|
274
|
+
const { groupMessageId, blockId, toolId, toolResult } = payload;
|
|
275
|
+
|
|
276
|
+
// Find the group message
|
|
277
|
+
const msg = draftState.find((m) => m.id === groupMessageId);
|
|
278
|
+
if (!msg || msg.role !== 'group' || !msg.children) return;
|
|
279
|
+
|
|
280
|
+
// Find the block within children
|
|
281
|
+
const block = msg.children.find((b) => b.id === blockId);
|
|
282
|
+
if (!block || !block.tools) return;
|
|
283
|
+
|
|
284
|
+
// Find the tool and update its result
|
|
285
|
+
const tool = block.tools.find((t) => t.id === toolId);
|
|
286
|
+
if (!tool) return;
|
|
287
|
+
|
|
288
|
+
// Update tool result (optimistic update)
|
|
289
|
+
tool.result = toolResult;
|
|
290
|
+
|
|
291
|
+
msg.updatedAt = Date.now();
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
case 'addGroupBlock': {
|
|
296
|
+
return produce(state, (draftState) => {
|
|
297
|
+
const { groupMessageId, blockId, value } = payload;
|
|
298
|
+
|
|
299
|
+
// Find the group message
|
|
300
|
+
const msg = draftState.find((m) => m.id === groupMessageId);
|
|
301
|
+
if (!msg || msg.role !== 'group' || !msg.children) return;
|
|
302
|
+
|
|
303
|
+
// Add new block to children
|
|
304
|
+
msg.children.push({
|
|
305
|
+
content: value.content,
|
|
306
|
+
id: blockId,
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
msg.updatedAt = Date.now();
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
|
|
229
313
|
default: {
|
|
230
314
|
throw new Error('暂未实现的 type,请检查 reducer');
|
|
231
315
|
}
|