flare-chat-core 0.2.3 → 0.2.5

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 +6372 -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 -190
  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 -156
  27. package/src/app/components/WorkspaceMainPane.jsx +0 -121
  28. package/src/app/components/WorkspaceSessionPane.jsx +0 -70
  29. package/src/app/components/WorkspaceTopBarSection.jsx +0 -71
  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 -201
  72. package/src/chat-core/messages/buildTimelineItems.knowledge-citation.test.mjs +0 -182
  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,69 +0,0 @@
1
- /**
2
- * Core runtime mode + debug gating.
3
- *
4
- * Env contract:
5
- * - VITE_FLARE_CHAT_RUNTIME_MODE: optional override, "development" | "production"
6
- * - VITE_FLARE_CHAT_DEBUG: optional debug switch, "1" | "true" enables debug logs
7
- *
8
- * Safety rule:
9
- * - Debug logs are allowed only when runtime mode is non-production.
10
- */
11
-
12
- function toBooleanFlag(value) {
13
- const normalized = String(value ?? '').trim().toLowerCase();
14
- return normalized === '1' || normalized === 'true' || normalized === 'yes' || normalized === 'on';
15
- }
16
-
17
- function normalizeMode(value) {
18
- const normalized = String(value ?? '').trim().toLowerCase();
19
- if (normalized === 'production' || normalized === 'prod') {
20
- return 'production';
21
- }
22
- if (normalized === 'development' || normalized === 'dev') {
23
- return 'development';
24
- }
25
- return '';
26
- }
27
-
28
- export function resolveRuntimeMode(envInput) {
29
- const env = (
30
- envInput
31
- && typeof envInput === 'object'
32
- && !Array.isArray(envInput)
33
- ) ? envInput : (import.meta?.env || {});
34
-
35
- const overrideMode = normalizeMode(env.VITE_FLARE_CHAT_RUNTIME_MODE);
36
- const modeFromVite = normalizeMode(env.MODE);
37
- const fallbackMode = env.PROD === true ? 'production' : 'development';
38
- const mode = overrideMode || modeFromVite || fallbackMode;
39
- const isProduction = mode === 'production';
40
- const isDevelopment = !isProduction;
41
- const debugRequested = toBooleanFlag(env.VITE_FLARE_CHAT_DEBUG);
42
- const debugEnabled = isDevelopment && debugRequested;
43
-
44
- return {
45
- mode,
46
- isProduction,
47
- isDevelopment,
48
- debugEnabled,
49
- };
50
- }
51
-
52
- const runtimeMode = resolveRuntimeMode();
53
-
54
- export function getCoreRuntimeMode() {
55
- return runtimeMode;
56
- }
57
-
58
- export function isCoreDebugEnabled() {
59
- return runtimeMode.debugEnabled;
60
- }
61
-
62
- export function debugCoreLog(...args) {
63
- if (!runtimeMode.debugEnabled) {
64
- return;
65
- }
66
- console.debug('[flare-chat-core:debug]', ...args);
67
- }
68
-
69
- export default getCoreRuntimeMode;
@@ -1,24 +0,0 @@
1
- export const SESSION_LOADED = 'SESSION_LOADED';
2
- export const SESSION_RESET = 'SESSION_RESET';
3
- export const SESSION_ERROR = 'SESSION_ERROR';
4
- export const TITLE_UPDATED = 'TITLE_UPDATED';
5
- export const MESSAGES_REFRESHED = 'MESSAGES_REFRESHED';
6
- export const MESSAGE_APPENDED = 'MESSAGE_APPENDED';
7
- export const STREAMING_RESET = 'STREAMING_RESET';
8
- export const STREAMING_CHUNK = 'STREAMING_CHUNK';
9
- export const STREAMING_REPLACE = 'STREAMING_REPLACE';
10
- export const AGENT_STATUS_SET = 'AGENT_STATUS_SET';
11
- export const THINKING_TRACE_SET = 'THINKING_TRACE_SET';
12
- export const EXECUTION_TRACE_SET = 'EXECUTION_TRACE_SET';
13
- export const STREAM_KNOWLEDGE_SEARCH_SET = 'STREAM_KNOWLEDGE_SEARCH_SET';
14
- export const STREAM_SOURCING_CANDIDATES_SET = 'STREAM_SOURCING_CANDIDATES_SET';
15
- export const STREAM_KNOWLEDGE_CITATION_SET = 'STREAM_KNOWLEDGE_CITATION_SET';
16
- export const STREAMING_DONE = 'STREAMING_DONE';
17
- export const DOC_GENERATED = 'DOC_GENERATED';
18
- export const LEGEND_HINT_SHOWN = 'LEGEND_HINT_SHOWN';
19
- export const EXECUTION_CARD_UPSERTED = 'EXECUTION_CARD_UPSERTED';
20
- export const UI_CARDS_SET = 'UI_CARDS_SET';
21
- export const LAST_USER_MESSAGE_SET = 'LAST_USER_MESSAGE_SET';
22
- export const UI_CARD_UPDATED = 'UI_CARD_UPDATED';
23
- export const INSTANCE_PROFILE_SET = 'INSTANCE_PROFILE_SET';
24
- export const SESSION_PROMOTED = 'SESSION_PROMOTED';
@@ -1,352 +0,0 @@
1
- import {
2
- SESSION_LOADED,
3
- SESSION_RESET,
4
- SESSION_ERROR,
5
- TITLE_UPDATED,
6
- MESSAGES_REFRESHED,
7
- MESSAGE_APPENDED,
8
- STREAMING_RESET,
9
- STREAMING_CHUNK,
10
- STREAMING_REPLACE,
11
- AGENT_STATUS_SET,
12
- THINKING_TRACE_SET,
13
- EXECUTION_TRACE_SET,
14
- STREAM_KNOWLEDGE_SEARCH_SET,
15
- STREAM_SOURCING_CANDIDATES_SET,
16
- STREAM_KNOWLEDGE_CITATION_SET,
17
- STREAMING_DONE,
18
- DOC_GENERATED,
19
- LEGEND_HINT_SHOWN,
20
- EXECUTION_CARD_UPSERTED,
21
- UI_CARDS_SET,
22
- LAST_USER_MESSAGE_SET,
23
- UI_CARD_UPDATED,
24
- INSTANCE_PROFILE_SET,
25
- SESSION_PROMOTED,
26
- } from './chatSessionActionTypes.js';
27
-
28
- export const initialStreaming = {
29
- content: '',
30
- agentStatus: null,
31
- thinkingTrace: '',
32
- executionTrace: null,
33
- knowledgeSearch: null,
34
- sourcingCandidates: null,
35
- knowledgeCitation: null,
36
- roundKey: '',
37
- };
38
-
39
- export const initialState = {
40
- sessionId: null,
41
- sessionTitle: '',
42
- sessionStatus: 'active',
43
- sessionDetail: null,
44
- instanceProfile: null,
45
- messages: [],
46
- executionCards: [],
47
- uiCards: [],
48
- lastUserMessage: '',
49
- generatedDoc: null,
50
- streaming: initialStreaming,
51
- sessionError: null,
52
- legendHintsShown: {
53
- knowledge_base: false,
54
- ai: false,
55
- },
56
- };
57
-
58
- export function reducer(state, { type, payload }) {
59
- switch (type) {
60
- case SESSION_LOADED: {
61
- const {
62
- sessionId,
63
- title,
64
- status,
65
- messages,
66
- detail,
67
- } = payload;
68
- return {
69
- ...state,
70
- sessionId,
71
- sessionTitle: title,
72
- sessionStatus: status || 'active',
73
- sessionDetail: (detail && typeof detail === 'object' && !Array.isArray(detail)) ? detail : null,
74
- instanceProfile: state.instanceProfile,
75
- messages,
76
- executionCards: [],
77
- uiCards: [],
78
- lastUserMessage: '',
79
- generatedDoc: null,
80
- streaming: initialStreaming,
81
- legendHintsShown: initialState.legendHintsShown,
82
- };
83
- }
84
-
85
- case SESSION_RESET:
86
- return { ...initialState, instanceProfile: state.instanceProfile };
87
-
88
- case SESSION_ERROR:
89
- return { ...state, sessionError: payload };
90
-
91
- case TITLE_UPDATED:
92
- return { ...state, sessionTitle: payload };
93
-
94
- case MESSAGES_REFRESHED:
95
- return { ...state, messages: payload };
96
-
97
- case MESSAGE_APPENDED:
98
- return {
99
- ...state,
100
- messages: [...state.messages, payload],
101
- lastUserMessage: payload.role === 'user' ? payload.content : state.lastUserMessage,
102
- };
103
-
104
- case LAST_USER_MESSAGE_SET:
105
- return { ...state, lastUserMessage: payload };
106
-
107
- case UI_CARDS_SET:
108
- return { ...state, uiCards: payload };
109
-
110
- case UI_CARD_UPDATED: {
111
- const nextCard = payload;
112
- return {
113
- ...state,
114
- uiCards: state.uiCards.map((card) =>
115
- card.id === nextCard.id ? { ...card, ...nextCard } : card
116
- ),
117
- };
118
- }
119
-
120
- case INSTANCE_PROFILE_SET:
121
- return { ...state, instanceProfile: payload };
122
-
123
- case SESSION_PROMOTED: {
124
- const sessionId = String(payload?.sessionId || '').trim();
125
- if (!sessionId) {
126
- return state;
127
- }
128
- const title = String(payload?.title || '').trim();
129
- const detailPayload = (
130
- payload?.detail
131
- && typeof payload.detail === 'object'
132
- && !Array.isArray(payload.detail)
133
- ) ? payload.detail : null;
134
- const nextDetail = detailPayload
135
- ? {
136
- ...(state.sessionDetail && typeof state.sessionDetail === 'object' ? state.sessionDetail : {}),
137
- ...detailPayload,
138
- sessionId,
139
- }
140
- : (
141
- state.sessionDetail && typeof state.sessionDetail === 'object'
142
- ? {
143
- ...state.sessionDetail,
144
- sessionId,
145
- }
146
- : null
147
- );
148
- return {
149
- ...state,
150
- sessionId,
151
- sessionTitle: title || state.sessionTitle,
152
- sessionStatus: String(payload?.status || state.sessionStatus || 'active'),
153
- sessionDetail: nextDetail,
154
- };
155
- }
156
-
157
- case EXECUTION_CARD_UPSERTED: {
158
- const nextCard = payload;
159
- const cardKey = nextCard.step_id || `${nextCard.agent}-${nextCard.label}-${nextCard.stage}`;
160
- const existingIndex = state.executionCards.findIndex((card) => {
161
- const existingKey = card.step_id || `${card.agent}-${card.label}-${card.stage}`;
162
- return existingKey === cardKey;
163
- });
164
-
165
- const updatedCards = existingIndex >= 0
166
- ? state.executionCards.map((card, index) =>
167
- index === existingIndex ? { ...card, ...nextCard } : card
168
- )
169
- : [...state.executionCards, nextCard];
170
-
171
- return {
172
- ...state,
173
- executionCards: updatedCards.slice(-6),
174
- };
175
- }
176
-
177
- case STREAMING_RESET:
178
- return { ...state, streaming: initialStreaming };
179
-
180
- case STREAMING_CHUNK:
181
- return {
182
- ...state,
183
- streaming: {
184
- ...state.streaming,
185
- content: state.streaming.content + payload,
186
- },
187
- };
188
-
189
- case STREAMING_REPLACE:
190
- return {
191
- ...state,
192
- streaming: {
193
- ...state.streaming,
194
- content: String(payload || ''),
195
- },
196
- };
197
-
198
- case AGENT_STATUS_SET:
199
- return {
200
- ...state,
201
- streaming: { ...state.streaming, agentStatus: payload },
202
- };
203
-
204
- case THINKING_TRACE_SET:
205
- return {
206
- ...state,
207
- streaming: { ...state.streaming, thinkingTrace: payload },
208
- };
209
-
210
- case EXECUTION_TRACE_SET:
211
- return {
212
- ...state,
213
- streaming: {
214
- ...state.streaming,
215
- executionTrace: {
216
- ...state.streaming.executionTrace,
217
- ...payload,
218
- },
219
- },
220
- };
221
-
222
- case STREAM_KNOWLEDGE_SEARCH_SET:
223
- return {
224
- ...state,
225
- streaming: {
226
- ...state.streaming,
227
- knowledgeSearch: (
228
- payload
229
- && typeof payload === 'object'
230
- && !Array.isArray(payload)
231
- ) ? payload : null,
232
- },
233
- };
234
-
235
- case STREAM_SOURCING_CANDIDATES_SET:
236
- return {
237
- ...state,
238
- streaming: {
239
- ...state.streaming,
240
- sourcingCandidates: (
241
- payload
242
- && typeof payload === 'object'
243
- && !Array.isArray(payload)
244
- ) ? payload : null,
245
- },
246
- };
247
-
248
- case STREAM_KNOWLEDGE_CITATION_SET:
249
- return {
250
- ...state,
251
- streaming: {
252
- ...state.streaming,
253
- knowledgeCitation: (
254
- payload
255
- && typeof payload === 'object'
256
- && !Array.isArray(payload)
257
- ) ? payload : null,
258
- },
259
- };
260
-
261
- case STREAMING_DONE: {
262
- const donePayload = (
263
- payload
264
- && typeof payload === 'object'
265
- && !Array.isArray(payload)
266
- ) ? payload : { content: payload };
267
- const doneContent = String(donePayload.content || '');
268
- const doneMeta = (
269
- donePayload.meta
270
- && typeof donePayload.meta === 'object'
271
- && !Array.isArray(donePayload.meta)
272
- ) ? donePayload.meta : {};
273
- const newMessages = doneContent
274
- ? [
275
- ...state.messages,
276
- {
277
- message_id: `temp-assistant-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
278
- role: 'assistant',
279
- content: doneContent,
280
- created_at: new Date().toISOString(),
281
- round_key: String(doneMeta.round_key || doneMeta.roundKey || '').trim(),
282
- round_state: String(doneMeta.round_state || doneMeta.roundState || '').trim(),
283
- chooser_state: (
284
- doneMeta.chooser_state
285
- && typeof doneMeta.chooser_state === 'object'
286
- && !Array.isArray(doneMeta.chooser_state)
287
- ) ? doneMeta.chooser_state : null,
288
- knowledge_search: (
289
- state.streaming.knowledgeSearch
290
- && typeof state.streaming.knowledgeSearch === 'object'
291
- && !Array.isArray(state.streaming.knowledgeSearch)
292
- ) ? state.streaming.knowledgeSearch : null,
293
- sourcing_candidates: (
294
- state.streaming.sourcingCandidates
295
- && typeof state.streaming.sourcingCandidates === 'object'
296
- && !Array.isArray(state.streaming.sourcingCandidates)
297
- ) ? state.streaming.sourcingCandidates : null,
298
- knowledge_citation: (
299
- state.streaming.knowledgeCitation
300
- && typeof state.streaming.knowledgeCitation === 'object'
301
- && !Array.isArray(state.streaming.knowledgeCitation)
302
- ) ? state.streaming.knowledgeCitation : null,
303
- agent_status: (
304
- state.streaming.agentStatus
305
- && typeof state.streaming.agentStatus === 'object'
306
- && !Array.isArray(state.streaming.agentStatus)
307
- ) ? state.streaming.agentStatus : null,
308
- thinking_trace: String(state.streaming.thinkingTrace || ''),
309
- execution_trace: (
310
- state.streaming.executionTrace
311
- && typeof state.streaming.executionTrace === 'object'
312
- && !Array.isArray(state.streaming.executionTrace)
313
- ) ? state.streaming.executionTrace : null,
314
- context_usage: (
315
- doneMeta.context_usage
316
- && typeof doneMeta.context_usage === 'object'
317
- && !Array.isArray(doneMeta.context_usage)
318
- ) ? doneMeta.context_usage : null,
319
- },
320
- ]
321
- : state.messages;
322
-
323
- return {
324
- ...state,
325
- messages: newMessages,
326
- streaming: initialStreaming,
327
- };
328
- }
329
-
330
- case DOC_GENERATED:
331
- return { ...state, generatedDoc: payload };
332
-
333
- case LEGEND_HINT_SHOWN:
334
- return {
335
- ...state,
336
- legendHintsShown: {
337
- ...state.legendHintsShown,
338
- [payload]: true,
339
- },
340
- };
341
-
342
- default:
343
- return state;
344
- }
345
- }
346
-
347
- export function requireAPI(api, name) {
348
- if (!api) {
349
- throw new Error(`${name} is required`);
350
- }
351
- return api;
352
- }
@@ -1,39 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import { reducer, initialState } from './chatSessionReducer.js';
4
- import {
5
- AGENT_STATUS_SET,
6
- THINKING_TRACE_SET,
7
- EXECUTION_TRACE_SET,
8
- STREAM_KNOWLEDGE_SEARCH_SET,
9
- STREAM_KNOWLEDGE_CITATION_SET,
10
- STREAMING_DONE,
11
- } from './chatSessionActionTypes.js';
12
-
13
- test('STREAMING_DONE snapshots thinking/search/citation metadata into assistant message', () => {
14
- let state = { ...initialState };
15
- state = reducer(state, { type: AGENT_STATUS_SET, payload: { status: 'completed', stage: 'analysis' } });
16
- state = reducer(state, { type: THINKING_TRACE_SET, payload: '阶段:上下文处理' });
17
- state = reducer(state, { type: EXECUTION_TRACE_SET, payload: { step_id: 'knowledge_search', status: 'completed' } });
18
- state = reducer(state, { type: STREAM_KNOWLEDGE_SEARCH_SET, payload: { run_id: 'retrieval-1', results: [{ id: 'r1' }] } });
19
- state = reducer(state, { type: STREAM_KNOWLEDGE_CITATION_SET, payload: { run_id: 'retrieval-1', citations: [{ citation_id: 'cite_1' }] } });
20
-
21
- state = reducer(state, {
22
- type: STREAMING_DONE,
23
- payload: {
24
- content: '总结完成',
25
- meta: {
26
- context_usage: { token_budget: 1200 },
27
- },
28
- },
29
- });
30
-
31
- const lastMessage = state.messages[state.messages.length - 1];
32
- assert.equal(lastMessage.role, 'assistant');
33
- assert.equal(lastMessage.content, '总结完成');
34
- assert.equal(lastMessage.thinking_trace, '阶段:上下文处理');
35
- assert.equal(lastMessage.execution_trace?.step_id, 'knowledge_search');
36
- assert.equal(lastMessage.knowledge_search?.run_id, 'retrieval-1');
37
- assert.equal(lastMessage.knowledge_citation?.run_id, 'retrieval-1');
38
- assert.equal(lastMessage.context_usage?.token_budget, 1200);
39
- });
@@ -1,2 +0,0 @@
1
- export { default as useChatSessionReducer, initialState } from './useChatSessionReducer.js';
2
- export { default as useSessionListController } from './useSessionListController.js';
@@ -1,44 +0,0 @@
1
- import { useCallback } from 'react';
2
- import {
3
- MESSAGES_REFRESHED,
4
- MESSAGE_APPENDED,
5
- } from './chatSessionActionTypes.js';
6
- import { requireAPI } from './chatSessionReducer.js';
7
-
8
- export function useMessageActions({ dispatch, messageAPI }) {
9
- const refreshMessages = useCallback(async (sessionId) => {
10
- const messageApi = requireAPI(messageAPI, 'messageAPI');
11
- const response = await messageApi.list(sessionId);
12
- const messagesWithIds = response.messages.map((msg, index) => ({
13
- ...msg,
14
- message_id: msg.message_id || `fallback-${Date.now()}-${index}`,
15
- }));
16
- dispatch({ type: MESSAGES_REFRESHED, payload: messagesWithIds });
17
- }, [dispatch, messageAPI]);
18
-
19
- const appendUserMessage = useCallback((content, metadata = {}) => {
20
- const payloadMeta = (
21
- metadata
22
- && typeof metadata === 'object'
23
- && !Array.isArray(metadata)
24
- )
25
- ? metadata
26
- : {};
27
- dispatch({
28
- type: MESSAGE_APPENDED,
29
- payload: {
30
- message_id: `temp-user-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
31
- role: 'user',
32
- content,
33
- created_at: new Date().toISOString(),
34
- ...payloadMeta,
35
- },
36
- });
37
- }, [dispatch]);
38
-
39
- return {
40
- refreshMessages,
41
- appendUserMessage,
42
- };
43
- }
44
-
@@ -1,131 +0,0 @@
1
- import { useCallback } from 'react';
2
- import {
3
- SESSION_LOADED,
4
- SESSION_RESET,
5
- TITLE_UPDATED,
6
- SESSION_PROMOTED,
7
- } from './chatSessionActionTypes.js';
8
- import { requireAPI } from './chatSessionReducer.js';
9
-
10
- export function useSessionCrudActions({ dispatch, sessionAPI, messageAPI }) {
11
- const loadSession = useCallback(async (sessionId) => {
12
- const sessionApi = requireAPI(sessionAPI, 'sessionAPI');
13
- const messageApi = requireAPI(messageAPI, 'messageAPI');
14
-
15
- const [detail, msgs] = await Promise.all([
16
- sessionApi.get(sessionId),
17
- messageApi.list(sessionId),
18
- ]);
19
-
20
- dispatch({
21
- type: SESSION_LOADED,
22
- payload: {
23
- sessionId,
24
- title: detail.title,
25
- status: detail.status || 'active',
26
- messages: msgs.messages,
27
- detail,
28
- },
29
- });
30
- return detail;
31
- }, [dispatch, messageAPI, sessionAPI]);
32
-
33
- const createSession = useCallback(async ({
34
- function_type,
35
- title,
36
- ...extraPayload
37
- } = {}) => {
38
- const sessionApi = requireAPI(sessionAPI, 'sessionAPI');
39
- const response = await sessionApi.create({ function_type, title, ...extraPayload });
40
-
41
- dispatch({
42
- type: SESSION_LOADED,
43
- payload: {
44
- sessionId: response.sessionId,
45
- title: String(response.title || title || '').trim(),
46
- status: response.status || 'active',
47
- messages: [],
48
- detail: response,
49
- },
50
- });
51
-
52
- return response.sessionId;
53
- }, [dispatch, sessionAPI]);
54
-
55
- const createOrLoadSession = useCallback(async ({
56
- function_type,
57
- defaultTitle,
58
- forceNew = false,
59
- ...extraPayload
60
- } = {}) => {
61
- const sessionApi = requireAPI(sessionAPI, 'sessionAPI');
62
- const messageApi = requireAPI(messageAPI, 'messageAPI');
63
-
64
- let sessionId;
65
- let title;
66
-
67
- if (forceNew) {
68
- title = defaultTitle;
69
- const response = await sessionApi.create({ function_type, title, ...extraPayload });
70
- sessionId = response.sessionId;
71
- } else {
72
- const sessionList = await sessionApi.list({
73
- function_type,
74
- status: 'active',
75
- page: 1,
76
- page_size: 1,
77
- ...extraPayload,
78
- });
79
-
80
- if (sessionList.sessions.length > 0) {
81
- sessionId = sessionList.sessions[0].sessionId;
82
- title = sessionList.sessions[0].title;
83
- } else {
84
- title = defaultTitle;
85
- const response = await sessionApi.create({ function_type, title, ...extraPayload });
86
- sessionId = response.sessionId;
87
- }
88
- }
89
-
90
- const [msgs, detail] = await Promise.all([
91
- messageApi.list(sessionId),
92
- sessionApi.get(sessionId),
93
- ]);
94
-
95
- dispatch({
96
- type: SESSION_LOADED,
97
- payload: {
98
- sessionId,
99
- title,
100
- status: detail.status || 'active',
101
- messages: msgs.messages,
102
- detail,
103
- },
104
- });
105
-
106
- return sessionId;
107
- }, [dispatch, messageAPI, sessionAPI]);
108
-
109
- const resetSession = useCallback(() => {
110
- dispatch({ type: SESSION_RESET });
111
- }, [dispatch]);
112
-
113
- const updateTitle = useCallback(async (sessionId, title) => {
114
- const sessionApi = requireAPI(sessionAPI, 'sessionAPI');
115
- await sessionApi.update(sessionId, { title });
116
- dispatch({ type: TITLE_UPDATED, payload: title });
117
- }, [dispatch, sessionAPI]);
118
-
119
- const promoteSession = useCallback((payload = {}) => {
120
- dispatch({ type: SESSION_PROMOTED, payload });
121
- }, [dispatch]);
122
-
123
- return {
124
- loadSession,
125
- createSession,
126
- createOrLoadSession,
127
- resetSession,
128
- updateTitle,
129
- promoteSession,
130
- };
131
- }