feat: Phase 2 - LLM Integration for Canvas
- Add canvas.ts MCP tool with validate_canvas_intent, execute_canvas_intent, interpret_canvas_intent - Add useCanvasChat.ts bridge hook connecting canvas to chat system - Update context_builder.py with canvas tool instructions - Add ExecuteDialog for study name input - Add ChatPanel for canvas-integrated Claude responses - Connect AtomizerCanvas to Claude via useCanvasChat Canvas workflow now: 1. Build graph visually 2. Click Validate/Analyze/Execute 3. Claude processes intent via MCP tools 4. Response shown in integrated chat panel Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
184
atomizer-dashboard/frontend/src/hooks/useCanvasChat.ts
Normal file
184
atomizer-dashboard/frontend/src/hooks/useCanvasChat.ts
Normal file
@@ -0,0 +1,184 @@
|
||||
/**
|
||||
* Canvas-Chat Bridge Hook
|
||||
*
|
||||
* Bridges the Canvas UI with the Chat system, allowing canvas intents
|
||||
* to be sent to Claude for intelligent execution.
|
||||
*/
|
||||
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useChat, ChatMode } from './useChat';
|
||||
import { OptimizationIntent, formatIntentForChat } from '../lib/canvas/intent';
|
||||
|
||||
interface UseCanvasChatOptions {
|
||||
mode?: ChatMode;
|
||||
onError?: (error: string) => void;
|
||||
}
|
||||
|
||||
interface CanvasChatState {
|
||||
isExecuting: boolean;
|
||||
lastIntent: OptimizationIntent | null;
|
||||
executionResult: ExecutionResult | null;
|
||||
}
|
||||
|
||||
interface ExecutionResult {
|
||||
success: boolean;
|
||||
action: string;
|
||||
studyName?: string;
|
||||
path?: string;
|
||||
error?: string;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export function useCanvasChat({
|
||||
mode = 'user',
|
||||
onError,
|
||||
}: UseCanvasChatOptions = {}) {
|
||||
const chat = useChat({ mode, onError });
|
||||
|
||||
const [state, setState] = useState<CanvasChatState>({
|
||||
isExecuting: false,
|
||||
lastIntent: null,
|
||||
executionResult: null,
|
||||
});
|
||||
|
||||
/**
|
||||
* Submit an intent for validation only (no execution)
|
||||
*/
|
||||
const validateIntent = useCallback(
|
||||
async (intent: OptimizationIntent): Promise<void> => {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
isExecuting: true,
|
||||
lastIntent: intent,
|
||||
executionResult: null,
|
||||
}));
|
||||
|
||||
// Format intent for chat and ask Claude to validate
|
||||
const message = `Please validate this canvas optimization intent:
|
||||
|
||||
${formatIntentForChat(intent)}
|
||||
|
||||
Use the validate_canvas_intent tool to check for errors and provide feedback.`;
|
||||
|
||||
await chat.sendMessage(message);
|
||||
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
isExecuting: false,
|
||||
}));
|
||||
},
|
||||
[chat]
|
||||
);
|
||||
|
||||
/**
|
||||
* Execute an intent (create study and optionally run)
|
||||
*/
|
||||
const executeIntent = useCallback(
|
||||
async (
|
||||
intent: OptimizationIntent,
|
||||
studyName: string,
|
||||
autoRun: boolean = false
|
||||
): Promise<void> => {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
isExecuting: true,
|
||||
lastIntent: intent,
|
||||
executionResult: null,
|
||||
}));
|
||||
|
||||
// Format intent for chat and ask Claude to execute
|
||||
const message = `Please execute this canvas optimization intent to create study "${studyName}"${autoRun ? ' and start the optimization' : ''}:
|
||||
|
||||
${formatIntentForChat(intent)}
|
||||
|
||||
Use the execute_canvas_intent tool with:
|
||||
- study_name: "${studyName}"
|
||||
- auto_run: ${autoRun}
|
||||
|
||||
After execution, provide a summary of what was created.`;
|
||||
|
||||
await chat.sendMessage(message);
|
||||
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
isExecuting: false,
|
||||
}));
|
||||
},
|
||||
[chat]
|
||||
);
|
||||
|
||||
/**
|
||||
* Get recommendations for an intent without executing
|
||||
*/
|
||||
const analyzeIntent = useCallback(
|
||||
async (intent: OptimizationIntent): Promise<void> => {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
isExecuting: true,
|
||||
lastIntent: intent,
|
||||
}));
|
||||
|
||||
const message = `Please analyze this canvas optimization intent and provide recommendations:
|
||||
|
||||
${formatIntentForChat(intent)}
|
||||
|
||||
Use the interpret_canvas_intent tool to:
|
||||
1. Analyze the problem characteristics
|
||||
2. Suggest the best optimization method
|
||||
3. Recommend trial budget
|
||||
4. Identify any potential issues
|
||||
|
||||
Provide your recommendations in a clear, actionable format.`;
|
||||
|
||||
await chat.sendMessage(message);
|
||||
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
isExecuting: false,
|
||||
}));
|
||||
},
|
||||
[chat]
|
||||
);
|
||||
|
||||
/**
|
||||
* Send a free-form message about the current canvas state
|
||||
*/
|
||||
const askAboutCanvas = useCallback(
|
||||
async (intent: OptimizationIntent, question: string): Promise<void> => {
|
||||
const message = `Given this canvas optimization intent:
|
||||
|
||||
${formatIntentForChat(intent)}
|
||||
|
||||
${question}`;
|
||||
|
||||
await chat.sendMessage(message);
|
||||
},
|
||||
[chat]
|
||||
);
|
||||
|
||||
return {
|
||||
// Chat state
|
||||
messages: chat.messages,
|
||||
isThinking: chat.isThinking || state.isExecuting,
|
||||
isConnected: chat.isConnected,
|
||||
error: chat.error,
|
||||
sessionId: chat.sessionId,
|
||||
mode: chat.mode,
|
||||
|
||||
// Canvas-specific state
|
||||
isExecuting: state.isExecuting,
|
||||
lastIntent: state.lastIntent,
|
||||
executionResult: state.executionResult,
|
||||
|
||||
// Actions
|
||||
validateIntent,
|
||||
executeIntent,
|
||||
analyzeIntent,
|
||||
askAboutCanvas,
|
||||
|
||||
// Base chat actions
|
||||
sendMessage: chat.sendMessage,
|
||||
clearMessages: chat.clearMessages,
|
||||
switchMode: chat.switchMode,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user