Spaces:
Running
Running
owenkaplinsky
commited on
Commit
·
f53803f
1
Parent(s):
d2d911c
Add parenthesis warning
Browse files- project/blocks.txt +1 -1
- project/chat.py +67 -24
- 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 |
-
#
|
| 1097 |
-
|
| 1098 |
-
|
| 1099 |
-
|
| 1100 |
-
|
| 1101 |
-
|
| 1102 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1103 |
|
| 1104 |
-
if
|
| 1105 |
-
|
| 1106 |
-
|
| 1107 |
-
|
| 1108 |
-
|
| 1109 |
-
|
| 1110 |
-
|
| 1111 |
-
|
| 1112 |
-
|
| 1113 |
-
|
| 1114 |
-
|
|
|
|
|
|
|
|
|
|
| 1115 |
else:
|
| 1116 |
-
|
| 1117 |
-
|
| 1118 |
-
|
| 1119 |
-
|
| 1120 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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') {
|