feat: enhance canvas and node components with error handling and retry logic

- Integrated retry logic for AI image generation to handle transient errors and improve user experience.
- Updated error categorization to provide more informative feedback based on different failure scenarios.
- Enhanced node components to display retry attempts and error messages, improving visibility during image generation failures.
- Refactored canvas and node components to include retry count in status updates, ensuring accurate tracking of generation attempts.
This commit is contained in:
Matthias
2026-03-27 11:35:18 +01:00
parent 99a359f330
commit 5da0204163
28 changed files with 1180 additions and 35 deletions

154
.cursor/debug-594b9f.log Normal file
View File

@@ -0,0 +1,154 @@
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7axgmhqz0gkt6sndpq6ersch83nysx","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606648051}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H2","location":"canvas.tsx:edgeSyncEffect","message":"edges passed to ReactFlow","data":{"edgeCount":6,"edges":[{"id":"jn7axgmhqz0gkt6sndpq6ersch83nysx","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7242a6vnazmg729y2nwfb4vx83nqgf","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7b8ee3z6p073bdecght4ba5d83m5mv","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7fr15mb7ds98dvw9w2wjj89983naj6","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79syh9wc7n20m6fg9r1191q183msb2","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","source":"js7fr15mb7ds98dvw9w2wjj89983naj6","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"left","typeofTH":"string","isNullTH":false},{"id":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","source":"js79syh9wc7n20m6fg9r1191q183msb2","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"right","typeofTH":"string","isNullTH":false}]},"timestamp":1774606648051}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7242a6vnazmg729y2nwfb4vx83nqgf","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606648051}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7axgmhqz0gkt6sndpq6ersch83nysx","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606648052}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7b8ee3z6p073bdecght4ba5d83m5mv","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606648051}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7b8ee3z6p073bdecght4ba5d83m5mv","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606648052}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606648052}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","sourceNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"left","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"left"},"timestamp":1774606648052}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","sourceNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"left","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"left"},"timestamp":1774606648051}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H2","location":"canvas.tsx:edgeSyncEffect","message":"edges passed to ReactFlow","data":{"edgeCount":6,"edges":[{"id":"jn7axgmhqz0gkt6sndpq6ersch83nysx","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7242a6vnazmg729y2nwfb4vx83nqgf","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7b8ee3z6p073bdecght4ba5d83m5mv","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7fr15mb7ds98dvw9w2wjj89983naj6","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79syh9wc7n20m6fg9r1191q183msb2","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","source":"js7fr15mb7ds98dvw9w2wjj89983naj6","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"left","typeofTH":"string","isNullTH":false},{"id":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","source":"js79syh9wc7n20m6fg9r1191q183msb2","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"right","typeofTH":"string","isNullTH":false}]},"timestamp":1774606648052}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","sourceNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"right","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"right"},"timestamp":1774606648052}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7242a6vnazmg729y2nwfb4vx83nqgf","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606648052}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606648051}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","sourceNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"right","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"right"},"timestamp":1774606648051}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7242a6vnazmg729y2nwfb4vx83nqgf","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606657711}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn78rknrhj507t3e123ba7ebqn83pnx4","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606657711}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7axgmhqz0gkt6sndpq6ersch83nysx","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606657711}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7b8ee3z6p073bdecght4ba5d83m5mv","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606657711}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H2","location":"canvas.tsx:edgeSyncEffect","message":"edges passed to ReactFlow","data":{"edgeCount":7,"edges":[{"id":"jn7axgmhqz0gkt6sndpq6ersch83nysx","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7242a6vnazmg729y2nwfb4vx83nqgf","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7b8ee3z6p073bdecght4ba5d83m5mv","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7fr15mb7ds98dvw9w2wjj89983naj6","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79syh9wc7n20m6fg9r1191q183msb2","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","source":"js7fr15mb7ds98dvw9w2wjj89983naj6","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"left","typeofTH":"string","isNullTH":false},{"id":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","source":"js79syh9wc7n20m6fg9r1191q183msb2","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"right","typeofTH":"string","isNullTH":false},{"id":"jn78rknrhj507t3e123ba7ebqn83pnx4","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false}]},"timestamp":1774606657711}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606657711}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7b8ee3z6p073bdecght4ba5d83m5mv","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606657712}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7axgmhqz0gkt6sndpq6ersch83nysx","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606657712}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606657712}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7242a6vnazmg729y2nwfb4vx83nqgf","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606657712}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","sourceNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"left","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"left"},"timestamp":1774606657712}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","sourceNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"left","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"left"},"timestamp":1774606657711}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","sourceNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"right","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"right"},"timestamp":1774606657712}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn78rknrhj507t3e123ba7ebqn83pnx4","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606657712}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","sourceNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"right","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"right"},"timestamp":1774606657711}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H2","location":"canvas.tsx:edgeSyncEffect","message":"edges passed to ReactFlow","data":{"edgeCount":7,"edges":[{"id":"jn7axgmhqz0gkt6sndpq6ersch83nysx","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7242a6vnazmg729y2nwfb4vx83nqgf","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7b8ee3z6p073bdecght4ba5d83m5mv","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7fr15mb7ds98dvw9w2wjj89983naj6","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79syh9wc7n20m6fg9r1191q183msb2","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","source":"js7fr15mb7ds98dvw9w2wjj89983naj6","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"left","typeofTH":"string","isNullTH":false},{"id":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","source":"js79syh9wc7n20m6fg9r1191q183msb2","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"right","typeofTH":"string","isNullTH":false},{"id":"jn78rknrhj507t3e123ba7ebqn83pnx4","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false}]},"timestamp":1774606657712}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7axgmhqz0gkt6sndpq6ersch83nysx","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606661452}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7242a6vnazmg729y2nwfb4vx83nqgf","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606661452}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7b8ee3z6p073bdecght4ba5d83m5mv","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606661452}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606661452}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","sourceNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"left","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"left"},"timestamp":1774606661452}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","sourceNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"right","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"right"},"timestamp":1774606661452}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn78rknrhj507t3e123ba7ebqn83pnx4","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606661452}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn76zkdqqkxnpkghrwaevm3j3x83qyyx","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js7380wns03f3m9zr10qfev0wn83q0nv","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606661452}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H2","location":"canvas.tsx:edgeSyncEffect","message":"edges passed to ReactFlow","data":{"edgeCount":8,"edges":[{"id":"jn7axgmhqz0gkt6sndpq6ersch83nysx","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7242a6vnazmg729y2nwfb4vx83nqgf","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7b8ee3z6p073bdecght4ba5d83m5mv","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7fr15mb7ds98dvw9w2wjj89983naj6","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79syh9wc7n20m6fg9r1191q183msb2","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","source":"js7fr15mb7ds98dvw9w2wjj89983naj6","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"left","typeofTH":"string","isNullTH":false},{"id":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","source":"js79syh9wc7n20m6fg9r1191q183msb2","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"right","typeofTH":"string","isNullTH":false},{"id":"jn78rknrhj507t3e123ba7ebqn83pnx4","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn76zkdqqkxnpkghrwaevm3j3x83qyyx","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js7380wns03f3m9zr10qfev0wn83q0nv","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false}]},"timestamp":1774606661452}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7axgmhqz0gkt6sndpq6ersch83nysx","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606661452}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7b8ee3z6p073bdecght4ba5d83m5mv","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606661452}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn78rknrhj507t3e123ba7ebqn83pnx4","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606661452}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7242a6vnazmg729y2nwfb4vx83nqgf","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606661452}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606661452}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","sourceNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"left","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"left"},"timestamp":1774606661452}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn76zkdqqkxnpkghrwaevm3j3x83qyyx","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js7380wns03f3m9zr10qfev0wn83q0nv","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606661453}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","sourceNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"right","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"right"},"timestamp":1774606661452}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H2","location":"canvas.tsx:edgeSyncEffect","message":"edges passed to ReactFlow","data":{"edgeCount":8,"edges":[{"id":"jn7axgmhqz0gkt6sndpq6ersch83nysx","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7242a6vnazmg729y2nwfb4vx83nqgf","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7b8ee3z6p073bdecght4ba5d83m5mv","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7fr15mb7ds98dvw9w2wjj89983naj6","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79syh9wc7n20m6fg9r1191q183msb2","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","source":"js7fr15mb7ds98dvw9w2wjj89983naj6","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"left","typeofTH":"string","isNullTH":false},{"id":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","source":"js79syh9wc7n20m6fg9r1191q183msb2","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"right","typeofTH":"string","isNullTH":false},{"id":"jn78rknrhj507t3e123ba7ebqn83pnx4","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn76zkdqqkxnpkghrwaevm3j3x83qyyx","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js7380wns03f3m9zr10qfev0wn83q0nv","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false}]},"timestamp":1774606661453}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7axgmhqz0gkt6sndpq6ersch83nysx","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606680465}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7242a6vnazmg729y2nwfb4vx83nqgf","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606680466}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606680466}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn78rknrhj507t3e123ba7ebqn83pnx4","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606680466}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7b8ee3z6p073bdecght4ba5d83m5mv","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606680466}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7242a6vnazmg729y2nwfb4vx83nqgf","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606680466}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H2","location":"canvas.tsx:edgeSyncEffect","message":"edges passed to ReactFlow","data":{"edgeCount":7,"edges":[{"id":"jn7axgmhqz0gkt6sndpq6ersch83nysx","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7242a6vnazmg729y2nwfb4vx83nqgf","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7b8ee3z6p073bdecght4ba5d83m5mv","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7fr15mb7ds98dvw9w2wjj89983naj6","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79syh9wc7n20m6fg9r1191q183msb2","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","source":"js7fr15mb7ds98dvw9w2wjj89983naj6","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"left","typeofTH":"string","isNullTH":false},{"id":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","source":"js79syh9wc7n20m6fg9r1191q183msb2","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"right","typeofTH":"string","isNullTH":false},{"id":"jn78rknrhj507t3e123ba7ebqn83pnx4","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false}]},"timestamp":1774606680466}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606680466}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","sourceNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"right","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"right"},"timestamp":1774606680466}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","sourceNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"right","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"right"},"timestamp":1774606680466}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","sourceNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"left","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"left"},"timestamp":1774606680466}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H2","location":"canvas.tsx:edgeSyncEffect","message":"edges passed to ReactFlow","data":{"edgeCount":7,"edges":[{"id":"jn7axgmhqz0gkt6sndpq6ersch83nysx","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7242a6vnazmg729y2nwfb4vx83nqgf","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7b8ee3z6p073bdecght4ba5d83m5mv","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7fr15mb7ds98dvw9w2wjj89983naj6","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79syh9wc7n20m6fg9r1191q183msb2","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","source":"js7fr15mb7ds98dvw9w2wjj89983naj6","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"left","typeofTH":"string","isNullTH":false},{"id":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","source":"js79syh9wc7n20m6fg9r1191q183msb2","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"right","typeofTH":"string","isNullTH":false},{"id":"jn78rknrhj507t3e123ba7ebqn83pnx4","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false}]},"timestamp":1774606680466}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7b8ee3z6p073bdecght4ba5d83m5mv","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606680466}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn78rknrhj507t3e123ba7ebqn83pnx4","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606680466}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7axgmhqz0gkt6sndpq6ersch83nysx","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606680466}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","sourceNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"left","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"left"},"timestamp":1774606680466}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7axgmhqz0gkt6sndpq6ersch83nysx","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606684760}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7242a6vnazmg729y2nwfb4vx83nqgf","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606684760}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7b8ee3z6p073bdecght4ba5d83m5mv","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606684760}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606684760}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","sourceNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"left","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"left"},"timestamp":1774606684760}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","sourceNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"right","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"right"},"timestamp":1774606684760}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn78rknrhj507t3e123ba7ebqn83pnx4","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606684760}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn741xv0z6ttznkfncsaansnz983qbse","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79vt1be2c1zab58j94ydfzp183pqdg","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606684760}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H2","location":"canvas.tsx:edgeSyncEffect","message":"edges passed to ReactFlow","data":{"edgeCount":8,"edges":[{"id":"jn7axgmhqz0gkt6sndpq6ersch83nysx","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7242a6vnazmg729y2nwfb4vx83nqgf","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7b8ee3z6p073bdecght4ba5d83m5mv","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7fr15mb7ds98dvw9w2wjj89983naj6","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79syh9wc7n20m6fg9r1191q183msb2","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","source":"js7fr15mb7ds98dvw9w2wjj89983naj6","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"left","typeofTH":"string","isNullTH":false},{"id":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","source":"js79syh9wc7n20m6fg9r1191q183msb2","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"right","typeofTH":"string","isNullTH":false},{"id":"jn78rknrhj507t3e123ba7ebqn83pnx4","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn741xv0z6ttznkfncsaansnz983qbse","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79vt1be2c1zab58j94ydfzp183pqdg","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false}]},"timestamp":1774606684760}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7axgmhqz0gkt6sndpq6ersch83nysx","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606684760}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7242a6vnazmg729y2nwfb4vx83nqgf","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606684760}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7b8ee3z6p073bdecght4ba5d83m5mv","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606684760}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn78rknrhj507t3e123ba7ebqn83pnx4","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606684761}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","sourceNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"right","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"right"},"timestamp":1774606684761}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn741xv0z6ttznkfncsaansnz983qbse","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79vt1be2c1zab58j94ydfzp183pqdg","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606684761}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606684761}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","sourceNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"left","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"left"},"timestamp":1774606684761}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H2","location":"canvas.tsx:edgeSyncEffect","message":"edges passed to ReactFlow","data":{"edgeCount":8,"edges":[{"id":"jn7axgmhqz0gkt6sndpq6ersch83nysx","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7242a6vnazmg729y2nwfb4vx83nqgf","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7b8ee3z6p073bdecght4ba5d83m5mv","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7fr15mb7ds98dvw9w2wjj89983naj6","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79syh9wc7n20m6fg9r1191q183msb2","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","source":"js7fr15mb7ds98dvw9w2wjj89983naj6","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"left","typeofTH":"string","isNullTH":false},{"id":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","source":"js79syh9wc7n20m6fg9r1191q183msb2","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"right","typeofTH":"string","isNullTH":false},{"id":"jn78rknrhj507t3e123ba7ebqn83pnx4","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn741xv0z6ttznkfncsaansnz983qbse","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79vt1be2c1zab58j94ydfzp183pqdg","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false}]},"timestamp":1774606684761}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7242a6vnazmg729y2nwfb4vx83nqgf","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606811016}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7a560btkzv97yv0qvk8ep1yd83qmn2","sourceNodeId":"js79vt1be2c1zab58j94ydfzp183pqdg","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"right","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"right"},"timestamp":1774606811016}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","sourceNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"left","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"left"},"timestamp":1774606811016}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7242a6vnazmg729y2nwfb4vx83nqgf","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606811016}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7axgmhqz0gkt6sndpq6ersch83nysx","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606811015}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7a560btkzv97yv0qvk8ep1yd83qmn2","sourceNodeId":"js79vt1be2c1zab58j94ydfzp183pqdg","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"right","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"right"},"timestamp":1774606811016}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7axgmhqz0gkt6sndpq6ersch83nysx","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606811016}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606811016}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","sourceNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"right","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"right"},"timestamp":1774606811016}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn741xv0z6ttznkfncsaansnz983qbse","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79vt1be2c1zab58j94ydfzp183pqdg","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606811016}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn78rknrhj507t3e123ba7ebqn83pnx4","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606811016}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn78rknrhj507t3e123ba7ebqn83pnx4","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606811016}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606811016}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","sourceNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"right","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"right"},"timestamp":1774606811016}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7b8ee3z6p073bdecght4ba5d83m5mv","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606811016}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn741xv0z6ttznkfncsaansnz983qbse","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79vt1be2c1zab58j94ydfzp183pqdg","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606811016}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H2","location":"canvas.tsx:edgeSyncEffect","message":"edges passed to ReactFlow","data":{"edgeCount":9,"edges":[{"id":"jn7axgmhqz0gkt6sndpq6ersch83nysx","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7242a6vnazmg729y2nwfb4vx83nqgf","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7b8ee3z6p073bdecght4ba5d83m5mv","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7fr15mb7ds98dvw9w2wjj89983naj6","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79syh9wc7n20m6fg9r1191q183msb2","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","source":"js7fr15mb7ds98dvw9w2wjj89983naj6","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"left","typeofTH":"string","isNullTH":false},{"id":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","source":"js79syh9wc7n20m6fg9r1191q183msb2","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"right","typeofTH":"string","isNullTH":false},{"id":"jn78rknrhj507t3e123ba7ebqn83pnx4","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn741xv0z6ttznkfncsaansnz983qbse","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79vt1be2c1zab58j94ydfzp183pqdg","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7a560btkzv97yv0qvk8ep1yd83qmn2","source":"js79vt1be2c1zab58j94ydfzp183pqdg","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"right","typeofTH":"string","isNullTH":false}]},"timestamp":1774606811016}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H2","location":"canvas.tsx:edgeSyncEffect","message":"edges passed to ReactFlow","data":{"edgeCount":9,"edges":[{"id":"jn7axgmhqz0gkt6sndpq6ersch83nysx","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7242a6vnazmg729y2nwfb4vx83nqgf","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7b8ee3z6p073bdecght4ba5d83m5mv","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7fr15mb7ds98dvw9w2wjj89983naj6","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79syh9wc7n20m6fg9r1191q183msb2","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","source":"js7fr15mb7ds98dvw9w2wjj89983naj6","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"left","typeofTH":"string","isNullTH":false},{"id":"jn72b68knm8y5tvjj6a6fj6h8n83n9a7","source":"js79syh9wc7n20m6fg9r1191q183msb2","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"right","typeofTH":"string","isNullTH":false},{"id":"jn78rknrhj507t3e123ba7ebqn83pnx4","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn741xv0z6ttznkfncsaansnz983qbse","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79vt1be2c1zab58j94ydfzp183pqdg","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7a560btkzv97yv0qvk8ep1yd83qmn2","source":"js79vt1be2c1zab58j94ydfzp183pqdg","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"right","typeofTH":"string","isNullTH":false}]},"timestamp":1774606811016}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7b8ee3z6p073bdecght4ba5d83m5mv","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606811016}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","sourceNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"left","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"left"},"timestamp":1774606811016}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H2","location":"canvas.tsx:edgeSyncEffect","message":"edges passed to ReactFlow","data":{"edgeCount":8,"edges":[{"id":"jn7axgmhqz0gkt6sndpq6ersch83nysx","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7242a6vnazmg729y2nwfb4vx83nqgf","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7b8ee3z6p073bdecght4ba5d83m5mv","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7fr15mb7ds98dvw9w2wjj89983naj6","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79syh9wc7n20m6fg9r1191q183msb2","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","source":"js7fr15mb7ds98dvw9w2wjj89983naj6","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"left","typeofTH":"string","isNullTH":false},{"id":"jn78rknrhj507t3e123ba7ebqn83pnx4","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn741xv0z6ttznkfncsaansnz983qbse","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79vt1be2c1zab58j94ydfzp183pqdg","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7a560btkzv97yv0qvk8ep1yd83qmn2","source":"js79vt1be2c1zab58j94ydfzp183pqdg","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"right","typeofTH":"string","isNullTH":false}]},"timestamp":1774606822672}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7242a6vnazmg729y2nwfb4vx83nqgf","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606822672}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7b8ee3z6p073bdecght4ba5d83m5mv","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606822671}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H2","location":"canvas.tsx:edgeSyncEffect","message":"edges passed to ReactFlow","data":{"edgeCount":8,"edges":[{"id":"jn7axgmhqz0gkt6sndpq6ersch83nysx","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7242a6vnazmg729y2nwfb4vx83nqgf","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7b8ee3z6p073bdecght4ba5d83m5mv","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7fr15mb7ds98dvw9w2wjj89983naj6","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79syh9wc7n20m6fg9r1191q183msb2","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","source":"js7fr15mb7ds98dvw9w2wjj89983naj6","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"left","typeofTH":"string","isNullTH":false},{"id":"jn78rknrhj507t3e123ba7ebqn83pnx4","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn741xv0z6ttznkfncsaansnz983qbse","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79vt1be2c1zab58j94ydfzp183pqdg","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7a560btkzv97yv0qvk8ep1yd83qmn2","source":"js79vt1be2c1zab58j94ydfzp183pqdg","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"right","typeofTH":"string","isNullTH":false}]},"timestamp":1774606822672}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7a560btkzv97yv0qvk8ep1yd83qmn2","sourceNodeId":"js79vt1be2c1zab58j94ydfzp183pqdg","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"right","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"right"},"timestamp":1774606822672}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn78rknrhj507t3e123ba7ebqn83pnx4","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606822672}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606822671}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7axgmhqz0gkt6sndpq6ersch83nysx","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606822671}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7242a6vnazmg729y2nwfb4vx83nqgf","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606822671}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn741xv0z6ttznkfncsaansnz983qbse","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79vt1be2c1zab58j94ydfzp183pqdg","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606822672}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","sourceNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"left","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"left"},"timestamp":1774606822672}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7axgmhqz0gkt6sndpq6ersch83nysx","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606822672}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7b8ee3z6p073bdecght4ba5d83m5mv","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606822672}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","sourceNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"left","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"left"},"timestamp":1774606822672}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606822672}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn78rknrhj507t3e123ba7ebqn83pnx4","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606822672}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7a560btkzv97yv0qvk8ep1yd83qmn2","sourceNodeId":"js79vt1be2c1zab58j94ydfzp183pqdg","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"right","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"right"},"timestamp":1774606822672}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn741xv0z6ttznkfncsaansnz983qbse","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79vt1be2c1zab58j94ydfzp183pqdg","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606822672}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7axgmhqz0gkt6sndpq6ersch83nysx","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606827178}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7242a6vnazmg729y2nwfb4vx83nqgf","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606827179}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7b8ee3z6p073bdecght4ba5d83m5mv","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606827179}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606827179}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","sourceNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"left","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"left"},"timestamp":1774606827179}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn78rknrhj507t3e123ba7ebqn83pnx4","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606827179}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn741xv0z6ttznkfncsaansnz983qbse","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79vt1be2c1zab58j94ydfzp183pqdg","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606827179}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H2","location":"canvas.tsx:edgeSyncEffect","message":"edges passed to ReactFlow","data":{"edgeCount":7,"edges":[{"id":"jn7axgmhqz0gkt6sndpq6ersch83nysx","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7242a6vnazmg729y2nwfb4vx83nqgf","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7b8ee3z6p073bdecght4ba5d83m5mv","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7fr15mb7ds98dvw9w2wjj89983naj6","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79syh9wc7n20m6fg9r1191q183msb2","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","source":"js7fr15mb7ds98dvw9w2wjj89983naj6","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"left","typeofTH":"string","isNullTH":false},{"id":"jn78rknrhj507t3e123ba7ebqn83pnx4","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn741xv0z6ttznkfncsaansnz983qbse","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79vt1be2c1zab58j94ydfzp183pqdg","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false}]},"timestamp":1774606827179}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7axgmhqz0gkt6sndpq6ersch83nysx","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606827179}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7242a6vnazmg729y2nwfb4vx83nqgf","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606827179}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7b8ee3z6p073bdecght4ba5d83m5mv","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606827179}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606827179}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H2","location":"canvas.tsx:edgeSyncEffect","message":"edges passed to ReactFlow","data":{"edgeCount":7,"edges":[{"id":"jn7axgmhqz0gkt6sndpq6ersch83nysx","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7242a6vnazmg729y2nwfb4vx83nqgf","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7b8ee3z6p073bdecght4ba5d83m5mv","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7fr15mb7ds98dvw9w2wjj89983naj6","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79syh9wc7n20m6fg9r1191q183msb2","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","source":"js7fr15mb7ds98dvw9w2wjj89983naj6","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"left","typeofTH":"string","isNullTH":false},{"id":"jn78rknrhj507t3e123ba7ebqn83pnx4","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn741xv0z6ttznkfncsaansnz983qbse","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79vt1be2c1zab58j94ydfzp183pqdg","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false}]},"timestamp":1774606827180}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","sourceNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"left","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"left"},"timestamp":1774606827179}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn741xv0z6ttznkfncsaansnz983qbse","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79vt1be2c1zab58j94ydfzp183pqdg","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606827180}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn78rknrhj507t3e123ba7ebqn83pnx4","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606827179}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7242a6vnazmg729y2nwfb4vx83nqgf","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606828375}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7axgmhqz0gkt6sndpq6ersch83nysx","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606828374}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn741xv0z6ttznkfncsaansnz983qbse","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79vt1be2c1zab58j94ydfzp183pqdg","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606828375}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H2","location":"canvas.tsx:edgeSyncEffect","message":"edges passed to ReactFlow","data":{"edgeCount":8,"edges":[{"id":"jn7axgmhqz0gkt6sndpq6ersch83nysx","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7242a6vnazmg729y2nwfb4vx83nqgf","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7b8ee3z6p073bdecght4ba5d83m5mv","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7fr15mb7ds98dvw9w2wjj89983naj6","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79syh9wc7n20m6fg9r1191q183msb2","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","source":"js7fr15mb7ds98dvw9w2wjj89983naj6","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"left","typeofTH":"string","isNullTH":false},{"id":"jn78rknrhj507t3e123ba7ebqn83pnx4","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn741xv0z6ttznkfncsaansnz983qbse","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79vt1be2c1zab58j94ydfzp183pqdg","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7cx57f8hss73bxy5qxbc4v7183qjt4","source":"js79syh9wc7n20m6fg9r1191q183msb2","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"right","typeofTH":"string","isNullTH":false}]},"timestamp":1774606828375}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn78rknrhj507t3e123ba7ebqn83pnx4","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606828375}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7b8ee3z6p073bdecght4ba5d83m5mv","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606828376}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606828375}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7axgmhqz0gkt6sndpq6ersch83nysx","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606828375}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn78rknrhj507t3e123ba7ebqn83pnx4","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606828376}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","sourceNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"left","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"left"},"timestamp":1774606828375}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","sourceNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"left","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"left"},"timestamp":1774606828376}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H2","location":"canvas.tsx:edgeSyncEffect","message":"edges passed to ReactFlow","data":{"edgeCount":8,"edges":[{"id":"jn7axgmhqz0gkt6sndpq6ersch83nysx","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7242a6vnazmg729y2nwfb4vx83nqgf","source":"js7bbr471t9fqerb27eh3p0ksd83n82c","target":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetHandle":"image-in","typeofTH":"string","isNullTH":false},{"id":"jn7b8ee3z6p073bdecght4ba5d83m5mv","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7fr15mb7ds98dvw9w2wjj89983naj6","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79syh9wc7n20m6fg9r1191q183msb2","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn79n3spvbdrqfgf9wd7h1rvgx83nrtv","source":"js7fr15mb7ds98dvw9w2wjj89983naj6","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"left","typeofTH":"string","isNullTH":false},{"id":"jn78rknrhj507t3e123ba7ebqn83pnx4","source":"js7ak7hkab3rpnxqc6xdzjphx583m665","target":"js7df78fpx4gpt1n50fj6hwyjs83pzxf","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn741xv0z6ttznkfncsaansnz983qbse","source":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","target":"js79vt1be2c1zab58j94ydfzp183pqdg","sourceHandle":"prompt-out","targetHandle":"prompt-in","typeofTH":"string","isNullTH":false},{"id":"jn7cx57f8hss73bxy5qxbc4v7183qjt4","source":"js79syh9wc7n20m6fg9r1191q183msb2","target":"js7cpdwr5v40hw20w55f2cet5583n1g7","sourceHandle":"image-out","targetHandle":"right","typeofTH":"string","isNullTH":false}]},"timestamp":1774606828376}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7cx57f8hss73bxy5qxbc4v7183qjt4","sourceNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"right","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"right"},"timestamp":1774606828376}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7b8ee3z6p073bdecght4ba5d83m5mv","sourceNodeId":"js7ak7hkab3rpnxqc6xdzjphx583m665","targetNodeId":"js7fr15mb7ds98dvw9w2wjj89983naj6","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606828375}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7242a6vnazmg729y2nwfb4vx83nqgf","sourceNodeId":"js7bbr471t9fqerb27eh3p0ksd83n82c","targetNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","rawTargetHandle":"image-in","typeofSourceHandle":"undefined","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":true,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedTH":"image-in"},"timestamp":1774606828375}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn741xv0z6ttznkfncsaansnz983qbse","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79vt1be2c1zab58j94ydfzp183pqdg","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606828376}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7cx57f8hss73bxy5qxbc4v7183qjt4","sourceNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","targetNodeId":"js7cpdwr5v40hw20w55f2cet5583n1g7","rawSourceHandle":"image-out","rawTargetHandle":"right","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"image-out","sanitizedTH":"right"},"timestamp":1774606828375}
{"sessionId":"594b9f","runId":"run1","hypothesisId":"H1-H3-H4","location":"canvas-utils.ts:convexEdgeToRF","message":"raw edge from convex","data":{"edgeId":"jn7frrkcn95k984f9w1b7vcv4x83mgpb","sourceNodeId":"js7dt20y2wyrt6mk1e1aee2pgd83mh4e","targetNodeId":"js79syh9wc7n20m6fg9r1191q183msb2","rawSourceHandle":"prompt-out","rawTargetHandle":"prompt-in","typeofSourceHandle":"string","typeofTargetHandle":"string","isNullSH":false,"isNullTH":false,"isUndefinedSH":false,"isUndefinedTH":false,"isStringNullSH":false,"isStringNullTH":false,"sanitizedSH":"prompt-out","sanitizedTH":"prompt-in"},"timestamp":1774606828376}

View File

@@ -0,0 +1,37 @@
"use client";
import Link from "next/link";
import { Button } from "@/components/ui/button";
type CanvasErrorProps = {
error: Error & { digest?: string };
unstable_retry: () => void;
};
export default function CanvasError({ error, unstable_retry }: CanvasErrorProps) {
return (
<main className="flex h-screen w-screen items-center justify-center bg-background px-4">
<div className="w-full max-w-md space-y-4 rounded-xl border bg-card p-6 shadow-sm">
<div className="space-y-1 text-center">
<h1 className="text-xl font-semibold">Canvas konnte nicht geladen werden</h1>
<p className="text-sm text-muted-foreground">
Beim Laden dieses Canvas ist ein Fehler aufgetreten.
</p>
{error.digest ? (
<p className="text-xs text-muted-foreground/80">Fehler-ID: {error.digest}</p>
) : null}
</div>
<div className="flex flex-col gap-2 sm:flex-row sm:justify-center">
<Button className="sm:flex-1" onClick={() => unstable_retry()}>
Erneut versuchen
</Button>
<Button asChild variant="outline" className="sm:flex-1">
<Link href="/dashboard">Zum Dashboard</Link>
</Button>
</div>
</div>
</main>
);
}

View File

@@ -1,6 +1,7 @@
import { notFound, redirect } from "next/navigation"; import { notFound, redirect } from "next/navigation";
import Canvas from "@/components/canvas/canvas"; import Canvas from "@/components/canvas/canvas";
import ConnectionBanner from "@/components/canvas/connection-banner";
import CanvasSidebar from "@/components/canvas/canvas-sidebar"; import CanvasSidebar from "@/components/canvas/canvas-sidebar";
import { api } from "@/convex/_generated/api"; import { api } from "@/convex/_generated/api";
import type { Id } from "@/convex/_generated/dataModel"; import type { Id } from "@/convex/_generated/dataModel";
@@ -50,7 +51,8 @@ export default async function CanvasPage({
return ( return (
<div className="flex h-screen w-screen overflow-hidden"> <div className="flex h-screen w-screen overflow-hidden">
<CanvasSidebar /> <CanvasSidebar />
<div className="flex-1"> <div className="relative flex-1">
<ConnectionBanner />
<Canvas canvasId={typedCanvasId} /> <Canvas canvasId={typedCanvasId} />
</div> </div>
</div> </div>

43
app/error.tsx Normal file
View File

@@ -0,0 +1,43 @@
"use client";
import { useEffect } from "react";
import { Button } from "@/components/ui/button";
type AppErrorProps = {
error: Error & { digest?: string };
unstable_retry: () => void;
};
export default function AppError({ error, unstable_retry }: AppErrorProps) {
useEffect(() => {
const safeError = {
name: error.name,
message:
process.env.NODE_ENV === "development"
? error.message
: "Unexpected application error",
digest: error.digest,
};
console.error("[app/error]", safeError);
}, [error]);
return (
<main className="flex min-h-screen items-center justify-center bg-background px-4">
<div className="w-full max-w-md space-y-4 rounded-xl border bg-card p-6 shadow-sm">
<div className="space-y-1 text-center">
<h1 className="text-xl font-semibold">Etwas ist schiefgelaufen</h1>
<p className="text-sm text-muted-foreground">
Wir konnten diesen Bereich nicht laden. Du kannst es direkt erneut
versuchen.
</p>
</div>
<Button className="w-full" onClick={() => unstable_retry()}>
Erneut versuchen
</Button>
</div>
</main>
);
}

40
app/global-error.tsx Normal file
View File

@@ -0,0 +1,40 @@
"use client";
import { Button } from "@/components/ui/button";
type GlobalErrorProps = {
error: Error & { digest?: string };
unstable_retry: () => void;
};
export default function GlobalError({
error,
unstable_retry,
}: GlobalErrorProps) {
return (
<html lang="de" className="h-full antialiased font-sans">
<body className="min-h-full bg-background text-foreground">
<main className="flex min-h-screen items-center justify-center px-4">
<div className="w-full max-w-md space-y-4 rounded-xl border bg-card p-6 shadow-sm">
<div className="space-y-1 text-center">
<h1 className="text-xl font-semibold">Schwerer Fehler</h1>
<p className="text-sm text-muted-foreground">
Die Anwendung konnte nicht dargestellt werden. Lade den Bereich
neu, um fortzufahren.
</p>
{error.digest ? (
<p className="text-xs text-muted-foreground/80">
Fehler-ID: {error.digest}
</p>
) : null}
</div>
<Button className="w-full" onClick={() => unstable_retry()}>
Erneut laden
</Button>
</div>
</main>
</body>
</html>
);
}

View File

@@ -3,7 +3,6 @@ import { Manrope } from "next/font/google";
import "./globals.css"; import "./globals.css";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { Providers } from "@/components/providers"; import { Providers } from "@/components/providers";
import { Toaster } from "@/components/ui/sonner";
import { InitUser } from "@/components/init-user"; import { InitUser } from "@/components/init-user";
import { getToken } from "@/lib/auth-server"; import { getToken } from "@/lib/auth-server";
@@ -31,7 +30,6 @@ export default async function RootLayout({
<Providers initialToken={initialToken}> <Providers initialToken={initialToken}>
<InitUser /> <InitUser />
{children} {children}
<Toaster />
</Providers> </Providers>
</body> </body>
</html> </html>

View File

@@ -21,6 +21,7 @@ import {
BackgroundVariant, BackgroundVariant,
} from "@xyflow/react"; } from "@xyflow/react";
import "@xyflow/react/dist/style.css"; import "@xyflow/react/dist/style.css";
import { toast } from "@/lib/toast";
import { useConvexAuth, useMutation, useQuery } from "convex/react"; import { useConvexAuth, useMutation, useQuery } from "convex/react";
import { api } from "@/convex/_generated/api"; import { api } from "@/convex/_generated/api";
@@ -113,6 +114,9 @@ const EDGE_INTERSECTION_HIGHLIGHT_STYLE: NonNullable<RFEdge["style"]> = {
strokeWidth: 2, strokeWidth: 2,
}; };
const GENERATION_FAILURE_WINDOW_MS = 5 * 60 * 1000;
const GENERATION_FAILURE_THRESHOLD = 3;
function getEdgeIdFromInteractionElement(element: Element): string | null { function getEdgeIdFromInteractionElement(element: Element): string | null {
const edgeContainer = element.closest(".react-flow__edge"); const edgeContainer = element.closest(".react-flow__edge");
if (!edgeContainer) return null; if (!edgeContainer) return null;
@@ -249,6 +253,63 @@ function CanvasInner({ canvasId }: CanvasInnerProps) {
const highlightedEdgeOriginalStyleRef = useRef<RFEdge["style"] | undefined>( const highlightedEdgeOriginalStyleRef = useRef<RFEdge["style"] | undefined>(
undefined, undefined,
); );
const recentGenerationFailureTimestampsRef = useRef<number[]>([]);
const previousNodeStatusRef = useRef<Map<string, string | undefined>>(new Map());
const hasInitializedGenerationFailureTrackingRef = useRef(false);
useEffect(() => {
if (!convexNodes) return;
const nextNodeStatusMap = new Map<string, string | undefined>();
let detectedGenerationFailures = 0;
for (const node of convexNodes) {
nextNodeStatusMap.set(node._id, node.status);
if (node.type !== "ai-image") {
continue;
}
const previousStatus = previousNodeStatusRef.current.get(node._id);
if (
hasInitializedGenerationFailureTrackingRef.current &&
node.status === "error" &&
previousStatus !== "error"
) {
detectedGenerationFailures += 1;
}
}
previousNodeStatusRef.current = nextNodeStatusMap;
if (!hasInitializedGenerationFailureTrackingRef.current) {
hasInitializedGenerationFailureTrackingRef.current = true;
return;
}
if (detectedGenerationFailures === 0) {
return;
}
const now = Date.now();
const recentFailures = recentGenerationFailureTimestampsRef.current.filter(
(timestamp) => now - timestamp <= GENERATION_FAILURE_WINDOW_MS,
);
for (let index = 0; index < detectedGenerationFailures; index += 1) {
recentFailures.push(now);
}
if (recentFailures.length >= GENERATION_FAILURE_THRESHOLD) {
toast.error(
"Mehrere Generierungen sind fehlgeschlagen. Bitte Prompt, Modell oder Credits prüfen.",
);
recentGenerationFailureTimestampsRef.current = [];
return;
}
recentGenerationFailureTimestampsRef.current = recentFailures;
}, [convexNodes]);
// ─── Convex → Lokaler State Sync ────────────────────────────── // ─── Convex → Lokaler State Sync ──────────────────────────────
useEffect(() => { useEffect(() => {

View File

@@ -0,0 +1,112 @@
"use client";
import { useEffect, useMemo, useRef, useState } from "react";
import { useConvexConnectionState } from "convex/react";
import { cn } from "@/lib/utils";
type BannerState = "hidden" | "reconnecting" | "disconnected" | "reconnected";
const RECONNECTED_HIDE_DELAY_MS = 1800;
export default function ConnectionBanner() {
const connectionState = useConvexConnectionState();
const previousConnectedRef = useRef(connectionState.isWebSocketConnected);
const [showReconnected, setShowReconnected] = useState(false);
const [isBrowserOnline, setIsBrowserOnline] = useState(
typeof navigator === "undefined" ? true : navigator.onLine,
);
useEffect(() => {
const handleOnline = () => setIsBrowserOnline(true);
const handleOffline = () => setIsBrowserOnline(false);
window.addEventListener("online", handleOnline);
window.addEventListener("offline", handleOffline);
return () => {
window.removeEventListener("online", handleOnline);
window.removeEventListener("offline", handleOffline);
};
}, []);
useEffect(() => {
const wasConnected = previousConnectedRef.current;
const isConnected = connectionState.isWebSocketConnected;
const didReconnect = !wasConnected && isConnected && connectionState.connectionCount > 1;
if (didReconnect) {
setShowReconnected(true);
}
if (!isConnected) {
setShowReconnected(false);
}
previousConnectedRef.current = isConnected;
}, [connectionState.connectionCount, connectionState.isWebSocketConnected]);
useEffect(() => {
if (!showReconnected) {
return;
}
const timeoutId = window.setTimeout(() => {
setShowReconnected(false);
}, RECONNECTED_HIDE_DELAY_MS);
return () => window.clearTimeout(timeoutId);
}, [showReconnected]);
const bannerState = useMemo<BannerState>(() => {
if (connectionState.isWebSocketConnected) {
return showReconnected ? "reconnected" : "hidden";
}
if (!isBrowserOnline) {
return "disconnected";
}
if (connectionState.hasEverConnected || connectionState.connectionRetries > 0) {
return "reconnecting";
}
return "hidden";
}, [
connectionState.connectionRetries,
connectionState.hasEverConnected,
connectionState.isWebSocketConnected,
isBrowserOnline,
showReconnected,
]);
if (bannerState === "hidden") {
return null;
}
const contentByState: Record<Exclude<BannerState, "hidden">, { dotClass: string; text: string }> = {
reconnecting: {
dotClass: "bg-amber-500",
text: "Verbindung wird wiederhergestellt…",
},
disconnected: {
dotClass: "bg-destructive",
text: "Keine Verbindung. Wir verbinden uns automatisch erneut.",
},
reconnected: {
dotClass: "bg-emerald-500",
text: "Verbindung wiederhergestellt",
},
};
const content = contentByState[bannerState];
return (
<div className="pointer-events-none absolute top-3 left-1/2 z-20 -translate-x-1/2">
<div className="inline-flex items-center gap-2 rounded-full border border-border/70 bg-card/90 px-3 py-1.5 text-xs text-muted-foreground shadow-sm backdrop-blur-sm">
<span className={cn("h-1.5 w-1.5 rounded-full", content.dotClass)} aria-hidden="true" />
<span>{content.text}</span>
</div>
</div>
);
}

View File

@@ -3,7 +3,7 @@
import { useMutation, useQuery } from "convex/react"; import { useMutation, useQuery } from "convex/react";
import { api } from "@/convex/_generated/api"; import { api } from "@/convex/_generated/api";
import { Coins } from "lucide-react"; import { Coins } from "lucide-react";
import { toast } from "sonner"; import { toast } from "@/lib/toast";
const TIER_LABELS: Record<string, string> = { const TIER_LABELS: Record<string, string> = {
free: "Free", free: "Free",

View File

@@ -1,12 +1,14 @@
"use client"; "use client";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { useRouter } from "next/navigation";
import { Handle, Position, useReactFlow, type NodeProps, type Node } from "@xyflow/react"; import { Handle, Position, useReactFlow, type NodeProps, type Node } from "@xyflow/react";
import { useAction } from "convex/react"; import { useAction } from "convex/react";
import { api } from "@/convex/_generated/api"; import { api } from "@/convex/_generated/api";
import type { Id } from "@/convex/_generated/dataModel"; import type { Id } from "@/convex/_generated/dataModel";
import BaseNodeWrapper from "./base-node-wrapper"; import BaseNodeWrapper from "./base-node-wrapper";
import { DEFAULT_MODEL_ID, getModel } from "@/lib/ai-models"; import { DEFAULT_MODEL_ID, getModel } from "@/lib/ai-models";
import { classifyError, type AiErrorCategory } from "@/lib/ai-errors";
import { DEFAULT_ASPECT_RATIO } from "@/lib/image-formats"; import { DEFAULT_ASPECT_RATIO } from "@/lib/image-formats";
import { import {
Loader2, Loader2,
@@ -14,6 +16,9 @@ import {
RefreshCw, RefreshCw,
ImageIcon, ImageIcon,
Coins, Coins,
Clock3,
ShieldAlert,
WifiOff,
} from "lucide-react"; } from "lucide-react";
type AiImageNodeData = { type AiImageNodeData = {
@@ -31,6 +36,7 @@ type AiImageNodeData = {
aspectRatio?: string; aspectRatio?: string;
outputWidth?: number; outputWidth?: number;
outputHeight?: number; outputHeight?: number;
retryCount?: number;
_status?: string; _status?: string;
_statusMessage?: string; _statusMessage?: string;
}; };
@@ -52,6 +58,7 @@ export default function AiImageNode({
}: NodeProps<AiImageNode>) { }: NodeProps<AiImageNode>) {
const nodeData = data as AiImageNodeData; const nodeData = data as AiImageNodeData;
const { getEdges, getNode } = useReactFlow(); const { getEdges, getNode } = useReactFlow();
const router = useRouter();
const [isGenerating, setIsGenerating] = useState(false); const [isGenerating, setIsGenerating] = useState(false);
const [localError, setLocalError] = useState<string | null>(null); const [localError, setLocalError] = useState<string | null>(null);
@@ -60,6 +67,12 @@ export default function AiImageNode({
const status = (nodeData._status ?? "idle") as NodeStatus; const status = (nodeData._status ?? "idle") as NodeStatus;
const errorMessage = nodeData._statusMessage; const errorMessage = nodeData._statusMessage;
const classifiedError = classifyError(errorMessage ?? localError);
const executingRetryCount =
typeof nodeData.retryCount === "number"
? nodeData.retryCount
: classifiedError.retryCount;
const isLoading = const isLoading =
status === "executing" || status === "executing" ||
@@ -111,8 +124,25 @@ export default function AiImageNode({
const modelName = const modelName =
getModel(nodeData.model ?? DEFAULT_MODEL_ID)?.name ?? "AI"; getModel(nodeData.model ?? DEFAULT_MODEL_ID)?.name ?? "AI";
const renderErrorIcon = (category: AiErrorCategory) => {
switch (category) {
case "insufficient_credits":
return <Coins className="h-8 w-8 text-amber-500" />;
case "rate_limited":
case "timeout":
return <Clock3 className="h-8 w-8 text-amber-500" />;
case "content_policy":
return <ShieldAlert className="h-8 w-8 text-destructive" />;
case "network":
return <WifiOff className="h-8 w-8 text-destructive" />;
default:
return <AlertCircle className="h-8 w-8 text-destructive" />;
}
};
return ( return (
<BaseNodeWrapper <BaseNodeWrapper
nodeType="ai-image"
selected={selected} selected={selected}
className="flex h-full w-full min-h-0 min-w-0 flex-col overflow-hidden" className="flex h-full w-full min-h-0 min-w-0 flex-col overflow-hidden"
> >
@@ -151,6 +181,13 @@ export default function AiImageNode({
{status === "clarifying" && "Clarifying…"} {status === "clarifying" && "Clarifying…"}
{(status === "executing" || isGenerating) && "Generating…"} {(status === "executing" || isGenerating) && "Generating…"}
</p> </p>
{(status === "executing" || isGenerating) &&
typeof executingRetryCount === "number" &&
executingRetryCount > 0 && (
<p className="relative z-10 text-[10px] text-amber-600 dark:text-amber-400">
Retry attempt {executingRetryCount}
</p>
)}
<p className="relative z-10 text-[10px] text-muted-foreground/60"> <p className="relative z-10 text-[10px] text-muted-foreground/60">
{modelName} {modelName}
</p> </p>
@@ -159,22 +196,42 @@ export default function AiImageNode({
{status === "error" && !isLoading && ( {status === "error" && !isLoading && (
<div className="absolute inset-0 z-10 flex flex-col items-center justify-center gap-3 bg-muted"> <div className="absolute inset-0 z-10 flex flex-col items-center justify-center gap-3 bg-muted">
<AlertCircle className="h-8 w-8 text-destructive" /> {renderErrorIcon(classifiedError.category)}
<p className="px-4 text-center text-xs font-medium text-destructive"> <p className="px-4 text-center text-xs font-medium text-destructive">
Generation failed {classifiedError.message}
</p> </p>
{classifiedError.detail && (
<p className="px-6 text-center text-[10px] text-muted-foreground"> <p className="px-6 text-center text-[10px] text-muted-foreground">
{errorMessage ?? localError ?? "Unknown error"} Credits not {classifiedError.detail}
charged
</p> </p>
)}
{classifiedError.creditsNotCharged && (
<p className="px-6 text-center text-[10px] text-muted-foreground">
Credits not charged
</p>
)}
<div className="mt-1 flex items-center gap-2">
{classifiedError.showTopUp && (
<button
type="button"
onClick={() => router.push("/settings/billing")}
className="nodrag flex items-center gap-1.5 rounded-md border border-amber-500/40 bg-amber-500/10 px-3 py-1.5 text-xs font-medium text-amber-700 transition-colors hover:bg-amber-500/20 dark:text-amber-300"
>
<Coins className="h-3 w-3" />
Top up credits
</button>
)}
{classifiedError.retryable && (
<button <button
type="button" type="button"
onClick={() => void handleRegenerate()} onClick={() => void handleRegenerate()}
className="nodrag mt-1 flex items-center gap-1.5 rounded-md border border-border bg-background px-3 py-1.5 text-xs font-medium transition-colors hover:bg-accent" className="nodrag flex items-center gap-1.5 rounded-md border border-border bg-background px-3 py-1.5 text-xs font-medium transition-colors hover:bg-accent"
> >
<RefreshCw className="h-3 w-3" /> <RefreshCw className="h-3 w-3" />
Try again Try again
</button> </button>
)}
</div>
</div> </div>
)} )}

View File

@@ -1,8 +1,10 @@
"use client"; "use client";
import type { ReactNode } from "react"; import type { ReactNode } from "react";
import { NodeErrorBoundary } from "./node-error-boundary";
interface BaseNodeWrapperProps { interface BaseNodeWrapperProps {
nodeType: string;
selected?: boolean; selected?: boolean;
status?: string; status?: string;
statusMessage?: string; statusMessage?: string;
@@ -11,6 +13,7 @@ interface BaseNodeWrapperProps {
} }
export default function BaseNodeWrapper({ export default function BaseNodeWrapper({
nodeType,
selected, selected,
status = "idle", status = "idle",
statusMessage, statusMessage,
@@ -35,7 +38,7 @@ export default function BaseNodeWrapper({
${className} ${className}
`} `}
> >
{children} <NodeErrorBoundary nodeType={nodeType}>{children}</NodeErrorBoundary>
{status === "error" && statusMessage && ( {status === "error" && statusMessage && (
<div className="px-3 pb-2 text-xs text-red-500 truncate"> <div className="px-3 pb-2 text-xs text-red-500 truncate">
{statusMessage} {statusMessage}

View File

@@ -63,7 +63,7 @@ export default function CompareNode({ data, selected }: NodeProps) {
}, []); }, []);
return ( return (
<BaseNodeWrapper selected={selected} className="w-[500px] p-0"> <BaseNodeWrapper nodeType="compare" selected={selected} className="w-[500px] p-0">
<div className="px-3 py-2 text-xs font-medium text-muted-foreground"> Compare</div> <div className="px-3 py-2 text-xs font-medium text-muted-foreground"> Compare</div>
<Handle <Handle

View File

@@ -59,6 +59,7 @@ export default function FrameNode({ id, data, selected, width, height }: NodePro
return ( return (
<BaseNodeWrapper <BaseNodeWrapper
nodeType="frame"
selected={selected} selected={selected}
className="relative h-full w-full border-2 border-dashed border-muted-foreground/40 !bg-transparent p-0 shadow-none" className="relative h-full w-full border-2 border-dashed border-muted-foreground/40 !bg-transparent p-0 shadow-none"
> >

View File

@@ -44,6 +44,7 @@ export default function GroupNode({ id, data, selected }: NodeProps<GroupNode>)
return ( return (
<BaseNodeWrapper <BaseNodeWrapper
nodeType="group"
selected={selected} selected={selected}
className="min-w-[200px] min-h-[150px] p-3 border-dashed" className="min-w-[200px] min-h-[150px] p-3 border-dashed"
> >

View File

@@ -116,7 +116,7 @@ export default function ImageNode({ id, data, selected }: NodeProps<ImageNode>)
}, []); }, []);
return ( return (
<BaseNodeWrapper selected={selected} status={data._status}> <BaseNodeWrapper nodeType="image" selected={selected} status={data._status}>
<Handle <Handle
type="target" type="target"
position={Position.Left} position={Position.Left}

View File

@@ -0,0 +1,66 @@
"use client";
import type { ErrorInfo, ReactNode } from "react";
import { Component } from "react";
interface NodeErrorBoundaryProps {
children: ReactNode;
nodeType: string;
}
interface NodeErrorBoundaryState {
hasError: boolean;
errorMessage?: string;
}
export class NodeErrorBoundary extends Component<
NodeErrorBoundaryProps,
NodeErrorBoundaryState
> {
state: NodeErrorBoundaryState = {
hasError: false,
};
static getDerivedStateFromError(error: Error): NodeErrorBoundaryState {
return {
hasError: true,
errorMessage: error.message,
};
}
override componentDidCatch(error: Error, errorInfo: ErrorInfo) {
console.error("Node rendering error", {
nodeType: this.props.nodeType,
error,
componentStack: errorInfo.componentStack,
});
}
private handleRetry = () => {
this.setState({ hasError: false, errorMessage: undefined });
};
override render() {
if (this.state.hasError) {
return (
<div className="m-2 rounded-md border border-destructive/40 bg-destructive/5 p-2 text-xs">
<p className="font-medium text-destructive">Node render failed ({this.props.nodeType})</p>
{this.state.errorMessage && (
<p className="mt-1 truncate text-destructive/90" title={this.state.errorMessage}>
{this.state.errorMessage}
</p>
)}
<button
type="button"
onClick={this.handleRetry}
className="nodrag mt-2 rounded border border-destructive/30 px-2 py-1 text-[11px] font-medium text-destructive transition-colors hover:bg-destructive/10"
>
Retry
</button>
</div>
);
}
return this.props.children;
}
}

View File

@@ -53,7 +53,7 @@ export default function NoteNode({ id, data, selected }: NodeProps<NoteNode>) {
); );
return ( return (
<BaseNodeWrapper selected={selected} className="w-52 p-3"> <BaseNodeWrapper nodeType="note" selected={selected} className="w-52 p-3">
<Handle <Handle
type="target" type="target"
position={Position.Left} position={Position.Left}

View File

@@ -243,6 +243,7 @@ export default function PromptNode({
return ( return (
<BaseNodeWrapper <BaseNodeWrapper
nodeType="prompt"
selected={selected} selected={selected}
status={nodeData._status} status={nodeData._status}
statusMessage={nodeData._statusMessage} statusMessage={nodeData._statusMessage}

View File

@@ -75,7 +75,12 @@ export default function TextNode({ id, data, selected }: NodeProps<TextNode>) {
); );
return ( return (
<BaseNodeWrapper selected={selected} status={data._status} className="relative"> <BaseNodeWrapper
nodeType="text"
selected={selected}
status={data._status}
className="relative"
>
<Handle <Handle
type="target" type="target"
position={Position.Left} position={Position.Left}

View File

@@ -3,7 +3,7 @@
import { useState, useCallback, useRef } from "react"; import { useState, useCallback, useRef } from "react";
import { useMutation } from "convex/react"; import { useMutation } from "convex/react";
import { ArrowUpRight, MoreHorizontal, Pencil } from "lucide-react"; import { ArrowUpRight, MoreHorizontal, Pencil } from "lucide-react";
import { toast } from "sonner"; import { toast } from "@/lib/toast";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { import {

View File

@@ -9,6 +9,7 @@ import Link from "next/link";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { authClient } from "@/lib/auth-client"; import { authClient } from "@/lib/auth-client";
import { Toaster } from "@/components/ui/sonner";
const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!); const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);
@@ -36,6 +37,7 @@ export function Providers({
Link={Link} Link={Link}
> >
{children} {children}
<Toaster position="bottom-right" />
</AuthUIProvider> </AuthUIProvider>
</ConvexBetterAuthProvider> </ConvexBetterAuthProvider>
</ThemeProvider> </ThemeProvider>

View File

@@ -6,6 +6,7 @@ import { CircleCheckIcon, InfoIcon, TriangleAlertIcon, OctagonXIcon, Loader2Icon
const Toaster = ({ ...props }: ToasterProps) => { const Toaster = ({ ...props }: ToasterProps) => {
const { theme = "system" } = useTheme() const { theme = "system" } = useTheme()
const { toastOptions, ...restProps } = props
return ( return (
<Sonner <Sonner
@@ -37,11 +38,14 @@ const Toaster = ({ ...props }: ToasterProps) => {
} as React.CSSProperties } as React.CSSProperties
} }
toastOptions={{ toastOptions={{
...toastOptions,
classNames: { classNames: {
toast: "cn-toast", toast: "cn-toast",
error: "border-destructive",
...toastOptions?.classNames,
}, },
}} }}
{...props} {...restProps}
/> />
) )
} }

View File

@@ -7,6 +7,155 @@ import {
IMAGE_MODELS, IMAGE_MODELS,
} from "./openrouter"; } from "./openrouter";
const MAX_IMAGE_RETRIES = 2;
type ErrorCategory =
| "credits"
| "policy"
| "timeout"
| "transient"
| "provider"
| "unknown";
function errorMessage(error: unknown): string {
if (error instanceof Error) return error.message;
return String(error ?? "Generation failed");
}
function parseOpenRouterStatus(message: string): number | null {
const match = message.match(/OpenRouter API error\s+(\d+)/i);
if (!match) return null;
const parsed = Number(match[1]);
return Number.isFinite(parsed) ? parsed : null;
}
function categorizeError(error: unknown): {
category: ErrorCategory;
retryable: boolean;
} {
const message = errorMessage(error);
const lower = message.toLowerCase();
const status = parseOpenRouterStatus(message);
if (
lower.includes("insufficient credits") ||
lower.includes("daily generation limit") ||
lower.includes("concurrent job limit")
) {
return { category: "credits", retryable: false };
}
if (
lower.includes("modell lehnt ab") ||
lower.includes("content policy") ||
lower.includes("policy") ||
lower.includes("moderation") ||
lower.includes("safety") ||
lower.includes("refusal") ||
lower.includes("policy_violation")
) {
return { category: "policy", retryable: false };
}
if (status !== null) {
if (status >= 500 || status === 408 || status === 429 || status === 499) {
return { category: "provider", retryable: true };
}
if (status >= 400 && status < 500) {
return { category: "provider", retryable: false };
}
}
if (
lower.includes("timeout") ||
lower.includes("timed out") ||
lower.includes("deadline") ||
lower.includes("abort") ||
lower.includes("etimedout")
) {
return { category: "timeout", retryable: true };
}
if (
lower.includes("fetch failed") ||
lower.includes("network") ||
lower.includes("connection") ||
lower.includes("econnreset") ||
lower.includes("temporarily unavailable") ||
lower.includes("service unavailable") ||
lower.includes("rate limit") ||
lower.includes("overloaded")
) {
return { category: "transient", retryable: true };
}
return { category: "unknown", retryable: false };
}
function formatTerminalStatusMessage(error: unknown): string {
const message = errorMessage(error).trim() || "Generation failed";
const { category } = categorizeError(error);
const prefixByCategory: Record<Exclude<ErrorCategory, "unknown">, string> = {
credits: "Credits",
policy: "Policy",
timeout: "Timeout",
transient: "Netzwerk",
provider: "Provider",
};
if (category === "unknown") {
return message;
}
const prefix = prefixByCategory[category];
if (message.toLowerCase().startsWith(prefix.toLowerCase())) {
return message;
}
return `${prefix}: ${message}`;
}
function wait(ms: number) {
return new Promise<void>((resolve) => {
setTimeout(resolve, ms);
});
}
async function generateImageWithAutoRetry(
operation: () => Promise<Awaited<ReturnType<typeof generateImageViaOpenRouter>>>,
onRetry: (
retryCount: number,
maxRetries: number,
failure: { message: string; category: ErrorCategory }
) => Promise<void>
) {
let lastError: unknown = null;
for (let attempt = 0; attempt <= MAX_IMAGE_RETRIES; attempt++) {
try {
return await operation();
} catch (error) {
lastError = error;
const { retryable, category } = categorizeError(error);
const retryCount = attempt + 1;
const hasRemainingRetry = retryCount <= MAX_IMAGE_RETRIES;
if (!retryable || !hasRemainingRetry) {
throw error;
}
await onRetry(retryCount, MAX_IMAGE_RETRIES, {
message: errorMessage(error),
category,
});
await wait(Math.min(1500, 400 * retryCount));
}
}
throw lastError ?? new Error("Generation failed");
}
export const generateImage = action({ export const generateImage = action({
args: { args: {
canvasId: v.id("canvases"), canvasId: v.id("canvases"),
@@ -45,8 +194,11 @@ export const generateImage = action({
await ctx.runMutation(api.nodes.updateStatus, { await ctx.runMutation(api.nodes.updateStatus, {
nodeId: args.nodeId, nodeId: args.nodeId,
status: "executing", status: "executing",
retryCount: 0,
}); });
let retryCount = 0;
try { try {
let referenceImageUrl: string | undefined; let referenceImageUrl: string | undefined;
if (args.referenceStorageId) { if (args.referenceStorageId) {
@@ -54,12 +206,28 @@ export const generateImage = action({
(await ctx.storage.getUrl(args.referenceStorageId)) ?? undefined; (await ctx.storage.getUrl(args.referenceStorageId)) ?? undefined;
} }
const result = await generateImageViaOpenRouter(apiKey, { const result = await generateImageWithAutoRetry(
() =>
generateImageViaOpenRouter(apiKey, {
prompt: args.prompt, prompt: args.prompt,
referenceImageUrl, referenceImageUrl,
model: modelId, model: modelId,
aspectRatio: args.aspectRatio, aspectRatio: args.aspectRatio,
}),
async (nextRetryCount, maxRetries, failure) => {
retryCount = nextRetryCount;
const reason =
typeof failure.message === "string"
? failure.message
: "temporärer Fehler";
await ctx.runMutation(api.nodes.updateStatus, {
nodeId: args.nodeId,
status: "executing",
retryCount: nextRetryCount,
statusMessage: `Retry ${nextRetryCount}/${maxRetries}${reason}`,
}); });
}
);
const binaryString = atob(result.imageBase64); const binaryString = atob(result.imageBase64);
const bytes = new Uint8Array(binaryString.length); const bytes = new Uint8Array(binaryString.length);
@@ -97,6 +265,7 @@ export const generateImage = action({
await ctx.runMutation(api.nodes.updateStatus, { await ctx.runMutation(api.nodes.updateStatus, {
nodeId: args.nodeId, nodeId: args.nodeId,
status: "done", status: "done",
retryCount,
}); });
if (reservationId) { if (reservationId) {
@@ -115,8 +284,8 @@ export const generateImage = action({
await ctx.runMutation(api.nodes.updateStatus, { await ctx.runMutation(api.nodes.updateStatus, {
nodeId: args.nodeId, nodeId: args.nodeId,
status: "error", status: "error",
statusMessage: retryCount,
error instanceof Error ? error.message : "Generation failed", statusMessage: formatTerminalStatusMessage(error),
}); });
throw error; throw error;

View File

@@ -160,6 +160,7 @@ export const create = mutation({
width: args.width, width: args.width,
height: args.height, height: args.height,
status: "idle", status: "idle",
retryCount: 0,
data: args.data, data: args.data,
parentId: args.parentId, parentId: args.parentId,
zIndex: args.zIndex, zIndex: args.zIndex,
@@ -276,14 +277,19 @@ export const updateStatus = mutation({
v.literal("error") v.literal("error")
), ),
statusMessage: v.optional(v.string()), statusMessage: v.optional(v.string()),
retryCount: v.optional(v.number()),
}, },
handler: async (ctx, { nodeId, status, statusMessage }) => { handler: async (ctx, { nodeId, status, statusMessage, retryCount }) => {
const user = await requireAuth(ctx); const user = await requireAuth(ctx);
const node = await ctx.db.get(nodeId); const node = await ctx.db.get(nodeId);
if (!node) throw new Error("Node not found"); if (!node) throw new Error("Node not found");
await getCanvasOrThrow(ctx, node.canvasId, user.userId); await getCanvasOrThrow(ctx, node.canvasId, user.userId);
const patch: { status: typeof status; statusMessage?: string } = { const patch: {
status: typeof status;
statusMessage?: string;
retryCount?: number;
} = {
status, status,
}; };
if (statusMessage !== undefined) { if (statusMessage !== undefined) {
@@ -291,6 +297,9 @@ export const updateStatus = mutation({
} else if (status === "done" || status === "executing" || status === "idle") { } else if (status === "done" || status === "executing" || status === "idle") {
patch.statusMessage = undefined; patch.statusMessage = undefined;
} }
if (retryCount !== undefined) {
patch.retryCount = retryCount;
}
await ctx.db.patch(nodeId, patch); await ctx.db.patch(nodeId, patch);
}, },
}); });

View File

@@ -183,6 +183,7 @@ export default defineSchema({
// Node-Status (UX-Strategie: Status direkt am Node sichtbar) // Node-Status (UX-Strategie: Status direkt am Node sichtbar)
status: nodeStatus, status: nodeStatus,
statusMessage: v.optional(v.string()), // z.B. "Timeout — Credits nicht abgebucht" statusMessage: v.optional(v.string()), // z.B. "Timeout — Credits nicht abgebucht"
retryCount: v.optional(v.number()), // Anzahl bereits durchgeführter Retries
// Typ-spezifische Daten // Typ-spezifische Daten
// Convex empfiehlt v.any() für polymorphe data-Felder // Convex empfiehlt v.any() für polymorphe data-Felder
// Type Safety wird über den `type`-Discriminator + Zod im Frontend sichergestellt // Type Safety wird über den `type`-Discriminator + Zod im Frontend sichergestellt

296
lib/ai-errors.ts Normal file
View File

@@ -0,0 +1,296 @@
export type AiErrorCategory =
| "insufficient_credits"
| "rate_limited"
| "content_policy"
| "timeout"
| "network"
| "server"
| "invalid_request"
| "unknown";
export interface AiError {
category: AiErrorCategory;
message: string;
detail?: string;
retryable: boolean;
creditsNotCharged: boolean;
showTopUp: boolean;
retryCount?: number;
}
type RawErrorObject = {
message?: unknown;
detail?: unknown;
category?: unknown;
retryCount?: unknown;
};
const CATEGORY_ALIASES: Record<string, AiErrorCategory> = {
insufficient_credits: "insufficient_credits",
insufficientcredits: "insufficient_credits",
not_enough_credits: "insufficient_credits",
notenoughcredits: "insufficient_credits",
credits: "insufficient_credits",
payment_required: "insufficient_credits",
paymentrequired: "insufficient_credits",
rate_limit: "rate_limited",
ratelimit: "rate_limited",
rate_limited: "rate_limited",
ratelimited: "rate_limited",
too_many_requests: "rate_limited",
toomanyrequests: "rate_limited",
content_policy: "content_policy",
contentpolicy: "content_policy",
safety: "content_policy",
timeout: "timeout",
timed_out: "timeout",
timedout: "timeout",
network: "network",
connection: "network",
server: "server",
invalid_request: "invalid_request",
invalidrequest: "invalid_request",
bad_request: "invalid_request",
badrequest: "invalid_request",
};
function normalizeCategory(value: string | undefined): AiErrorCategory | undefined {
if (!value) return undefined;
const normalized = value.toLowerCase().replace(/[^a-z]/g, "");
return CATEGORY_ALIASES[normalized];
}
function extractRetryCount(rawText: string, rawObj: RawErrorObject | null): number | undefined {
if (typeof rawObj?.retryCount === "number" && Number.isFinite(rawObj.retryCount)) {
return rawObj.retryCount;
}
const retryCountMatch = rawText.match(/retry(?:_?count)?\s*[:=]\s*(\d{1,3})/i);
if (retryCountMatch?.[1]) {
return Number.parseInt(retryCountMatch[1], 10);
}
const attemptMatch = rawText.match(/(?:attempt|retry)\s*#?\s*(\d{1,3})/i);
if (attemptMatch?.[1]) {
return Number.parseInt(attemptMatch[1], 10);
}
return undefined;
}
function cleanPrefixMessage(text: string): { category?: AiErrorCategory; message: string } {
const trimmed = text.trim();
const bracketPrefix = trimmed.match(/^\[([a-zA-Z_\- ]+)\]\s*[:\-]?\s*(.+)$/);
if (bracketPrefix?.[1] && bracketPrefix[2]) {
const category = normalizeCategory(bracketPrefix[1]);
if (category) {
return {
category,
message: bracketPrefix[2].trim(),
};
}
}
const plainPrefix = trimmed.match(/^([a-zA-Z_\- ]{3,40})\s*[:|\-]\s*(.+)$/);
if (plainPrefix?.[1] && plainPrefix[2]) {
const category = normalizeCategory(plainPrefix[1]);
if (category) {
return {
category,
message: plainPrefix[2].trim(),
};
}
}
return { message: trimmed };
}
function splitMessageAndDetail(message: string): { message: string; detail?: string } {
const separators = [" — ", " - ", "\n"];
for (const separator of separators) {
const index = message.indexOf(separator);
if (index <= 0) continue;
const lead = message.slice(0, index).trim();
const tail = message.slice(index + separator.length).trim();
if (lead && tail) {
return { message: lead, detail: tail };
}
}
return { message };
}
function inferCategoryFromText(text: string): AiErrorCategory {
const lower = text.toLowerCase();
const openRouterStatus = lower.match(/openrouter api error\s*(\d{3})/i);
if (openRouterStatus?.[1]) {
const status = Number.parseInt(openRouterStatus[1], 10);
if (status === 402) return "insufficient_credits";
if (status === 408 || status === 504) return "timeout";
if (status === 429) return "rate_limited";
if (status >= 500) return "server";
if (status >= 400) return "invalid_request";
}
if (
lower.includes("insufficient credits") ||
lower.includes("not enough credits") ||
lower.includes("credit balance") ||
lower.includes("guthaben") ||
lower.includes("nicht genug credits")
) {
return "insufficient_credits";
}
if (
lower.includes("too many requests") ||
lower.includes("rate limit") ||
lower.includes("ratelimit") ||
lower.includes("429")
) {
return "rate_limited";
}
if (
lower.includes("timeout") ||
lower.includes("timed out") ||
lower.includes("deadline exceeded")
) {
return "timeout";
}
if (
lower.includes("network") ||
lower.includes("connection") ||
lower.includes("fetch failed") ||
lower.includes("econn")
) {
return "network";
}
if (
lower.includes("policy") ||
lower.includes("safety") ||
lower.includes("refusal") ||
lower.includes("modell lehnt ab")
) {
return "content_policy";
}
if (
lower.includes("invalid") ||
lower.includes("bad request") ||
lower.includes("unknown model") ||
lower.includes("missing")
) {
return "invalid_request";
}
if (lower.includes("server") || lower.includes("5xx")) {
return "server";
}
return "unknown";
}
function defaultsForCategory(category: AiErrorCategory): Omit<AiError, "category" | "detail" | "retryCount"> {
switch (category) {
case "insufficient_credits":
return {
message: "Not enough credits for this generation",
retryable: false,
creditsNotCharged: true,
showTopUp: true,
};
case "rate_limited":
return {
message: "The model is busy right now",
retryable: true,
creditsNotCharged: true,
showTopUp: false,
};
case "content_policy":
return {
message: "The request was blocked by model safety rules",
retryable: false,
creditsNotCharged: true,
showTopUp: false,
};
case "timeout":
return {
message: "The generation timed out",
retryable: true,
creditsNotCharged: true,
showTopUp: false,
};
case "network":
return {
message: "Network issue while contacting the model",
retryable: true,
creditsNotCharged: true,
showTopUp: false,
};
case "server":
return {
message: "The AI service returned a server error",
retryable: true,
creditsNotCharged: true,
showTopUp: false,
};
case "invalid_request":
return {
message: "The request could not be processed",
retryable: false,
creditsNotCharged: true,
showTopUp: false,
};
case "unknown":
default:
return {
message: "Generation failed",
retryable: true,
creditsNotCharged: true,
showTopUp: false,
};
}
}
export function classifyError(rawError: unknown): AiError {
const rawObj: RawErrorObject | null =
rawError != null && typeof rawError === "object"
? (rawError as RawErrorObject)
: null;
const rawMessage =
typeof rawError === "string"
? rawError
: rawError instanceof Error
? rawError.message
: typeof rawObj?.message === "string"
? rawObj.message
: "";
const rawDetail = typeof rawObj?.detail === "string" ? rawObj.detail.trim() : undefined;
const prefixed = cleanPrefixMessage(rawMessage);
const explicitCategory =
normalizeCategory(typeof rawObj?.category === "string" ? rawObj.category : undefined) ??
prefixed.category;
const category = explicitCategory ?? inferCategoryFromText(prefixed.message);
const defaults = defaultsForCategory(category);
const split = splitMessageAndDetail(prefixed.message);
const message = split.message || defaults.message;
return {
category,
message,
detail: split.detail ?? rawDetail,
retryable: defaults.retryable,
creditsNotCharged: defaults.creditsNotCharged,
showTopUp: defaults.showTopUp,
retryCount: extractRetryCount(rawMessage, rawObj),
};
}

View File

@@ -17,6 +17,7 @@ export function convexNodeToRF(node: Doc<"nodes">): RFNode {
// Status direkt in data durchreichen, damit Node-Komponenten darauf zugreifen können // Status direkt in data durchreichen, damit Node-Komponenten darauf zugreifen können
_status: node.status, _status: node.status,
_statusMessage: node.statusMessage, _statusMessage: node.statusMessage,
retryCount: node.retryCount,
}, },
parentId: node.parentId ?? undefined, parentId: node.parentId ?? undefined,
zIndex: node.zIndex, zIndex: node.zIndex,

82
lib/toast.ts Normal file
View File

@@ -0,0 +1,82 @@
import type { ReactNode } from "react"
import { isValidElement } from "react"
import { toast as sonnerToast, type ExternalToast } from "sonner"
const SUCCESS_DURATION = 4000
const ERROR_DURATION = 6000
type SonnerPromiseInput<T> = Parameters<typeof sonnerToast.promise<T>>[0]
type SonnerPromiseOptions<T> = Parameters<typeof sonnerToast.promise<T>>[1]
type SonnerPromiseData<T> = NonNullable<SonnerPromiseOptions<T>>
function hasMessage(
value: unknown,
): value is {
message: ReactNode
duration?: number
} {
return (
typeof value === "object" &&
value !== null &&
!isValidElement(value) &&
"message" in value
)
}
function withStateDuration<T>(state: unknown, duration: number): unknown {
if (state === undefined) {
return undefined
}
if (typeof state === "function") {
return async (value: T) => {
const result = await state(value)
return withStateDuration(result, duration)
}
}
if (hasMessage(state)) {
return {
...state,
duration: state.duration ?? duration,
}
}
return {
message: state as ReactNode,
duration,
}
}
export const toast = {
success(message: ReactNode, options?: ExternalToast) {
return sonnerToast.success(message, {
...options,
duration: options?.duration ?? SUCCESS_DURATION,
})
},
error(message: ReactNode, options?: ExternalToast) {
return sonnerToast.error(message, {
...options,
duration: options?.duration ?? ERROR_DURATION,
})
},
loading(message: ReactNode, options?: ExternalToast) {
return sonnerToast.loading(message, options)
},
dismiss(id?: number | string) {
return sonnerToast.dismiss(id)
},
promise<T>(promise: SonnerPromiseInput<T>, options?: SonnerPromiseOptions<T>) {
return sonnerToast.promise(promise, {
...options,
success: withStateDuration<T>(options?.success, SUCCESS_DURATION) as SonnerPromiseData<T>["success"],
error: withStateDuration<T>(options?.error, ERROR_DURATION) as SonnerPromiseData<T>["error"],
})
},
}
export const toastDuration = {
success: SUCCESS_DURATION,
error: ERROR_DURATION,
} as const