From edb089c8f53b1895ce86df482b65de6af3edd20f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 01:19:12 +0000 Subject: [PATCH 1/5] Initial plan From c728d4934151bdb4d071bc9f4b0fcf51e6496c27 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 01:22:13 +0000 Subject: [PATCH 2/5] Add iterative chart functionality by passing conversation history to LLM Co-authored-by: evcatalyst <8740078+evcatalyst@users.noreply.github.com> --- chartspec/llmRouter.js | 21 +++++++++++++++++++-- chartspec/main.js | 3 ++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/chartspec/llmRouter.js b/chartspec/llmRouter.js index ad12cde..6e1887b 100644 --- a/chartspec/llmRouter.js +++ b/chartspec/llmRouter.js @@ -29,6 +29,8 @@ IMPORTANT: 4. Choose appropriate chart types (scatter, bar, line, pie, histogram, box, heatmap, table) 5. Apply filters, groupBy, and aggregations when appropriate 6. For groupBy, specify columns array and aggregations object with format: { columnName: { func: 'sum|mean|count|min|max' } } +7. When user asks to modify or update an existing chart, review the previous ChartSpec in the conversation and apply only the requested changes while preserving other settings +8. For iterative requests (e.g., "change the axis", "update colors"), build upon the previous specification Example response: { @@ -145,16 +147,31 @@ async function callLLM(provider, apiKey, messages) { * @param {Array} columns - Available columns * @param {Array} sampleRows - Sample rows * @param {Object} currentSpec - Current ChartSpec (optional) + * @param {Array} chatHistory - Previous conversation messages (optional) * @returns {Promise} New ChartSpec object */ -export async function getUpdatedChartSpec(provider, apiKey, userMessage, columns, sampleRows, currentSpec = null) { +export async function getUpdatedChartSpec(provider, apiKey, userMessage, columns, sampleRows, currentSpec = null, chatHistory = []) { const systemPrompt = buildSystemPrompt(columns, sampleRows); const messages = [ { role: 'system', content: systemPrompt } ]; - if (currentSpec) { + // Include conversation history for context + if (chatHistory && chatHistory.length > 0) { + chatHistory.forEach(msg => { + if (msg.role === 'user') { + messages.push({ role: 'user', content: msg.content }); + } else if (msg.role === 'assistant') { + // Convert spec object to JSON string for assistant messages + const content = typeof msg.content === 'object' + ? JSON.stringify(msg.content) + : msg.content; + messages.push({ role: 'assistant', content }); + } + }); + } else if (currentSpec) { + // Fallback to old behavior if no chat history provided messages.push({ role: 'assistant', content: `Current spec: ${JSON.stringify(currentSpec)}` diff --git a/chartspec/main.js b/chartspec/main.js index 9cc6bf3..1be386a 100644 --- a/chartspec/main.js +++ b/chartspec/main.js @@ -576,7 +576,8 @@ async function handleSendMessage() { userMessage, columns, sampleRows, - state.currentSpec + state.currentSpec, + state.chatHistory ); // Update chat with spec From a5235ac30c76d905e92839efafe61048ff7f9704 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 01:26:01 +0000 Subject: [PATCH 3/5] Address code review feedback: improve edge case handling Co-authored-by: evcatalyst <8740078+evcatalyst@users.noreply.github.com> --- chartspec/llmRouter.js | 5 ++++- chartspec/main.js | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/chartspec/llmRouter.js b/chartspec/llmRouter.js index 6e1887b..3e608ca 100644 --- a/chartspec/llmRouter.js +++ b/chartspec/llmRouter.js @@ -164,10 +164,13 @@ export async function getUpdatedChartSpec(provider, apiKey, userMessage, columns messages.push({ role: 'user', content: msg.content }); } else if (msg.role === 'assistant') { // Convert spec object to JSON string for assistant messages - const content = typeof msg.content === 'object' + const content = (msg.content != null && typeof msg.content === 'object' && !Array.isArray(msg.content)) ? JSON.stringify(msg.content) : msg.content; messages.push({ role: 'assistant', content }); + } else { + // Log unexpected message types for debugging + console.warn(`Unexpected message role in chat history: ${msg.role}`); } }); } else if (currentSpec) { diff --git a/chartspec/main.js b/chartspec/main.js index 1be386a..2fb3104 100644 --- a/chartspec/main.js +++ b/chartspec/main.js @@ -583,7 +583,9 @@ async function handleSendMessage() { // Update chat with spec updateChatMessage(loadingId, JSON.stringify(spec, null, 2)); - // Store spec + // Store spec and update chat history + // Note: We update history here (after successful LLM response) even if rendering fails, + // so the user can continue to iterate on the spec state.currentSpec = spec; state.chatHistory.push({ role: 'user', content: userMessage }); state.chatHistory.push({ role: 'assistant', content: spec }); From 0267bea49e6ecdf56f9adeedf04dad3c179f9aa8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 01:29:13 +0000 Subject: [PATCH 4/5] Add robust error handling for circular references and improve debug logging Co-authored-by: evcatalyst <8740078+evcatalyst@users.noreply.github.com> --- chartspec/llmRouter.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/chartspec/llmRouter.js b/chartspec/llmRouter.js index 3e608ca..76b5465 100644 --- a/chartspec/llmRouter.js +++ b/chartspec/llmRouter.js @@ -159,18 +159,25 @@ export async function getUpdatedChartSpec(provider, apiKey, userMessage, columns // Include conversation history for context if (chatHistory && chatHistory.length > 0) { - chatHistory.forEach(msg => { + chatHistory.forEach((msg, index) => { if (msg.role === 'user') { messages.push({ role: 'user', content: msg.content }); } else if (msg.role === 'assistant') { // Convert spec object to JSON string for assistant messages - const content = (msg.content != null && typeof msg.content === 'object' && !Array.isArray(msg.content)) - ? JSON.stringify(msg.content) - : msg.content; + let content = msg.content; + if (msg.content != null && typeof msg.content === 'object' && !Array.isArray(msg.content)) { + try { + content = JSON.stringify(msg.content); + } catch (e) { + // Handle circular references or non-serializable values + console.error(`Failed to stringify assistant message at index ${index}:`, e.message); + content = '[Invalid JSON object]'; + } + } messages.push({ role: 'assistant', content }); } else { // Log unexpected message types for debugging - console.warn(`Unexpected message role in chat history: ${msg.role}`); + console.warn(`Unexpected message role at index ${index}:`, msg.role, 'Full message:', msg); } }); } else if (currentSpec) { From c988d03d8353b9a199ac31114f6e5ecc57b5c275 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 01:31:42 +0000 Subject: [PATCH 5/5] Refine null checks, error messages, and comment formatting Co-authored-by: evcatalyst <8740078+evcatalyst@users.noreply.github.com> --- chartspec/llmRouter.js | 4 ++-- chartspec/main.js | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/chartspec/llmRouter.js b/chartspec/llmRouter.js index 76b5465..b8852f6 100644 --- a/chartspec/llmRouter.js +++ b/chartspec/llmRouter.js @@ -165,13 +165,13 @@ export async function getUpdatedChartSpec(provider, apiKey, userMessage, columns } else if (msg.role === 'assistant') { // Convert spec object to JSON string for assistant messages let content = msg.content; - if (msg.content != null && typeof msg.content === 'object' && !Array.isArray(msg.content)) { + if (msg.content !== null && msg.content !== undefined && typeof msg.content === 'object' && !Array.isArray(msg.content)) { try { content = JSON.stringify(msg.content); } catch (e) { // Handle circular references or non-serializable values console.error(`Failed to stringify assistant message at index ${index}:`, e.message); - content = '[Invalid JSON object]'; + content = `[Serialization Error: ${e.message}]`; } } messages.push({ role: 'assistant', content }); diff --git a/chartspec/main.js b/chartspec/main.js index 2fb3104..c8b706a 100644 --- a/chartspec/main.js +++ b/chartspec/main.js @@ -583,9 +583,11 @@ async function handleSendMessage() { // Update chat with spec updateChatMessage(loadingId, JSON.stringify(spec, null, 2)); - // Store spec and update chat history - // Note: We update history here (after successful LLM response) even if rendering fails, - // so the user can continue to iterate on the spec + /** + * Store spec and update chat history + * Note: We update history here (after successful LLM response) even if rendering fails, + * so the user can continue to iterate on the spec + */ state.currentSpec = spec; state.chatHistory.push({ role: 'user', content: userMessage }); state.chatHistory.push({ role: 'assistant', content: spec });