* Formulate data: send instruction to derive/refine endpoint and process the result. * Handles request building, dialog continuation, table/concept creation, and error handling. * Chart creation is delegated to the caller via the createChart callback.
(options: FormulateDataOptions)
| 334 | * Chart creation is delegated to the caller via the createChart callback. |
| 335 | */ |
| 336 | async function formulateData(options: FormulateDataOptions): Promise<void> { |
| 337 | const { |
| 338 | instruction, mode, actionTableIds, currentTable, |
| 339 | overrideTableId, currentVisualization, expectedVisualization, |
| 340 | triggerChart, createChart, |
| 341 | onStarted, onSuccess, onError, onFinally, |
| 342 | } = options; |
| 343 | |
| 344 | if (actionTableIds.length === 0) return; |
| 345 | |
| 346 | onStarted?.(); |
| 347 | |
| 348 | const actionTables = actionTableIds.map(id => tables.find(t => t.id === id) as DictTable); |
| 349 | |
| 350 | // Build input_tables payload (shared across all request variants) |
| 351 | const inputTablesPayload = actionTables.map(t => ({ |
| 352 | name: t.virtual?.tableId || t.id.replace(/\.[^/.]+$/, ""), |
| 353 | rows: t.rows, |
| 354 | })); |
| 355 | |
| 356 | // Determine primary table names for agent context prioritization |
| 357 | // For derived tables, all source tables are primary; for source tables, just the current one |
| 358 | const primaryTableNames = (() => { |
| 359 | if (currentTable.derive && !currentTable.anchored) { |
| 360 | return (currentTable.derive.source as string[]).map(id => { |
| 361 | const t = tables.find(tbl => tbl.id === id); |
| 362 | return t?.virtual?.tableId || id.replace(/\.[^/.]+$/, ""); |
| 363 | }); |
| 364 | } |
| 365 | return [currentTable.virtual?.tableId || currentTable.id.replace(/\.[^/.]+$/, "")]; |
| 366 | })(); |
| 367 | |
| 368 | // Build base request body |
| 369 | let messageBody: any = { |
| 370 | mode, |
| 371 | input_tables: inputTablesPayload, |
| 372 | primary_tables: primaryTableNames, |
| 373 | extra_prompt: instruction, |
| 374 | model: activeModel, |
| 375 | ...(currentVisualization ? { current_visualization: currentVisualization } : {}), |
| 376 | ...(expectedVisualization ? { expected_visualization: expectedVisualization } : {}), |
| 377 | }; |
| 378 | let engine = getUrls().DERIVE_DATA; |
| 379 | |
| 380 | // Handle dialog continuation / refinement |
| 381 | if (currentTable.derive?.dialog && !currentTable.anchored) { |
| 382 | const sourceTableIds = currentTable.derive.source; |
| 383 | const tableIdsChanged = !sourceTableIds.every((id: string) => actionTableIds.includes(id)) || |
| 384 | !actionTableIds.every(id => sourceTableIds.includes(id)); |
| 385 | |
| 386 | if (mode === 'ideate' || tableIdsChanged) { |
| 387 | // Start fresh with prior dialog as additional context |
| 388 | messageBody.additional_messages = currentTable.derive.dialog; |
| 389 | engine = getUrls().DERIVE_DATA; |
| 390 | } else { |
| 391 | // Refine: continue existing dialog |
| 392 | messageBody = { |
| 393 | mode, |
no test coverage detected