* Stream ideas/recommendations from the exploration agent via SSE.
(options: StreamIdeasOptions)
| 222 | * Stream ideas/recommendations from the exploration agent via SSE. |
| 223 | */ |
| 224 | async function streamIdeas(options: StreamIdeasOptions): Promise<void> { |
| 225 | const { |
| 226 | actionTableIds, currentTable, |
| 227 | onIdeas, onThinkingBuffer, onLoadingChange, onProgress, |
| 228 | currentChartImage, currentDataSample, |
| 229 | startQuestion, |
| 230 | } = options; |
| 231 | |
| 232 | onLoadingChange(true); |
| 233 | onThinkingBuffer(""); |
| 234 | onIdeas([]); |
| 235 | |
| 236 | let timeoutId: ReturnType<typeof setTimeout> | undefined; |
| 237 | let timedOut = false; |
| 238 | try { |
| 239 | const focusedThread = buildFocusedThread(currentTable); |
| 240 | const otherThreads = buildOtherThreads(currentTable); |
| 241 | const actionTables = actionTableIds.map(id => tables.find(t => t.id === id) as DictTable); |
| 242 | |
| 243 | const messageBody = JSON.stringify({ |
| 244 | model: activeModel, |
| 245 | input_tables: actionTables.map(t => ({ |
| 246 | name: t.virtual?.tableId || t.id.replace(/\.[^/.]+$/, ""), |
| 247 | })), |
| 248 | primary_tables: (() => { |
| 249 | if (currentTable.derive && !currentTable.anchored) { |
| 250 | return (currentTable.derive.source as string[]).map(id => { |
| 251 | const t = tables.find(tbl => tbl.id === id); |
| 252 | return t?.virtual?.tableId || id.replace(/\.[^/.]+$/, ""); |
| 253 | }); |
| 254 | } |
| 255 | return [currentTable.virtual?.tableId || currentTable.id.replace(/\.[^/.]+$/, "")]; |
| 256 | })(), |
| 257 | ...(focusedThread.length > 0 ? { focused_thread: focusedThread } : {}), |
| 258 | ...(otherThreads.length > 0 ? { other_threads: otherThreads } : {}), |
| 259 | ...(currentChartImage ? { current_chart: currentChartImage } : {}), |
| 260 | ...(startQuestion ? { start_question: startQuestion } : {}), |
| 261 | }); |
| 262 | |
| 263 | const engine = getUrls().GET_RECOMMENDATION_QUESTIONS; |
| 264 | const controller = new AbortController(); |
| 265 | timeoutId = setTimeout(() => { timedOut = true; controller.abort(); }, config.formulateTimeoutSeconds * 1000); |
| 266 | |
| 267 | const questions: IdeaItem[] = []; |
| 268 | for await (const event of streamRequest(engine, { |
| 269 | method: 'POST', |
| 270 | headers: { 'Content-Type': 'application/json' }, |
| 271 | body: messageBody, |
| 272 | }, controller.signal)) { |
| 273 | if (event.type === 'error') { |
| 274 | throw new Error(event.error ? getErrorMessage(event.error) : t('messages.error')); |
| 275 | } |
| 276 | if (event.type === 'warning') { |
| 277 | dispatch(dfActions.addMessages({ |
| 278 | timestamp: Date.now(), type: 'warning', |
| 279 | component: 'exploration', |
| 280 | value: (event as any).warning?.message ?? 'Warning from server', |
| 281 | })); |
no test coverage detected