- 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>
185 lines
4.3 KiB
TypeScript
185 lines
4.3 KiB
TypeScript
/**
|
|
* 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,
|
|
};
|
|
}
|