owenkaplinsky commited on
Commit
f53803f
·
1 Parent(s): d2d911c

Add parenthesis warning

Browse files
Files changed (3) hide show
  1. project/blocks.txt +1 -1
  2. project/chat.py +67 -24
  3. project/src/index.js +0 -74
project/blocks.txt CHANGED
@@ -28,7 +28,7 @@ VALUE: math_single(inputs(OP: "ROOT/ABS/NEG/LN/LOG10/EXP/POW10", NUM: value)) //
28
  VALUE: math_number_property(inputs(PROPERTY: "EVEN/ODD/PRIME/WHOLE/POSITIVE/NEGATIVE", NUMBER_TO_CHECK: value)) // Boolean output
29
  VALUE: math_round(inputs(OP: "ROUND/ROUNDUP/ROUNDDOWN", NUM: value))
30
  VALUE: math_modulo(inputs(DIVIDEND: value, DIVISOR: value))
31
- VALUE: math_constrain(VALUE: value, LOW: value, HIGH: value)
32
  VALUE: math_random_int(inputs(FROM: value, TO: value))
33
 
34
  # Text
 
28
  VALUE: math_number_property(inputs(PROPERTY: "EVEN/ODD/PRIME/WHOLE/POSITIVE/NEGATIVE", NUMBER_TO_CHECK: value)) // Boolean output
29
  VALUE: math_round(inputs(OP: "ROUND/ROUNDUP/ROUNDDOWN", NUM: value))
30
  VALUE: math_modulo(inputs(DIVIDEND: value, DIVISOR: value))
31
+ VALUE: math_constrain(inputs(VALUE: value, LOW: value, HIGH: value))
32
  VALUE: math_random_int(inputs(FROM: value, TO: value))
33
 
34
  # Text
project/chat.py CHANGED
@@ -786,7 +786,9 @@ def create_gradio_interface():
786
 
787
  4. **Check the create_mcp block state:** Before using `type: "input"` and `input_name: "name"`, verify that the create_mcp block has outputs defined in the workspace state. If you do not see `outputs(...)` in the create_mcp block, do NOT use these parameters.
788
 
789
- 5. Perform the actions in order without asking for approval or asking to wait for intermediate results."""
 
 
790
  tools = [
791
  {
792
  "type": "function",
@@ -1093,31 +1095,72 @@ def create_gradio_interface():
1093
  placement_type = function_args.get("type", None)
1094
  input_name = function_args.get("input_name", None)
1095
 
1096
- # Check if this is the first MCP output block creation attempt
1097
- is_first_output_attempt = (
1098
- not first_output_block_attempted and
1099
- placement_type == "input" and
1100
- input_name and
1101
- input_name.startswith("R")
1102
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1103
 
1104
- if is_first_output_attempt:
1105
- # Mark that we've attempted an output block in this conversation
1106
- first_output_block_attempted = True
1107
- # Return warning instead of creating the block
1108
- tool_result = "[TOOL] Automated warning: Make sure your output block contains the full and entire value needed. Block placement was **not** executed. Retry with the full command needed in one go."
1109
- result_label = "Output Block Warning"
1110
- print(Fore.YELLOW + f"[FIRST OUTPUT BLOCK] Intercepted first output block attempt with command `{command}`." + Style.RESET_ALL)
1111
- else:
1112
- # Normal block creation
1113
- if blockID is None:
1114
- print(Fore.YELLOW + f"Agent created block with command `{command}`." + Style.RESET_ALL)
 
 
 
1115
  else:
1116
- print(Fore.YELLOW + f"Agent created block with command `{command}`, type: {placement_type}, blockID: `{blockID}`." + Style.RESET_ALL)
1117
- if input_name:
1118
- print(Fore.YELLOW + f" Input name: {input_name}" + Style.RESET_ALL)
1119
- tool_result = create_block(command, blockID, placement_type, input_name)
1120
- result_label = "Create Operation"
 
 
 
 
1121
 
1122
  elif function_name == "create_variable":
1123
  name = function_args.get("name", "")
 
786
 
787
  4. **Check the create_mcp block state:** Before using `type: "input"` and `input_name: "name"`, verify that the create_mcp block has outputs defined in the workspace state. If you do not see `outputs(...)` in the create_mcp block, do NOT use these parameters.
788
 
789
+ 5. Perform the actions in order without asking for approval or asking to wait for intermediate results.
790
+
791
+ 6. Before stopping, you must confirm that every single output slot of the MCP block is filled. You must explicitly confirm this and if not all output slots are filled in, you must do so immediately."""
792
  tools = [
793
  {
794
  "type": "function",
 
1095
  placement_type = function_args.get("type", None)
1096
  input_name = function_args.get("input_name", None)
1097
 
1098
+ # Validate that parentheses are balanced, ignoring ones in strings
1099
+ # Allow leniency: auto-add up to 1 missing closing parenthesis
1100
+ command_stripped = command.strip()
1101
+ open_parens = 0
1102
+ close_parens = 0
1103
+ in_string = False
1104
+ string_char = ''
1105
+ i = 0
1106
+ while i < len(command_stripped):
1107
+ char = command_stripped[i]
1108
+ # Handle string escaping
1109
+ if char in ('"', "'") and (i == 0 or command_stripped[i-1] != '\\'):
1110
+ if not in_string:
1111
+ in_string = True
1112
+ string_char = char
1113
+ elif char == string_char:
1114
+ in_string = False
1115
+ # Count parentheses only outside of strings
1116
+ elif not in_string:
1117
+ if char == '(':
1118
+ open_parens += 1
1119
+ elif char == ')':
1120
+ close_parens += 1
1121
+ i += 1
1122
+
1123
+ paren_diff = open_parens - close_parens
1124
+ if paren_diff == 1:
1125
+ # Auto-fix: add one closing parenthesis
1126
+ command = command_stripped + ')'
1127
+ print(Fore.YELLOW + f"[LENIENCY] Auto-fixed 1 missing closing parenthesis." + Style.RESET_ALL)
1128
+ # Continue with block creation below
1129
+ tool_result = None
1130
+ result_label = ""
1131
+ elif paren_diff > 1:
1132
+ tool_result = f"[ERROR] Malformatted command: Too many unbalanced parentheses ({paren_diff} missing). The attempted command was:\n\n`{command_stripped}`\n\nPlease retry with properly balanced parentheses."
1133
+ result_label = "Command Format Error"
1134
+ print(Fore.RED + f"[VALIDATION ERROR] Unbalanced parentheses: {open_parens} open, {close_parens} close." + Style.RESET_ALL)
1135
+ elif paren_diff < 0:
1136
+ tool_result = f"[ERROR] Malformatted command: Too many closing parentheses ({-paren_diff} extra). The attempted command was:\n\n`{command_stripped}`\n\nPlease retry with properly balanced parentheses."
1137
+ result_label = "Command Format Error"
1138
+ print(Fore.RED + f"[VALIDATION ERROR] Unbalanced parentheses: {open_parens} open, {close_parens} close." + Style.RESET_ALL)
1139
 
1140
+ # Only proceed if validation passed (no error was set)
1141
+ if tool_result is None:
1142
+ # Check if this is the first MCP output block creation attempt
1143
+ if (not first_output_block_attempted and
1144
+ placement_type == "input" and
1145
+ input_name and
1146
+ input_name.startswith("R")):
1147
+ is_first_output_attempt = True
1148
+ # Mark that we've attempted an output block in this conversation
1149
+ first_output_block_attempted = True
1150
+ # Return warning instead of creating the block
1151
+ tool_result = "[TOOL] Automated warning: Make sure your output block contains the full and entire value needed. Block placement was **not** executed. Retry with the full command needed in one go."
1152
+ result_label = "Output Block Warning"
1153
+ print(Fore.YELLOW + f"[FIRST OUTPUT BLOCK] Intercepted first output block attempt with command `{command}`." + Style.RESET_ALL)
1154
  else:
1155
+ # Normal block creation
1156
+ if blockID is None:
1157
+ print(Fore.YELLOW + f"Agent created block with command `{command}`." + Style.RESET_ALL)
1158
+ else:
1159
+ print(Fore.YELLOW + f"Agent created block with command `{command}`, type: {placement_type}, blockID: `{blockID}`." + Style.RESET_ALL)
1160
+ if input_name:
1161
+ print(Fore.YELLOW + f" Input name: {input_name}" + Style.RESET_ALL)
1162
+ tool_result = create_block(command, blockID, placement_type, input_name)
1163
+ result_label = "Create Operation"
1164
 
1165
  elif function_name == "create_variable":
1166
  name = function_args.get("name", "")
project/src/index.js CHANGED
@@ -503,80 +503,6 @@ const setupUnifiedStream = () => {
503
 
504
  console.log('[SSE CREATE] inputsContent to parse:', inputsContent);
505
 
506
- // VALIDATION: Check for malformed input - if inputsContent contains unmatched parentheses
507
- // If there are missing closing parentheses (1-2), automatically add them
508
- let validateParenCount = 0;
509
- let validateQuotes = false;
510
- let validateQuoteChar = '';
511
- for (let i = 0; i < inputsContent.length; i++) {
512
- const char = inputsContent[i];
513
- if ((char === '"' || char === "'") && (i === 0 || inputsContent[i - 1] !== '\\')) {
514
- if (!validateQuotes) {
515
- validateQuotes = true;
516
- validateQuoteChar = char;
517
- } else if (char === validateQuoteChar) {
518
- validateQuotes = false;
519
- }
520
- }
521
- if (!validateQuotes) {
522
- if (char === '(') validateParenCount++;
523
- else if (char === ')') validateParenCount--;
524
- }
525
- }
526
-
527
- // If parentheses are unbalanced, try to fix by adding closing parentheses
528
- if (validateParenCount > 0) {
529
- if (validateParenCount <= 2) {
530
- console.log(`[SSE CREATE] Auto-fixing ${validateParenCount} missing closing parentheses in block '${blockType}'`);
531
-
532
- // Smart insertion: find the best place to insert closing parentheses
533
- // Look for the last comma at depth 0 (which separates key-value pairs)
534
- let bestInsertPos = inputsContent.length; // Default to end
535
- let depth = 0;
536
- let inQuotes = false;
537
- let quoteChar = '';
538
-
539
- for (let i = inputsContent.length - 1; i >= 0; i--) {
540
- const char = inputsContent[i];
541
-
542
- // Handle quotes (from right to left)
543
- if ((char === '"' || char === "'") && (i === 0 || inputsContent[i - 1] !== '\\')) {
544
- if (!inQuotes) {
545
- inQuotes = true;
546
- quoteChar = char;
547
- } else if (char === quoteChar) {
548
- inQuotes = false;
549
- }
550
- }
551
-
552
- // Handle parentheses (from right to left, so reverse the logic)
553
- if (!inQuotes) {
554
- if (char === ')') depth++;
555
- else if (char === '(') depth--;
556
- }
557
-
558
- // Found the last comma at depth 0 - this separates the last nested block from following keys
559
- if (char === ',' && depth === 0 && !inQuotes) {
560
- bestInsertPos = i;
561
- break;
562
- }
563
- }
564
-
565
- // Insert the closing parentheses at the best position
566
- if (bestInsertPos < inputsContent.length && inputsContent[bestInsertPos] === ',') {
567
- // Insert right before the comma
568
- inputsContent = inputsContent.slice(0, bestInsertPos) + ')'.repeat(validateParenCount) + inputsContent.slice(bestInsertPos);
569
- } else {
570
- // Fallback: insert at end
571
- inputsContent += ')'.repeat(validateParenCount);
572
- }
573
- } else {
574
- throw new Error(`Malformed block specification for '${blockType}': too many unmatched opening parentheses (${validateParenCount}). This usually means a nested block specification is malformed. Received: ${inputsContent}`);
575
- }
576
- } else if (validateParenCount < 0) {
577
- throw new Error(`Malformed block specification for '${blockType}': more closing parentheses than opening. Received: ${inputsContent}`);
578
- }
579
-
580
  // VALIDATION: Check if trying to place a value block under a statement block
581
  // Value blocks have an output connection but no previous connection
582
  if (placementType === 'under') {
 
503
 
504
  console.log('[SSE CREATE] inputsContent to parse:', inputsContent);
505
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
506
  // VALIDATION: Check if trying to place a value block under a statement block
507
  // Value blocks have an output connection but no previous connection
508
  if (placementType === 'under') {