flare-chat-core 0.2.1 → 0.2.3

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 (120) hide show
  1. package/README.md +28 -0
  2. package/docs/CAPABILITY-INVENTORY.md +42 -0
  3. package/docs/CHAT-CORE-BOUNDARY.md +47 -0
  4. package/docs/CORE-APP-REALIGNMENT-WORKLOAD-2026-04-18.md +86 -0
  5. package/docs/SSOT-CHAT-CORE-BOUNDARY.md +73 -0
  6. package/docs/SSOT-CHAT-CORE-DATAFLOW.md +97 -0
  7. package/index.html +12 -0
  8. package/package.json +24 -2
  9. package/src/adapters/index.js +6 -0
  10. package/src/adapters/message-api.adapter.js +59 -0
  11. package/src/adapters/session-api.adapter.js +133 -0
  12. package/src/adapters/session-message-api.http.js +161 -0
  13. package/src/adapters/session-message-api.js +34 -0
  14. package/src/adapters/session-message-api.normalize-source-record.test.mjs +180 -0
  15. package/src/adapters/session-message-api.normalizers.js +153 -0
  16. package/src/adapters/source-api.adapter.js +135 -0
  17. package/src/adapters/sse-client.js +244 -0
  18. package/src/adapters/sse-event-dispatcher.js +121 -0
  19. package/src/app/App.jsx +11 -0
  20. package/src/app/AppProviders.jsx +12 -0
  21. package/src/app/ChatWorkspaceScreen.jsx +33 -0
  22. package/src/app/WorkspaceLayout.jsx +190 -0
  23. package/src/app/components/AppCanvasPanel.jsx +64 -0
  24. package/src/app/components/TriggerThresholdPopoverContent.jsx +122 -0
  25. package/src/app/components/WorkspaceBodySection.jsx +156 -0
  26. package/src/app/components/WorkspaceMainPane.jsx +121 -0
  27. package/src/app/components/WorkspaceSessionPane.jsx +70 -0
  28. package/src/app/components/WorkspaceTopBarSection.jsx +71 -0
  29. package/src/app/core-chat-entry/ComposerSectionNode.jsx +241 -0
  30. package/src/app/core-chat-entry/attachmentSendRefs.js +154 -0
  31. package/src/app/core-chat-entry/attachmentSendRefs.test.mjs +101 -0
  32. package/src/app/core-chat-entry/composerActionRouter.js +26 -0
  33. package/src/app/core-chat-entry/constants.js +108 -0
  34. package/src/app/core-chat-entry/selectors.js +28 -0
  35. package/src/app/core-chat-entry/useAppActionErrorGuards.js +68 -0
  36. package/src/app/core-chat-entry/useChatCorePipelines.js +110 -0
  37. package/src/app/core-chat-entry/useComposerModeSuggestion.js +89 -0
  38. package/src/app/core-chat-entry/useDevCapabilityStatusNote.js +22 -0
  39. package/src/app/core-chat-entry/useProjectNameEditing.js +41 -0
  40. package/src/app/core-chat-entry/useProjectSourceUpload.js +341 -0
  41. package/src/app/core-chat-entry/useRealApiReadinessGate.js +103 -0
  42. package/src/app/core-chat-entry/useUnavailableActionError.js +29 -0
  43. package/src/app/core-chat-entry/useWorkspaceCanvasController.jsx +177 -0
  44. package/src/app/core-chat-entry/useWorkspaceCanvasProjection.jsx +171 -0
  45. package/src/app/core-chat-entry/useWorkspaceComposerController.jsx +199 -0
  46. package/src/app/core-chat-entry/useWorkspaceController.jsx +226 -0
  47. package/src/app/core-chat-entry/useWorkspacePanels.js +55 -0
  48. package/src/app/hooks/useComposerAttachmentSync.js +223 -0
  49. package/src/app/hooks/useComposerChooserHandlers.js +52 -0
  50. package/src/app/hooks/useSendWithContextRefs.js +140 -0
  51. package/src/app/hooks/useSendWithContextRefs.test.mjs +29 -0
  52. package/src/app/hooks/useUserThresholdProfile.js +121 -0
  53. package/src/app/index.js +1 -0
  54. package/src/app/selectors/assistantTextSelector.js +73 -0
  55. package/src/app/selectors/canvasEvidenceSummarySelector.js +28 -0
  56. package/src/app/selectors/canvasReportTemplateSelector.js +28 -0
  57. package/src/app/selectors/canvasTabsSelector.js +58 -0
  58. package/src/app/selectors/evidenceProjectionSelector.js +175 -0
  59. package/src/app/selectors/evidenceProjectionSelector.test.mjs +107 -0
  60. package/src/app/selectors/modeSuggestionSelector.js +50 -0
  61. package/src/chat-core/app/mockRuntime.js +291 -0
  62. package/src/chat-core/app/useAppStream.js +187 -0
  63. package/src/chat-core/app/useAppStream.refs.test.mjs +44 -0
  64. package/src/chat-core/app/useAppStream.request-body.test.mjs +116 -0
  65. package/src/chat-core/app/useCoreChatApp.js +115 -0
  66. package/src/chat-core/facade/useBasicConversationFacade.js +280 -0
  67. package/src/chat-core/index.js +9 -1
  68. package/src/chat-core/messages/buildTimelineItems.analysis-route.test.mjs +36 -0
  69. package/src/chat-core/messages/buildTimelineItems.js +139 -13
  70. package/src/chat-core/messages/buildTimelineItems.knowledge-citation.test.mjs +182 -0
  71. package/src/chat-core/messages/contextUsageDefaults.js +3 -0
  72. package/src/chat-core/messages/contextUsageViewModel.js +147 -0
  73. package/src/chat-core/messages/contextUsageViewModel.test.mjs +74 -0
  74. package/src/chat-core/messages/useContextUsageViewModel.js +41 -0
  75. package/src/chat-core/orchestration/useBasicSendHandler.js +55 -0
  76. package/src/chat-core/pipelines/build-action-request.js +46 -0
  77. package/src/chat-core/pipelines/build-stream-request.js +74 -0
  78. package/src/chat-core/pipelines/entity-extraction.js +159 -0
  79. package/src/chat-core/pipelines/preprocess-message.js +16 -0
  80. package/src/chat-core/pipelines/stream-persist-utils.js +32 -0
  81. package/src/chat-core/pipelines/transport/send-mock-stream.js +86 -0
  82. package/src/chat-core/pipelines/transport/send-real-stream.js +330 -0
  83. package/src/chat-core/pipelines/transport/send-real-stream.test.mjs +27 -0
  84. package/src/chat-core/pipelines/transport/send-sourcing-search.js +86 -0
  85. package/src/chat-core/pipelines/transport/send-sourcing-search.test.mjs +14 -0
  86. package/src/chat-core/pipelines/transport/sourcing-response-templates.js +55 -0
  87. package/src/chat-core/pipelines/transport/sourcing-search-api.js +155 -0
  88. package/src/chat-core/runtime/runtimeMode.js +69 -0
  89. package/src/chat-core/session/chatSessionActionTypes.js +24 -0
  90. package/src/chat-core/session/chatSessionReducer.js +352 -0
  91. package/src/chat-core/session/chatSessionReducer.streaming-done.test.mjs +39 -0
  92. package/src/chat-core/session/index.js +2 -0
  93. package/src/chat-core/session/sessionActionsMessages.js +44 -0
  94. package/src/chat-core/session/sessionActionsSessionCrud.js +131 -0
  95. package/src/chat-core/session/sessionActionsStreaming.js +80 -0
  96. package/src/chat-core/session/sessionActionsUiState.js +51 -0
  97. package/src/chat-core/session/useChatSessionReducer.js +62 -455
  98. package/src/chat-core/session/useSessionListController.js +67 -0
  99. package/src/chat-core/stream/sse-client.js +1 -244
  100. package/src/chat-core/stream/sse-event-dispatcher.js +1 -0
  101. package/src/chat-core/stream/sse-events.js +1 -867
  102. package/src/chat-core/stream/useSSEStream.js +1 -356
  103. package/src/chat-core/stream/useStreamSendController.js +46 -0
  104. package/src/contracts/context-ssot.js +47 -0
  105. package/src/contracts/index.js +1 -0
  106. package/src/contracts/sse-events/base-parsers.js +79 -0
  107. package/src/contracts/sse-events/domain-parsers.js +3 -0
  108. package/src/contracts/sse-events/internal-normalizers.js +143 -0
  109. package/src/contracts/sse-events/parsers-intake.js +235 -0
  110. package/src/contracts/sse-events/parsers-runtime.js +37 -0
  111. package/src/contracts/sse-events/parsers-sourcing.js +179 -0
  112. package/src/contracts/sse-events/patch-event-parser.js +121 -0
  113. package/src/contracts/sse-events/runtime-parsers.js +79 -0
  114. package/src/contracts/sse-events.js +4 -0
  115. package/src/index.js +5 -0
  116. package/src/main.jsx +28 -0
  117. package/src/orchestration/index.js +6 -0
  118. package/src/orchestration/useSSEStream.js +221 -0
  119. package/src/state/index.js +4 -0
  120. package/vite.config.js +36 -0
@@ -0,0 +1,122 @@
1
+ import React from 'react';
2
+ import { InfoCircleOutlined } from '@ant-design/icons';
3
+ import { Divider, Popover, Slider, Space, Switch, Typography } from 'antd';
4
+
5
+ const { Text } = Typography;
6
+
7
+ export default function TriggerThresholdPopoverContent({
8
+ evidenceStrictMode,
9
+ setEvidenceStrictMode,
10
+ evidenceHitScoreThreshold,
11
+ setEvidenceHitScoreThreshold,
12
+ languageGuardEnabled,
13
+ setLanguageGuardEnabled,
14
+ friendlyToneEnabled,
15
+ setFriendlyToneEnabled,
16
+ questionModeSuggestionEnabled,
17
+ setQuestionModeSuggestionEnabled,
18
+ }) {
19
+ const rowStyle = {
20
+ alignItems: 'center',
21
+ display: 'flex',
22
+ gap: 12,
23
+ justifyContent: 'space-between',
24
+ minHeight: 32,
25
+ };
26
+ const leftColumnStyle = {
27
+ flex: 1,
28
+ minWidth: 0,
29
+ };
30
+ const rightColumnStyle = {
31
+ alignItems: 'center',
32
+ display: 'flex',
33
+ flexShrink: 0,
34
+ gap: 8,
35
+ justifyContent: 'flex-end',
36
+ minWidth: 116,
37
+ };
38
+ const infoIconStyle = {
39
+ color: 'rgba(0, 0, 0, 0.35)',
40
+ cursor: 'pointer',
41
+ fontSize: 13,
42
+ };
43
+ const renderInfoIcon = (description) => (
44
+ <Popover
45
+ content={<Text style={{ fontSize: 12 }} type="secondary">{description}</Text>}
46
+ overlayStyle={{ maxWidth: 280 }}
47
+ placement="topLeft"
48
+ trigger={['hover', 'click']}
49
+ >
50
+ <InfoCircleOutlined style={infoIconStyle} />
51
+ </Popover>
52
+ );
53
+
54
+ return (
55
+ <div style={{ maxWidth: 320, minWidth: 320, width: 320 }}>
56
+ <Space direction="vertical" size={6} style={{ width: '100%' }}>
57
+ <Text strong>触发阈值与文案风格</Text>
58
+ <div style={rowStyle}>
59
+ <div style={leftColumnStyle}>
60
+ <Text>证据命中严格模式</Text>
61
+ </div>
62
+ <div style={rightColumnStyle}>
63
+ {renderInfoIcon('开启后:仅在具体语义线索命中时展示证据,不再只靠泛关键词。')}
64
+ <Switch checked={evidenceStrictMode} onChange={setEvidenceStrictMode} />
65
+ </div>
66
+ </div>
67
+ <div style={rowStyle}>
68
+ <div style={leftColumnStyle}>
69
+ <Text>证据分数阈值</Text>
70
+ </div>
71
+ <div style={rightColumnStyle}>
72
+ {renderInfoIcon('开启严格模式后,分数低于阈值的证据不会展示。')}
73
+ </div>
74
+ </div>
75
+ <Text type="secondary" style={{ fontSize: 12, marginTop: -2 }}>
76
+ {`当前值:${Number(evidenceHitScoreThreshold || 0).toFixed(2)}`}
77
+ </Text>
78
+ <div style={{ marginTop: -2 }}>
79
+ <Slider
80
+ disabled={!evidenceStrictMode}
81
+ max={1}
82
+ min={0}
83
+ onChange={setEvidenceHitScoreThreshold}
84
+ step={0.01}
85
+ style={{ margin: 0, width: '100%' }}
86
+ value={evidenceHitScoreThreshold}
87
+ />
88
+ </div>
89
+ <Divider style={{ margin: '4px 0' }} />
90
+ <div style={rowStyle}>
91
+ <div style={leftColumnStyle}>
92
+ <Text>文案去系统痕迹</Text>
93
+ </div>
94
+ <div style={rightColumnStyle}>
95
+ {renderInfoIcon('开启后:自动隐藏 mode= / goal= / provider_status 等技术痕迹文案。')}
96
+ <Switch checked={languageGuardEnabled} onChange={setLanguageGuardEnabled} />
97
+ </div>
98
+ </div>
99
+ <Divider style={{ margin: '4px 0' }} />
100
+ <div style={rowStyle}>
101
+ <div style={leftColumnStyle}>
102
+ <Text>友好回复风格</Text>
103
+ </div>
104
+ <div style={rightColumnStyle}>
105
+ {renderInfoIcon('开启后:自动补充更自然的开头与结尾。')}
106
+ <Switch checked={friendlyToneEnabled} onChange={setFriendlyToneEnabled} />
107
+ </div>
108
+ </div>
109
+ <Divider style={{ margin: '4px 0' }} />
110
+ <div style={rowStyle}>
111
+ <div style={leftColumnStyle}>
112
+ <Text>问题回复建议</Text>
113
+ </div>
114
+ <div style={rightColumnStyle}>
115
+ {renderInfoIcon('开启后:当助手提出问题时,统一建议打开梳理模式。')}
116
+ <Switch checked={questionModeSuggestionEnabled} onChange={setQuestionModeSuggestionEnabled} />
117
+ </div>
118
+ </div>
119
+ </Space>
120
+ </div>
121
+ );
122
+ }
@@ -0,0 +1,156 @@
1
+ import React from 'react';
2
+ import {
3
+ ChatWorkspaceSourcesPanel,
4
+ ChatWorkspaceConversationPane,
5
+ ChatWorkspaceProjectInitView,
6
+ } from 'flare-chat-ui';
7
+
8
+ export default function WorkspaceBodySection({
9
+ hasProject,
10
+ activeWorkspaceTab,
11
+ setActiveWorkspaceTab,
12
+ themeTokens,
13
+ projectItems,
14
+ resolvedUILabels,
15
+ handleCreateProject,
16
+ composerNode,
17
+ contentMaxWidth,
18
+ handleOpenSourcePicker,
19
+ handleRemoveSource,
20
+ handleRetrySource,
21
+ handleViewSourceDetail,
22
+ sourceActionError,
23
+ sourceItems,
24
+ sourceRemovingId,
25
+ sourceSyncLoading,
26
+ sourceUploadLoading,
27
+ showCanvasPanel,
28
+ canvasPanelNode,
29
+ streamError,
30
+ streamLoading,
31
+ onStreamRetry,
32
+ renderedTimelineItems,
33
+ onUICardAction,
34
+ registry,
35
+ currentInputValue,
36
+ showAllScenarios,
37
+ onToggleShowAllScenarios,
38
+ visibleScenarios,
39
+ onScenarioCardClick,
40
+ isCompactLayout,
41
+ }) {
42
+ const tabItems = [
43
+ { label: resolvedUILabels.tab_chats || '会话', value: 'chats' },
44
+ { label: resolvedUILabels.tab_sources || '资料', value: 'sources' },
45
+ ];
46
+ const activeTabIndex = Math.max(
47
+ 0,
48
+ tabItems.findIndex((item) => item.value === activeWorkspaceTab),
49
+ );
50
+
51
+ const compactTabSwitchNode = (hasProject && isCompactLayout) ? (
52
+ <div style={{ padding: '8px 12px 6px' }}>
53
+ <div
54
+ className="flare-workspace-tab-switch"
55
+ role="tablist"
56
+ aria-label="workspace tabs"
57
+ >
58
+ <span
59
+ className="flare-workspace-tab-switch-thumb"
60
+ style={{ transform: `translateX(${activeTabIndex * 100}%)` }}
61
+ />
62
+ {tabItems.map((item) => {
63
+ const active = item.value === activeWorkspaceTab;
64
+ return (
65
+ <button
66
+ key={item.value}
67
+ aria-selected={active}
68
+ className={`flare-workspace-tab-switch-item${active ? ' is-active' : ''}`}
69
+ onClick={() => setActiveWorkspaceTab(item.value)}
70
+ role="tab"
71
+ type="button"
72
+ >
73
+ {item.label}
74
+ </button>
75
+ );
76
+ })}
77
+ </div>
78
+ </div>
79
+ ) : null;
80
+
81
+ if (!hasProject) {
82
+ return (
83
+ <ChatWorkspaceProjectInitView
84
+ isCompactLayout={isCompactLayout}
85
+ themeTokens={themeTokens}
86
+ resolvedProductName="F.L.A.R.E"
87
+ resolvedProductTag="项目协同工作台"
88
+ hasProjectItems={projectItems.length > 0}
89
+ resolvedUILabels={resolvedUILabels}
90
+ handleCreateProject={handleCreateProject}
91
+ />
92
+ );
93
+ }
94
+
95
+ if (activeWorkspaceTab === 'sources') {
96
+ return (
97
+ <>
98
+ {compactTabSwitchNode}
99
+ <ChatWorkspaceSourcesPanel
100
+ composerNode={composerNode}
101
+ contentMaxWidth={contentMaxWidth}
102
+ handleOpenSourcePicker={handleOpenSourcePicker}
103
+ handleRemoveSource={handleRemoveSource}
104
+ handleRetrySource={handleRetrySource}
105
+ handleViewSourceDetail={handleViewSourceDetail}
106
+ isCompactLayout={isCompactLayout}
107
+ resolvedUILabels={resolvedUILabels}
108
+ sourceActionError={sourceActionError}
109
+ sourceItems={sourceItems}
110
+ sourceRemovingId={sourceRemovingId}
111
+ sourceSyncLoading={sourceSyncLoading}
112
+ sourceUploadLoading={sourceUploadLoading}
113
+ themeTokens={themeTokens}
114
+ />
115
+ </>
116
+ );
117
+ }
118
+
119
+ return (
120
+ <>
121
+ {compactTabSwitchNode}
122
+ <ChatWorkspaceConversationPane
123
+ themeTokens={themeTokens}
124
+ isCompactLayout={isCompactLayout}
125
+ resolvedActiveModeKey="auto"
126
+ canvasWorkspaceFullscreenMode={false}
127
+ showCanvasPanel={showCanvasPanel}
128
+ canvasPanelNode={canvasPanelNode}
129
+ composerNode={composerNode}
130
+ contentMaxWidth={contentMaxWidth}
131
+ streamError={streamError}
132
+ streamLoading={streamLoading}
133
+ onStreamRetry={onStreamRetry}
134
+ renderedTimeline={{
135
+ isEmpty: renderedTimelineItems.length === 0,
136
+ items: renderedTimelineItems,
137
+ }}
138
+ onUICardAction={onUICardAction}
139
+ registry={registry}
140
+ resolvedUILabels={resolvedUILabels}
141
+ showWorkspaceDebugPanel={false}
142
+ resolvedDevMode="full_effects"
143
+ workspaceEventLog={[]}
144
+ workspaceDocSnapshot={{}}
145
+ shouldRenderRecommendationPanel={renderedTimelineItems.length === 0}
146
+ currentInputValue={currentInputValue}
147
+ recommendationPanelTitle="起步入口"
148
+ canExpandScenarios
149
+ showAllScenarios={showAllScenarios}
150
+ onToggleShowAllScenarios={onToggleShowAllScenarios}
151
+ visibleScenarios={visibleScenarios}
152
+ onScenarioCardClick={onScenarioCardClick}
153
+ />
154
+ </>
155
+ );
156
+ }
@@ -0,0 +1,121 @@
1
+ import React from 'react';
2
+ import WorkspaceTopBarSection from './WorkspaceTopBarSection.jsx';
3
+ import WorkspaceBodySection from './WorkspaceBodySection.jsx';
4
+
5
+ export default function WorkspaceMainPane({
6
+ themeTokens,
7
+ hasProject,
8
+ viewModel,
9
+ projectSlot,
10
+ projectNameEditing,
11
+ projectNameDraft,
12
+ setProjectNameDraft,
13
+ handleProjectNameSave,
14
+ handleProjectNameCancel,
15
+ projectDisplayName,
16
+ handleProjectNameStartEdit,
17
+ activeWorkspaceTab,
18
+ setActiveWorkspaceTab,
19
+ resolvedUILabels,
20
+ activeSession,
21
+ knowledgeHubPopoverContent,
22
+ knowledgeHubPopoverOpen,
23
+ setKnowledgeHubPopoverOpen,
24
+ handleOpenKnowledgeHub,
25
+ showCanvasPanel,
26
+ handleToggleWorkspacePanel,
27
+ projectItems,
28
+ actionGuards,
29
+ composerNode,
30
+ contentMaxWidth,
31
+ handleOpenSourcePicker,
32
+ handleRemoveSource,
33
+ handleRetrySource,
34
+ handleViewSourceDetail,
35
+ sourceActionError,
36
+ sourceItems,
37
+ sourceRemovingId,
38
+ sourceSyncLoading,
39
+ sourceUploadLoading,
40
+ canvasPanelNode,
41
+ renderedTimelineItems,
42
+ handleUICardAction,
43
+ generativeRegistry,
44
+ showAllScenarios,
45
+ setShowAllScenarios,
46
+ visibleScenarios,
47
+ isCompactLayout,
48
+ showSidebarMenuButton,
49
+ handleOpenSidebarMenu,
50
+ }) {
51
+ const resolvedSessionDigestText = activeSession
52
+ ? `当前会话:${String(activeSession.preview || activeSession.title || '').trim()}`
53
+ : '';
54
+ return (
55
+ <div style={{ background: themeTokens.panelBg, display: 'flex', flexDirection: 'column', minWidth: 0 }}>
56
+ {hasProject ? (
57
+ <WorkspaceTopBarSection
58
+ hasConversationStarted={viewModel.timeline.items.length > 0}
59
+ projectSlot={projectSlot}
60
+ projectNameEditing={projectNameEditing}
61
+ projectNameDraft={projectNameDraft}
62
+ setProjectNameDraft={setProjectNameDraft}
63
+ handleProjectNameSave={handleProjectNameSave}
64
+ handleProjectNameCancel={handleProjectNameCancel}
65
+ resolvedProjectDisplayName={projectDisplayName}
66
+ handleProjectNameStartEdit={handleProjectNameStartEdit}
67
+ activeWorkspaceTab={activeWorkspaceTab}
68
+ setActiveWorkspaceTab={setActiveWorkspaceTab}
69
+ themeTokens={themeTokens}
70
+ resolvedUILabels={resolvedUILabels}
71
+ hasSessionDigest={Boolean(activeSession)}
72
+ resolvedSessionDigest={resolvedSessionDigestText}
73
+ knowledgeHubPopoverContent={knowledgeHubPopoverContent}
74
+ knowledgeHubPopoverOpen={knowledgeHubPopoverOpen}
75
+ handleKnowledgeHubOpenChange={setKnowledgeHubPopoverOpen}
76
+ handleOpenKnowledgeHub={handleOpenKnowledgeHub}
77
+ showCanvasPanel={showCanvasPanel}
78
+ handleToggleWorkspacePanel={handleToggleWorkspacePanel}
79
+ isCompactLayout={isCompactLayout}
80
+ showSidebarMenuButton={showSidebarMenuButton}
81
+ handleOpenSidebarMenu={handleOpenSidebarMenu}
82
+ />
83
+ ) : null}
84
+
85
+ <WorkspaceBodySection
86
+ hasProject={hasProject}
87
+ activeWorkspaceTab={activeWorkspaceTab}
88
+ setActiveWorkspaceTab={setActiveWorkspaceTab}
89
+ themeTokens={themeTokens}
90
+ projectItems={projectItems}
91
+ resolvedUILabels={resolvedUILabels}
92
+ handleCreateProject={actionGuards.handleCreateProject}
93
+ composerNode={composerNode}
94
+ contentMaxWidth={contentMaxWidth}
95
+ handleOpenSourcePicker={handleOpenSourcePicker}
96
+ handleRemoveSource={handleRemoveSource}
97
+ handleRetrySource={handleRetrySource}
98
+ handleViewSourceDetail={handleViewSourceDetail}
99
+ sourceActionError={sourceActionError}
100
+ sourceItems={sourceItems}
101
+ sourceRemovingId={sourceRemovingId}
102
+ sourceSyncLoading={sourceSyncLoading}
103
+ sourceUploadLoading={sourceUploadLoading}
104
+ showCanvasPanel={showCanvasPanel}
105
+ canvasPanelNode={canvasPanelNode}
106
+ streamError={actionGuards.streamError}
107
+ streamLoading={viewModel.timeline.loading}
108
+ onStreamRetry={viewModel.toolbar.onRefreshSessions}
109
+ renderedTimelineItems={renderedTimelineItems}
110
+ onUICardAction={handleUICardAction}
111
+ registry={generativeRegistry}
112
+ currentInputValue={viewModel.composer.value}
113
+ showAllScenarios={showAllScenarios}
114
+ onToggleShowAllScenarios={() => setShowAllScenarios((prev) => !prev)}
115
+ visibleScenarios={visibleScenarios}
116
+ onScenarioCardClick={(entry) => viewModel.composer.onChange({ target: { value: entry.prompt } })}
117
+ isCompactLayout={isCompactLayout}
118
+ />
119
+ </div>
120
+ );
121
+ }
@@ -0,0 +1,70 @@
1
+ import React from 'react';
2
+ import { SessionListPane } from 'flare-chat-ui';
3
+
4
+ export default function WorkspaceSessionPane({
5
+ themeTokens,
6
+ viewModel,
7
+ actionGuards,
8
+ apiReadinessGate,
9
+ hasProject,
10
+ projectItems,
11
+ projectSlot,
12
+ sessions,
13
+ resolvedUILabels,
14
+ onAfterSidebarAction,
15
+ }) {
16
+ const handleAfterAction = () => {
17
+ if (typeof onAfterSidebarAction === 'function') {
18
+ onAfterSidebarAction();
19
+ }
20
+ };
21
+
22
+ return (
23
+ <div style={{ minWidth: 0 }}>
24
+ <SessionListPane
25
+ activeSessionId={viewModel.sessionList.activeSessionId}
26
+ error={actionGuards.sessionPaneError}
27
+ loading={viewModel.timeline.loading || apiReadinessGate.checking}
28
+ onCreateProject={() => {
29
+ actionGuards.handleCreateProject?.();
30
+ handleAfterAction();
31
+ }}
32
+ onCreateSession={(project) => {
33
+ actionGuards.handleCreateSession?.(project);
34
+ handleAfterAction();
35
+ }}
36
+ onNewSession={(project) => {
37
+ actionGuards.handleCreateSession?.(project);
38
+ handleAfterAction();
39
+ }}
40
+ onOperationClick={() => {}}
41
+ onProjectSelect={(project) => {
42
+ viewModel.sessionList.onProjectSelect?.(project);
43
+ handleAfterAction();
44
+ }}
45
+ onSelectSession={(sessionId) => {
46
+ viewModel.sessionList.onSelectSession?.(sessionId);
47
+ handleAfterAction();
48
+ }}
49
+ onRenameSession={viewModel.sessionList.onRenameSession}
50
+ onArchiveSession={viewModel.sessionList.onArchiveSession}
51
+ operations={[]}
52
+ operationsTitle={resolvedUILabels.sidebar_operations_title}
53
+ projectItems={hasProject ? projectItems : []}
54
+ projectSlot={hasProject ? projectSlot : null}
55
+ compact={false}
56
+ emptyProjectsLabel={resolvedUILabels.project_list_empty}
57
+ emptySessionsLabel="暂无会话"
58
+ loadErrorMessage={apiReadinessGate.error ? 'API 预检失败' : '加载会话列表失败'}
59
+ createProjectLabel={resolvedUILabels.new_project_button}
60
+ createSessionInProjectLabel={resolvedUILabels.new_session_button}
61
+ newSessionLabel={resolvedUILabels.new_session_button}
62
+ sessions={sessions}
63
+ sortProjectsByNameLabel={resolvedUILabels.project_sort_by_name}
64
+ sortProjectsLabel={resolvedUILabels.project_sort_by_updated}
65
+ themeTokens={themeTokens}
66
+ title={hasProject ? '会话历史' : '项目列表'}
67
+ />
68
+ </div>
69
+ );
70
+ }
@@ -0,0 +1,71 @@
1
+ import React from 'react';
2
+ import { Typography } from 'antd';
3
+ import { ChatWorkspaceTopBar } from 'flare-chat-ui';
4
+
5
+ const { Text } = Typography;
6
+
7
+ export default function WorkspaceTopBarSection({
8
+ hasConversationStarted,
9
+ projectSlot,
10
+ projectNameEditing,
11
+ projectNameDraft,
12
+ setProjectNameDraft,
13
+ handleProjectNameSave,
14
+ handleProjectNameCancel,
15
+ resolvedProjectDisplayName,
16
+ handleProjectNameStartEdit,
17
+ activeWorkspaceTab,
18
+ setActiveWorkspaceTab,
19
+ themeTokens,
20
+ resolvedUILabels,
21
+ hasSessionDigest,
22
+ resolvedSessionDigest,
23
+ knowledgeHubPopoverContent,
24
+ knowledgeHubPopoverOpen,
25
+ handleKnowledgeHubOpenChange,
26
+ handleOpenKnowledgeHub,
27
+ showCanvasPanel,
28
+ handleToggleWorkspacePanel,
29
+ isCompactLayout,
30
+ showSidebarMenuButton,
31
+ handleOpenSidebarMenu,
32
+ }) {
33
+ return (
34
+ <ChatWorkspaceTopBar
35
+ hasConversationStarted={hasConversationStarted}
36
+ projectSlot={projectSlot}
37
+ projectNameEditing={projectNameEditing}
38
+ projectNameDraft={projectNameDraft}
39
+ setProjectNameDraft={setProjectNameDraft}
40
+ handleProjectNameSave={handleProjectNameSave}
41
+ handleProjectNameCancel={handleProjectNameCancel}
42
+ resolvedProjectDisplayName={resolvedProjectDisplayName}
43
+ handleProjectNameStartEdit={handleProjectNameStartEdit}
44
+ isCompactLayout={isCompactLayout}
45
+ activeWorkspaceTab={activeWorkspaceTab}
46
+ setActiveWorkspaceTab={setActiveWorkspaceTab}
47
+ segmentedThemeStyle={{}}
48
+ themeTokens={themeTokens}
49
+ resolvedUILabels={resolvedUILabels}
50
+ resolvedProductName={resolvedProjectDisplayName}
51
+ customerRoleFallback="FLARE"
52
+ hasSessionDigest={hasSessionDigest}
53
+ resolvedSessionDigest={resolvedSessionDigest}
54
+ knowledgeHubPopoverContent={knowledgeHubPopoverContent}
55
+ knowledgeHubPopoverOpen={knowledgeHubPopoverOpen}
56
+ handleKnowledgeHubOpenChange={handleKnowledgeHubOpenChange}
57
+ handleOpenKnowledgeHub={handleOpenKnowledgeHub}
58
+ mcpHubPopoverContent={<Text type="secondary">MCP(演示)</Text>}
59
+ mcpHubPopoverOpen={false}
60
+ handleMcpHubOpenChange={() => {}}
61
+ handleOpenMcpHub={() => {}}
62
+ workspaceOpenButtonVisible
63
+ hasUnseenWorkspaceUpdate={false}
64
+ showCanvasPanel={showCanvasPanel}
65
+ handleToggleWorkspacePanel={handleToggleWorkspacePanel}
66
+ showSidebarMenuButton={showSidebarMenuButton}
67
+ handleOpenSidebarMenu={handleOpenSidebarMenu}
68
+ showWorkspaceTabSwitch={!isCompactLayout}
69
+ />
70
+ );
71
+ }