circuit-bricks
Version:
A modular, Lego-style SVG circuit component system for React (ALPHA - Not for production use)
1 lines • 95.1 kB
Source Map (JSON)
{"version":3,"file":"llm-mlbSdAKd.mjs","names":["circuit: CircuitState","issues: ValidationIssue[]","schema: ComponentSchema","category: string","componentId: string","query: string","results: ComponentSearchResult[]","matchedFields: string[]","componentsByCategory: Record<string, ComponentInfo[]>","circuit: CircuitState","components: ComponentInstance[]","suggestions: ConnectionSuggestion[]","description: string","wires: Wire[]","requiredComponents: ComponentRequirement[]","components: ComponentRequirement[]","componentPositions: Record<string, { x: number; y: number }>","missingComponents: ComponentRequirement[]","generatedSchemas: ComponentSchema[]","schema: ComponentSchema","requirement: ComponentRequirement","props: Record<string, any>","circuitType: string","capacitor","resistor","circuit: CircuitState","errors: string[]","warnings: string[]","suggestions: string[]","component: ComponentInstance","wire: Wire","components: ComponentInstance[]"],"sources":["../../src/utils/circuitValidation.ts","../../src/llm/componentDiscovery.ts","../../src/llm/circuitGeneration.ts","../../src/llm/validation.ts","../../src/llm/index.ts"],"sourcesContent":["/**\n * Circuit validation utilities\n *\n * Functions to validate circuit connections and integrity.\n */\n\nimport { CircuitState, ComponentInstance, Wire } from '../schemas/componentSchema';\nimport { getComponentSchema } from '../registry';\nimport { validateCircuitState } from './zodValidation';\nimport { ValidationIssue } from '../schemas/componentSchema';\n\n/**\n * Validate a circuit for common issues\n *\n * @param circuit - The circuit state to validate\n * @returns Array of validation issues\n */\nexport function validateCircuit(circuit: CircuitState): ValidationIssue[] {\n // First validate the circuit structure using ZOD\n const validationResult = validateCircuitState(circuit);\n\n if (!validationResult.success) {\n return [{\n type: 'error',\n message: `Invalid circuit structure: ${validationResult.error}`\n }];\n }\n\n const issues: ValidationIssue[] = [];\n\n // Check for missing components in wire connections\n issues.push(...validateWireConnections(circuit));\n\n // Check for floating inputs/outputs\n issues.push(...validateFloatingPorts(circuit));\n\n // Check for short circuits\n issues.push(...validateShortCircuits(circuit));\n\n return issues;\n}\n\n/**\n * Validate wire connections to ensure they reference valid components\n */\nfunction validateWireConnections(circuit: CircuitState): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n const componentIds = new Set(circuit.components.map(c => c.id));\n\n for (const wire of circuit.wires) {\n // Check source component exists\n if (!componentIds.has(wire.from.componentId)) {\n issues.push({\n type: 'error',\n message: `Wire connected to non-existent component ID: ${wire.from.componentId}`,\n wireId: wire.id\n });\n }\n\n // Check destination component exists\n if (!componentIds.has(wire.to.componentId)) {\n issues.push({\n type: 'error',\n message: `Wire connected to non-existent component ID: ${wire.to.componentId}`,\n wireId: wire.id\n });\n }\n\n // Validate port IDs\n const sourceComponent = circuit.components.find(c => c.id === wire.from.componentId);\n const destComponent = circuit.components.find(c => c.id === wire.to.componentId);\n\n if (sourceComponent) {\n const schema = getComponentSchema(sourceComponent.type);\n if (schema && !schema.ports.some(p => p.id === wire.from.portId)) {\n issues.push({\n type: 'error',\n message: `Wire connected to non-existent port: ${wire.from.portId} on component ${sourceComponent.type}`,\n wireId: wire.id\n });\n }\n }\n\n if (destComponent) {\n const schema = getComponentSchema(destComponent.type);\n if (schema && !schema.ports.some(p => p.id === wire.to.portId)) {\n issues.push({\n type: 'error',\n message: `Wire connected to non-existent port: ${wire.to.portId} on component ${destComponent.type}`,\n wireId: wire.id\n });\n }\n }\n }\n\n return issues;\n}\n\n/**\n * Check for floating input/output ports that should be connected\n */\nfunction validateFloatingPorts(circuit: CircuitState): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n const connectedPorts = new Map<string, Set<string>>();\n\n // Build a map of all connected ports\n for (const wire of circuit.wires) {\n if (!connectedPorts.has(wire.from.componentId)) {\n connectedPorts.set(wire.from.componentId, new Set());\n }\n if (!connectedPorts.has(wire.to.componentId)) {\n connectedPorts.set(wire.to.componentId, new Set());\n }\n\n connectedPorts.get(wire.from.componentId)!.add(wire.from.portId);\n connectedPorts.get(wire.to.componentId)!.add(wire.to.portId);\n }\n\n // Check each component for floating ports\n for (const component of circuit.components) {\n const schema = getComponentSchema(component.type);\n if (!schema) continue;\n\n const componentConnectedPorts = connectedPorts.get(component.id) || new Set();\n\n for (const port of schema.ports) {\n if (port.type === 'input' && !componentConnectedPorts.has(port.id)) {\n issues.push({\n type: 'warning',\n message: `Floating input port: ${port.id} on ${schema.name} (${component.id})`,\n componentId: component.id\n });\n }\n\n if (port.type === 'output' && !componentConnectedPorts.has(port.id)) {\n issues.push({\n type: 'warning',\n message: `Floating output port: ${port.id} on ${schema.name} (${component.id})`,\n componentId: component.id\n });\n }\n }\n }\n\n return issues;\n}\n\n/**\n * Check for short circuits (multiple outputs connected together)\n */\nfunction validateShortCircuits(circuit: CircuitState): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n const connectionGraph = new Map<string, Set<string>>();\n\n // Build a connection graph\n for (const wire of circuit.wires) {\n const fromKey = `${wire.from.componentId}-${wire.from.portId}`;\n const toKey = `${wire.to.componentId}-${wire.to.portId}`;\n\n if (!connectionGraph.has(fromKey)) {\n connectionGraph.set(fromKey, new Set());\n }\n if (!connectionGraph.has(toKey)) {\n connectionGraph.set(toKey, new Set());\n }\n\n connectionGraph.get(fromKey)!.add(toKey);\n connectionGraph.get(toKey)!.add(fromKey);\n }\n\n // Create a map of port types\n const portTypes = new Map<string, string>();\n for (const component of circuit.components) {\n const schema = getComponentSchema(component.type);\n if (!schema) continue;\n\n for (const port of schema.ports) {\n portTypes.set(`${component.id}-${port.id}`, port.type);\n }\n }\n\n // Find connected output ports\n const visited = new Set<string>();\n const connectedComponents = [];\n\n // For each port\n for (const [port, connections] of connectionGraph.entries()) {\n if (visited.has(port)) continue;\n\n // Do a BFS to find all connected ports\n const connectedPorts = new Set<string>();\n const queue = [port];\n visited.add(port);\n\n while (queue.length > 0) {\n const currentPort = queue.shift()!;\n connectedPorts.add(currentPort);\n\n for (const connectedPort of connectionGraph.get(currentPort) || []) {\n if (!visited.has(connectedPort)) {\n queue.push(connectedPort);\n visited.add(connectedPort);\n }\n }\n }\n\n // Count output ports in this connected component\n const outputPorts = [...connectedPorts].filter(p =>\n portTypes.get(p) === 'output'\n );\n\n if (outputPorts.length > 1) {\n issues.push({\n type: 'error',\n message: `Short circuit detected: ${outputPorts.length} output ports connected together`,\n });\n }\n }\n\n return issues;\n}\n\nexport default validateCircuit;\n","/**\n * Component Discovery API for LLM Integration\n *\n * This module provides functions that allow LLMs to discover and understand\n * what components are available in the circuit-bricks registry.\n */\n\nimport {\n getAllComponents,\n getComponentsByCategory,\n getComponentSchema\n} from '../registry';\nimport { ComponentSchema } from '../schemas/componentSchema';\nimport {\n ComponentInfo,\n LLMRegistryMetadata,\n ComponentSearchResult\n} from './types';\n\n/**\n * Convert a ComponentSchema to simplified ComponentInfo for LLM consumption\n */\nfunction schemaToComponentInfo(schema: ComponentSchema): ComponentInfo {\n return {\n id: schema.id,\n name: schema.name,\n category: schema.category,\n description: schema.description,\n ports: schema.ports.map(port => ({\n id: port.id,\n type: port.type,\n label: port.label\n })),\n properties: schema.properties.map(prop => ({\n key: prop.key,\n label: prop.label,\n type: prop.type,\n default: prop.default,\n unit: prop.unit,\n options: prop.options\n }))\n };\n}\n\n/**\n * List all available components in a format optimized for LLM consumption\n *\n * @returns Array of simplified component information\n */\nexport function listAvailableComponents(): ComponentInfo[] {\n const allComponents = getAllComponents();\n return allComponents.map(schemaToComponentInfo);\n}\n\n/**\n * Get components filtered by category\n *\n * @param category - The category to filter by\n * @returns Array of components in the specified category\n */\nexport function listComponentsByCategory(category: string): ComponentInfo[] {\n const components = getComponentsByCategory(category);\n return components.map(schemaToComponentInfo);\n}\n\n/**\n * Get detailed information about a specific component\n *\n * @param componentId - The ID of the component to get details for\n * @returns Detailed component information or null if not found\n */\nexport function getComponentDetails(componentId: string): ComponentInfo | null {\n const schema = getComponentSchema(componentId);\n if (!schema) {\n return null;\n }\n return schemaToComponentInfo(schema);\n}\n\n/**\n * Get all available component categories\n *\n * @returns Array of unique category names\n */\nexport function getAllCategories(): string[] {\n const allComponents = getAllComponents();\n const categories = [...new Set(allComponents.map(c => c.category))];\n return categories.sort();\n}\n\n/**\n * Search components by name, description, or category\n *\n * @param query - Search query string\n * @returns Array of search results with relevance scores\n */\nexport function searchComponents(query: string): ComponentSearchResult[] {\n const allComponents = getAllComponents();\n const searchTerm = query.toLowerCase();\n\n const results: ComponentSearchResult[] = [];\n\n for (const schema of allComponents) {\n const matchedFields: string[] = [];\n let relevanceScore = 0;\n\n // Check name match (highest priority)\n if (schema.name.toLowerCase().includes(searchTerm)) {\n matchedFields.push('name');\n relevanceScore += 10;\n }\n\n // Check ID match\n if (schema.id.toLowerCase().includes(searchTerm)) {\n matchedFields.push('id');\n relevanceScore += 8;\n }\n\n // Check category match\n if (schema.category.toLowerCase().includes(searchTerm)) {\n matchedFields.push('category');\n relevanceScore += 5;\n }\n\n // Check description match\n if (schema.description.toLowerCase().includes(searchTerm)) {\n matchedFields.push('description');\n relevanceScore += 3;\n }\n\n // Check property names\n for (const prop of schema.properties) {\n if (prop.label.toLowerCase().includes(searchTerm) ||\n prop.key.toLowerCase().includes(searchTerm)) {\n matchedFields.push('properties');\n relevanceScore += 1;\n break;\n }\n }\n\n if (relevanceScore > 0) {\n results.push({\n component: schemaToComponentInfo(schema),\n relevanceScore,\n matchedFields\n });\n }\n }\n\n // Sort by relevance score (highest first)\n return results.sort((a, b) => b.relevanceScore - a.relevanceScore);\n}\n\n/**\n * Get registry metadata optimized for LLM consumption\n *\n * @returns Comprehensive registry metadata\n */\nexport function getRegistryMetadata(): LLMRegistryMetadata {\n const allComponents = getAllComponents();\n const categories = getAllCategories();\n\n const componentsByCategory: Record<string, ComponentInfo[]> = {};\n\n for (const category of categories) {\n componentsByCategory[category] = listComponentsByCategory(category);\n }\n\n return {\n totalComponents: allComponents.length,\n categories,\n componentsByCategory,\n lastUpdated: new Date().toISOString()\n };\n}\n\n/**\n * Get a human-readable summary of the component registry\n *\n * @returns String summary of all available components\n */\nexport function getRegistrySummary(): string {\n const metadata = getRegistryMetadata();\n\n let summary = `# Circuit-Bricks Component Registry\\n\\n`;\n summary += `Total Components: ${metadata.totalComponents}\\n`;\n summary += `Categories: ${metadata.categories.length}\\n\\n`;\n\n for (const category of metadata.categories) {\n const components = metadata.componentsByCategory[category];\n summary += `## ${category.charAt(0).toUpperCase() + category.slice(1)} (${components.length} components)\\n\\n`;\n\n for (const component of components) {\n summary += `### ${component.name} (${component.id})\\n`;\n summary += `${component.description}\\n\\n`;\n summary += `**Ports:** ${component.ports.map(p => `${p.id} (${p.type})`).join(', ')}\\n`;\n\n if (component.properties.length > 0) {\n summary += `**Properties:** ${component.properties.map(p => `${p.label} (${p.type})`).join(', ')}\\n`;\n }\n\n summary += '\\n';\n }\n }\n\n summary += `\\n*Last updated: ${metadata.lastUpdated}*`;\n\n return summary;\n}\n\n/**\n * Get a detailed summary of a specific component for LLM consumption\n *\n * @param componentId - The ID of the component to summarize\n * @returns Detailed string summary or null if component not found\n */\nexport function getComponentDetailedSummary(componentId: string): string | null {\n const component = getComponentDetails(componentId);\n if (!component) {\n return null;\n }\n\n let summary = `# ${component.name} (${component.id})\\n\\n`;\n summary += `**Category:** ${component.category}\\n`;\n summary += `**Description:** ${component.description}\\n\\n`;\n\n summary += `## Ports\\n`;\n for (const port of component.ports) {\n summary += `- **${port.id}** (${port.type})`;\n if (port.label) {\n summary += `: ${port.label}`;\n }\n summary += '\\n';\n }\n\n if (component.properties.length > 0) {\n summary += `\\n## Properties\\n`;\n for (const prop of component.properties) {\n summary += `- **${prop.label}** (${prop.key})\\n`;\n summary += ` - Type: ${prop.type}\\n`;\n summary += ` - Default: ${prop.default}\\n`;\n\n if (prop.unit) {\n summary += ` - Unit: ${prop.unit}\\n`;\n }\n\n if (prop.options) {\n summary += ` - Options: ${prop.options.map(o => `${o.value} (${o.label})`).join(', ')}\\n`;\n }\n\n summary += '\\n';\n }\n }\n\n return summary;\n}\n","/**\n * Circuit Generation Helpers for LLM Integration\n *\n * This module provides functions to help LLMs generate and understand circuits.\n */\n\nimport { ComponentInstance, Wire, CircuitState, ComponentSchema } from '../schemas/componentSchema';\nimport { getComponentSchema, registerComponent } from '../registry';\nimport {\n CircuitDescription,\n CircuitTemplate,\n ConnectionSuggestion,\n ComponentRequirement,\n CircuitAnalysisResult\n} from './types';\n\n/**\n * Generate a human-readable description of a circuit\n *\n * @param circuit - The circuit state to describe\n * @returns Detailed circuit description\n */\nexport function describeCircuit(circuit: CircuitState): CircuitDescription {\n const components = circuit.components.map(comp => {\n const schema = getComponentSchema(comp.type);\n return {\n id: comp.id,\n type: comp.type,\n name: schema?.name || comp.type,\n position: comp.position,\n properties: comp.props\n };\n });\n\n const connections = circuit.wires.map(wire => {\n const fromComp = circuit.components.find(c => c.id === wire.from.componentId);\n const toComp = circuit.components.find(c => c.id === wire.to.componentId);\n const fromSchema = fromComp ? getComponentSchema(fromComp.type) : null;\n const toSchema = toComp ? getComponentSchema(toComp.type) : null;\n\n return {\n from: {\n component: fromSchema?.name || wire.from.componentId,\n port: wire.from.portId\n },\n to: {\n component: toSchema?.name || wire.to.componentId,\n port: wire.to.portId\n },\n description: `${fromSchema?.name || 'Component'} ${wire.from.portId} → ${toSchema?.name || 'Component'} ${wire.to.portId}`\n };\n });\n\n // Analyze circuit\n const categories = [...new Set(components.map(c => {\n const schema = getComponentSchema(c.type);\n return schema?.category || 'unknown';\n }))];\n\n const powerSources = components\n .filter(c => {\n const schema = getComponentSchema(c.type);\n return schema?.category === 'power' ||\n schema?.id === 'battery' ||\n schema?.id === 'voltage-source';\n })\n .map(c => c.name);\n\n const hasGround = components.some(c => {\n const schema = getComponentSchema(c.type);\n return schema?.id === 'ground';\n });\n\n // Generate summary\n let summary = `This circuit contains ${components.length} components and ${connections.length} connections. `;\n\n if (powerSources.length > 0) {\n summary += `Power is provided by ${powerSources.join(', ')}. `;\n }\n\n if (hasGround) {\n summary += `The circuit includes a ground connection. `;\n }\n\n summary += `Components span ${categories.length} categories: ${categories.join(', ')}.`;\n\n return {\n summary,\n components,\n connections,\n analysis: {\n totalComponents: components.length,\n totalConnections: connections.length,\n categories,\n powerSources,\n hasGround\n }\n };\n}\n\n/**\n * Suggest valid connections between components in a circuit\n *\n * @param components - Array of component instances\n * @returns Array of connection suggestions\n */\nexport function suggestConnections(components: ComponentInstance[]): ConnectionSuggestion[] {\n const suggestions: ConnectionSuggestion[] = [];\n\n // Get component schemas for analysis\n const componentData = components.map(comp => ({\n instance: comp,\n schema: getComponentSchema(comp.type)\n })).filter(data => data.schema !== undefined);\n\n // Find power sources and ground\n const powerSources = componentData.filter(data =>\n data.schema!.category === 'power' ||\n data.schema!.id === 'battery' ||\n data.schema!.id === 'voltage-source'\n );\n\n const grounds = componentData.filter(data => data.schema!.id === 'ground');\n\n // Suggest power connections\n for (const powerSource of powerSources) {\n const positivePort = powerSource.schema!.ports.find(p =>\n p.id === 'positive' || p.type === 'output'\n );\n\n if (positivePort) {\n // Suggest connecting power to input ports of other components\n for (const comp of componentData) {\n if (comp.instance.id === powerSource.instance.id) continue;\n\n const inputPorts = comp.schema!.ports.filter(p => p.type === 'input');\n for (const inputPort of inputPorts) {\n suggestions.push({\n from: {\n componentId: powerSource.instance.id,\n portId: positivePort.id\n },\n to: {\n componentId: comp.instance.id,\n portId: inputPort.id\n },\n reason: `Connect power source to ${comp.schema!.name} input`,\n confidence: 0.8\n });\n }\n }\n }\n }\n\n // Suggest ground connections\n if (grounds.length > 0) {\n const ground = grounds[0];\n const groundPort = ground.schema!.ports.find(p => p.id === 'terminal');\n\n if (groundPort) {\n // Suggest connecting negative terminals to ground\n for (const powerSource of powerSources) {\n const negativePort = powerSource.schema!.ports.find(p =>\n p.id === 'negative'\n );\n\n if (negativePort) {\n suggestions.push({\n from: {\n componentId: powerSource.instance.id,\n portId: negativePort.id\n },\n to: {\n componentId: ground.instance.id,\n portId: groundPort.id\n },\n reason: 'Connect power source negative to ground',\n confidence: 0.9\n });\n }\n }\n\n // Suggest connecting output ports to ground\n for (const comp of componentData) {\n if (comp.instance.id === ground.instance.id) continue;\n\n const outputPorts = comp.schema!.ports.filter(p =>\n p.type === 'output' || p.id === 'cathode' || p.id === 'emitter'\n );\n\n for (const outputPort of outputPorts) {\n suggestions.push({\n from: {\n componentId: comp.instance.id,\n portId: outputPort.id\n },\n to: {\n componentId: ground.instance.id,\n portId: groundPort.id\n },\n reason: `Connect ${comp.schema!.name} output to ground`,\n confidence: 0.7\n });\n }\n }\n }\n }\n\n // Sort by confidence\n return suggestions.sort((a, b) => b.confidence - a.confidence);\n}\n\n/**\n * Generate a basic circuit template from a description\n *\n * @param description - Text description of the desired circuit\n * @returns Basic circuit template\n */\nexport function generateCircuitTemplate(description: string): CircuitTemplate {\n const lowerDesc = description.toLowerCase();\n\n // Simple pattern matching for common circuits\n let templateId = 'basic';\n let templateName = 'Basic Circuit';\n let components: ComponentInstance[] = [];\n let wires: Wire[] = [];\n\n // LED circuit pattern\n if (lowerDesc.includes('led') || lowerDesc.includes('light')) {\n templateId = 'led-circuit';\n templateName = 'LED Circuit';\n\n components = [\n {\n id: 'battery1',\n type: 'battery',\n position: { x: 100, y: 150 },\n props: { voltage: 9 }\n },\n {\n id: 'resistor1',\n type: 'resistor',\n position: { x: 250, y: 150 },\n props: { resistance: 330, tolerance: 5 }\n },\n {\n id: 'led1',\n type: 'led',\n position: { x: 400, y: 150 },\n props: { color: '#ff0000', forwardVoltage: 1.8 }\n },\n {\n id: 'ground1',\n type: 'ground',\n position: { x: 250, y: 250 },\n props: {}\n }\n ];\n\n wires = [\n {\n id: 'wire1',\n from: { componentId: 'battery1', portId: 'positive' },\n to: { componentId: 'resistor1', portId: 'left' }\n },\n {\n id: 'wire2',\n from: { componentId: 'resistor1', portId: 'right' },\n to: { componentId: 'led1', portId: 'anode' }\n },\n {\n id: 'wire3',\n from: { componentId: 'led1', portId: 'cathode' },\n to: { componentId: 'ground1', portId: 'terminal' }\n },\n {\n id: 'wire4',\n from: { componentId: 'battery1', portId: 'negative' },\n to: { componentId: 'ground1', portId: 'terminal' }\n }\n ];\n }\n // Voltage divider pattern\n else if (lowerDesc.includes('voltage divider') || lowerDesc.includes('divider')) {\n templateId = 'voltage-divider';\n templateName = 'Voltage Divider';\n\n components = [\n {\n id: 'battery1',\n type: 'battery',\n position: { x: 100, y: 100 },\n props: { voltage: 9 }\n },\n {\n id: 'resistor1',\n type: 'resistor',\n position: { x: 250, y: 100 },\n props: { resistance: 1000, tolerance: 5 }\n },\n {\n id: 'resistor2',\n type: 'resistor',\n position: { x: 250, y: 200 },\n props: { resistance: 1000, tolerance: 5 }\n },\n {\n id: 'ground1',\n type: 'ground',\n position: { x: 250, y: 300 },\n props: {}\n }\n ];\n\n wires = [\n {\n id: 'wire1',\n from: { componentId: 'battery1', portId: 'positive' },\n to: { componentId: 'resistor1', portId: 'left' }\n },\n {\n id: 'wire2',\n from: { componentId: 'resistor1', portId: 'right' },\n to: { componentId: 'resistor2', portId: 'left' }\n },\n {\n id: 'wire3',\n from: { componentId: 'resistor2', portId: 'right' },\n to: { componentId: 'ground1', portId: 'terminal' }\n },\n {\n id: 'wire4',\n from: { componentId: 'battery1', portId: 'negative' },\n to: { componentId: 'ground1', portId: 'terminal' }\n }\n ];\n }\n\n return {\n id: templateId,\n name: templateName,\n description: `Generated template for: ${description}`,\n category: 'generated',\n components,\n wires\n };\n}\n\n/**\n * Analyze circuit requirements from user description\n *\n * This function identifies what components are needed for a circuit based on\n * the user's natural language description.\n *\n * @param description - Natural language description of the desired circuit\n * @returns Analysis result with required components and availability\n */\nexport function analyzeCircuitRequirements(description: string): CircuitAnalysisResult {\n const lowerDesc = description.toLowerCase();\n\n // Circuit type detection\n let circuitType = 'unknown';\n let circuitDescription = '';\n let requiredComponents: ComponentRequirement[] = [];\n\n // LCR Circuit Pattern\n if (lowerDesc.includes('lcr') || (lowerDesc.includes('inductor') && lowerDesc.includes('capacitor') && lowerDesc.includes('resistor'))) {\n circuitType = 'LCR Circuit';\n circuitDescription = 'A circuit containing an inductor (L), capacitor (C), and resistor (R) - typically used for resonance and filtering applications';\n\n requiredComponents = [\n {\n id: 'inductor',\n name: 'Inductor',\n category: 'passive',\n description: 'A passive component that stores energy in a magnetic field',\n isAvailable: false,\n reason: 'Component not found in registry',\n suggestedProperties: [\n { key: 'inductance', label: 'Inductance', type: 'number', default: 10, unit: 'mH' },\n { key: 'tolerance', label: 'Tolerance', type: 'number', default: 5, unit: '%' }\n ],\n suggestedPorts: [\n { id: 'left', type: 'inout' },\n { id: 'right', type: 'inout' }\n ]\n },\n {\n id: 'capacitor',\n name: 'Capacitor',\n category: 'passive',\n description: 'A passive component that stores electrical energy in an electric field',\n isAvailable: true,\n reason: 'Available in component registry'\n },\n {\n id: 'resistor',\n name: 'Resistor',\n category: 'passive',\n description: 'A passive component that implements electrical resistance',\n isAvailable: true,\n reason: 'Available in component registry'\n },\n {\n id: 'battery',\n name: 'Battery',\n category: 'power',\n description: 'DC voltage source for powering the circuit',\n isAvailable: true,\n reason: 'Available in component registry'\n },\n {\n id: 'ground',\n name: 'Ground',\n category: 'reference',\n description: 'Reference point for the circuit',\n isAvailable: true,\n reason: 'Available in component registry'\n }\n ];\n }\n // RC Circuit Pattern\n else if (lowerDesc.includes('rc') || (lowerDesc.includes('resistor') && lowerDesc.includes('capacitor'))) {\n circuitType = 'RC Circuit';\n circuitDescription = 'A circuit containing a resistor (R) and capacitor (C) - used for timing and filtering applications';\n\n requiredComponents = [\n {\n id: 'resistor',\n name: 'Resistor',\n category: 'passive',\n description: 'A passive component that implements electrical resistance',\n isAvailable: true,\n reason: 'Available in component registry'\n },\n {\n id: 'capacitor',\n name: 'Capacitor',\n category: 'passive',\n description: 'A passive component that stores electrical energy in an electric field',\n isAvailable: true,\n reason: 'Available in component registry'\n },\n {\n id: 'battery',\n name: 'Battery',\n category: 'power',\n description: 'DC voltage source for powering the circuit',\n isAvailable: true,\n reason: 'Available in component registry'\n },\n {\n id: 'ground',\n name: 'Ground',\n category: 'reference',\n description: 'Reference point for the circuit',\n isAvailable: true,\n reason: 'Available in component registry'\n }\n ];\n }\n // LED Circuit Pattern\n else if (lowerDesc.includes('led') || lowerDesc.includes('light')) {\n circuitType = 'LED Circuit';\n circuitDescription = 'A circuit to drive an LED with proper current limiting';\n\n requiredComponents = [\n {\n id: 'led',\n name: 'LED',\n category: 'output',\n description: 'Light-emitting diode',\n isAvailable: true,\n reason: 'Available in component registry'\n },\n {\n id: 'resistor',\n name: 'Current Limiting Resistor',\n category: 'passive',\n description: 'Resistor to limit current through the LED',\n isAvailable: true,\n reason: 'Available in component registry'\n },\n {\n id: 'battery',\n name: 'Battery',\n category: 'power',\n description: 'DC voltage source for powering the circuit',\n isAvailable: true,\n reason: 'Available in component registry'\n },\n {\n id: 'ground',\n name: 'Ground',\n category: 'reference',\n description: 'Reference point for the circuit',\n isAvailable: true,\n reason: 'Available in component registry'\n }\n ];\n }\n // Default case - try to extract component names\n else {\n circuitType = 'Custom Circuit';\n circuitDescription = `Custom circuit based on description: ${description}`;\n\n // Basic component detection\n const componentKeywords = [\n { keyword: 'resistor', id: 'resistor', name: 'Resistor', category: 'passive' },\n { keyword: 'capacitor', id: 'capacitor', name: 'Capacitor', category: 'passive' },\n { keyword: 'inductor', id: 'inductor', name: 'Inductor', category: 'passive' },\n { keyword: 'led', id: 'led', name: 'LED', category: 'output' },\n { keyword: 'diode', id: 'diode', name: 'Diode', category: 'semiconductor' },\n { keyword: 'transistor', id: 'transistor-npn', name: 'Transistor', category: 'semiconductor' },\n { keyword: 'battery', id: 'battery', name: 'Battery', category: 'power' },\n { keyword: 'switch', id: 'switch', name: 'Switch', category: 'control' }\n ];\n\n for (const comp of componentKeywords) {\n if (lowerDesc.includes(comp.keyword)) {\n const schema = getComponentSchema(comp.id);\n requiredComponents.push({\n id: comp.id,\n name: comp.name,\n category: comp.category,\n description: schema?.description || `${comp.name} component`,\n isAvailable: !!schema,\n reason: schema ? 'Available in component registry' : 'Component not found in registry'\n });\n }\n }\n\n // Always add power and ground for complete circuits\n if (requiredComponents.length > 0) {\n const hasPower = requiredComponents.some(c => c.category === 'power');\n const hasGround = requiredComponents.some(c => c.id === 'ground');\n\n if (!hasPower) {\n requiredComponents.push({\n id: 'battery',\n name: 'Battery',\n category: 'power',\n description: 'DC voltage source for powering the circuit',\n isAvailable: true,\n reason: 'Available in component registry'\n });\n }\n\n if (!hasGround) {\n requiredComponents.push({\n id: 'ground',\n name: 'Ground',\n category: 'reference',\n description: 'Reference point for the circuit',\n isAvailable: true,\n reason: 'Available in component registry'\n });\n }\n }\n }\n\n // Check actual availability in registry\n for (const component of requiredComponents) {\n const schema = getComponentSchema(component.id);\n component.isAvailable = !!schema;\n if (schema) {\n component.reason = 'Available in component registry';\n } else {\n component.reason = 'Component not found in registry - will be auto-generated';\n }\n }\n\n // Separate available and missing components\n const availableComponents = requiredComponents.filter(c => c.isAvailable);\n const missingComponents = requiredComponents.filter(c => !c.isAvailable);\n\n // Generate suggested layout\n const suggestedLayout = generateCircuitLayout(requiredComponents);\n\n return {\n circuitType,\n description: circuitDescription,\n requiredComponents,\n missingComponents,\n availableComponents,\n suggestedLayout\n };\n}\n\n/**\n * Generate a suggested layout for circuit components\n *\n * @param components - Array of component requirements\n * @returns Suggested layout with positions\n */\nfunction generateCircuitLayout(components: ComponentRequirement[]): {\n width: number;\n height: number;\n componentPositions: Record<string, { x: number; y: number }>;\n} {\n const componentPositions: Record<string, { x: number; y: number }> = {};\n\n // Simple grid layout\n const gridSpacing = 150;\n const startX = 100;\n const startY = 100;\n\n let currentX = startX;\n let currentY = startY;\n let maxX = startX;\n let maxY = startY;\n\n // Place power sources first (left side)\n const powerComponents = components.filter(c => c.category === 'power');\n for (const comp of powerComponents) {\n componentPositions[comp.id] = { x: currentX, y: currentY };\n currentY += gridSpacing;\n maxY = Math.max(maxY, currentY);\n }\n\n // Place passive components in the middle\n currentX += gridSpacing;\n currentY = startY;\n const passiveComponents = components.filter(c => c.category === 'passive');\n for (const comp of passiveComponents) {\n componentPositions[comp.id] = { x: currentX, y: currentY };\n currentY += gridSpacing;\n maxY = Math.max(maxY, currentY);\n if (currentY > startY + gridSpacing * 2) {\n currentX += gridSpacing;\n currentY = startY;\n }\n }\n\n // Place output components on the right\n currentX += gridSpacing;\n currentY = startY;\n const outputComponents = components.filter(c => c.category === 'output' || c.category === 'semiconductor');\n for (const comp of outputComponents) {\n componentPositions[comp.id] = { x: currentX, y: currentY };\n currentY += gridSpacing;\n maxY = Math.max(maxY, currentY);\n }\n\n // Place ground at the bottom center\n const groundComponent = components.find(c => c.id === 'ground');\n if (groundComponent) {\n componentPositions[groundComponent.id] = {\n x: startX + gridSpacing,\n y: maxY + gridSpacing\n };\n maxY += gridSpacing * 2;\n }\n\n maxX = Math.max(maxX, currentX + 100);\n\n return {\n width: maxX + 100,\n height: maxY + 100,\n componentPositions\n };\n}\n\n/**\n * Auto-generate missing component schemas\n *\n * This function creates component schemas for missing components based on\n * electrical engineering knowledge and existing component patterns.\n *\n * @param missingComponents - Array of missing component requirements\n * @returns Array of generated component schemas\n */\nexport function generateMissingComponents(missingComponents: ComponentRequirement[]): ComponentSchema[] {\n const generatedSchemas: ComponentSchema[] = [];\n\n for (const missing of missingComponents) {\n let schema: ComponentSchema;\n\n switch (missing.id) {\n case 'inductor':\n schema = {\n id: 'inductor',\n name: 'Inductor',\n category: 'passive',\n description: 'A passive component that stores energy in a magnetic field',\n defaultWidth: 80,\n defaultHeight: 30,\n ports: [\n { id: 'left', x: 0, y: 15, type: 'inout' },\n { id: 'right', x: 80, y: 15, type: 'inout' }\n ],\n properties: [\n {\n key: 'inductance',\n label: 'Inductance',\n type: 'number',\n unit: 'mH',\n default: 10,\n min: 0\n },\n {\n key: 'tolerance',\n label: 'Tolerance',\n type: 'number',\n unit: '%',\n default: 5,\n min: 0,\n max: 20\n }\n ],\n svgPath: \"M10,15 h10 C25,5 25,25 35,15 C45,5 45,25 55,15 C65,5 65,25 70,15 h10\"\n };\n break;\n\n case 'transformer':\n schema = {\n id: 'transformer',\n name: 'Transformer',\n category: 'passive',\n description: 'A device that transfers electrical energy between circuits through electromagnetic induction',\n defaultWidth: 100,\n defaultHeight: 80,\n ports: [\n { id: 'primary_left', x: 0, y: 20, type: 'input', label: 'P1' },\n { id: 'primary_right', x: 0, y: 60, type: 'input', label: 'P2' },\n { id: 'secondary_left', x: 100, y: 20, type: 'output', label: 'S1' },\n { id: 'secondary_right', x: 100, y: 60, type: 'output', label: 'S2' }\n ],\n properties: [\n {\n key: 'turns_ratio',\n label: 'Turns Ratio',\n type: 'number',\n default: 1,\n min: 0.1\n },\n {\n key: 'primary_inductance',\n label: 'Primary Inductance',\n type: 'number',\n unit: 'mH',\n default: 100,\n min: 0\n }\n ],\n svgPath: \"M20,20 C30,10 30,30 40,20 C50,10 50,30 60,20 M60,20 C70,10 70,30 80,20 C90,10 90,30 100,20 M20,60 C30,50 30,70 40,60 C50,50 50,70 60,60 M60,60 C70,50 70,70 80,60 C90,50 90,70 100,60\"\n };\n break;\n\n case 'op-amp':\n schema = {\n id: 'op-amp',\n name: 'Operational Amplifier',\n category: 'integrated',\n description: 'A high-gain voltage amplifier with differential inputs',\n defaultWidth: 80,\n defaultHeight: 60,\n ports: [\n { id: 'in_positive', x: 0, y: 20, type: 'input', label: '+' },\n { id: 'in_negative', x: 0, y: 40, type: 'input', label: '-' },\n { id: 'output', x: 80, y: 30, type: 'output', label: 'Out' },\n { id: 'vcc', x: 40, y: 0, type: 'input', label: 'V+' },\n { id: 'vee', x: 40, y: 60, type: 'input', label: 'V-' }\n ],\n properties: [\n {\n key: 'gain',\n label: 'Open Loop Gain',\n type: 'number',\n default: 100000,\n min: 1\n },\n {\n key: 'supply_voltage',\n label: 'Supply Voltage',\n type: 'number',\n unit: 'V',\n default: 15,\n min: 3\n }\n ],\n svgPath: \"M10,10 L10,50 L70,30 Z M40,0 L40,10 M40,50 L40,60\"\n };\n break;\n\n default:\n // Generic component generation based on category\n schema = generateGenericComponent(missing);\n break;\n }\n\n generatedSchemas.push(schema);\n }\n\n return generatedSchemas;\n}\n\n/**\n * Generate a generic component schema based on component requirements\n */\nfunction generateGenericComponent(requirement: ComponentRequirement): ComponentSchema {\n const defaultPorts = requirement.suggestedPorts || [\n { id: 'left', type: 'inout' as const },\n { id: 'right', type: 'inout' as const }\n ];\n\n const defaultProperties = requirement.suggestedProperties || [\n {\n key: 'value',\n label: 'Value',\n type: 'number' as const,\n default: 1\n }\n ];\n\n return {\n id: requirement.id,\n name: requirement.name,\n category: requirement.category,\n description: requirement.description,\n defaultWidth: 60,\n defaultHeight: 30,\n ports: defaultPorts.map((port, index) => ({\n id: port.id,\n x: index === 0 ? 0 : 60,\n y: 15,\n type: port.type,\n label: port.label\n })),\n properties: defaultProperties.map(prop => ({\n key: prop.key,\n label: prop.label,\n type: prop.type as 'number' | 'boolean' | 'select' | 'text' | 'color',\n default: prop.default,\n unit: prop.unit\n })),\n svgPath: \"M10,15 h40 M0,15 h10 M50,15 h10\" // Simple line representation\n };\n}\n\n/**\n * Generate a complete circuit with auto-generated missing components\n *\n * This is the main function that orchestrates the entire circuit generation process:\n * 1. Analyzes requirements from description\n * 2. Identifies missing components\n * 3. Auto-generates missing component schemas\n * 4. Registers them in the registry\n * 5. Creates the complete circuit with proper connections\n * 6. Returns the circuit ready for rendering\n *\n * @param description - Natural language description of the desired circuit\n * @returns Complete circuit template with all components and connections\n */\nexport function generateCompleteCircuit(description: string): CircuitTemplate {\n // Step 1: Analyze what components are needed\n const analysis = analyzeCircuitRequirements(description);\n\n // Step 2: Auto-generate and register missing components\n if (analysis.missingComponents.length > 0) {\n const generatedSchemas = generateMissingComponents(analysis.missingComponents);\n\n // Register the generated components\n for (const schema of generatedSchemas) {\n registerComponent(schema);\n }\n }\n\n // Step 3: Create component instances with proper positioning\n const components: ComponentInstance[] = [];\n const layout = analysis.suggestedLayout;\n\n for (const requirement of analysis.requiredComponents) {\n const position = layout?.componentPositions[requirement.id] || { x: 100, y: 100 };\n const schema = getComponentSchema(requirement.id);\n\n if (schema) {\n // Use default properties from the schema\n const props: Record<string, any> = {};\n for (const prop of schema.properties) {\n props[prop.key] = prop.default;\n }\n\n components.push({\n id: requirement.id + '1', // Add instance number\n type: requirement.id,\n position,\n props\n });\n }\n }\n\n // Step 4: Generate intelligent connections\n const wires = generateIntelligentConnections(components, analysis.circuitType);\n\n return {\n id: analysis.circuitType.toLowerCase().replace(/\\s+/g, '-'),\n name: analysis.circuitType,\n description: analysis.description,\n category: 'auto-generated',\n components,\n wires\n };\n}\n\n/**\n * Generate intelligent wire connections based on circuit type and electrical principles\n */\nfunction generateIntelligentConnections(components: ComponentInstance[], circuitType: string): Wire[] {\n const wires: Wire[] = [];\n let wireCounter = 1;\n\n // Find key components\n const powerSource = components.find(c => c.type === 'battery' || c.type === 'voltage-source');\n const ground = components.find(c => c.type === 'ground');\n const passiveComponents = components.filter(c =>\n c.type === 'resistor' || c.type === 'capacitor' || c.type === 'inductor'\n );\n const activeComponents = components.filter(c =>\n c.type === 'led' || c.type === 'diode' || c.type.includes('transistor')\n );\n\n if (!powerSource || !ground) {\n return wires; // Can't create meaningful connections without power and ground\n }\n\n // Circuit-specific connection patterns\n switch (circuitType) {\n case 'LCR Circuit':\n // Series LCR circuit: Power -> L -> C -> R -> Ground\n if (passiveComponents.length >= 3) {\n const inductor = passiveComponents.find(c => c.type === 'inductor');\n const capacitor = passiveComponents.find(c => c.type === 'capacitor');\n const resistor = passiveComponents.find(c => c.type === 'resistor');\n\n if (inductor && capacitor && resistor) {\n // Power positive to inductor\n wires.push({\n id: `wire${wireCounter++}`,\n from: { componentId: powerSource.id, portId: 'positive' },\n to: { componentId: inductor.id, portId: 'left' }\n });\n\n // Inductor to capacitor\n wires.push({\n id: `wire${wireCounter++}`,\n from: { componentId: inductor.id, portId: 'right' },\n to: { componentId: capacitor.id, portId: 'left' }\n });\n\n // Capacitor to resistor\n wires.push({\n id: `wire${wireCounter++}`,\n from: { componentId: capacitor.id, portId: 'right' },\n to: { componentId: resistor.id, portId: 'left' }\n });\n\n // Resistor to ground\n wires.push({\n id: `wire${wireCounter++}`,\n from: { componentId: resistor.id, portId: 'right' },\n to: { componentId: ground.id, portId: 'terminal' }\n });\n\n // Power negative to ground\n wires.push({\n id: `wire${wireCounter++}`,\n from: { componentId: powerSource.id, portId: 'negative' },\n to: { componentId: ground.id, portId: 'terminal' }\n });\n }\n }\n break;\n\n case 'RC Circuit':\n // Series RC circuit: Power -> R -> C -> Ground\n const resistor = passiveComponents.find(c => c.type === 'resistor');\n const capacitor = passiveComponents.find(c => c.type === 'capacitor');\n\n if (resistor && capacitor) {\n wires.push({\n id: `wire${wireCounter++}`,\n from: { componentId: powerSource.id, portId: 'positive' },\n to: { componentId: resistor.id, portId: 'left' }\n });\n\n wires.push({\n id: `wire${wireCounter++}`,\n from: { componentId: resistor.id, portId: 'right' },\n to: { componentId: capacitor.id, portId: 'left' }\n });\n\n wires.push({\n id: `wire${wireCounter++}`,\n from: { componentId: capacitor.id, portId: 'right' },\n to: { componentId: ground.id, portId: 'terminal' }\n });\n\n wires.push({\n id: `wire${wireCounter++}`,\n from: { componentId: powerSource.id, portId: 'negative' },\n to: { componentId: ground.id, portId: 'terminal' }\n });\n }\n break;\n\n case 'LED Circuit':\n // LED circuit: Power -> Resistor -> LED -> Ground\n const currentLimitingResistor = passiveComponents.find(c => c.type === 'resistor');\n const led = activeComponents.find(c => c.type === 'led');\n\n if (currentLimitingResistor && led) {\n wires.push({\n id: `wire${wireCounter++}`,\n from: { componentId: powerSource.id, portId: 'positive' },\n to: { componentId: currentLimitingResistor.id, portId: 'left' }\n });\n\n wires.push({\n id: `wire${wireCounter++}`,\n from: { componentId: currentLimitingResistor.id, portId: 'right' },\n to: { componentId: led.id, portId: 'anode' }\n });\n\n wires.push({\n id: `wire${wireCounter++}`,\n from: { componentId: led.id, portId: 'cathode' },\n to: { componentId: ground.id, portId: 'terminal' }\n });\n\n wires.push({\n id: `wire${wireCounter++}`,\n from: { componentId: powerSource.id, portId: 'negative' },\n to: { componentId: ground.id, portId: 'terminal' }\n });\n }\n break;\n\n default:\n // Generic series connection for unknown circuits\n if (passiveComponents.length > 0) {\n // Connect power to first component\n wires.push({\n id: `wire${wireCounter++}`,\n from: { componentId: powerSource.id, portId: 'positive' },\n to: { componentId: passiveComponents[0].id, portId: 'left' }\n });\n\n // Chain components together\n for (let i = 0; i < passiveComponents.length - 1; i++) {\n wires.push({\n id: `wire${wireCounter++}`,\n from: { componentId: passiveComponents[i].id, portId: 'right' },\n to: { componentId: passiveComponents[i + 1].id, portId: 'left' }\n });\n }\n\n // Connect last component to ground\n const lastComponent = passiveComponents[passiveComponents.length - 1];\n wire