docs: Comprehensive documentation update for Dashboard V3 and Canvas

## Documentation Updates
- DASHBOARD.md: Updated to V3.0 with Canvas V3 features, file browser, introspection
- DASHBOARD_IMPLEMENTATION_STATUS.md: Marked Canvas V3 features as COMPLETE
- CANVAS.md: New comprehensive guide for Canvas Builder V3 with all features
- CLAUDE.md: Added dashboard quick reference and Canvas V3 features

## Canvas V3 Features Documented
- File Browser: Browse studies directory for model files
- Model Introspection: Auto-discover expressions, solver type, dependencies
- One-Click Add: Add expressions as design variables instantly
- Claude Bug Fixes: WebSocket reconnection, SQL errors resolved
- Health Check: /api/health endpoint for monitoring

## Backend Services
- NX introspection service with expression discovery
- File browser API with type filtering
- Claude session management improvements
- Context builder enhancements

## Frontend Components
- FileBrowser: Modal for file selection with search
- IntrospectionPanel: View discovered model information
- ExpressionSelector: Dropdown for design variable configuration
- Improved chat hooks with reconnection logic

## Plan Documents
- Added RALPH_LOOP_CANVAS_V2/V3 implementation records
- Added ATOMIZER_DASHBOARD_V2_MASTER_PLAN
- Added investigation and sync documentation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-16 20:48:58 -05:00
parent 1c7c7aff05
commit ac5e9b4054
23 changed files with 10860 additions and 773 deletions

View File

@@ -235,7 +235,302 @@ function intentToConfig(intent: CanvasIntent, studyName: string): Record<string,
};
}
// Canvas modification tools - return instructions for the frontend to apply
interface CanvasModification {
action: 'add_node' | 'update_node' | 'remove_node' | 'add_edge' | 'remove_edge';
nodeType?: string;
nodeId?: string;
data?: Record<string, unknown>;
source?: string;
target?: string;
edgeId?: string;
}
export const canvasTools: AtomizerTool[] = [
// Canvas Modification Tools
{
definition: {
name: "canvas_add_node",
description:
"Add a new node to the canvas. Use this when the user asks to add a design variable, extractor, objective, constraint, etc. Returns a modification instruction for the frontend.",
inputSchema: {
type: "object" as const,
properties: {
node_type: {
type: "string",
enum: ["designVar", "extractor", "objective", "constraint", "surrogate"],
description: "Type of node to add",
},
label: {
type: "string",
description: "Display label for the node",
},
// Design variable properties
expression_name: {
type: "string",
description: "For designVar: the NX expression name",
},
min_value: {
type: "number",
description: "For designVar: minimum value",
},
max_value: {
type: "number",
description: "For designVar: maximum value",
},
baseline: {
type: "number",
description: "For designVar: baseline/initial value",
},
unit: {
type: "string",
description: "For designVar: unit (mm, deg, etc.)",
},
// Extractor properties
extractor_id: {
type: "string",
description: "For extractor: extractor ID (E1-E10)",
},
extractor_type: {
type: "string",
description: "For extractor: type (zernike_opd, displacement, mass, etc.)",
},
// Objective properties
direction: {
type: "string",
enum: ["minimize", "maximize"],
description: "For objective: optimization direction",
},
weight: {
type: "number",
description: "For objective: weight in weighted sum",
},
// Constraint properties
operator: {
type: "string",
enum: ["<=", ">=", "<", ">", "=="],
description: "For constraint: comparison operator",
},
value: {
type: "number",
description: "For constraint: threshold value",
},
},
required: ["node_type", "label"],
},
},
handler: async (args) => {
const nodeType = args.node_type as string;
const label = args.label as string;
// Build node data based on type
const data: Record<string, unknown> = {
label,
configured: true,
};
switch (nodeType) {
case "designVar":
data.expressionName = args.expression_name || label;
if (args.min_value !== undefined) data.minValue = args.min_value;
if (args.max_value !== undefined) data.maxValue = args.max_value;
if (args.baseline !== undefined) data.baseline = args.baseline;
if (args.unit) data.unit = args.unit;
data.enabled = true;
break;
case "extractor":
data.extractorId = args.extractor_id || "E5";
data.extractorName = label;
data.extractorType = args.extractor_type;
break;
case "objective":
data.name = label;
data.direction = args.direction || "minimize";
data.weight = args.weight || 1;
break;
case "constraint":
data.name = label;
data.operator = args.operator || "<=";
data.value = args.value || 0;
break;
case "surrogate":
data.enabled = true;
data.modelType = "MLP";
break;
}
const modification: CanvasModification = {
action: "add_node",
nodeType,
data,
};
return {
content: [
{
type: "text",
text: JSON.stringify({
success: true,
modification,
message: `Added ${nodeType} node "${label}" to the canvas.`,
}, null, 2),
},
],
};
},
},
{
definition: {
name: "canvas_update_node",
description:
"Update an existing node's properties on the canvas. Use this when the user asks to change bounds, weights, names, etc.",
inputSchema: {
type: "object" as const,
properties: {
node_id: {
type: "string",
description: "ID of the node to update (or label/name to find it)",
},
find_by: {
type: "string",
enum: ["id", "label", "expression_name"],
description: "How to find the node (default: label)",
},
updates: {
type: "object",
description: "Key-value pairs of properties to update",
},
},
required: ["node_id", "updates"],
},
},
handler: async (args) => {
const nodeId = args.node_id as string;
const findBy = (args.find_by as string) || "label";
const updates = args.updates as Record<string, unknown>;
const modification: CanvasModification = {
action: "update_node",
nodeId,
data: {
findBy,
...updates,
},
};
return {
content: [
{
type: "text",
text: JSON.stringify({
success: true,
modification,
message: `Updated node "${nodeId}" with: ${JSON.stringify(updates)}`,
}, null, 2),
},
],
};
},
},
{
definition: {
name: "canvas_remove_node",
description: "Remove a node from the canvas.",
inputSchema: {
type: "object" as const,
properties: {
node_id: {
type: "string",
description: "ID or label of the node to remove",
},
find_by: {
type: "string",
enum: ["id", "label"],
description: "How to find the node (default: label)",
},
},
required: ["node_id"],
},
},
handler: async (args) => {
const nodeId = args.node_id as string;
const findBy = (args.find_by as string) || "label";
const modification: CanvasModification = {
action: "remove_node",
nodeId,
data: { findBy },
};
return {
content: [
{
type: "text",
text: JSON.stringify({
success: true,
modification,
message: `Removed node "${nodeId}" from the canvas.`,
}, null, 2),
},
],
};
},
},
{
definition: {
name: "canvas_connect_nodes",
description: "Create an edge (connection) between two nodes on the canvas.",
inputSchema: {
type: "object" as const,
properties: {
source: {
type: "string",
description: "Source node (ID or label)",
},
target: {
type: "string",
description: "Target node (ID or label)",
},
find_by: {
type: "string",
enum: ["id", "label"],
description: "How to find nodes (default: label)",
},
},
required: ["source", "target"],
},
},
handler: async (args) => {
const source = args.source as string;
const target = args.target as string;
const findBy = (args.find_by as string) || "label";
const modification: CanvasModification = {
action: "add_edge",
source,
target,
data: { findBy },
};
return {
content: [
{
type: "text",
text: JSON.stringify({
success: true,
modification,
message: `Connected "${source}" to "${target}".`,
}, null, 2),
},
],
};
},
},
// Original Intent Processing Tools
{
definition: {
name: "validate_canvas_intent",