flare-chat-core 0.2.2 → 0.2.4

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 (122) hide show
  1. package/dist/index.js +6343 -0
  2. package/package.json +19 -22
  3. package/docs/CAPABILITY-INVENTORY.md +0 -42
  4. package/docs/CHAT-CORE-BOUNDARY.md +0 -47
  5. package/docs/CORE-APP-REALIGNMENT-WORKLOAD-2026-04-18.md +0 -86
  6. package/docs/SSOT-CHAT-CORE-BOUNDARY.md +0 -73
  7. package/docs/SSOT-CHAT-CORE-DATAFLOW.md +0 -97
  8. package/index.html +0 -12
  9. package/scripts/check.sh +0 -15
  10. package/src/adapters/index.js +0 -6
  11. package/src/adapters/message-api.adapter.js +0 -59
  12. package/src/adapters/session-api.adapter.js +0 -133
  13. package/src/adapters/session-message-api.http.js +0 -161
  14. package/src/adapters/session-message-api.js +0 -34
  15. package/src/adapters/session-message-api.normalize-source-record.test.mjs +0 -180
  16. package/src/adapters/session-message-api.normalizers.js +0 -153
  17. package/src/adapters/source-api.adapter.js +0 -135
  18. package/src/adapters/sse-client.js +0 -244
  19. package/src/adapters/sse-event-dispatcher.js +0 -121
  20. package/src/app/App.jsx +0 -11
  21. package/src/app/AppProviders.jsx +0 -12
  22. package/src/app/ChatWorkspaceScreen.jsx +0 -33
  23. package/src/app/WorkspaceLayout.jsx +0 -125
  24. package/src/app/components/AppCanvasPanel.jsx +0 -64
  25. package/src/app/components/TriggerThresholdPopoverContent.jsx +0 -122
  26. package/src/app/components/WorkspaceBodySection.jsx +0 -109
  27. package/src/app/components/WorkspaceMainPane.jsx +0 -113
  28. package/src/app/components/WorkspaceSessionPane.jsx +0 -48
  29. package/src/app/components/WorkspaceTopBarSection.jsx +0 -65
  30. package/src/app/core-chat-entry/ComposerSectionNode.jsx +0 -241
  31. package/src/app/core-chat-entry/attachmentSendRefs.js +0 -154
  32. package/src/app/core-chat-entry/attachmentSendRefs.test.mjs +0 -101
  33. package/src/app/core-chat-entry/composerActionRouter.js +0 -26
  34. package/src/app/core-chat-entry/constants.js +0 -108
  35. package/src/app/core-chat-entry/selectors.js +0 -28
  36. package/src/app/core-chat-entry/useAppActionErrorGuards.js +0 -68
  37. package/src/app/core-chat-entry/useChatCorePipelines.js +0 -110
  38. package/src/app/core-chat-entry/useComposerModeSuggestion.js +0 -89
  39. package/src/app/core-chat-entry/useDevCapabilityStatusNote.js +0 -22
  40. package/src/app/core-chat-entry/useProjectNameEditing.js +0 -41
  41. package/src/app/core-chat-entry/useProjectSourceUpload.js +0 -341
  42. package/src/app/core-chat-entry/useRealApiReadinessGate.js +0 -103
  43. package/src/app/core-chat-entry/useUnavailableActionError.js +0 -29
  44. package/src/app/core-chat-entry/useWorkspaceCanvasController.jsx +0 -177
  45. package/src/app/core-chat-entry/useWorkspaceCanvasProjection.jsx +0 -171
  46. package/src/app/core-chat-entry/useWorkspaceComposerController.jsx +0 -199
  47. package/src/app/core-chat-entry/useWorkspaceController.jsx +0 -226
  48. package/src/app/core-chat-entry/useWorkspacePanels.js +0 -55
  49. package/src/app/hooks/useComposerAttachmentSync.js +0 -223
  50. package/src/app/hooks/useComposerChooserHandlers.js +0 -52
  51. package/src/app/hooks/useSendWithContextRefs.js +0 -140
  52. package/src/app/hooks/useSendWithContextRefs.test.mjs +0 -29
  53. package/src/app/hooks/useUserThresholdProfile.js +0 -121
  54. package/src/app/index.js +0 -1
  55. package/src/app/selectors/assistantTextSelector.js +0 -73
  56. package/src/app/selectors/canvasEvidenceSummarySelector.js +0 -28
  57. package/src/app/selectors/canvasReportTemplateSelector.js +0 -28
  58. package/src/app/selectors/canvasTabsSelector.js +0 -58
  59. package/src/app/selectors/evidenceProjectionSelector.js +0 -175
  60. package/src/app/selectors/evidenceProjectionSelector.test.mjs +0 -107
  61. package/src/app/selectors/modeSuggestionSelector.js +0 -50
  62. package/src/chat-core/app/mockRuntime.js +0 -291
  63. package/src/chat-core/app/useAppStream.js +0 -187
  64. package/src/chat-core/app/useAppStream.refs.test.mjs +0 -44
  65. package/src/chat-core/app/useAppStream.request-body.test.mjs +0 -116
  66. package/src/chat-core/app/useCoreChatApp.js +0 -115
  67. package/src/chat-core/facade/useBasicConversationFacade.js +0 -280
  68. package/src/chat-core/index.js +0 -14
  69. package/src/chat-core/input/useChatInput.js +0 -103
  70. package/src/chat-core/messages/buildTimelineItems.analysis-route.test.mjs +0 -36
  71. package/src/chat-core/messages/buildTimelineItems.js +0 -233
  72. package/src/chat-core/messages/buildTimelineItems.knowledge-citation.test.mjs +0 -183
  73. package/src/chat-core/messages/contextUsageDefaults.js +0 -3
  74. package/src/chat-core/messages/contextUsageViewModel.js +0 -147
  75. package/src/chat-core/messages/contextUsageViewModel.test.mjs +0 -74
  76. package/src/chat-core/messages/useContextUsageViewModel.js +0 -41
  77. package/src/chat-core/orchestration/useBasicSendHandler.js +0 -55
  78. package/src/chat-core/pipelines/build-action-request.js +0 -46
  79. package/src/chat-core/pipelines/build-stream-request.js +0 -74
  80. package/src/chat-core/pipelines/entity-extraction.js +0 -159
  81. package/src/chat-core/pipelines/preprocess-message.js +0 -16
  82. package/src/chat-core/pipelines/stream-persist-utils.js +0 -32
  83. package/src/chat-core/pipelines/transport/send-mock-stream.js +0 -86
  84. package/src/chat-core/pipelines/transport/send-real-stream.js +0 -330
  85. package/src/chat-core/pipelines/transport/send-real-stream.test.mjs +0 -27
  86. package/src/chat-core/pipelines/transport/send-sourcing-search.js +0 -86
  87. package/src/chat-core/pipelines/transport/send-sourcing-search.test.mjs +0 -14
  88. package/src/chat-core/pipelines/transport/sourcing-response-templates.js +0 -55
  89. package/src/chat-core/pipelines/transport/sourcing-search-api.js +0 -155
  90. package/src/chat-core/runtime/runtimeMode.js +0 -69
  91. package/src/chat-core/session/chatSessionActionTypes.js +0 -24
  92. package/src/chat-core/session/chatSessionReducer.js +0 -352
  93. package/src/chat-core/session/chatSessionReducer.streaming-done.test.mjs +0 -39
  94. package/src/chat-core/session/index.js +0 -2
  95. package/src/chat-core/session/sessionActionsMessages.js +0 -44
  96. package/src/chat-core/session/sessionActionsSessionCrud.js +0 -131
  97. package/src/chat-core/session/sessionActionsStreaming.js +0 -80
  98. package/src/chat-core/session/sessionActionsUiState.js +0 -51
  99. package/src/chat-core/session/useChatSessionReducer.js +0 -131
  100. package/src/chat-core/session/useSessionListController.js +0 -67
  101. package/src/chat-core/stream/sse-client.js +0 -1
  102. package/src/chat-core/stream/sse-event-dispatcher.js +0 -1
  103. package/src/chat-core/stream/sse-events.js +0 -1
  104. package/src/chat-core/stream/useSSEStream.js +0 -1
  105. package/src/chat-core/stream/useStreamSendController.js +0 -46
  106. package/src/contracts/context-ssot.js +0 -47
  107. package/src/contracts/index.js +0 -1
  108. package/src/contracts/sse-events/base-parsers.js +0 -79
  109. package/src/contracts/sse-events/domain-parsers.js +0 -3
  110. package/src/contracts/sse-events/internal-normalizers.js +0 -143
  111. package/src/contracts/sse-events/parsers-intake.js +0 -235
  112. package/src/contracts/sse-events/parsers-runtime.js +0 -37
  113. package/src/contracts/sse-events/parsers-sourcing.js +0 -179
  114. package/src/contracts/sse-events/patch-event-parser.js +0 -121
  115. package/src/contracts/sse-events/runtime-parsers.js +0 -79
  116. package/src/contracts/sse-events.js +0 -4
  117. package/src/index.js +0 -6
  118. package/src/main.jsx +0 -28
  119. package/src/orchestration/index.js +0 -6
  120. package/src/orchestration/useSSEStream.js +0 -221
  121. package/src/state/index.js +0 -4
  122. package/vite.config.js +0 -36
@@ -1,177 +0,0 @@
1
- import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
- import { createDefaultGenerativeRegistry } from 'flare-generative-ui';
3
- import { parseSourcingCandidates } from '../../contracts/sse-events.js';
4
- import { requestSourcingSearchApi } from '../../chat-core/pipelines/transport/sourcing-search-api.js';
5
- import { useWorkspaceCanvasProjection } from './useWorkspaceCanvasProjection.jsx';
6
-
7
- export function useWorkspaceCanvasController({
8
- apiBaseUrl,
9
- projectId,
10
- userId,
11
- activeSessionId,
12
- timeline,
13
- composerModeKey,
14
- evidenceStrictMode,
15
- evidenceHitScoreThreshold,
16
- showCanvasPanel,
17
- setShowCanvasPanel,
18
- canvasActiveTabKey,
19
- setCanvasActiveTabKey,
20
- canvasFullscreenOpen,
21
- setCanvasFullscreenOpen,
22
- inputState,
23
- themeTokens,
24
- languageGuardEnabled,
25
- friendlyToneEnabled,
26
- }) {
27
- const [canvasFocusEvidenceAnchorId, setCanvasFocusEvidenceAnchorId] = useState('');
28
- const [sourcingLoadedTopK, setSourcingLoadedTopK] = useState(8);
29
- const [sourcingHasMore, setSourcingHasMore] = useState(false);
30
- const [sourcingLoadingMore, setSourcingLoadingMore] = useState(false);
31
- const [sourcingDisplayedResultIds, setSourcingDisplayedResultIds] = useState([]);
32
- const sourcingMaxTopK = 100;
33
- const hadSourcingEvidenceRef = useRef(false);
34
-
35
- useEffect(() => {
36
- hadSourcingEvidenceRef.current = false;
37
- setSourcingHasMore(false);
38
- setSourcingLoadedTopK(8);
39
- setSourcingDisplayedResultIds([]);
40
- }, [activeSessionId]);
41
-
42
- const handleUICardAction = useCallback((action) => {
43
- const actionType = String(action?.type || action?.action_key || '').trim();
44
- if (actionType === 'open_evidence_citation') {
45
- const citationId = String(action?.citation_id || '').trim();
46
- setShowCanvasPanel(true);
47
- setCanvasActiveTabKey('evidence');
48
- setCanvasFocusEvidenceAnchorId(citationId ? `retrieval-evidence-${citationId}` : '');
49
- return;
50
- }
51
- if (actionType.includes('canvas') || actionType.includes('evidence') || actionType.includes('sourcing')) {
52
- setShowCanvasPanel(true);
53
- setCanvasActiveTabKey(actionType.includes('sourcing') ? 'sourcing' : 'evidence');
54
- }
55
- }, [setCanvasActiveTabKey, setShowCanvasPanel]);
56
-
57
- const generativeRegistry = useMemo(() => {
58
- const registry = createDefaultGenerativeRegistry();
59
- registry.register('knowledge_search', () => null);
60
- registry.register('sourcing_candidates', () => null);
61
- return registry;
62
- }, []);
63
-
64
- useEffect(() => {
65
- if (!canvasFocusEvidenceAnchorId) {
66
- return;
67
- }
68
- const timer = setTimeout(() => setCanvasFocusEvidenceAnchorId(''), 1600);
69
- return () => clearTimeout(timer);
70
- }, [canvasFocusEvidenceAnchorId]);
71
-
72
- useEffect(() => {
73
- const sourcingItem = [...(Array.isArray(timeline.items) ? timeline.items : [])]
74
- .reverse()
75
- .find((item) => String(item?.type || '').trim() === 'sourcing_candidates');
76
- const payload = (
77
- sourcingItem?.payload
78
- && typeof sourcingItem.payload === 'object'
79
- && !Array.isArray(sourcingItem.payload)
80
- ) ? sourcingItem.payload : null;
81
- if (!payload) {
82
- setSourcingHasMore(false);
83
- setSourcingLoadedTopK(8);
84
- setSourcingDisplayedResultIds([]);
85
- return;
86
- }
87
- const candidates = Array.isArray(payload.candidates) ? payload.candidates : [];
88
- const nextIds = candidates
89
- .map((item) => String(item?.result_id || item?.id || '').trim())
90
- .filter(Boolean);
91
- setSourcingDisplayedResultIds(nextIds);
92
- setSourcingHasMore(payload.has_more === true);
93
- if (Number.isFinite(Number(payload.requested_top_k))) {
94
- setSourcingLoadedTopK(Number(payload.requested_top_k));
95
- }
96
- }, [timeline.items]);
97
-
98
- const handleCanvasSourcingLoadMore = useCallback(async () => {
99
- if (sourcingLoadingMore || !sourcingHasMore || sourcingLoadedTopK >= sourcingMaxTopK) {
100
- return;
101
- }
102
- const sourcingItem = [...(Array.isArray(timeline.items) ? timeline.items : [])]
103
- .reverse()
104
- .find((item) => String(item?.type || '').trim() === 'sourcing_candidates');
105
- const payload = (
106
- sourcingItem?.payload
107
- && typeof sourcingItem.payload === 'object'
108
- && !Array.isArray(sourcingItem.payload)
109
- ) ? sourcingItem.payload : null;
110
- const query = String(payload?.query || '').trim();
111
- const currentSessionId = String(activeSessionId || '').trim();
112
- if (!query || !currentSessionId) {
113
- return;
114
- }
115
- const nextTopK = Math.min(sourcingLoadedTopK + 8, sourcingMaxTopK);
116
- setSourcingLoadingMore(true);
117
- try {
118
- const { sourcingPayload } = await requestSourcingSearchApi({
119
- apiBaseUrl,
120
- projectId,
121
- userId,
122
- sessionId: currentSessionId,
123
- query,
124
- topK: nextTopK,
125
- appendMode: true,
126
- lockExistingOrder: true,
127
- baseResultIds: sourcingDisplayedResultIds,
128
- });
129
- timeline.onSourcingCandidates?.(parseSourcingCandidates(sourcingPayload));
130
- setSourcingLoadedTopK(Number(sourcingPayload.requested_top_k) || nextTopK);
131
- setSourcingHasMore(sourcingPayload.has_more === true);
132
- } catch (_error) {
133
- setSourcingHasMore(true);
134
- } finally {
135
- setSourcingLoadingMore(false);
136
- }
137
- }, [
138
- activeSessionId,
139
- apiBaseUrl,
140
- projectId,
141
- sourcingDisplayedResultIds,
142
- sourcingHasMore,
143
- sourcingLoadedTopK,
144
- sourcingLoadingMore,
145
- timeline,
146
- userId,
147
- ]);
148
-
149
- const { canvasPanelNode, renderedTimelineItems } = useWorkspaceCanvasProjection({
150
- timelineItems: timeline.items,
151
- composerModeKey,
152
- evidenceStrictMode,
153
- evidenceHitScoreThreshold,
154
- showCanvasPanel,
155
- canvasFocusEvidenceAnchorId,
156
- setCanvasActiveTabKey,
157
- hadSourcingEvidenceRef,
158
- setShowCanvasPanel,
159
- canvasActiveTabKey,
160
- canvasFullscreenOpen,
161
- setCanvasFullscreenOpen,
162
- inputState,
163
- themeTokens,
164
- languageGuardEnabled,
165
- friendlyToneEnabled,
166
- sourcingHasMore,
167
- sourcingLoadingMore,
168
- onCanvasSourcingLoadMore: handleCanvasSourcingLoadMore,
169
- });
170
-
171
- return {
172
- canvasPanelNode,
173
- renderedTimelineItems,
174
- handleUICardAction,
175
- generativeRegistry,
176
- };
177
- }
@@ -1,171 +0,0 @@
1
- import React, { useEffect, useMemo } from 'react';
2
- import { debugCoreLog, getCoreRuntimeMode } from '../../chat-core/runtime/runtimeMode.js';
3
- import { RESOLVED_UI_LABELS, RESPONSE_STYLE_POLICY } from './constants.js';
4
- import { selectProjectedCanvasEvidenceItems } from '../selectors/evidenceProjectionSelector.js';
5
- import {
6
- selectCanvasAutoTab,
7
- selectCanvasEvidencePresence,
8
- selectCanvasTabs,
9
- selectResolvedCanvasEvidenceTabKey,
10
- selectShouldAutoOpenCanvasForSourcing,
11
- } from '../selectors/canvasTabsSelector.js';
12
- import { selectCanvasEvidenceSummary } from '../selectors/canvasEvidenceSummarySelector.js';
13
- import { selectRenderedTimelineItems } from '../selectors/assistantTextSelector.js';
14
- import { selectCanvasReportTemplate } from '../selectors/canvasReportTemplateSelector.js';
15
- import AppCanvasPanel from '../components/AppCanvasPanel.jsx';
16
-
17
- export function useWorkspaceCanvasProjection({
18
- timelineItems,
19
- composerModeKey,
20
- evidenceStrictMode,
21
- evidenceHitScoreThreshold,
22
- showCanvasPanel,
23
- canvasFocusEvidenceAnchorId,
24
- setCanvasActiveTabKey,
25
- hadSourcingEvidenceRef,
26
- setShowCanvasPanel,
27
- canvasActiveTabKey,
28
- canvasFullscreenOpen,
29
- setCanvasFullscreenOpen,
30
- inputState,
31
- themeTokens,
32
- languageGuardEnabled,
33
- friendlyToneEnabled,
34
- sourcingHasMore = false,
35
- sourcingLoadingMore = false,
36
- onCanvasSourcingLoadMore,
37
- } = {}) {
38
- const canvasEvidenceItems = useMemo(() => selectProjectedCanvasEvidenceItems({
39
- timelineItems,
40
- composerModeKey,
41
- evidenceStrictMode,
42
- evidenceHitScoreThreshold,
43
- }), [composerModeKey, evidenceHitScoreThreshold, evidenceStrictMode, timelineItems]);
44
-
45
- const canvasReportTemplate = useMemo(
46
- () => selectCanvasReportTemplate(timelineItems),
47
- [timelineItems],
48
- );
49
-
50
- useEffect(() => {
51
- const runtimeMode = getCoreRuntimeMode();
52
- debugCoreLog('canvas.projection', {
53
- mode: runtimeMode.mode,
54
- evidenceCount: canvasEvidenceItems.length,
55
- hasReportTemplate: Boolean(canvasReportTemplate),
56
- timelineTypes: (Array.isArray(timelineItems) ? timelineItems : [])
57
- .map((item) => String(item?.type || '').trim())
58
- .filter(Boolean),
59
- });
60
- }, [canvasEvidenceItems.length, canvasReportTemplate, timelineItems]);
61
-
62
- useEffect(() => {
63
- const nextAutoTab = selectCanvasAutoTab({
64
- canvasEvidenceItems,
65
- canvasFocusEvidenceAnchorId,
66
- showCanvasPanel,
67
- canvasActiveTabKey,
68
- });
69
- if (nextAutoTab && nextAutoTab !== canvasActiveTabKey) {
70
- setCanvasActiveTabKey(nextAutoTab);
71
- }
72
- }, [
73
- canvasActiveTabKey,
74
- canvasEvidenceItems,
75
- canvasFocusEvidenceAnchorId,
76
- setCanvasActiveTabKey,
77
- showCanvasPanel,
78
- ]);
79
-
80
- const { hasSourcingEvidenceRows, hasRetrievalEvidenceRows } = useMemo(
81
- () => selectCanvasEvidencePresence(canvasEvidenceItems),
82
- [canvasEvidenceItems],
83
- );
84
- const isPlanMode = String(composerModeKey || '').trim() === 'requirement_canvas';
85
-
86
- useEffect(() => {
87
- if (selectShouldAutoOpenCanvasForSourcing({
88
- hasSourcingEvidenceRows,
89
- hadSourcingEvidence: hadSourcingEvidenceRef?.current,
90
- })) {
91
- setShowCanvasPanel(true);
92
- setCanvasActiveTabKey('sourcing');
93
- }
94
- if (hadSourcingEvidenceRef) {
95
- hadSourcingEvidenceRef.current = hasSourcingEvidenceRows;
96
- }
97
- }, [hadSourcingEvidenceRef, hasSourcingEvidenceRows, setCanvasActiveTabKey, setShowCanvasPanel]);
98
-
99
- const canvasTabs = useMemo(() => selectCanvasTabs({
100
- isPlanMode,
101
- canvasReportTemplate,
102
- hasSourcingEvidenceRows,
103
- hasRetrievalEvidenceRows,
104
- resolvedUILabels: RESOLVED_UI_LABELS,
105
- }), [canvasReportTemplate, hasRetrievalEvidenceRows, hasSourcingEvidenceRows, isPlanMode]);
106
-
107
- const resolvedCanvasEvidenceTabKey = useMemo(() => selectResolvedCanvasEvidenceTabKey({
108
- hasSourcingEvidenceRows,
109
- canvasActiveTabKey,
110
- }), [canvasActiveTabKey, hasSourcingEvidenceRows]);
111
- const canvasEvidenceSummary = useMemo(
112
- () => selectCanvasEvidenceSummary(canvasEvidenceItems),
113
- [canvasEvidenceItems],
114
- );
115
-
116
- const canvasPanelNode = useMemo(() => (
117
- <AppCanvasPanel
118
- canvasActiveTabKey={canvasActiveTabKey}
119
- showCanvasPanel={showCanvasPanel}
120
- resolvedUILabels={RESOLVED_UI_LABELS}
121
- canvasFullscreenOpen={canvasFullscreenOpen}
122
- canvasTabs={canvasTabs}
123
- resolvedCanvasEvidenceTabKey={resolvedCanvasEvidenceTabKey}
124
- canvasEvidenceSummary={canvasEvidenceSummary}
125
- canvasEvidenceItems={canvasEvidenceItems}
126
- canvasFocusEvidenceAnchorId={canvasFocusEvidenceAnchorId}
127
- canvasSourcingHasMore={sourcingHasMore}
128
- canvasSourcingLoadingMore={sourcingLoadingMore}
129
- onCanvasSourcingLoadMore={onCanvasSourcingLoadMore}
130
- canvasReportTemplate={canvasReportTemplate}
131
- inputState={inputState}
132
- setCanvasActiveTabKey={setCanvasActiveTabKey}
133
- setCanvasFullscreenOpen={setCanvasFullscreenOpen}
134
- setShowCanvasPanel={setShowCanvasPanel}
135
- themeTokens={themeTokens}
136
- />
137
- ), [
138
- canvasActiveTabKey,
139
- canvasEvidenceItems,
140
- canvasEvidenceSummary,
141
- canvasFocusEvidenceAnchorId,
142
- canvasFullscreenOpen,
143
- onCanvasSourcingLoadMore,
144
- canvasReportTemplate,
145
- sourcingHasMore,
146
- sourcingLoadingMore,
147
- canvasTabs,
148
- inputState,
149
- resolvedCanvasEvidenceTabKey,
150
- setCanvasActiveTabKey,
151
- setCanvasFullscreenOpen,
152
- setShowCanvasPanel,
153
- showCanvasPanel,
154
- themeTokens,
155
- ]);
156
-
157
- const renderedTimelineItems = useMemo(() => selectRenderedTimelineItems({
158
- timelineItems,
159
- languageGuardEnabled,
160
- friendlyToneEnabled,
161
- responseStylePolicy: RESPONSE_STYLE_POLICY,
162
- }), [friendlyToneEnabled, languageGuardEnabled, timelineItems]);
163
-
164
- return {
165
- canvasPanelNode,
166
- renderedTimelineItems,
167
- canvasEvidenceItems,
168
- };
169
- }
170
-
171
- export default useWorkspaceCanvasProjection;
@@ -1,199 +0,0 @@
1
- import React, { useMemo, useState } from 'react';
2
- import { Typography } from 'antd';
3
- import ComposerSectionNode from './ComposerSectionNode.jsx';
4
- import {
5
- WORKSPACE_CONTENT_MAX_WIDTH,
6
- RESOLVED_UI_LABELS,
7
- MODE_SWITCH_OPTIONS,
8
- MODE_SUGGESTION_TIP_RULES,
9
- } from './constants.js';
10
- import { useAppActionErrorGuards } from './useAppActionErrorGuards.js';
11
- import {
12
- selectLatestAssistantQuestionPendingReply,
13
- selectModeSuggestionContextFlags,
14
- selectModeSuggestionTipRules,
15
- } from '../selectors/modeSuggestionSelector.js';
16
- import { useComposerAttachmentSync } from '../hooks/useComposerAttachmentSync.js';
17
- import { useSendWithContextRefs } from '../hooks/useSendWithContextRefs.js';
18
- import { useComposerChooserHandlers } from '../hooks/useComposerChooserHandlers.js';
19
- import { useUserThresholdProfile } from '../hooks/useUserThresholdProfile.js';
20
- import TriggerThresholdPopoverContent from '../components/TriggerThresholdPopoverContent.jsx';
21
-
22
- const { Text } = Typography;
23
-
24
- export function useWorkspaceComposerController({
25
- userId,
26
- projectId,
27
- activeSessionId,
28
- realApi,
29
- viewModel,
30
- apiReadinessGate,
31
- blockedApiError,
32
- sourceItems,
33
- activeWorkspaceTab,
34
- setActiveWorkspaceTab,
35
- setShowCanvasPanel,
36
- setCanvasActiveTabKey,
37
- themeTokens,
38
- }) {
39
- const {
40
- evidenceStrictMode,
41
- setEvidenceStrictMode,
42
- evidenceHitScoreThreshold,
43
- setEvidenceHitScoreThreshold,
44
- languageGuardEnabled,
45
- setLanguageGuardEnabled,
46
- friendlyToneEnabled,
47
- setFriendlyToneEnabled,
48
- questionModeSuggestionEnabled,
49
- setQuestionModeSuggestionEnabled,
50
- } = useUserThresholdProfile({ userId, projectId });
51
-
52
- const [composerModeKey, setComposerModeKey] = useState('auto');
53
- const [sourcingChooser, setSourcingChooser] = useState(null);
54
- const [, setSourcingChooserDismissDraftKey] = useState('');
55
-
56
- const composerFileList = Array.isArray(viewModel.composer.fileList)
57
- ? viewModel.composer.fileList
58
- : [];
59
-
60
- const {
61
- composerFileListRef,
62
- hasNonReadyAttachments,
63
- readyAttachmentRefs,
64
- } = useComposerAttachmentSync({
65
- composerFileList,
66
- onSyncFileList: viewModel.composer.onSyncFileList,
67
- realSourceApi: realApi?.sourceAPI || null,
68
- projectId,
69
- userId,
70
- activeSessionId,
71
- });
72
-
73
- const latestSourcingContext = useMemo(() => {
74
- const sourcingItem = [...(Array.isArray(viewModel.timeline.items) ? viewModel.timeline.items : [])]
75
- .reverse()
76
- .find((item) => String(item?.type || '').trim() === 'sourcing_candidates');
77
- const payload = (
78
- sourcingItem?.payload
79
- && typeof sourcingItem.payload === 'object'
80
- && !Array.isArray(sourcingItem.payload)
81
- ) ? sourcingItem.payload : {};
82
- const latestSourcingQuery = String(payload?.query || '').trim();
83
- const latestSourcingResultIds = (Array.isArray(payload?.candidates) ? payload.candidates : [])
84
- .map((item) => String(item?.result_id || item?.id || '').trim())
85
- .filter(Boolean);
86
- return {
87
- latestSourcingQuery,
88
- latestSourcingResultIds,
89
- };
90
- }, [viewModel.timeline.items]);
91
-
92
- const handleSendWithSourceRefs = useSendWithContextRefs({
93
- composerModeKey,
94
- setSourcingChooser,
95
- sourceItems,
96
- composer: viewModel.composer,
97
- activeWorkspaceTab,
98
- setActiveWorkspaceTab,
99
- composerFileListRef,
100
- hasNonReadyAttachments,
101
- readyAttachmentRefs,
102
- latestSourcingQuery: latestSourcingContext.latestSourcingQuery,
103
- latestSourcingResultIds: latestSourcingContext.latestSourcingResultIds,
104
- });
105
-
106
- const actionGuards = useAppActionErrorGuards({
107
- blocked: apiReadinessGate.blocked,
108
- blockedError: blockedApiError,
109
- sessionListError: apiReadinessGate.error || viewModel.sessionList.error || null,
110
- composerError: viewModel.composer.error || null,
111
- onCreateProject: viewModel.sessionList.onCreateProject,
112
- onCreateSession: viewModel.sessionList.onCreateSession,
113
- onSend: handleSendWithSourceRefs,
114
- });
115
-
116
- const inputState = {
117
- inputValue: viewModel.composer.value,
118
- fileList: viewModel.composer.fileList,
119
- handleInputChange: viewModel.composer.onChange,
120
- handleRemoveFile: viewModel.composer.onRemoveFile,
121
- };
122
-
123
- const latestAssistantQuestionPendingReply = useMemo(
124
- () => selectLatestAssistantQuestionPendingReply(viewModel.timeline.items),
125
- [viewModel.timeline.items],
126
- );
127
-
128
- const suggestionTipRules = useMemo(() => selectModeSuggestionTipRules({
129
- baseRules: MODE_SUGGESTION_TIP_RULES,
130
- questionModeSuggestionEnabled,
131
- }), [questionModeSuggestionEnabled]);
132
-
133
- const suggestionContextFlags = useMemo(() => selectModeSuggestionContextFlags({
134
- latestAssistantQuestionPendingReply,
135
- }), [latestAssistantQuestionPendingReply]);
136
-
137
- const { onComposerActionSelect, onComposerChooserDismiss } = useComposerChooserHandlers({
138
- setComposerModeKey,
139
- setSourcingChooser,
140
- setShowCanvasPanel,
141
- setCanvasActiveTabKey,
142
- setSourcingChooserDismissDraftKey,
143
- activeSessionId: viewModel.sessionList.activeSessionId,
144
- composerValue: viewModel.composer.value,
145
- });
146
-
147
- const triggerThresholdPopoverContent = (
148
- <TriggerThresholdPopoverContent
149
- evidenceStrictMode={evidenceStrictMode}
150
- setEvidenceStrictMode={setEvidenceStrictMode}
151
- evidenceHitScoreThreshold={evidenceHitScoreThreshold}
152
- setEvidenceHitScoreThreshold={setEvidenceHitScoreThreshold}
153
- languageGuardEnabled={languageGuardEnabled}
154
- setLanguageGuardEnabled={setLanguageGuardEnabled}
155
- friendlyToneEnabled={friendlyToneEnabled}
156
- setFriendlyToneEnabled={setFriendlyToneEnabled}
157
- questionModeSuggestionEnabled={questionModeSuggestionEnabled}
158
- setQuestionModeSuggestionEnabled={setQuestionModeSuggestionEnabled}
159
- />
160
- );
161
-
162
- const composerNode = (
163
- <ComposerSectionNode
164
- themeTokens={themeTokens}
165
- contentMaxWidth={WORKSPACE_CONTENT_MAX_WIDTH}
166
- streamLoading={viewModel.composer.loading}
167
- sendDisabled={hasNonReadyAttachments}
168
- resolvedUILabels={RESOLVED_UI_LABELS}
169
- modeSwitchOptions={MODE_SWITCH_OPTIONS}
170
- inputState={inputState}
171
- onAttachFiles={viewModel.composer.onAttachFiles}
172
- onSend={actionGuards.handleSend}
173
- effectiveComposerChooser={sourcingChooser}
174
- onComposerActionSelect={onComposerActionSelect}
175
- onComposerChooserDismiss={onComposerChooserDismiss}
176
- initialModeKey={composerModeKey}
177
- onModeChanged={setComposerModeKey}
178
- userId={userId}
179
- shouldRenderModeSuggestion
180
- tipRules={suggestionTipRules}
181
- suggestionContextFlags={suggestionContextFlags}
182
- intentEscalationPolicyPopoverContent={triggerThresholdPopoverContent}
183
- contextGaugePopoverContent={
184
- <Text type="secondary">{String(viewModel.contextUsage?.text || '上下文窗口占用(暂无数据)')}</Text>
185
- }
186
- />
187
- );
188
-
189
- return {
190
- actionGuards,
191
- inputState,
192
- composerNode,
193
- composerModeKey,
194
- languageGuardEnabled,
195
- friendlyToneEnabled,
196
- evidenceStrictMode,
197
- evidenceHitScoreThreshold,
198
- };
199
- }