flare-chat-core 0.2.1 → 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 +170 -12
  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 +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
@@ -1,244 +1 @@
1
- const API_BASE_URL = import.meta.env.DEV ? '' : import.meta.env.VITE_API_URL || '';
2
- const DEFAULT_ENDPOINT = '/api/v1/chat/stream';
3
-
4
- function joinUrl(baseUrl, endpoint) {
5
- if (!baseUrl) {
6
- return endpoint;
7
- }
8
-
9
- if (!endpoint) {
10
- return baseUrl;
11
- }
12
-
13
- return `${baseUrl.replace(/\/+$/, '')}/${endpoint.replace(/^\/+/, '')}`;
14
- }
15
-
16
- function buildClientRequestId() {
17
- const random = Math.random().toString(36).slice(2, 10);
18
- return `req_${Date.now()}_${random}`;
19
- }
20
-
21
- export class SSEClient {
22
- constructor({ endpoint = DEFAULT_ENDPOINT, baseUrl = API_BASE_URL } = {}) {
23
- this.abortController = null;
24
- this.endpoint = endpoint;
25
- this.baseUrl = baseUrl;
26
- this.activeRequestId = '';
27
- this.authReadyPromise = null;
28
- this.authReadyAtMs = 0;
29
- }
30
-
31
- async sendMessage(sessionOrParams, contentArg, onEventArg, onCompleteArg, onErrorArg, optionsArg = {}) {
32
- const isObjectCall = typeof sessionOrParams === 'object' && sessionOrParams !== null;
33
- const params = isObjectCall
34
- ? sessionOrParams
35
- : {
36
- sessionId: sessionOrParams,
37
- content: contentArg,
38
- enabledCapabilities: optionsArg.enabledCapabilities || [],
39
- };
40
-
41
- const sessionId = params.sessionId;
42
- const content = params.content;
43
- const enabledCapabilities = Array.isArray(params.enabledCapabilities) ? params.enabledCapabilities : [];
44
- const modeKey = typeof params.modeKey === 'string' ? params.modeKey.trim() : '';
45
- const manualModeKey = typeof params.manualModeKey === 'string' ? params.manualModeKey.trim() : '';
46
- const payloadExtra = (
47
- params.payloadExtra
48
- && typeof params.payloadExtra === 'object'
49
- && !Array.isArray(params.payloadExtra)
50
- )
51
- ? params.payloadExtra
52
- : {};
53
- const onEvent = isObjectCall ? contentArg : onEventArg;
54
- const onComplete = isObjectCall ? onEventArg : onCompleteArg;
55
- const onError = isObjectCall ? onCompleteArg : onErrorArg;
56
- const url = params.url || joinUrl(params.baseUrl ?? this.baseUrl, params.endpoint || this.endpoint);
57
- const command = typeof params.command === 'string' && params.command.trim()
58
- ? params.command.trim()
59
- : (typeof payloadExtra.command === 'string' && payloadExtra.command.trim() ? payloadExtra.command.trim() : 'send_message');
60
- const clientRequestId = typeof params.clientRequestId === 'string' && params.clientRequestId.trim()
61
- ? params.clientRequestId.trim()
62
- : buildClientRequestId();
63
- const contractVersion = typeof params.contractVersion === 'string' && params.contractVersion.trim()
64
- ? params.contractVersion.trim()
65
- : 'flare.v1';
66
- const lastTurnId = typeof params.lastTurnId === 'string' ? params.lastTurnId.trim() : '';
67
- const token = typeof params.token === 'string' ? params.token.trim() : '';
68
- const onTiming = typeof params.onTiming === 'function' ? params.onTiming : null;
69
- const authProvider = (
70
- params.auth
71
- && typeof params.auth === 'object'
72
- && !Array.isArray(params.auth)
73
- ) ? params.auth : null;
74
-
75
- const nowMs = Date.now();
76
- onTiming?.({
77
- point: 't_submit',
78
- at_ms: nowMs,
79
- request_id: clientRequestId,
80
- session_id: String(sessionId || '').trim(),
81
- });
82
-
83
- const waitAuthReady = async () => {
84
- if (!authProvider || typeof authProvider.ensureReady !== 'function') {
85
- return {
86
- authorizationToken: token,
87
- authReadyAtMs: nowMs,
88
- };
89
- }
90
- if (!this.authReadyPromise) {
91
- this.authReadyPromise = Promise.resolve()
92
- .then(() => authProvider.ensureReady())
93
- .then((resolved) => {
94
- this.authReadyAtMs = Date.now();
95
- return resolved || null;
96
- })
97
- .finally(() => {
98
- this.authReadyPromise = null;
99
- });
100
- }
101
- const authResult = await this.authReadyPromise;
102
- const tokenFromAuthResult = typeof authResult?.token === 'string' ? authResult.token.trim() : '';
103
- const tokenFromProvider = typeof authProvider.getToken === 'function'
104
- ? String(authProvider.getToken() || '').trim()
105
- : '';
106
- return {
107
- authorizationToken: tokenFromAuthResult || tokenFromProvider || token,
108
- authReadyAtMs: this.authReadyAtMs || Date.now(),
109
- };
110
- };
111
-
112
- const currentRequestId = clientRequestId;
113
- if (this.abortController) {
114
- this.abortController.abort();
115
- this.abortController = null;
116
- }
117
- this.abortController = new AbortController();
118
- this.activeRequestId = currentRequestId;
119
-
120
- try {
121
- const authResolved = await waitAuthReady();
122
- onTiming?.({
123
- point: 't_auth_ready',
124
- at_ms: authResolved.authReadyAtMs || Date.now(),
125
- request_id: currentRequestId,
126
- session_id: String(sessionId || '').trim(),
127
- });
128
- if (this.activeRequestId !== currentRequestId) {
129
- return;
130
- }
131
- const response = await fetch(url, {
132
- method: 'POST',
133
- headers: {
134
- 'Content-Type': 'application/json',
135
- ...(authResolved.authorizationToken ? { Authorization: `Bearer ${authResolved.authorizationToken}` } : {}),
136
- },
137
- body: JSON.stringify({
138
- contract_version: contractVersion,
139
- client_request_id: clientRequestId,
140
- command,
141
- last_turn_id: lastTurnId || null,
142
- message: content,
143
- session_id: sessionId,
144
- enabled_capabilities: enabledCapabilities,
145
- ...(modeKey ? { mode: modeKey } : {}),
146
- ...(manualModeKey ? { manual_mode: manualModeKey } : {}),
147
- payload: {
148
- message: content,
149
- ...(modeKey ? { mode: modeKey } : {}),
150
- ...(manualModeKey ? { manual_mode: manualModeKey } : {}),
151
- ...payloadExtra,
152
- },
153
- }),
154
- signal: this.abortController.signal,
155
- });
156
- onTiming?.({
157
- point: 't_stream_connected',
158
- at_ms: Date.now(),
159
- request_id: currentRequestId,
160
- session_id: String(sessionId || '').trim(),
161
- });
162
-
163
- if (!response.ok) {
164
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
165
- }
166
-
167
- const reader = response.body.getReader();
168
- const decoder = new TextDecoder();
169
- let buffer = '';
170
- let currentEvent = '';
171
-
172
- while (true) {
173
- const { done, value } = await reader.read();
174
- if (done) break;
175
-
176
- buffer += decoder.decode(value, { stream: true });
177
- const lines = buffer.split('\n');
178
- buffer = lines.pop() || '';
179
-
180
- for (const line of lines) {
181
- if (line.startsWith('event:')) {
182
- currentEvent = line.substring(6).trim();
183
- continue;
184
- }
185
-
186
- if (!line.startsWith('data:')) {
187
- continue;
188
- }
189
-
190
- const data = line.substring(5).trim();
191
- if (!data || !currentEvent) {
192
- continue;
193
- }
194
-
195
- try {
196
- const eventData = JSON.parse(data);
197
- if (this.activeRequestId !== currentRequestId) {
198
- return;
199
- }
200
- onEvent?.({
201
- type: currentEvent,
202
- data: eventData,
203
- });
204
-
205
- if (currentEvent === 'complete' || currentEvent === 'done') {
206
- await onComplete?.();
207
- if (this.activeRequestId === currentRequestId) {
208
- this.abortController = null;
209
- this.activeRequestId = '';
210
- }
211
- return;
212
- }
213
- } catch (error) {
214
- console.error('SSE 数据解析失败:', error, 'data:', data);
215
- }
216
- }
217
- }
218
-
219
- await onComplete?.();
220
- if (this.activeRequestId === currentRequestId) {
221
- this.abortController = null;
222
- this.activeRequestId = '';
223
- }
224
- } catch (error) {
225
- if (error?.name === 'AbortError') {
226
- return;
227
- }
228
-
229
- onError?.(error instanceof Error ? error.message : '发送消息失败');
230
- if (this.activeRequestId === currentRequestId) {
231
- this.abortController = null;
232
- this.activeRequestId = '';
233
- }
234
- }
235
- }
236
-
237
- abort() {
238
- if (this.abortController) {
239
- this.abortController.abort();
240
- this.abortController = null;
241
- }
242
- this.activeRequestId = '';
243
- }
244
- }
1
+ export { SSEClient } from '../../adapters/sse-client.js';
@@ -0,0 +1 @@
1
+ export * from '../../adapters/sse-event-dispatcher.js';