flare-chat-core 0.2.0 → 0.2.2

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 +125 -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 +109 -0
  26. package/src/app/components/WorkspaceMainPane.jsx +113 -0
  27. package/src/app/components/WorkspaceSessionPane.jsx +48 -0
  28. package/src/app/components/WorkspaceTopBarSection.jsx +65 -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 +172 -11
  70. package/src/chat-core/messages/buildTimelineItems.knowledge-citation.test.mjs +183 -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 +67 -390
  98. package/src/chat-core/session/useSessionListController.js +67 -0
  99. package/src/chat-core/stream/sse-client.js +1 -142
  100. package/src/chat-core/stream/sse-event-dispatcher.js +1 -0
  101. package/src/chat-core/stream/sse-events.js +1 -598
  102. package/src/chat-core/stream/useSSEStream.js +1 -273
  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
package/src/main.jsx ADDED
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom/client';
3
+ import 'antd/dist/reset.css';
4
+ import ChatApp from './app/App.jsx';
5
+
6
+ const FUNCTION_TYPE = import.meta.env.VITE_FLARE_CHAT_FUNCTION_TYPE || 'chat_component_debug';
7
+ const DEFAULT_SESSION_TITLE = import.meta.env.VITE_FLARE_CHAT_DEFAULT_SESSION_TITLE || '调试会话';
8
+ const PROJECT_ID = import.meta.env.VITE_FLARE_CHAT_PROJECT_ID || 'project_demo_001';
9
+ const USER_ID = import.meta.env.VITE_FLARE_CHAT_USER_ID || 'user_demo_001';
10
+ const DEV_DEFAULT_BACKEND = String(import.meta.env.VITE_FLARE_CHAT_DEV_DEFAULT_BACKEND || 'real').toLowerCase();
11
+ const KERNEL_BASE_URL = import.meta.env.VITE_FLARE_CHAT_KERNEL_BASE_URL || 'http://127.0.0.1:18002';
12
+ const API_BASE_URL = import.meta.env.VITE_FLARE_CHAT_API_BASE_URL || '';
13
+ const API_TOKEN = import.meta.env.VITE_FLARE_CHAT_API_TOKEN || '';
14
+
15
+ ReactDOM.createRoot(document.getElementById('root')).render(
16
+ <React.StrictMode>
17
+ <ChatApp
18
+ functionType={FUNCTION_TYPE}
19
+ defaultSessionTitle={DEFAULT_SESSION_TITLE}
20
+ projectId={PROJECT_ID}
21
+ userId={USER_ID}
22
+ backendMode={DEV_DEFAULT_BACKEND}
23
+ kernelBaseUrl={KERNEL_BASE_URL}
24
+ apiBaseUrl={API_BASE_URL}
25
+ apiToken={API_TOKEN}
26
+ />
27
+ </React.StrictMode>
28
+ );
@@ -0,0 +1,6 @@
1
+ export { useBasicSendHandler } from '../chat-core/orchestration/useBasicSendHandler.js';
2
+ export { useStreamSendController } from '../chat-core/stream/useStreamSendController.js';
3
+ export { useSessionListController } from '../chat-core/session/useSessionListController.js';
4
+ export { useBasicConversationFacade } from '../chat-core/facade/useBasicConversationFacade.js';
5
+ export { useCoreChatApp } from '../chat-core/app/useCoreChatApp.js';
6
+ export { useSSEStream } from './useSSEStream.js';
@@ -0,0 +1,221 @@
1
+ import { useRef, useState, useCallback, useEffect } from 'react';
2
+ import { SSEClient } from '../adapters/sse-client.js';
3
+ import { dispatchSSEEvent } from '../adapters/sse-event-dispatcher.js';
4
+
5
+ function classifyError(errorMessage) {
6
+ if (!errorMessage) return 'unknown';
7
+
8
+ const lowerMsg = errorMessage.toLowerCase();
9
+ if (lowerMsg.includes('network') || lowerMsg.includes('fetch')) return 'network';
10
+ if (lowerMsg.includes('timeout') || lowerMsg.includes('timed out')) return 'timeout';
11
+ if (/\b(500|502|503|504)\b/.test(lowerMsg)) return 'api';
12
+ return 'unknown';
13
+ }
14
+
15
+ export function useSSEStream(sessionId) {
16
+ const clientRef = useRef(new SSEClient());
17
+ const [loading, setLoading] = useState(false);
18
+ const [error, setError] = useState(null);
19
+ const accumulatedRef = useRef('');
20
+ const lastMessageRef = useRef({ content: '', handlers: {} });
21
+
22
+ const send = useCallback(async (content, handlers = {}, options = {}) => {
23
+ const hasSessionOverride = Object.prototype.hasOwnProperty.call(options, 'sessionIdOverride');
24
+ const resolvedSessionId = hasSessionOverride ? options.sessionIdOverride : sessionId;
25
+ if (!content.trim()) return;
26
+
27
+ lastMessageRef.current = { content, handlers, options };
28
+ setError(null);
29
+ accumulatedRef.current = '';
30
+ setLoading(true);
31
+ let latestSessionId = String(resolvedSessionId || '').trim();
32
+
33
+ const {
34
+ onAck,
35
+ onAgentStatus,
36
+ onThinkingTrace,
37
+ onExecutionTrace,
38
+ onContent,
39
+ onTextReplace,
40
+ onPhaseStart,
41
+ onPhaseUpdate,
42
+ onPhaseEnd,
43
+ onPatch,
44
+ onDone,
45
+ onTrace,
46
+ onWorkspaceActivation,
47
+ onUICards,
48
+ onKnowledgeBaseState,
49
+ onFieldProgress,
50
+ onRequirementDraft,
51
+ onNextActions,
52
+ onSourcingCandidates,
53
+ onRiskSummary,
54
+ onShortlistUpdated,
55
+ onEvaluationReportReady,
56
+ onCategoryIdentified,
57
+ onFieldsUpdated,
58
+ onInstanceProfile,
59
+ onModeRuntime,
60
+ onAgentRuntime,
61
+ onSkillRuntime,
62
+ onModeSwitchReason,
63
+ onKnowledgeSearch,
64
+ onKnowledgeCitation,
65
+ onOrchestrationStatus,
66
+ onCanvasState,
67
+ onCanvasRevision,
68
+ onPlanBlock,
69
+ onDoc,
70
+ onCapabilitySuggestion,
71
+ onPatchEvent,
72
+ onError,
73
+ onComplete,
74
+ } = handlers;
75
+
76
+ const eventHandler = (event) => {
77
+ dispatchSSEEvent(event, {
78
+ handlers: {
79
+ onAck,
80
+ onPhaseStart,
81
+ onPhaseUpdate,
82
+ onPhaseEnd,
83
+ onPatch,
84
+ onAgentStatus,
85
+ onThinkingTrace,
86
+ onExecutionTrace,
87
+ onContent,
88
+ onTextReplace,
89
+ onDone,
90
+ onTrace,
91
+ onWorkspaceActivation,
92
+ onUICards,
93
+ onKnowledgeBaseState,
94
+ onFieldProgress,
95
+ onRequirementDraft,
96
+ onNextActions,
97
+ onSourcingCandidates,
98
+ onRiskSummary,
99
+ onShortlistUpdated,
100
+ onEvaluationReportReady,
101
+ onCategoryIdentified,
102
+ onFieldsUpdated,
103
+ onInstanceProfile,
104
+ onModeRuntime,
105
+ onAgentRuntime,
106
+ onSkillRuntime,
107
+ onModeSwitchReason,
108
+ onKnowledgeSearch,
109
+ onKnowledgeCitation,
110
+ onOrchestrationStatus,
111
+ onCanvasState,
112
+ onCanvasRevision,
113
+ onPlanBlock,
114
+ onDoc,
115
+ onCapabilitySuggestion,
116
+ onPatchEvent,
117
+ onError,
118
+ },
119
+ appendChunk: (chunk) => {
120
+ accumulatedRef.current += chunk;
121
+ },
122
+ replaceChunk: (contentValue) => {
123
+ accumulatedRef.current = contentValue;
124
+ },
125
+ setLatestSessionId: (sessionValue) => {
126
+ latestSessionId = sessionValue;
127
+ },
128
+ });
129
+ };
130
+
131
+ const completeHandler = async () => {
132
+ setLoading(false);
133
+ await onComplete?.(accumulatedRef.current, {
134
+ sessionId: latestSessionId || null,
135
+ });
136
+ accumulatedRef.current = '';
137
+ };
138
+
139
+ const transportErrorHandler = (errorMessage) => {
140
+ setLoading(false);
141
+ const errorType = classifyError(errorMessage);
142
+ setError({ message: errorMessage, type: errorType });
143
+ onError?.({ message: errorMessage });
144
+ accumulatedRef.current = '';
145
+ };
146
+
147
+ const requestOptions = {
148
+ sessionId: String(resolvedSessionId || '').trim() || null,
149
+ content,
150
+ enabledCapabilities: Array.isArray(options.enabledCapabilities) ? options.enabledCapabilities : [],
151
+ modeKey: typeof options.modeKey === 'string' ? options.modeKey : '',
152
+ manualModeKey: typeof options.manualModeKey === 'string' ? options.manualModeKey : '',
153
+ command: typeof options.command === 'string' ? options.command : '',
154
+ clientRequestId: typeof options.clientRequestId === 'string' ? options.clientRequestId : '',
155
+ contractVersion: typeof options.contractVersion === 'string' ? options.contractVersion : '',
156
+ lastTurnId: typeof options.lastTurnId === 'string' ? options.lastTurnId : '',
157
+ payloadExtra: (
158
+ options.payloadExtra
159
+ && typeof options.payloadExtra === 'object'
160
+ && !Array.isArray(options.payloadExtra)
161
+ )
162
+ ? options.payloadExtra
163
+ : {},
164
+ endpoint: options.endpoint,
165
+ baseUrl: options.baseUrl,
166
+ url: options.url,
167
+ token: typeof options.token === 'string' ? options.token : '',
168
+ auth: (
169
+ options.auth
170
+ && typeof options.auth === 'object'
171
+ && !Array.isArray(options.auth)
172
+ ) ? options.auth : undefined,
173
+ onTiming: typeof options.onTiming === 'function' ? options.onTiming : undefined,
174
+ };
175
+
176
+ if (!requestOptions.enabledCapabilities.length) {
177
+ delete requestOptions.enabledCapabilities;
178
+ }
179
+ if (!requestOptions.modeKey) delete requestOptions.modeKey;
180
+ if (!requestOptions.manualModeKey) delete requestOptions.manualModeKey;
181
+ if (!requestOptions.command) delete requestOptions.command;
182
+ if (!requestOptions.clientRequestId) delete requestOptions.clientRequestId;
183
+ if (!requestOptions.contractVersion) delete requestOptions.contractVersion;
184
+ if (!requestOptions.lastTurnId) delete requestOptions.lastTurnId;
185
+ if (!Object.keys(requestOptions.payloadExtra || {}).length) delete requestOptions.payloadExtra;
186
+
187
+ if (!requestOptions.endpoint) delete requestOptions.endpoint;
188
+ if (!requestOptions.baseUrl) delete requestOptions.baseUrl;
189
+ if (!requestOptions.url) delete requestOptions.url;
190
+ if (!requestOptions.token) delete requestOptions.token;
191
+ if (!requestOptions.auth) delete requestOptions.auth;
192
+ if (!requestOptions.onTiming) delete requestOptions.onTiming;
193
+
194
+ await clientRef.current.sendMessage(
195
+ requestOptions,
196
+ eventHandler,
197
+ completeHandler,
198
+ transportErrorHandler
199
+ );
200
+ }, [sessionId]);
201
+
202
+ const retry = useCallback(async () => {
203
+ const { content, handlers, options } = lastMessageRef.current;
204
+ if (!content) return;
205
+ await send(content, handlers, options);
206
+ }, [send]);
207
+
208
+ const abort = useCallback(() => {
209
+ clientRef.current.abort();
210
+ setLoading(false);
211
+ accumulatedRef.current = '';
212
+ }, []);
213
+
214
+ useEffect(() => () => {
215
+ clientRef.current.abort();
216
+ }, []);
217
+
218
+ return { send, loading, error, retry, abort };
219
+ }
220
+
221
+ export default useSSEStream;
@@ -0,0 +1,4 @@
1
+ export {
2
+ useChatSessionReducer,
3
+ initialState as chatSessionInitialState,
4
+ } from '../chat-core/session/index.js';
package/vite.config.js ADDED
@@ -0,0 +1,36 @@
1
+ import path from 'node:path';
2
+ import { defineConfig } from 'vite';
3
+ import react from '@vitejs/plugin-react';
4
+
5
+ const devPort = 9000;
6
+ const previewPort = 9001;
7
+ const devHost = process.env.FLARE_CHAT_CORE_DEV_HOST || '127.0.0.1';
8
+ const workspaceRoot = path.resolve(__dirname, '..', '..');
9
+
10
+ export default defineConfig({
11
+ plugins: [react()],
12
+ resolve: {
13
+ alias: [
14
+ { find: /^@\//, replacement: `${path.resolve(__dirname, 'src')}/` },
15
+ { find: /^flare-chat-core$/, replacement: path.resolve(__dirname, 'src', 'index.js') },
16
+ { find: /^flare-generative-ui$/, replacement: path.resolve(__dirname, '..', 'flare-generative-ui', 'src', 'index.js') },
17
+ { find: /^flare-canvas-ui$/, replacement: path.resolve(__dirname, '..', 'flare-canvas-ui', 'src', 'index.js') },
18
+ { find: /^@dva89\/flare-api-client-ts$/, replacement: path.resolve(__dirname, '..', 'flare-api-client-ts', 'src', 'index.js') },
19
+ { find: /^react$/, replacement: path.resolve(workspaceRoot, 'node_modules', 'react') },
20
+ { find: /^react-dom$/, replacement: path.resolve(workspaceRoot, 'node_modules', 'react-dom') },
21
+ { find: /^antd$/, replacement: path.resolve(workspaceRoot, 'node_modules', 'antd') },
22
+ { find: /^@ant-design\/icons$/, replacement: path.resolve(workspaceRoot, 'node_modules', '@ant-design', 'icons') },
23
+ ],
24
+ },
25
+ server: {
26
+ host: devHost,
27
+ port: devPort,
28
+ fs: {
29
+ allow: [workspaceRoot],
30
+ },
31
+ },
32
+ preview: {
33
+ host: devHost,
34
+ port: previewPort,
35
+ },
36
+ });