* Build peripheral thread summaries — leaf tables in the workspace that * are NOT part of the focused chain. Mirrors the data agent's Tier 3 * context (`SimpleChartRecBox.exploreFromChat`): all leaves except the * focused one, with per-step `display → chart_type (encodings)` lines
(currentTable: DictTable)
| 161 | * using resolved field names. |
| 162 | */ |
| 163 | function buildOtherThreads(currentTable: DictTable): any[] { |
| 164 | // Collect all table IDs in the focused thread |
| 165 | const focusedIds = new Set<string>(); |
| 166 | if (currentTable.derive && !currentTable.anchored) { |
| 167 | const triggers = getTriggers(currentTable, tables); |
| 168 | for (const t of triggers) { |
| 169 | focusedIds.add(t.resultTableId); |
| 170 | } |
| 171 | } |
| 172 | focusedIds.add(currentTable.id); |
| 173 | |
| 174 | // Find every leaf table (no children, or all children anchored) that |
| 175 | // is derived from somewhere and NOT part of the focused chain. |
| 176 | const otherThreads: any[] = []; |
| 177 | for (const table of tables) { |
| 178 | if (focusedIds.has(table.id)) continue; |
| 179 | if (!table.derive) continue; |
| 180 | const children = tables.filter(c => c.derive?.trigger?.tableId === table.id); |
| 181 | const isLeaf = children.length === 0 || children.every(c => c.anchored); |
| 182 | if (!isLeaf) continue; |
| 183 | |
| 184 | const triggers = getTriggers(table, tables); |
| 185 | if (triggers.length === 0) continue; |
| 186 | |
| 187 | const STEP_FINDING_CHAR_LIMIT = 200; |
| 188 | const steps = triggers.map(trigger => { |
| 189 | const instr = trigger.interaction?.find(e => e.role === 'instruction'); |
| 190 | const label = instr?.displayContent || instr?.content || trigger.resultTableId; |
| 191 | // Use the actual rendered chart, not the trigger's "Auto" stub. |
| 192 | const chart = resolveChartForTable(trigger.resultTableId); |
| 193 | const chartType = chart?.chartType && chart.chartType !== 'Auto' ? chart.chartType : ''; |
| 194 | const encStr = Object.entries(chartEncodingsByName(chart)) |
| 195 | .map(([k, v]) => `${k}: ${v}`) |
| 196 | .join(', '); |
| 197 | // Per-step agent commentary: the `summary` entry the visualize |
| 198 | // action emits after running this step. |
| 199 | let finding = trigger.interaction?.find( |
| 200 | e => e.role === 'summary', |
| 201 | )?.content?.trim() || ''; |
| 202 | if (finding.length > STEP_FINDING_CHAR_LIMIT) { |
| 203 | finding = finding.slice(0, STEP_FINDING_CHAR_LIMIT - 1).trimEnd() + '…'; |
| 204 | } |
| 205 | const head = `${label}${chartType ? ` → ${chartType}` : ''}${encStr ? ` (${encStr})` : ''}`; |
| 206 | return finding ? `${head} — finding: ${finding}` : head; |
| 207 | }); |
| 208 | |
| 209 | const sourceTableId = triggers[0].tableId; |
| 210 | const sourceTable = tables.find(t => t.id === sourceTableId); |
| 211 | otherThreads.push({ |
| 212 | source_table: sourceTable?.virtual?.tableId || sourceTableId, |
| 213 | leaf_table: table.virtual?.tableId || table.id, |
| 214 | step_count: triggers.length, |
| 215 | steps, |
| 216 | }); |
| 217 | } |
| 218 | return otherThreads; |
| 219 | } |
| 220 |
no test coverage detected