/* =================================================================== KabelFlux — AI Tools panel (views-ai-tools.jsx) Exposes window.AIToolsPanel. One card hosting the read-only AI helpers: narrate, parts intelligence, continuity, change-impact, standards Q&A. ES2015-safe (no object-rest, no {...} literals). =================================================================== */ const AIToolsPanel = ({ pid }) => { const { useState } = React; const [importWires, setImportWires] = useState([]); const [tool, setTool] = useState('narrate'); const [failure, setFailure] = useState(''); const [change, setChange] = useState(''); const [question, setQuestion] = useState(''); const [excerpt, setExcerpt] = useState(''); const [email, setEmail] = useState(''); const [out, setOut] = useState(''); const [busy, setBusy] = useState(false); const TOOLS = [ { k: 'narrate', l: 'Narrate harness' }, { k: 'parts', l: 'Parts intelligence' }, { k: 'continuity', l: 'Continuity troubleshooter' }, { k: 'change', l: 'Change impact' }, { k: 'standards', l: 'Standards Q&A' }, { k: 'wire-sizing', l: 'Wire sizing' }, { k: 'quote', l: 'Quote estimate' }, { k: 'build', l: 'Build instructions' }, { k: 'rfq', l: 'RFQ triage' }, { k: 'anomaly', l: 'Anomaly check' }, { k: 'estimates', l: 'Estimates (length/bundle)' }, { k: 'det-quote', l: 'Quote (deterministic)' }, { k: 'import', l: 'Smart import (CSV)' }, { k: 'import-netlist', l: 'Netlist / KBL import' }, ]; async function run() { if (busy || !pid) return; setOut(''); setBusy(true); let acc = ''; const onEv = function (ev) { if (ev.type === 'text') { acc += ev.text; setOut(acc); } else if (ev.type === 'error') { setOut(ev.message || 'AI request failed.'); } }; if (tool === 'narrate') await window.kfxAiNarrateStream(pid, onEv); else if (tool === 'parts') await window.kfxAiPartsStream(pid, onEv); else if (tool === 'continuity') await window.kfxAiContinuityStream(pid, failure, onEv); else if (tool === 'change') await window.kfxAiChangeImpactStream(pid, change, onEv); else if (tool === 'standards') await window.kfxAiStandardsStream(pid, question, excerpt, onEv); else if (tool === 'wire-sizing') await window.kfxAiWireSizingStream(pid, onEv); else if (tool === 'quote') await window.kfxAiQuoteStream(pid, onEv); else if (tool === 'build') await window.kfxAiBuildInstructionsStream(pid, onEv); else if (tool === 'rfq') await window.kfxAiRfqStream(pid, email, onEv); else if (tool === 'anomaly') await window.kfxAiAnomalyStream(pid, onEv); else if (tool === 'det-quote') { try { const q = await window.kfxQuote(pid); const lines = ['Deterministic quote (margin ' + q.margin_pct + '%):', '']; (q.breaks || []).forEach(function (b) { lines.push('Qty ' + b.qty + ': unit ' + b.unit_price + ' (cost ' + b.unit_cost + '), extended ' + b.extended_price + ', lead ' + b.lead_time_days + 'd'); if ((b.long_lead_parts || []).length) lines.push(' Long-lead: ' + b.long_lead_parts.join(', ')); }); if ((q.unpriced_parts || []).length) { lines.push(''); lines.push('UNPRICED: ' + q.unpriced_parts.join(', ') + ' — import supplier prices in Settings'); } lines.push(''); lines.push('Download: use the quote XLSX export for the customer-facing sheet.'); setOut(lines.join('\n')); } catch (e) { setOut('Quote failed: ' + (e && e.message ? e.message : e)); } } else if (tool === 'estimates') { try { const d = await window.kfxGetEstimates(pid); const lines = ['Wire lengths (estimated, mm):']; (d.lengths || []).forEach(function (l) { lines.push(' #' + l.id + ': ' + l.length_mm + ' mm'); }); lines.push(''); lines.push('Bundles (estimated OD):'); (d.bundles || []).forEach(function (b) { lines.push(' ' + b.group + ': ' + b.wire_count + ' wires, ~' + b.bundle_od_mm + ' mm'); }); if (d.cost) { lines.push(''); lines.push('Labour (' + d.cost.labour.total_minutes + ' min @ ' + d.cost.labour_rate + '/hr = ' + d.cost.labour_cost + '):'); (d.cost.labour.breakdown || []).forEach(function (i) { lines.push(' ' + i.op + ': ' + i.minutes + ' min'); }); lines.push('Material: wire ' + d.cost.material.wire_cost + ' + consumables ' + d.cost.material.consumable_cost + ' + connectors ' + d.cost.material.connector_cost + ' = ' + d.cost.material.total); if ((d.cost.material.unpriced_parts || []).length) lines.push(' Unpriced: ' + d.cost.material.unpriced_parts.join(', ')); lines.push('Overhead (' + d.cost.overhead_pct + '%): ' + d.cost.overhead_cost); lines.push('TOTAL: ' + d.cost.total); } setOut(lines.join('\n')); } catch (e) { setOut('Estimate failed: ' + (e && e.message ? e.message : e)); } } setBusy(false); } return (

AI tools

{TOOLS.map(function (t) { return ( ); })}
{tool === 'continuity' && ( )} {tool === 'change' && ( )} {tool === 'standards' && (