Added logs to track the issues, started doing changes based on the school api project
Some checks failed
Build / build (push) Has been cancelled

This commit is contained in:
Ankitkumar Satapara
2026-04-24 00:44:57 +05:30
parent baa7ae5579
commit 5cf8dd32a2
3 changed files with 87 additions and 5 deletions

View File

@@ -198,7 +198,7 @@ namespace Nodify.Calculator.Execution.Handlers
var bodyNode = loopBodyConnection?.Input?.Operation; var bodyNode = loopBodyConnection?.Input?.Operation;
if (bodyNode != null) if (bodyNode != null)
ctx.Executor.TraverseChainPublic(bodyNode, "end", ctx.Connections, new HashSet<string>(), true); ctx.Executor.ExecuteLinearChain(bodyNode, ctx.Connections);
} }
ctx.Log($"[FOREACH] Loop completed. {array.Count} iterations executed."); ctx.Log($"[FOREACH] Loop completed. {array.Count} iterations executed.");
} }

View File

@@ -56,13 +56,35 @@ namespace Nodify.Calculator.Execution.Resolvers
{ {
// Split's model input is the Square-shaped connector // Split's model input is the Square-shaped connector
var modelInput = node.Input.FirstOrDefault(i => i.Shape == ConnectorShape.Square); var modelInput = node.Input.FirstOrDefault(i => i.Shape == ConnectorShape.Square);
if (modelInput == null) return null; if (modelInput == null)
{
ctx.Log("[SPLIT] No Square input connector found.", logType.Warning);
return null;
}
var modelJson = ctx.Read(modelInput); var modelJson = ctx.Read(modelInput);
ctx.Log($"[SPLIT] Input JSON: {(modelJson?.Length > 120 ? modelJson.Substring(0, 120) + "..." : modelJson ?? "(null)")}");
if (string.IsNullOrWhiteSpace(modelJson)) return null; if (string.IsNullOrWhiteSpace(modelJson)) return null;
var propName = ResolverUtils.NormalizeConnectorName(outputConnector.Title); var propName = ResolverUtils.NormalizeConnectorName(outputConnector.Title);
return ResolverUtils.ExtractJsonProperty(modelJson, propName); ctx.Log($"[SPLIT] Looking for property: \"{propName}\"");
// Try direct property extraction first
var result = ResolverUtils.ExtractJsonProperty(modelJson, propName);
// If not found at top level, try unwrapping a "data" envelope
if (result == null)
{
var dataInner = ResolverUtils.ExtractJsonProperty(modelJson, "data");
if (!string.IsNullOrWhiteSpace(dataInner))
{
ctx.Log("[SPLIT] Property not found at top level, unwrapping \"data\" envelope...");
result = ResolverUtils.ExtractJsonProperty(dataInner, propName);
}
}
ctx.Log($"[SPLIT] Resolved \"{propName}\" = {result ?? "(null)"}");
return result;
} }
} }

View File

@@ -208,24 +208,51 @@ namespace Nodify.Calculator
var sourceOp = sourceConnector?.Operation; var sourceOp = sourceConnector?.Operation;
var srcNodeId = sourceOp?.NodeId; var srcNodeId = sourceOp?.NodeId;
OnLogMe?.Invoke($"[RESOLVE] Reading input \"{input.Title}\" ? source node \"{sourceOp?.Title}\" (connector \"{sourceConnector?.Title}\")");
// 1. Flow-executed nodes record their result in outputs[nodeId]. // 1. Flow-executed nodes record their result in outputs[nodeId].
if (srcNodeId != null && outputs.TryGetValue(srcNodeId, out var producedVal)) if (srcNodeId != null && outputs.TryGetValue(srcNodeId, out var producedVal))
{
OnLogMe?.Invoke($"[RESOLVE] Found in outputs[{sourceOp?.Title}]: {(producedVal?.Length > 80 ? producedVal.Substring(0, 80) + "..." : producedVal)}");
return producedVal; return producedVal;
}
// 2. Generic dispatch for non-flow (sideband) nodes. // 2. Generic dispatch for non-flow (sideband) nodes.
if (sourceOp != null && sourceConnector != null) if (sourceOp != null && sourceConnector != null)
{ {
OnLogMe?.Invoke($"[RESOLVE] No cached output for \"{sourceOp.Title}\", trying value resolvers...");
var resCtx = new ValueResolutionContext(this, connections); var resCtx = new ValueResolutionContext(this, connections);
foreach (var resolver in _valueResolvers) foreach (var resolver in _valueResolvers)
{ {
if (!resolver.CanResolve(sourceOp, sourceConnector)) continue; if (!resolver.CanResolve(sourceOp, sourceConnector)) continue;
OnLogMe?.Invoke($"[RESOLVE] Matched resolver: {resolver.GetType().Name}");
var resolved = resolver.Resolve(sourceOp, sourceConnector, resCtx); var resolved = resolver.Resolve(sourceOp, sourceConnector, resCtx);
if (!string.IsNullOrEmpty(resolved)) if (!string.IsNullOrEmpty(resolved))
{
OnLogMe?.Invoke($"[RESOLVE] Resolver returned: {(resolved.Length > 80 ? resolved.Substring(0, 80) + "..." : resolved)}");
return resolved; return resolved;
} }
OnLogMe?.Invoke($"[RESOLVE] Resolver returned null/empty, trying next...", logType.Warning);
}
OnLogMe?.Invoke($"[RESOLVE] No resolver produced a value for \"{sourceOp.Title}\"", logType.Warning);
// 2b. Fallback: if no resolver handled this non-flow node, try to recursively
// resolve its first data input and pass the value through (generic passthrough).
var fallbackInput = sourceOp.Input.FirstOrDefault(i => i.Shape != ConnectorShape.Triangle);
if (fallbackInput != null)
{
OnLogMe?.Invoke($"[RESOLVE] Attempting generic passthrough for \"{sourceOp.Title}\"...");
var passthrough = TryReadInputValue(fallbackInput, connections);
if (!string.IsNullOrEmpty(passthrough))
{
OnLogMe?.Invoke($"[RESOLVE] Passthrough returned: {(passthrough.Length > 80 ? passthrough.Substring(0, 80) + "..." : passthrough)}");
return passthrough;
}
}
} }
// 3/4. Fall back to connector/default values. // 3/4. Fall back to connector/default values.
OnLogMe?.Invoke($"[RESOLVE] Falling back to connector Value: {sourceConnector?.Value}", logType.Warning);
if (sourceConnector?.Value != null) if (sourceConnector?.Value != null)
return sourceConnector.Value.ToString(); return sourceConnector.Value.ToString();
return input.Value.ToString(); return input.Value.ToString();
@@ -483,6 +510,39 @@ namespace Nodify.Calculator
HashSet<string> visited, bool isExecute) HashSet<string> visited, bool isExecute)
=> TraverseChain(node, endNodeTitle, connections, visited, isExecute); => TraverseChain(node, endNodeTitle, connections, visited, isExecute);
/// <summary>
/// Executes a linear chain of nodes without requiring an "End" node.
/// Used for loop bodies where the chain simply terminates at the last node.
/// </summary>
internal void ExecuteLinearChain(OperationViewModel startNode,
ICollection<ConnectionViewModel> connections)
{
var visited = new HashSet<string>();
var current = startNode;
while (current != null)
{
if (visited.Contains(current.NodeId))
break;
visited.Add(current.NodeId);
SetNodeState(current, ExecutionState.Running);
System.Threading.Thread.Sleep(AnimationDelayMs / 2);
StartExecution(current, connections);
SetNodeState(current, ExecutionState.Completed);
// Find next node via outgoing Triangle connection
var outConn = connections.FirstOrDefault(c => c.Output?.Operation == current && c.Output.Shape == ConnectorShape.Triangle);
if (outConn?.Input?.Operation == null)
break;
SetConnectionActive(outConn, true);
System.Threading.Thread.Sleep(AnimationDelayMs);
SetConnectionActive(outConn, false);
current = outConn.Input.Operation;
}
}
internal void AddNewModelPublic(OperationInfoViewModel model) internal void AddNewModelPublic(OperationInfoViewModel model)
=> editorViewModel.Calculator.OperationsMenu.AddNewModel(model); => editorViewModel.Calculator.OperationsMenu.AddNewModel(model);