Spaces:
Running
Running
owenkaplinsky
commited on
Commit
·
c0bd4ef
1
Parent(s):
59cfebc
Fix bug; improve prompt
Browse files- project/chat.py +112 -108
- project/src/index.js +27 -17
project/chat.py
CHANGED
|
@@ -135,13 +135,13 @@ def delete_block(block_id):
|
|
| 135 |
traceback.print_exc()
|
| 136 |
return f"Error deleting block: {str(e)}"
|
| 137 |
|
| 138 |
-
def create_block(block_spec,
|
| 139 |
try:
|
| 140 |
print(f"[CREATE REQUEST] Attempting to create block: {block_spec}")
|
| 141 |
-
if
|
| 142 |
-
print(f"[CREATE REQUEST]
|
| 143 |
if input_name:
|
| 144 |
-
print(f"[CREATE REQUEST]
|
| 145 |
|
| 146 |
# Generate a unique request ID
|
| 147 |
import uuid
|
|
@@ -151,10 +151,12 @@ def create_block(block_spec, under_block_id=None, input_name=None):
|
|
| 151 |
if request_id in creation_results:
|
| 152 |
creation_results.pop(request_id)
|
| 153 |
|
| 154 |
-
# Add to creation queue with optional
|
| 155 |
queue_data = {"request_id": request_id, "block_spec": block_spec}
|
| 156 |
-
if
|
| 157 |
-
queue_data["
|
|
|
|
|
|
|
| 158 |
if input_name:
|
| 159 |
queue_data["input_name"] = input_name
|
| 160 |
creation_queue.put(queue_data)
|
|
@@ -169,11 +171,11 @@ def create_block(block_spec, under_block_id=None, input_name=None):
|
|
| 169 |
while time.time() - start_time < timeout:
|
| 170 |
if request_id in creation_results:
|
| 171 |
result = creation_results.pop(request_id)
|
| 172 |
-
print(f"[CREATE RESULT] Received result for {request_id}: success={result.get('success')}, error={result.get('error')}")
|
| 173 |
if result["success"]:
|
| 174 |
return f"[TOOL] Successfully created block: {result.get('block_id', 'unknown')}"
|
| 175 |
else:
|
| 176 |
-
|
|
|
|
| 177 |
time.sleep(check_interval)
|
| 178 |
|
| 179 |
print(f"[CREATE TIMEOUT] No response received for request {request_id} after {timeout} seconds")
|
|
@@ -296,7 +298,6 @@ async def unified_stream():
|
|
| 296 |
if request_key not in sent_requests:
|
| 297 |
sent_requests.add(request_key)
|
| 298 |
deletion_request["type"] = "delete" # Add type identifier
|
| 299 |
-
print(f"[SSE SEND] Sending deletion request for block: {block_id}")
|
| 300 |
yield f"data: {json.dumps(deletion_request)}\n\n"
|
| 301 |
|
| 302 |
# Clear from sent_requests after 10 seconds
|
|
@@ -314,7 +315,6 @@ async def unified_stream():
|
|
| 314 |
if request_key not in sent_requests:
|
| 315 |
sent_requests.add(request_key)
|
| 316 |
creation_request["type"] = "create" # Add type identifier
|
| 317 |
-
print(f"[SSE SEND] Sending creation request with ID: {request_id}")
|
| 318 |
yield f"data: {json.dumps(creation_request)}\n\n"
|
| 319 |
|
| 320 |
# Clear from sent_requests after 10 seconds
|
|
@@ -332,7 +332,6 @@ async def unified_stream():
|
|
| 332 |
if request_key not in sent_requests:
|
| 333 |
sent_requests.add(request_key)
|
| 334 |
variable_request["type"] = "variable" # Add type identifier
|
| 335 |
-
print(f"[SSE SEND] Sending variable creation request with ID: {request_id}")
|
| 336 |
yield f"data: {json.dumps(variable_request)}\n\n"
|
| 337 |
|
| 338 |
# Clear from sent_requests after 10 seconds
|
|
@@ -350,7 +349,6 @@ async def unified_stream():
|
|
| 350 |
if request_key not in sent_requests:
|
| 351 |
sent_requests.add(request_key)
|
| 352 |
edit_request["type"] = "edit_mcp" # Add type identifier
|
| 353 |
-
print(f"[SSE SEND] Sending edit MCP request with ID: {request_id}")
|
| 354 |
yield f"data: {json.dumps(edit_request)}\n\n"
|
| 355 |
|
| 356 |
# Clear from sent_requests after 10 seconds
|
|
@@ -387,16 +385,10 @@ async def unified_stream():
|
|
| 387 |
async def creation_result(request: Request):
|
| 388 |
data = await request.json()
|
| 389 |
request_id = data.get("request_id")
|
| 390 |
-
|
| 391 |
-
error = data.get("error")
|
| 392 |
-
block_id = data.get("block_id")
|
| 393 |
-
|
| 394 |
-
print(f"[CREATION RESULT RECEIVED] request_id={request_id}, success={success}, error={error}, block_id={block_id}")
|
| 395 |
-
|
| 396 |
if request_id:
|
| 397 |
# Store the result for the create_block function to retrieve
|
| 398 |
creation_results[request_id] = data
|
| 399 |
-
print(f"[CREATION RESULT STORED] Results dict now has {len(creation_results)} items")
|
| 400 |
|
| 401 |
return {"received": True}
|
| 402 |
|
|
@@ -443,12 +435,9 @@ async def edit_mcp_result(request: Request):
|
|
| 443 |
success = data.get("success")
|
| 444 |
error = data.get("error")
|
| 445 |
|
| 446 |
-
print(f"[EDIT MCP RESULT RECEIVED] request_id={request_id}, success={success}, error={error}")
|
| 447 |
-
|
| 448 |
if request_id:
|
| 449 |
# Store the result for the edit_mcp function to retrieve
|
| 450 |
edit_mcp_results[request_id] = data
|
| 451 |
-
print(f"[EDIT MCP RESULT STORED] Results dict now has {len(edit_mcp_results)} items")
|
| 452 |
|
| 453 |
return {"received": True}
|
| 454 |
|
|
@@ -564,17 +553,16 @@ def create_gradio_interface():
|
|
| 564 |
# Hardcoded system prompt
|
| 565 |
|
| 566 |
SYSTEM_PROMPT = f"""You are an AI assistant that helps users build **MCP servers** using Blockly blocks.
|
| 567 |
-
MCP lets AI systems define tools with specific inputs and outputs that any LLM can call.
|
| 568 |
|
| 569 |
You'll receive the workspace state in this format:
|
| 570 |
`blockId | block_name(inputs(input_name: value))`
|
| 571 |
|
| 572 |
-
|
|
|
|
|
|
|
|
|
|
| 573 |
- `create_mcp` and `func_def` use `blockId | block_name(inputs(input_name: type), outputs(output_name: value))`
|
| 574 |
- Indentation or nesting shows logic hierarchy (like loops or conditionals).
|
| 575 |
-
|
| 576 |
-
Note that the `blockId` before the pipe `|` is each block's unique identifier. The ID can have a | in it. But,
|
| 577 |
-
the real separator will always have a space before and after it.
|
| 578 |
|
| 579 |
---
|
| 580 |
|
|
@@ -613,52 +601,53 @@ def create_gradio_interface():
|
|
| 613 |
|
| 614 |
{blocks_context}
|
| 615 |
|
| 616 |
-
You
|
| 617 |
-
You cannot create a `create_mcp` block, but you may edit its inputs using the dedicated tool.
|
| 618 |
-
|
| 619 |
-
### Placing Blocks in MCP Inputs
|
| 620 |
-
You can place blocks directly into the MCP block's inputs using the `input` parameter:
|
| 621 |
-
- Use `input: "X0"`, `input: "X1"`, etc. to place a block into an input slot
|
| 622 |
-
- Use `input: "R0"`, `input: "R1"`, etc. to place a block into an output slot
|
| 623 |
-
- **This feature can ONLY be used with the MCP block** - you cannot place blocks into inputs of other blocks this way
|
| 624 |
-
- The block will replace whatever is currently in that input
|
| 625 |
-
|
| 626 |
-
Example: Create a text block and put it in the MCP's first input:
|
| 627 |
-
`text(inputs(TEXT: "hello"))` with `input: "X0"`
|
| 628 |
|
| 629 |
-
|
| 630 |
-
|
| 631 |
-
|
| 632 |
-
|
| 633 |
-
-
|
| 634 |
-
|
| 635 |
-
|
| 636 |
-
|
| 637 |
-
-
|
| 638 |
-
-
|
| 639 |
-
-
|
| 640 |
-
- If the parent block ID is not yet available, wait and do not create the child.
|
| 641 |
-
|
| 642 |
-
2. **Value-level nesting (output blocks)**
|
| 643 |
-
These produce values and must be nested inside another block's input.
|
| 644 |
-
They must be fully nested in a *single* create call.
|
| 645 |
-
Example:
|
| 646 |
-
`math_arithmetic(inputs(A: math_number(inputs(NUM: 1)), B: math_number(inputs(NUM: 1))))`
|
| 647 |
-
|
| 648 |
-
Rules for all value blocks:
|
| 649 |
-
- No raw strings, numbers, booleans, or values.
|
| 650 |
-
- Strings must use a `text` block.
|
| 651 |
-
- Numbers must use `math_number`.
|
| 652 |
-
- Any value input must contain a block, never a raw value.
|
| 653 |
-
|
| 654 |
-
For blocks with infinite inputs (...N), inputs may be omitted.
|
| 655 |
|
| 656 |
-
|
| 657 |
|
| 658 |
-
|
| 659 |
-
|
| 660 |
-
-
|
| 661 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 662 |
|
| 663 |
You may NEVER create functions. You must only use code inside the MCP block itself.
|
| 664 |
|
|
@@ -681,40 +670,52 @@ def create_gradio_interface():
|
|
| 681 |
|
| 682 |
---
|
| 683 |
|
| 684 |
-
|
| 685 |
|
| 686 |
-
|
| 687 |
|
| 688 |
-
|
| 689 |
|
| 690 |
-
|
| 691 |
|
| 692 |
-
|
| 693 |
-
- Identify required inputs
|
| 694 |
-
- Identify required outputs
|
| 695 |
-
- Identify intermediate computations
|
| 696 |
-
- Identify loops, conditionals, and sub-logic
|
| 697 |
|
| 698 |
-
|
| 699 |
-
Include:
|
| 700 |
-
- Required block types
|
| 701 |
-
- Which blocks are top-level
|
| 702 |
-
- Which blocks must be nested
|
| 703 |
-
- Which must be created via single-call value nesting
|
| 704 |
-
- The order of tool calls
|
| 705 |
-
- Where each block will be placed
|
| 706 |
|
| 707 |
-
|
|
|
|
|
|
|
| 708 |
|
| 709 |
-
|
|
|
|
|
|
|
|
|
|
| 710 |
|
| 711 |
-
|
| 712 |
|
| 713 |
-
|
|
|
|
|
|
|
|
|
|
| 714 |
|
| 715 |
---
|
| 716 |
|
| 717 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 718 |
"""
|
| 719 |
|
| 720 |
tools = [
|
|
@@ -744,13 +745,18 @@ def create_gradio_interface():
|
|
| 744 |
"type": "string",
|
| 745 |
"description": "The create block command using the custom DSL format.",
|
| 746 |
},
|
| 747 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 748 |
"type": "string",
|
| 749 |
-
"
|
|
|
|
| 750 |
},
|
| 751 |
-
"
|
| 752 |
"type": "string",
|
| 753 |
-
"description": "
|
| 754 |
},
|
| 755 |
},
|
| 756 |
"required": ["command"],
|
|
@@ -850,9 +856,6 @@ def create_gradio_interface():
|
|
| 850 |
input_items.append({"role": "user", "content": human})
|
| 851 |
input_items.append({"role": "assistant", "content": ai})
|
| 852 |
|
| 853 |
-
# Debug
|
| 854 |
-
print(f"[DEBUG] Context received: {context if context else 'No context available'}")
|
| 855 |
-
|
| 856 |
# Build instructions
|
| 857 |
instructions = SYSTEM_PROMPT
|
| 858 |
if context:
|
|
@@ -1009,15 +1012,16 @@ def create_gradio_interface():
|
|
| 1009 |
|
| 1010 |
elif function_name == "create_block":
|
| 1011 |
command = function_args.get("command", "")
|
| 1012 |
-
|
| 1013 |
-
|
| 1014 |
-
|
|
|
|
| 1015 |
print(Fore.YELLOW + f"Agent created block with command `{command}`." + Style.RESET_ALL)
|
| 1016 |
-
|
| 1017 |
-
print(Fore.YELLOW + f"Agent created block with command `{command}`,
|
| 1018 |
-
|
| 1019 |
-
print(Fore.YELLOW + f"
|
| 1020 |
-
tool_result = create_block(command,
|
| 1021 |
result_label = "Create Operation"
|
| 1022 |
|
| 1023 |
elif function_name == "create_variable":
|
|
|
|
| 135 |
traceback.print_exc()
|
| 136 |
return f"Error deleting block: {str(e)}"
|
| 137 |
|
| 138 |
+
def create_block(block_spec, blockID=None, placement_type=None, input_name=None):
|
| 139 |
try:
|
| 140 |
print(f"[CREATE REQUEST] Attempting to create block: {block_spec}")
|
| 141 |
+
if blockID:
|
| 142 |
+
print(f"[CREATE REQUEST] Placement type: {placement_type}, block ID: {blockID}")
|
| 143 |
if input_name:
|
| 144 |
+
print(f"[CREATE REQUEST] Input name: {input_name}")
|
| 145 |
|
| 146 |
# Generate a unique request ID
|
| 147 |
import uuid
|
|
|
|
| 151 |
if request_id in creation_results:
|
| 152 |
creation_results.pop(request_id)
|
| 153 |
|
| 154 |
+
# Add to creation queue with optional blockID, placement_type, and input_name
|
| 155 |
queue_data = {"request_id": request_id, "block_spec": block_spec}
|
| 156 |
+
if blockID:
|
| 157 |
+
queue_data["blockID"] = blockID
|
| 158 |
+
if placement_type:
|
| 159 |
+
queue_data["placement_type"] = placement_type
|
| 160 |
if input_name:
|
| 161 |
queue_data["input_name"] = input_name
|
| 162 |
creation_queue.put(queue_data)
|
|
|
|
| 171 |
while time.time() - start_time < timeout:
|
| 172 |
if request_id in creation_results:
|
| 173 |
result = creation_results.pop(request_id)
|
|
|
|
| 174 |
if result["success"]:
|
| 175 |
return f"[TOOL] Successfully created block: {result.get('block_id', 'unknown')}"
|
| 176 |
else:
|
| 177 |
+
error_msg = result.get('error') or 'Unknown error'
|
| 178 |
+
return f"[TOOL] Failed to create block: {error_msg}"
|
| 179 |
time.sleep(check_interval)
|
| 180 |
|
| 181 |
print(f"[CREATE TIMEOUT] No response received for request {request_id} after {timeout} seconds")
|
|
|
|
| 298 |
if request_key not in sent_requests:
|
| 299 |
sent_requests.add(request_key)
|
| 300 |
deletion_request["type"] = "delete" # Add type identifier
|
|
|
|
| 301 |
yield f"data: {json.dumps(deletion_request)}\n\n"
|
| 302 |
|
| 303 |
# Clear from sent_requests after 10 seconds
|
|
|
|
| 315 |
if request_key not in sent_requests:
|
| 316 |
sent_requests.add(request_key)
|
| 317 |
creation_request["type"] = "create" # Add type identifier
|
|
|
|
| 318 |
yield f"data: {json.dumps(creation_request)}\n\n"
|
| 319 |
|
| 320 |
# Clear from sent_requests after 10 seconds
|
|
|
|
| 332 |
if request_key not in sent_requests:
|
| 333 |
sent_requests.add(request_key)
|
| 334 |
variable_request["type"] = "variable" # Add type identifier
|
|
|
|
| 335 |
yield f"data: {json.dumps(variable_request)}\n\n"
|
| 336 |
|
| 337 |
# Clear from sent_requests after 10 seconds
|
|
|
|
| 349 |
if request_key not in sent_requests:
|
| 350 |
sent_requests.add(request_key)
|
| 351 |
edit_request["type"] = "edit_mcp" # Add type identifier
|
|
|
|
| 352 |
yield f"data: {json.dumps(edit_request)}\n\n"
|
| 353 |
|
| 354 |
# Clear from sent_requests after 10 seconds
|
|
|
|
| 385 |
async def creation_result(request: Request):
|
| 386 |
data = await request.json()
|
| 387 |
request_id = data.get("request_id")
|
| 388 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 389 |
if request_id:
|
| 390 |
# Store the result for the create_block function to retrieve
|
| 391 |
creation_results[request_id] = data
|
|
|
|
| 392 |
|
| 393 |
return {"received": True}
|
| 394 |
|
|
|
|
| 435 |
success = data.get("success")
|
| 436 |
error = data.get("error")
|
| 437 |
|
|
|
|
|
|
|
| 438 |
if request_id:
|
| 439 |
# Store the result for the edit_mcp function to retrieve
|
| 440 |
edit_mcp_results[request_id] = data
|
|
|
|
| 441 |
|
| 442 |
return {"received": True}
|
| 443 |
|
|
|
|
| 553 |
# Hardcoded system prompt
|
| 554 |
|
| 555 |
SYSTEM_PROMPT = f"""You are an AI assistant that helps users build **MCP servers** using Blockly blocks.
|
|
|
|
| 556 |
|
| 557 |
You'll receive the workspace state in this format:
|
| 558 |
`blockId | block_name(inputs(input_name: value))`
|
| 559 |
|
| 560 |
+
Block ID parsing: Block IDs are everything before ` | ` (space-pipe-space). IDs are always complex/long strings.
|
| 561 |
+
Example: `?fHZRh^|us|9bECO![$= | text(inputs(TEXT: "hello"))`, ID is `?fHZRh^|us|9bECO![$=`
|
| 562 |
+
|
| 563 |
+
Special cases:
|
| 564 |
- `create_mcp` and `func_def` use `blockId | block_name(inputs(input_name: type), outputs(output_name: value))`
|
| 565 |
- Indentation or nesting shows logic hierarchy (like loops or conditionals).
|
|
|
|
|
|
|
|
|
|
| 566 |
|
| 567 |
---
|
| 568 |
|
|
|
|
| 601 |
|
| 602 |
{blocks_context}
|
| 603 |
|
| 604 |
+
You cannot create a `create_mcp` block, but you may edit its inputs using the `edit_mcp` tool.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 605 |
|
| 606 |
+
### Block Types: Statement vs Value
|
| 607 |
+
**Statement blocks** are containers that hold other blocks inside them. They can have blocks above or below them:
|
| 608 |
+
- Loops (repeat, while, for)
|
| 609 |
+
- Conditionals (if/else)
|
| 610 |
+
- Any block that wraps other blocks
|
| 611 |
+
|
| 612 |
+
**Value blocks** produce a value and plug into another block's input:
|
| 613 |
+
- Math blocks (math_number, math_arithmetic)
|
| 614 |
+
- Text blocks (text, text_join)
|
| 615 |
+
- Logic blocks (logic_compare, logic_operation)
|
| 616 |
+
- Any block that outputs a result for something else to use
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 617 |
|
| 618 |
+
### How to Place Blocks
|
| 619 |
|
| 620 |
+
**Placement types** - use `blockID` and `type` parameters:
|
| 621 |
+
|
| 622 |
+
- `type: "under"` - For statement blocks inside containers. Create the container first, then create statement blocks using the container's ID.
|
| 623 |
+
Example: Create a loop first, then use `blockID: loopID, type: "under"` to place code inside it.
|
| 624 |
+
Also for stackable blocks: create one, get its ID, then create the next one with the previous block's ID and `type: "under"`.
|
| 625 |
+
|
| 626 |
+
- `type: "input"` - ONLY for value blocks placed in MCP output slots. Provide `input_name` with the output slot name (R0, R1, R2, etc).
|
| 627 |
+
Example: `text(inputs(TEXT: "hello"))` with `type: "input", input_name: "R0"` places the text block in the MCP's first output slot.
|
| 628 |
+
|
| 629 |
+
**Value block nesting** - For value blocks inside other blocks: nest them directly in the create_block command (do not use `blockID` or `type`).
|
| 630 |
+
Example: `math_arithmetic(inputs(A: math_number(inputs(NUM: 5)), B: math_number(inputs(NUM: 3))))`
|
| 631 |
+
|
| 632 |
+
**CRITICAL for value block expressions**: You MUST build the entire nested structure in ONE create_block call. You cannot:
|
| 633 |
+
- Create blocks in stages
|
| 634 |
+
- Create intermediate blocks first and connect them later
|
| 635 |
+
- Break a value expression into multiple separate create_block calls
|
| 636 |
+
This is impossible. Value blocks can only be built by nesting them inside the create_block command.
|
| 637 |
+
Example: `math_arithmetic(inputs(A: math_number(inputs(NUM: 1)), B: math_arithmetic(inputs(A: math_number(inputs(NUM: 2)), B: math_number(inputs(NUM: 3))))))`
|
| 638 |
+
|
| 639 |
+
### Input Rules
|
| 640 |
+
Every block must have `inputs()`. For blocks that grow like `make_json` or `text_join`, add as many inputs as needed:
|
| 641 |
+
- `text_join(inputs(ADD0: text(inputs(TEXT: "hello")), ADD1: text(inputs(TEXT: "world"))))`
|
| 642 |
+
The blocks list will have comments saying something like "you can make as many N as you want" if this is allowed for that block.
|
| 643 |
+
|
| 644 |
+
**String values must always be quoted with double quotes.** All configuration values (like operation names, parameter values, etc.) that are strings must be `"quoted"`:
|
| 645 |
+
- WRONG: `math_single(inputs(OP: ROOT, NUM: value)`
|
| 646 |
+
- CORRECT: `math_single(inputs(OP: "ROOT", NUM: value)`
|
| 647 |
+
|
| 648 |
+
For value inputs, never use raw values. Always wrap in a block:
|
| 649 |
+
- WRONG: `math_arithmetic(inputs(A: 5, B: "hi"))`
|
| 650 |
+
- RIGHT: `math_arithmetic(inputs(A: math_number(inputs(NUM: 5)), B: text(inputs(TEXT: "hi"))))`
|
| 651 |
|
| 652 |
You may NEVER create functions. You must only use code inside the MCP block itself.
|
| 653 |
|
|
|
|
| 670 |
|
| 671 |
---
|
| 672 |
|
| 673 |
+
## VALUE BLOCK CONSTRUCTION: ABSOLUTE RULE
|
| 674 |
|
| 675 |
+
**Value blocks and value expressions must be built entirely in a SINGLE create_block call.**
|
| 676 |
|
| 677 |
+
This is not negotiable. There is no alternative method. There is no workaround.
|
| 678 |
|
| 679 |
+
When you need to create value blocks (math blocks, text blocks, logic blocks, comparison blocks, or any block that produces a value for another block to use), you must nest all of them together in one create_block call. All child blocks, all nested blocks, all sub-expressions must be included in that single call.
|
| 680 |
|
| 681 |
+
**For any value expression, you have exactly ONE option: build it all in a single create_block call with all children nested inside.**
|
|
|
|
|
|
|
|
|
|
|
|
|
| 682 |
|
| 683 |
+
You cannot call create_block multiple times for one value expression. You cannot create intermediate blocks and connect them later. These are not possible.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 684 |
|
| 685 |
+
**Correct:**
|
| 686 |
+
`text_join(inputs(ADD0: text(inputs(TEXT: "a")), ADD1: text(inputs(TEXT: "b")), ADD2: text(inputs(TEXT: "c"))))`
|
| 687 |
+
This is ONE call with all blocks nested in it.
|
| 688 |
|
| 689 |
+
**Prohibited:**
|
| 690 |
+
- `create_block(text(...))` then `create_block(text(...))` then `create_block(text(...))`: You cannot do this
|
| 691 |
+
- Create one block, get its ID, then try to place other blocks in its inputs later: You cannot do this
|
| 692 |
+
- Break a math expression across multiple calls: You cannot do this
|
| 693 |
|
| 694 |
+
**Statement blocks are different.** Loops and conditionals require sequential calls because you need the container's ID first to place code inside it. But value blocks are not containers. They are atomic. Build the entire structure in one call or not at all.
|
| 695 |
|
| 696 |
+
---
|
| 697 |
+
|
| 698 |
+
Tool responses appear under the assistant role, but they are not part of your own words. Never treat tool output as
|
| 699 |
+
something you said, and never fabricate or echo fake tool outputs.
|
| 700 |
|
| 701 |
---
|
| 702 |
|
| 703 |
+
## REQUIRED PLANNING PHASE BEFORE ANY TOOL CALL
|
| 704 |
+
|
| 705 |
+
Before creating or deleting any blocks, always begin with a *Planning Phase*:
|
| 706 |
+
|
| 707 |
+
0. Acknowledge the `VALUE BLOCK CONSTRUCTION: ABSOLUTE RULE` section and how you are prohibited from doing multi step calls for value blocks, and must do it in one create block call.
|
| 708 |
+
|
| 709 |
+
1. **Analyze the user's request.** Identify all required inputs, outputs, intermediate steps, loops, and conditionals.
|
| 710 |
+
|
| 711 |
+
2. **Write pseudocode showing the complete flow** using readable syntax like function calls and control structures.
|
| 712 |
+
This is for *your own* understanding: work out the logic *before* translating to blocks.
|
| 713 |
+
Example: `for item in items: result = process(item); output = combine(result)`
|
| 714 |
+
|
| 715 |
+
3. **Create a build order**: which blocks are top-level, which nest inside others, which are value expressions that must be built in one call.
|
| 716 |
+
|
| 717 |
+
4. Perform the actions in order without asking for approval or asking to wait for intermediate results.
|
| 718 |
+
|
| 719 |
"""
|
| 720 |
|
| 721 |
tools = [
|
|
|
|
| 745 |
"type": "string",
|
| 746 |
"description": "The create block command using the custom DSL format.",
|
| 747 |
},
|
| 748 |
+
"blockID": {
|
| 749 |
+
"type": "string",
|
| 750 |
+
"description": "The ID of the target block for placement.",
|
| 751 |
+
},
|
| 752 |
+
"type": {
|
| 753 |
"type": "string",
|
| 754 |
+
"enum": ["under", "input"],
|
| 755 |
+
"description": "Placement type. 'under' for statement blocks inside containers. 'input' only for value blocks in MCP outputs.",
|
| 756 |
},
|
| 757 |
+
"input_name": {
|
| 758 |
"type": "string",
|
| 759 |
+
"description": "Specific MCP input slot name when type is 'input'. Use 'RN', where N is the number of the output slot you want to put something into.",
|
| 760 |
},
|
| 761 |
},
|
| 762 |
"required": ["command"],
|
|
|
|
| 856 |
input_items.append({"role": "user", "content": human})
|
| 857 |
input_items.append({"role": "assistant", "content": ai})
|
| 858 |
|
|
|
|
|
|
|
|
|
|
| 859 |
# Build instructions
|
| 860 |
instructions = SYSTEM_PROMPT
|
| 861 |
if context:
|
|
|
|
| 1012 |
|
| 1013 |
elif function_name == "create_block":
|
| 1014 |
command = function_args.get("command", "")
|
| 1015 |
+
blockID = function_args.get("blockID", None)
|
| 1016 |
+
placement_type = function_args.get("type", None)
|
| 1017 |
+
input_name = function_args.get("input_name", None)
|
| 1018 |
+
if blockID is None:
|
| 1019 |
print(Fore.YELLOW + f"Agent created block with command `{command}`." + Style.RESET_ALL)
|
| 1020 |
+
else:
|
| 1021 |
+
print(Fore.YELLOW + f"Agent created block with command `{command}`, type: {placement_type}, blockID: `{blockID}`." + Style.RESET_ALL)
|
| 1022 |
+
if input_name:
|
| 1023 |
+
print(Fore.YELLOW + f" Input name: {input_name}" + Style.RESET_ALL)
|
| 1024 |
+
tool_result = create_block(command, blockID, placement_type, input_name)
|
| 1025 |
result_label = "Create Operation"
|
| 1026 |
|
| 1027 |
elif function_name == "create_variable":
|
project/src/index.js
CHANGED
|
@@ -657,14 +657,19 @@ const setupUnifiedStream = () => {
|
|
| 657 |
|
| 658 |
if (newBlock) {
|
| 659 |
blockId = newBlock.id;
|
|
|
|
| 660 |
|
| 661 |
-
//
|
| 662 |
-
if (data.
|
|
|
|
|
|
|
| 663 |
const mcpBlock = ws.getBlocksByType('create_mcp')[0];
|
| 664 |
if (mcpBlock) {
|
| 665 |
-
|
|
|
|
|
|
|
| 666 |
if (input && input.connection) {
|
| 667 |
-
console.log('[SSE CREATE] Placing block into MCP
|
| 668 |
// Disconnect any existing block
|
| 669 |
const existingBlock = input.connection.targetBlock();
|
| 670 |
if (existingBlock) {
|
|
@@ -673,25 +678,27 @@ const setupUnifiedStream = () => {
|
|
| 673 |
// Connect the new block
|
| 674 |
if (newBlock.outputConnection) {
|
| 675 |
input.connection.connect(newBlock.outputConnection);
|
| 676 |
-
console.log('[SSE CREATE] Successfully placed block into
|
| 677 |
} else {
|
| 678 |
-
error = `Block has no output connection to connect to MCP
|
| 679 |
console.error('[SSE CREATE]', error);
|
| 680 |
}
|
| 681 |
} else {
|
| 682 |
-
|
|
|
|
|
|
|
| 683 |
console.error('[SSE CREATE]', error);
|
| 684 |
}
|
| 685 |
} else {
|
| 686 |
-
error =
|
| 687 |
console.error('[SSE CREATE]', error);
|
| 688 |
}
|
| 689 |
}
|
| 690 |
-
// If
|
| 691 |
-
else if (data.
|
| 692 |
-
const parentBlock = ws.getBlockById(data.
|
| 693 |
if (parentBlock) {
|
| 694 |
-
console.log('[SSE CREATE] Attaching to parent block:', data.
|
| 695 |
|
| 696 |
// Find an appropriate input to connect to
|
| 697 |
// Try common statement inputs first
|
|
@@ -744,15 +751,18 @@ const setupUnifiedStream = () => {
|
|
| 744 |
}
|
| 745 |
|
| 746 |
if (!connected) {
|
| 747 |
-
|
|
|
|
| 748 |
}
|
| 749 |
} else {
|
| 750 |
-
|
|
|
|
| 751 |
}
|
| 752 |
}
|
| 753 |
|
| 754 |
-
success
|
| 755 |
-
|
|
|
|
| 756 |
} else {
|
| 757 |
throw new Error(`Failed to create block from specification`);
|
| 758 |
}
|
|
@@ -950,7 +960,7 @@ const updateCode = () => {
|
|
| 950 |
code = "import numbers\n\n" + code;
|
| 951 |
}
|
| 952 |
|
| 953 |
-
code = "import gradio as gr\n\n" + code
|
| 954 |
|
| 955 |
if (codeEl) {
|
| 956 |
codeEl.textContent = code;
|
|
|
|
| 657 |
|
| 658 |
if (newBlock) {
|
| 659 |
blockId = newBlock.id;
|
| 660 |
+
success = true; // Block was created successfully
|
| 661 |
|
| 662 |
+
// Handle placement based on placement_type
|
| 663 |
+
if (data.placement_type === 'input') {
|
| 664 |
+
// Place into MCP block's output slot
|
| 665 |
+
// For type: 'input', find the first MCP block and use input_name for the slot
|
| 666 |
const mcpBlock = ws.getBlocksByType('create_mcp')[0];
|
| 667 |
if (mcpBlock) {
|
| 668 |
+
// input_name specifies which output slot (e.g., "R0", "R1")
|
| 669 |
+
const inputSlot = data.input_name;
|
| 670 |
+
const input = mcpBlock.getInput(inputSlot);
|
| 671 |
if (input && input.connection) {
|
| 672 |
+
console.log('[SSE CREATE] Placing block into MCP output slot:', inputSlot);
|
| 673 |
// Disconnect any existing block
|
| 674 |
const existingBlock = input.connection.targetBlock();
|
| 675 |
if (existingBlock) {
|
|
|
|
| 678 |
// Connect the new block
|
| 679 |
if (newBlock.outputConnection) {
|
| 680 |
input.connection.connect(newBlock.outputConnection);
|
| 681 |
+
console.log('[SSE CREATE] Successfully placed block into slot:', inputSlot);
|
| 682 |
} else {
|
| 683 |
+
error = `Block has no output connection to connect to MCP slot ${inputSlot}`;
|
| 684 |
console.error('[SSE CREATE]', error);
|
| 685 |
}
|
| 686 |
} else {
|
| 687 |
+
// Try to get all available inputs on the MCP block for debugging
|
| 688 |
+
const availableInputs = mcpBlock.inputList.map(inp => inp.name).join(', ');
|
| 689 |
+
error = `Output slot '${inputSlot}' not found. Available inputs: ${availableInputs}`;
|
| 690 |
console.error('[SSE CREATE]', error);
|
| 691 |
}
|
| 692 |
} else {
|
| 693 |
+
error = `No MCP block found in workspace`;
|
| 694 |
console.error('[SSE CREATE]', error);
|
| 695 |
}
|
| 696 |
}
|
| 697 |
+
// If placement_type is 'under', attach the new block under the parent
|
| 698 |
+
else if (data.placement_type === 'under') {
|
| 699 |
+
const parentBlock = ws.getBlockById(data.blockID);
|
| 700 |
if (parentBlock) {
|
| 701 |
+
console.log('[SSE CREATE] Attaching to parent block:', data.blockID);
|
| 702 |
|
| 703 |
// Find an appropriate input to connect to
|
| 704 |
// Try common statement inputs first
|
|
|
|
| 751 |
}
|
| 752 |
|
| 753 |
if (!connected) {
|
| 754 |
+
error = `Could not find suitable connection point on parent block`;
|
| 755 |
+
console.warn('[SSE CREATE]', error);
|
| 756 |
}
|
| 757 |
} else {
|
| 758 |
+
error = `Parent block not found: ${data.blockID}`;
|
| 759 |
+
console.warn('[SSE CREATE]', error);
|
| 760 |
}
|
| 761 |
}
|
| 762 |
|
| 763 |
+
if (success) {
|
| 764 |
+
console.log('[SSE CREATE] Successfully created block with children:', blockId, newBlock.type);
|
| 765 |
+
}
|
| 766 |
} else {
|
| 767 |
throw new Error(`Failed to create block from specification`);
|
| 768 |
}
|
|
|
|
| 960 |
code = "import numbers\n\n" + code;
|
| 961 |
}
|
| 962 |
|
| 963 |
+
code = "import gradio as gr\nimport math\n\n" + code
|
| 964 |
|
| 965 |
if (codeEl) {
|
| 966 |
codeEl.textContent = code;
|