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.
- package/README.md +28 -0
- package/docs/CAPABILITY-INVENTORY.md +42 -0
- package/docs/CHAT-CORE-BOUNDARY.md +47 -0
- package/docs/CORE-APP-REALIGNMENT-WORKLOAD-2026-04-18.md +86 -0
- package/docs/SSOT-CHAT-CORE-BOUNDARY.md +73 -0
- package/docs/SSOT-CHAT-CORE-DATAFLOW.md +97 -0
- package/index.html +12 -0
- package/package.json +24 -2
- package/src/adapters/index.js +6 -0
- package/src/adapters/message-api.adapter.js +59 -0
- package/src/adapters/session-api.adapter.js +133 -0
- package/src/adapters/session-message-api.http.js +161 -0
- package/src/adapters/session-message-api.js +34 -0
- package/src/adapters/session-message-api.normalize-source-record.test.mjs +180 -0
- package/src/adapters/session-message-api.normalizers.js +153 -0
- package/src/adapters/source-api.adapter.js +135 -0
- package/src/adapters/sse-client.js +244 -0
- package/src/adapters/sse-event-dispatcher.js +121 -0
- package/src/app/App.jsx +11 -0
- package/src/app/AppProviders.jsx +12 -0
- package/src/app/ChatWorkspaceScreen.jsx +33 -0
- package/src/app/WorkspaceLayout.jsx +190 -0
- package/src/app/components/AppCanvasPanel.jsx +64 -0
- package/src/app/components/TriggerThresholdPopoverContent.jsx +122 -0
- package/src/app/components/WorkspaceBodySection.jsx +156 -0
- package/src/app/components/WorkspaceMainPane.jsx +121 -0
- package/src/app/components/WorkspaceSessionPane.jsx +70 -0
- package/src/app/components/WorkspaceTopBarSection.jsx +71 -0
- package/src/app/core-chat-entry/ComposerSectionNode.jsx +241 -0
- package/src/app/core-chat-entry/attachmentSendRefs.js +154 -0
- package/src/app/core-chat-entry/attachmentSendRefs.test.mjs +101 -0
- package/src/app/core-chat-entry/composerActionRouter.js +26 -0
- package/src/app/core-chat-entry/constants.js +108 -0
- package/src/app/core-chat-entry/selectors.js +28 -0
- package/src/app/core-chat-entry/useAppActionErrorGuards.js +68 -0
- package/src/app/core-chat-entry/useChatCorePipelines.js +110 -0
- package/src/app/core-chat-entry/useComposerModeSuggestion.js +89 -0
- package/src/app/core-chat-entry/useDevCapabilityStatusNote.js +22 -0
- package/src/app/core-chat-entry/useProjectNameEditing.js +41 -0
- package/src/app/core-chat-entry/useProjectSourceUpload.js +341 -0
- package/src/app/core-chat-entry/useRealApiReadinessGate.js +103 -0
- package/src/app/core-chat-entry/useUnavailableActionError.js +29 -0
- package/src/app/core-chat-entry/useWorkspaceCanvasController.jsx +177 -0
- package/src/app/core-chat-entry/useWorkspaceCanvasProjection.jsx +171 -0
- package/src/app/core-chat-entry/useWorkspaceComposerController.jsx +199 -0
- package/src/app/core-chat-entry/useWorkspaceController.jsx +226 -0
- package/src/app/core-chat-entry/useWorkspacePanels.js +55 -0
- package/src/app/hooks/useComposerAttachmentSync.js +223 -0
- package/src/app/hooks/useComposerChooserHandlers.js +52 -0
- package/src/app/hooks/useSendWithContextRefs.js +140 -0
- package/src/app/hooks/useSendWithContextRefs.test.mjs +29 -0
- package/src/app/hooks/useUserThresholdProfile.js +121 -0
- package/src/app/index.js +1 -0
- package/src/app/selectors/assistantTextSelector.js +73 -0
- package/src/app/selectors/canvasEvidenceSummarySelector.js +28 -0
- package/src/app/selectors/canvasReportTemplateSelector.js +28 -0
- package/src/app/selectors/canvasTabsSelector.js +58 -0
- package/src/app/selectors/evidenceProjectionSelector.js +175 -0
- package/src/app/selectors/evidenceProjectionSelector.test.mjs +107 -0
- package/src/app/selectors/modeSuggestionSelector.js +50 -0
- package/src/chat-core/app/mockRuntime.js +291 -0
- package/src/chat-core/app/useAppStream.js +187 -0
- package/src/chat-core/app/useAppStream.refs.test.mjs +44 -0
- package/src/chat-core/app/useAppStream.request-body.test.mjs +116 -0
- package/src/chat-core/app/useCoreChatApp.js +115 -0
- package/src/chat-core/facade/useBasicConversationFacade.js +280 -0
- package/src/chat-core/index.js +9 -1
- package/src/chat-core/messages/buildTimelineItems.analysis-route.test.mjs +36 -0
- package/src/chat-core/messages/buildTimelineItems.js +139 -13
- package/src/chat-core/messages/buildTimelineItems.knowledge-citation.test.mjs +182 -0
- package/src/chat-core/messages/contextUsageDefaults.js +3 -0
- package/src/chat-core/messages/contextUsageViewModel.js +147 -0
- package/src/chat-core/messages/contextUsageViewModel.test.mjs +74 -0
- package/src/chat-core/messages/useContextUsageViewModel.js +41 -0
- package/src/chat-core/orchestration/useBasicSendHandler.js +55 -0
- package/src/chat-core/pipelines/build-action-request.js +46 -0
- package/src/chat-core/pipelines/build-stream-request.js +74 -0
- package/src/chat-core/pipelines/entity-extraction.js +159 -0
- package/src/chat-core/pipelines/preprocess-message.js +16 -0
- package/src/chat-core/pipelines/stream-persist-utils.js +32 -0
- package/src/chat-core/pipelines/transport/send-mock-stream.js +86 -0
- package/src/chat-core/pipelines/transport/send-real-stream.js +330 -0
- package/src/chat-core/pipelines/transport/send-real-stream.test.mjs +27 -0
- package/src/chat-core/pipelines/transport/send-sourcing-search.js +86 -0
- package/src/chat-core/pipelines/transport/send-sourcing-search.test.mjs +14 -0
- package/src/chat-core/pipelines/transport/sourcing-response-templates.js +55 -0
- package/src/chat-core/pipelines/transport/sourcing-search-api.js +155 -0
- package/src/chat-core/runtime/runtimeMode.js +69 -0
- package/src/chat-core/session/chatSessionActionTypes.js +24 -0
- package/src/chat-core/session/chatSessionReducer.js +352 -0
- package/src/chat-core/session/chatSessionReducer.streaming-done.test.mjs +39 -0
- package/src/chat-core/session/index.js +2 -0
- package/src/chat-core/session/sessionActionsMessages.js +44 -0
- package/src/chat-core/session/sessionActionsSessionCrud.js +131 -0
- package/src/chat-core/session/sessionActionsStreaming.js +80 -0
- package/src/chat-core/session/sessionActionsUiState.js +51 -0
- package/src/chat-core/session/useChatSessionReducer.js +62 -455
- package/src/chat-core/session/useSessionListController.js +67 -0
- package/src/chat-core/stream/sse-client.js +1 -244
- package/src/chat-core/stream/sse-event-dispatcher.js +1 -0
- package/src/chat-core/stream/sse-events.js +1 -867
- package/src/chat-core/stream/useSSEStream.js +1 -356
- package/src/chat-core/stream/useStreamSendController.js +46 -0
- package/src/contracts/context-ssot.js +47 -0
- package/src/contracts/index.js +1 -0
- package/src/contracts/sse-events/base-parsers.js +79 -0
- package/src/contracts/sse-events/domain-parsers.js +3 -0
- package/src/contracts/sse-events/internal-normalizers.js +143 -0
- package/src/contracts/sse-events/parsers-intake.js +235 -0
- package/src/contracts/sse-events/parsers-runtime.js +37 -0
- package/src/contracts/sse-events/parsers-sourcing.js +179 -0
- package/src/contracts/sse-events/patch-event-parser.js +121 -0
- package/src/contracts/sse-events/runtime-parsers.js +79 -0
- package/src/contracts/sse-events.js +4 -0
- package/src/index.js +5 -0
- package/src/main.jsx +28 -0
- package/src/orchestration/index.js +6 -0
- package/src/orchestration/useSSEStream.js +221 -0
- package/src/state/index.js +4 -0
- package/vite.config.js +36 -0
|
@@ -1,463 +1,64 @@
|
|
|
1
|
-
import { useReducer,
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const AGENT_STATUS_SET = 'AGENT_STATUS_SET';
|
|
13
|
-
const THINKING_TRACE_SET = 'THINKING_TRACE_SET';
|
|
14
|
-
const EXECUTION_TRACE_SET = 'EXECUTION_TRACE_SET';
|
|
15
|
-
const STREAMING_DONE = 'STREAMING_DONE';
|
|
16
|
-
const DOC_GENERATED = 'DOC_GENERATED';
|
|
17
|
-
const LEGEND_HINT_SHOWN = 'LEGEND_HINT_SHOWN';
|
|
18
|
-
const EXECUTION_CARD_UPSERTED = 'EXECUTION_CARD_UPSERTED';
|
|
19
|
-
const UI_CARDS_SET = 'UI_CARDS_SET';
|
|
20
|
-
const LAST_USER_MESSAGE_SET = 'LAST_USER_MESSAGE_SET';
|
|
21
|
-
const UI_CARD_UPDATED = 'UI_CARD_UPDATED';
|
|
22
|
-
const INSTANCE_PROFILE_SET = 'INSTANCE_PROFILE_SET';
|
|
23
|
-
const SESSION_PROMOTED = 'SESSION_PROMOTED';
|
|
24
|
-
|
|
25
|
-
const initialStreaming = {
|
|
26
|
-
content: '',
|
|
27
|
-
agentStatus: null,
|
|
28
|
-
thinkingTrace: '',
|
|
29
|
-
executionTrace: null,
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export const initialState = {
|
|
33
|
-
sessionId: null,
|
|
34
|
-
sessionTitle: '',
|
|
35
|
-
sessionStatus: 'active',
|
|
36
|
-
sessionDetail: null,
|
|
37
|
-
instanceProfile: null,
|
|
38
|
-
messages: [],
|
|
39
|
-
executionCards: [],
|
|
40
|
-
uiCards: [],
|
|
41
|
-
lastUserMessage: '',
|
|
42
|
-
generatedDoc: null,
|
|
43
|
-
streaming: initialStreaming,
|
|
44
|
-
sessionError: null,
|
|
45
|
-
legendHintsShown: {
|
|
46
|
-
knowledge_base: false,
|
|
47
|
-
ai: false,
|
|
48
|
-
},
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
function reducer(state, { type, payload }) {
|
|
52
|
-
switch (type) {
|
|
53
|
-
case SESSION_LOADED: {
|
|
54
|
-
const {
|
|
55
|
-
sessionId,
|
|
56
|
-
title,
|
|
57
|
-
status,
|
|
58
|
-
messages,
|
|
59
|
-
detail,
|
|
60
|
-
} = payload;
|
|
61
|
-
return {
|
|
62
|
-
...state,
|
|
63
|
-
sessionId,
|
|
64
|
-
sessionTitle: title,
|
|
65
|
-
sessionStatus: status || 'active',
|
|
66
|
-
sessionDetail: (detail && typeof detail === 'object' && !Array.isArray(detail)) ? detail : null,
|
|
67
|
-
instanceProfile: state.instanceProfile,
|
|
68
|
-
messages,
|
|
69
|
-
executionCards: [],
|
|
70
|
-
uiCards: [],
|
|
71
|
-
lastUserMessage: '',
|
|
72
|
-
generatedDoc: null,
|
|
73
|
-
streaming: initialStreaming,
|
|
74
|
-
legendHintsShown: initialState.legendHintsShown,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
case SESSION_RESET:
|
|
79
|
-
return { ...initialState, instanceProfile: state.instanceProfile };
|
|
80
|
-
|
|
81
|
-
case SESSION_ERROR:
|
|
82
|
-
return { ...state, sessionError: payload };
|
|
83
|
-
|
|
84
|
-
case TITLE_UPDATED:
|
|
85
|
-
return { ...state, sessionTitle: payload };
|
|
86
|
-
|
|
87
|
-
case MESSAGES_REFRESHED:
|
|
88
|
-
return { ...state, messages: payload };
|
|
89
|
-
|
|
90
|
-
case MESSAGE_APPENDED:
|
|
91
|
-
return {
|
|
92
|
-
...state,
|
|
93
|
-
messages: [...state.messages, payload],
|
|
94
|
-
lastUserMessage: payload.role === 'user' ? payload.content : state.lastUserMessage,
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
case LAST_USER_MESSAGE_SET:
|
|
98
|
-
return { ...state, lastUserMessage: payload };
|
|
99
|
-
|
|
100
|
-
case UI_CARDS_SET:
|
|
101
|
-
return { ...state, uiCards: payload };
|
|
102
|
-
|
|
103
|
-
case UI_CARD_UPDATED: {
|
|
104
|
-
const nextCard = payload;
|
|
105
|
-
return {
|
|
106
|
-
...state,
|
|
107
|
-
uiCards: state.uiCards.map((card) =>
|
|
108
|
-
card.id === nextCard.id ? { ...card, ...nextCard } : card
|
|
109
|
-
),
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
case INSTANCE_PROFILE_SET:
|
|
114
|
-
return { ...state, instanceProfile: payload };
|
|
115
|
-
|
|
116
|
-
case SESSION_PROMOTED: {
|
|
117
|
-
const sessionId = String(payload?.sessionId || '').trim();
|
|
118
|
-
if (!sessionId) {
|
|
119
|
-
return state;
|
|
120
|
-
}
|
|
121
|
-
const title = String(payload?.title || '').trim();
|
|
122
|
-
const detailPayload = (
|
|
123
|
-
payload?.detail
|
|
124
|
-
&& typeof payload.detail === 'object'
|
|
125
|
-
&& !Array.isArray(payload.detail)
|
|
126
|
-
) ? payload.detail : null;
|
|
127
|
-
const nextDetail = detailPayload
|
|
128
|
-
? {
|
|
129
|
-
...(state.sessionDetail && typeof state.sessionDetail === 'object' ? state.sessionDetail : {}),
|
|
130
|
-
...detailPayload,
|
|
131
|
-
sessionId,
|
|
132
|
-
}
|
|
133
|
-
: (
|
|
134
|
-
state.sessionDetail && typeof state.sessionDetail === 'object'
|
|
135
|
-
? {
|
|
136
|
-
...state.sessionDetail,
|
|
137
|
-
sessionId,
|
|
138
|
-
}
|
|
139
|
-
: null
|
|
140
|
-
);
|
|
141
|
-
return {
|
|
142
|
-
...state,
|
|
143
|
-
sessionId,
|
|
144
|
-
sessionTitle: title || state.sessionTitle,
|
|
145
|
-
sessionStatus: String(payload?.status || state.sessionStatus || 'active'),
|
|
146
|
-
sessionDetail: nextDetail,
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
case EXECUTION_CARD_UPSERTED: {
|
|
151
|
-
const nextCard = payload;
|
|
152
|
-
const cardKey = nextCard.step_id || `${nextCard.agent}-${nextCard.label}-${nextCard.stage}`;
|
|
153
|
-
const existingIndex = state.executionCards.findIndex((card) => {
|
|
154
|
-
const existingKey = card.step_id || `${card.agent}-${card.label}-${card.stage}`;
|
|
155
|
-
return existingKey === cardKey;
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
const updatedCards = existingIndex >= 0
|
|
159
|
-
? state.executionCards.map((card, index) =>
|
|
160
|
-
index === existingIndex ? { ...card, ...nextCard } : card
|
|
161
|
-
)
|
|
162
|
-
: [...state.executionCards, nextCard];
|
|
163
|
-
|
|
164
|
-
return {
|
|
165
|
-
...state,
|
|
166
|
-
executionCards: updatedCards.slice(-6),
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
case STREAMING_RESET:
|
|
171
|
-
return { ...state, streaming: initialStreaming };
|
|
172
|
-
|
|
173
|
-
case STREAMING_CHUNK:
|
|
174
|
-
return {
|
|
175
|
-
...state,
|
|
176
|
-
streaming: {
|
|
177
|
-
...state.streaming,
|
|
178
|
-
content: state.streaming.content + payload,
|
|
179
|
-
},
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
case STREAMING_REPLACE:
|
|
183
|
-
return {
|
|
184
|
-
...state,
|
|
185
|
-
streaming: {
|
|
186
|
-
...state.streaming,
|
|
187
|
-
content: String(payload || ''),
|
|
188
|
-
},
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
case AGENT_STATUS_SET:
|
|
192
|
-
return {
|
|
193
|
-
...state,
|
|
194
|
-
streaming: { ...state.streaming, agentStatus: payload },
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
case THINKING_TRACE_SET:
|
|
198
|
-
return {
|
|
199
|
-
...state,
|
|
200
|
-
streaming: { ...state.streaming, thinkingTrace: payload },
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
case EXECUTION_TRACE_SET:
|
|
204
|
-
return {
|
|
205
|
-
...state,
|
|
206
|
-
streaming: {
|
|
207
|
-
...state.streaming,
|
|
208
|
-
executionTrace: {
|
|
209
|
-
...state.streaming.executionTrace,
|
|
210
|
-
...payload,
|
|
211
|
-
},
|
|
212
|
-
},
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
case STREAMING_DONE: {
|
|
216
|
-
const newMessages = payload
|
|
217
|
-
? [
|
|
218
|
-
...state.messages,
|
|
219
|
-
{
|
|
220
|
-
message_id: `temp-assistant-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
221
|
-
role: 'assistant',
|
|
222
|
-
content: payload,
|
|
223
|
-
created_at: new Date().toISOString(),
|
|
224
|
-
},
|
|
225
|
-
]
|
|
226
|
-
: state.messages;
|
|
227
|
-
|
|
228
|
-
return {
|
|
229
|
-
...state,
|
|
230
|
-
messages: newMessages,
|
|
231
|
-
streaming: initialStreaming,
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
case DOC_GENERATED:
|
|
236
|
-
return { ...state, generatedDoc: payload };
|
|
237
|
-
|
|
238
|
-
case LEGEND_HINT_SHOWN:
|
|
239
|
-
return {
|
|
240
|
-
...state,
|
|
241
|
-
legendHintsShown: {
|
|
242
|
-
...state.legendHintsShown,
|
|
243
|
-
[payload]: true,
|
|
244
|
-
},
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
default:
|
|
248
|
-
return state;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
function requireAPI(api, name) {
|
|
253
|
-
if (!api) {
|
|
254
|
-
throw new Error(`${name} is required`);
|
|
255
|
-
}
|
|
256
|
-
return api;
|
|
257
|
-
}
|
|
1
|
+
import { useReducer, useMemo } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
initialState,
|
|
4
|
+
reducer,
|
|
5
|
+
} from './chatSessionReducer.js';
|
|
6
|
+
import { useSessionCrudActions } from './sessionActionsSessionCrud.js';
|
|
7
|
+
import { useMessageActions } from './sessionActionsMessages.js';
|
|
8
|
+
import { useStreamingActions } from './sessionActionsStreaming.js';
|
|
9
|
+
import { useUiStateActions } from './sessionActionsUiState.js';
|
|
10
|
+
|
|
11
|
+
export { initialState } from './chatSessionReducer.js';
|
|
258
12
|
|
|
259
13
|
export default function useChatSessionReducer(deps = {}) {
|
|
260
14
|
const { sessionAPI, messageAPI } = deps;
|
|
261
15
|
const [state, dispatch] = useReducer(reducer, initialState);
|
|
262
16
|
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
function_type,
|
|
309
|
-
defaultTitle,
|
|
310
|
-
forceNew = false,
|
|
311
|
-
...extraPayload
|
|
312
|
-
} = {}) => {
|
|
313
|
-
const sessionApi = requireAPI(sessionAPI, 'sessionAPI');
|
|
314
|
-
const messageApi = requireAPI(messageAPI, 'messageAPI');
|
|
315
|
-
|
|
316
|
-
let sessionId;
|
|
317
|
-
let title;
|
|
318
|
-
|
|
319
|
-
if (forceNew) {
|
|
320
|
-
title = defaultTitle;
|
|
321
|
-
const response = await sessionApi.create({ function_type, title, ...extraPayload });
|
|
322
|
-
sessionId = response.sessionId;
|
|
323
|
-
} else {
|
|
324
|
-
const sessionList = await sessionApi.list({
|
|
325
|
-
function_type,
|
|
326
|
-
status: 'active',
|
|
327
|
-
page: 1,
|
|
328
|
-
page_size: 1,
|
|
329
|
-
...extraPayload,
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
if (sessionList.sessions.length > 0) {
|
|
333
|
-
sessionId = sessionList.sessions[0].sessionId;
|
|
334
|
-
title = sessionList.sessions[0].title;
|
|
335
|
-
} else {
|
|
336
|
-
title = defaultTitle;
|
|
337
|
-
const response = await sessionApi.create({ function_type, title, ...extraPayload });
|
|
338
|
-
sessionId = response.sessionId;
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
const [msgs, detail] = await Promise.all([
|
|
343
|
-
messageApi.list(sessionId),
|
|
344
|
-
sessionApi.get(sessionId),
|
|
345
|
-
]);
|
|
346
|
-
|
|
347
|
-
dispatch({
|
|
348
|
-
type: SESSION_LOADED,
|
|
349
|
-
payload: {
|
|
350
|
-
sessionId,
|
|
351
|
-
title,
|
|
352
|
-
status: detail.status || 'active',
|
|
353
|
-
messages: msgs.messages,
|
|
354
|
-
detail,
|
|
355
|
-
},
|
|
356
|
-
});
|
|
357
|
-
|
|
358
|
-
return sessionId;
|
|
359
|
-
}, [sessionAPI, messageAPI]);
|
|
360
|
-
|
|
361
|
-
const resetSession = useCallback(() => {
|
|
362
|
-
dispatch({ type: SESSION_RESET });
|
|
363
|
-
}, []);
|
|
364
|
-
|
|
365
|
-
const updateTitle = useCallback(async (sessionId, title) => {
|
|
366
|
-
const sessionApi = requireAPI(sessionAPI, 'sessionAPI');
|
|
367
|
-
await sessionApi.update(sessionId, { title });
|
|
368
|
-
dispatch({ type: TITLE_UPDATED, payload: title });
|
|
369
|
-
}, [sessionAPI]);
|
|
370
|
-
|
|
371
|
-
const promoteSession = useCallback((payload = {}) => {
|
|
372
|
-
dispatch({ type: SESSION_PROMOTED, payload });
|
|
373
|
-
}, []);
|
|
374
|
-
|
|
375
|
-
const refreshMessages = useCallback(async (sessionId) => {
|
|
376
|
-
const messageApi = requireAPI(messageAPI, 'messageAPI');
|
|
377
|
-
const response = await messageApi.list(sessionId);
|
|
378
|
-
const messagesWithIds = response.messages.map((msg, index) => ({
|
|
379
|
-
...msg,
|
|
380
|
-
message_id: msg.message_id || `fallback-${Date.now()}-${index}`,
|
|
381
|
-
}));
|
|
382
|
-
dispatch({ type: MESSAGES_REFRESHED, payload: messagesWithIds });
|
|
383
|
-
}, [messageAPI]);
|
|
384
|
-
|
|
385
|
-
const appendUserMessage = useCallback((content, metadata = {}) => {
|
|
386
|
-
const payloadMeta = (
|
|
387
|
-
metadata
|
|
388
|
-
&& typeof metadata === 'object'
|
|
389
|
-
&& !Array.isArray(metadata)
|
|
390
|
-
)
|
|
391
|
-
? metadata
|
|
392
|
-
: {};
|
|
393
|
-
dispatch({
|
|
394
|
-
type: MESSAGE_APPENDED,
|
|
395
|
-
payload: {
|
|
396
|
-
message_id: `temp-user-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
397
|
-
role: 'user',
|
|
398
|
-
content,
|
|
399
|
-
created_at: new Date().toISOString(),
|
|
400
|
-
...payloadMeta,
|
|
401
|
-
},
|
|
402
|
-
});
|
|
403
|
-
}, []);
|
|
404
|
-
|
|
405
|
-
const setUICards = useCallback((cards) => {
|
|
406
|
-
dispatch({ type: UI_CARDS_SET, payload: Array.isArray(cards) ? cards : [] });
|
|
407
|
-
}, []);
|
|
408
|
-
|
|
409
|
-
const updateUICard = useCallback((card) => {
|
|
410
|
-
dispatch({ type: UI_CARD_UPDATED, payload: card });
|
|
411
|
-
}, []);
|
|
412
|
-
|
|
413
|
-
const setLastUserMessage = useCallback((content) => {
|
|
414
|
-
dispatch({ type: LAST_USER_MESSAGE_SET, payload: content || '' });
|
|
415
|
-
}, []);
|
|
416
|
-
|
|
417
|
-
const resetStreaming = useCallback(() => {
|
|
418
|
-
dispatch({ type: STREAMING_RESET });
|
|
419
|
-
}, []);
|
|
420
|
-
|
|
421
|
-
const appendStreamChunk = useCallback((chunk) => {
|
|
422
|
-
dispatch({ type: STREAMING_CHUNK, payload: chunk });
|
|
423
|
-
}, []);
|
|
424
|
-
|
|
425
|
-
const replaceStreamContent = useCallback((content) => {
|
|
426
|
-
dispatch({ type: STREAMING_REPLACE, payload: content });
|
|
427
|
-
}, []);
|
|
428
|
-
|
|
429
|
-
const setAgentStatus = useCallback((agentStatus) => {
|
|
430
|
-
dispatch({ type: AGENT_STATUS_SET, payload: agentStatus });
|
|
431
|
-
}, []);
|
|
432
|
-
|
|
433
|
-
const setThinkingTrace = useCallback((trace) => {
|
|
434
|
-
dispatch({ type: THINKING_TRACE_SET, payload: trace });
|
|
435
|
-
}, []);
|
|
436
|
-
|
|
437
|
-
const setExecutionTrace = useCallback((executionTrace) => {
|
|
438
|
-
dispatch({ type: EXECUTION_TRACE_SET, payload: executionTrace });
|
|
439
|
-
dispatch({ type: EXECUTION_CARD_UPSERTED, payload: executionTrace });
|
|
440
|
-
}, []);
|
|
441
|
-
|
|
442
|
-
const completeStreaming = useCallback((finalContent) => {
|
|
443
|
-
dispatch({ type: STREAMING_DONE, payload: finalContent });
|
|
444
|
-
}, []);
|
|
445
|
-
|
|
446
|
-
const setGeneratedDoc = useCallback((doc) => {
|
|
447
|
-
dispatch({ type: DOC_GENERATED, payload: doc });
|
|
448
|
-
}, []);
|
|
449
|
-
|
|
450
|
-
const markLegendHintShown = useCallback((sourceType) => {
|
|
451
|
-
dispatch({ type: LEGEND_HINT_SHOWN, payload: sourceType });
|
|
452
|
-
}, []);
|
|
453
|
-
|
|
454
|
-
const setSessionError = useCallback((error) => {
|
|
455
|
-
dispatch({ type: SESSION_ERROR, payload: error });
|
|
456
|
-
}, []);
|
|
457
|
-
|
|
458
|
-
const setInstanceProfile = useCallback((profile) => {
|
|
459
|
-
dispatch({ type: INSTANCE_PROFILE_SET, payload: profile || null });
|
|
460
|
-
}, []);
|
|
17
|
+
const sessionCrudActions = useSessionCrudActions({
|
|
18
|
+
dispatch,
|
|
19
|
+
sessionAPI,
|
|
20
|
+
messageAPI,
|
|
21
|
+
});
|
|
22
|
+
const messageActions = useMessageActions({
|
|
23
|
+
dispatch,
|
|
24
|
+
messageAPI,
|
|
25
|
+
});
|
|
26
|
+
const streamingActions = useStreamingActions({ dispatch });
|
|
27
|
+
const uiStateActions = useUiStateActions({ dispatch });
|
|
28
|
+
|
|
29
|
+
const {
|
|
30
|
+
loadSession,
|
|
31
|
+
createSession,
|
|
32
|
+
createOrLoadSession,
|
|
33
|
+
resetSession,
|
|
34
|
+
updateTitle,
|
|
35
|
+
promoteSession,
|
|
36
|
+
} = sessionCrudActions;
|
|
37
|
+
const {
|
|
38
|
+
refreshMessages,
|
|
39
|
+
appendUserMessage,
|
|
40
|
+
} = messageActions;
|
|
41
|
+
const {
|
|
42
|
+
resetStreaming,
|
|
43
|
+
appendStreamChunk,
|
|
44
|
+
replaceStreamContent,
|
|
45
|
+
setAgentStatus,
|
|
46
|
+
setThinkingTrace,
|
|
47
|
+
setExecutionTrace,
|
|
48
|
+
setKnowledgeSearch,
|
|
49
|
+
setSourcingCandidates,
|
|
50
|
+
setKnowledgeCitation,
|
|
51
|
+
completeStreaming,
|
|
52
|
+
} = streamingActions;
|
|
53
|
+
const {
|
|
54
|
+
setUICards,
|
|
55
|
+
updateUICard,
|
|
56
|
+
setLastUserMessage,
|
|
57
|
+
setGeneratedDoc,
|
|
58
|
+
markLegendHintShown,
|
|
59
|
+
setSessionError,
|
|
60
|
+
setInstanceProfile,
|
|
61
|
+
} = uiStateActions;
|
|
461
62
|
|
|
462
63
|
return useMemo(() => ({
|
|
463
64
|
sessionId: state.sessionId,
|
|
@@ -490,6 +91,9 @@ export default function useChatSessionReducer(deps = {}) {
|
|
|
490
91
|
setAgentStatus,
|
|
491
92
|
setThinkingTrace,
|
|
492
93
|
setExecutionTrace,
|
|
94
|
+
setKnowledgeSearch,
|
|
95
|
+
setSourcingCandidates,
|
|
96
|
+
setKnowledgeCitation,
|
|
493
97
|
completeStreaming,
|
|
494
98
|
setGeneratedDoc,
|
|
495
99
|
setInstanceProfile,
|
|
@@ -514,6 +118,9 @@ export default function useChatSessionReducer(deps = {}) {
|
|
|
514
118
|
setAgentStatus,
|
|
515
119
|
setThinkingTrace,
|
|
516
120
|
setExecutionTrace,
|
|
121
|
+
setKnowledgeSearch,
|
|
122
|
+
setSourcingCandidates,
|
|
123
|
+
setKnowledgeCitation,
|
|
517
124
|
completeStreaming,
|
|
518
125
|
setGeneratedDoc,
|
|
519
126
|
setInstanceProfile,
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { useCallback, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Session list lifecycle controller.
|
|
5
|
+
*
|
|
6
|
+
* @param {object} params - Hook params.
|
|
7
|
+
* @param {object} params.sessionAPI - Session API provider.
|
|
8
|
+
* @param {object} params.listParams - Session list query params.
|
|
9
|
+
* @param {Function} params.onStarted - Optional started callback.
|
|
10
|
+
* @param {Function} params.onSucceeded - Optional succeeded callback.
|
|
11
|
+
* @param {Function} params.onFailed - Optional failed callback.
|
|
12
|
+
* @returns {{sessions: Array<object>, loading: boolean, error: any, loadSessionList: Function}}
|
|
13
|
+
*/
|
|
14
|
+
export default function useSessionListController({
|
|
15
|
+
sessionAPI,
|
|
16
|
+
listParams = {},
|
|
17
|
+
onStarted,
|
|
18
|
+
onSucceeded,
|
|
19
|
+
onFailed,
|
|
20
|
+
} = {}) {
|
|
21
|
+
const [sessions, setSessions] = useState([]);
|
|
22
|
+
const [loading, setLoading] = useState(false);
|
|
23
|
+
const [error, setError] = useState(null);
|
|
24
|
+
const [hasLoaded, setHasLoaded] = useState(false);
|
|
25
|
+
|
|
26
|
+
const loadSessionList = useCallback(async (options = {}) => {
|
|
27
|
+
if (!sessionAPI?.list) {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
const background = options?.background === true;
|
|
31
|
+
const shouldShowLoading = !background && !hasLoaded;
|
|
32
|
+
|
|
33
|
+
onStarted?.();
|
|
34
|
+
if (shouldShowLoading) {
|
|
35
|
+
setLoading(true);
|
|
36
|
+
}
|
|
37
|
+
if (!background) {
|
|
38
|
+
setError(null);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const response = await sessionAPI.list(listParams);
|
|
43
|
+
const resolvedSessions = Array.isArray(response?.sessions) ? response.sessions : [];
|
|
44
|
+
setSessions(resolvedSessions);
|
|
45
|
+
setHasLoaded(true);
|
|
46
|
+
onSucceeded?.(resolvedSessions);
|
|
47
|
+
return resolvedSessions;
|
|
48
|
+
} catch (nextError) {
|
|
49
|
+
setError(nextError);
|
|
50
|
+
onFailed?.(nextError);
|
|
51
|
+
throw nextError;
|
|
52
|
+
} finally {
|
|
53
|
+
if (shouldShowLoading) {
|
|
54
|
+
setLoading(false);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}, [hasLoaded, listParams, onFailed, onStarted, onSucceeded, sessionAPI]);
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
sessions,
|
|
61
|
+
loading,
|
|
62
|
+
error,
|
|
63
|
+
loadSessionList,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export { useSessionListController };
|