owenkaplinsky commited on
Commit
078dc2d
·
1 Parent(s): 94902a1

Add workspace language

Browse files
project/src/generators/chat.js ADDED
@@ -0,0 +1,245 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import * as Blockly from 'blockly';
2
+
3
+ // Create a custom generator for the chat/AI language
4
+ class ChatGenerator extends Blockly.Generator {
5
+ constructor(name) {
6
+ super(name);
7
+ // Custom order definitions for the chat language if needed
8
+ this.ORDER_ATOMIC = 0;
9
+ }
10
+
11
+ // Override scrub_ to handle how blocks are joined
12
+ scrub_(block, code, thisOnly) {
13
+ const nextBlock = block.nextConnection && block.nextConnection.targetBlock();
14
+ let nextCode = '';
15
+ if (nextBlock) {
16
+ nextCode = this.blockToCode(nextBlock);
17
+ }
18
+ return code + nextCode;
19
+ }
20
+ }
21
+
22
+ // Create an instance of the chat generator
23
+ export const chatGenerator = new ChatGenerator('Chat');
24
+
25
+ // Export forBlock for custom block definitions
26
+ export const forBlock = Object.create(null);
27
+
28
+ /*
29
+
30
+ This file is for the secondary code generator.
31
+ It is not meant to be shown to the user, but rather to communicate the state of the workspace to an AI chat assistant in a simplistic text format.
32
+
33
+ */
34
+
35
+ forBlock['create_mcp'] = function (block, generator) {
36
+ const inputParams = [];
37
+ const outputParams = [];
38
+ let i = 0;
39
+
40
+ // Build list of input parameters with types
41
+ while (block.getInput('X' + i)) {
42
+ const input = block.getInput('X' + i);
43
+ if (input && input.connection && input.connection.targetBlock()) {
44
+ const paramName = (block.inputNames_ && block.inputNames_[i]) || ('arg' + i);
45
+ const type = (block.inputTypes_ && block.inputTypes_[i]) || 'string';
46
+ inputParams.push(`${paramName}: ${type}`);
47
+ }
48
+ i++;
49
+ }
50
+
51
+ // Build list of output parameters with values (not types)
52
+ if (block.outputCount_ && block.outputCount_ > 0 && block.getInput('R0')) {
53
+ for (let r = 0; r < block.outputCount_; r++) {
54
+ const outputName = (block.outputNames_ && block.outputNames_[r]) || `result${r}`;
55
+ let returnValue = generator.valueToCode(block, 'R' + r, chatGenerator.ORDER_ATOMIC) || 'None';
56
+
57
+ // Replace placeholder args with actual names
58
+ if (returnValue && block.inputNames_) {
59
+ for (let j = 0; j < block.inputNames_.length; j++) {
60
+ const paramName = block.inputNames_[j];
61
+ returnValue = returnValue.replace(new RegExp(`arg${j}\\b`, 'g'), paramName);
62
+ }
63
+ }
64
+
65
+ outputParams.push(`${outputName}: ${returnValue}`);
66
+ }
67
+ }
68
+
69
+ // Main function body
70
+ let body = generator.statementToCode(block, 'BODY');
71
+
72
+ // Construct the create_mcp call with inputs and outputs
73
+ let code = `create_mcp(inputs(${inputParams.join(', ')}), outputs(${outputParams.join(', ')}))\n`;
74
+
75
+ // Add the function body
76
+ if (body) {
77
+ code += body;
78
+ }
79
+
80
+ return code;
81
+ };
82
+
83
+ forBlock['func_def'] = function (block, generator) {
84
+ const name = block.getFieldValue('NAME');
85
+ const inputParams = [];
86
+ const outputParams = [];
87
+ let i = 0;
88
+
89
+ // Build list of input parameters with types
90
+ while (block.getInput('X' + i)) {
91
+ const input = block.getInput('X' + i);
92
+ if (input && input.connection && input.connection.targetBlock()) {
93
+ const paramName = (block.inputNames_ && block.inputNames_[i]) || ('arg' + i);
94
+ const type = (block.inputTypes_ && block.inputTypes_[i]) || 'string';
95
+ inputParams.push(`${paramName}: ${type}`);
96
+ }
97
+ i++;
98
+ }
99
+
100
+ // Build list of output parameters with values (not types)
101
+ if (block.outputCount_ && block.outputCount_ > 0 && block.getInput('R0')) {
102
+ for (let r = 0; r < block.outputCount_; r++) {
103
+ const outputName = (block.outputNames_ && block.outputNames_[r]) || `output${r}`;
104
+ let returnValue = generator.valueToCode(block, 'R' + r, chatGenerator.ORDER_ATOMIC) || 'None';
105
+
106
+ // Replace placeholder args with actual names
107
+ if (returnValue && block.inputNames_) {
108
+ for (let j = 0; j < block.inputNames_.length; j++) {
109
+ const paramName = block.inputNames_[j];
110
+ returnValue = returnValue.replace(new RegExp(`arg${j}\\b`, 'g'), paramName);
111
+ }
112
+ }
113
+
114
+ outputParams.push(`${outputName}: ${returnValue}`);
115
+ }
116
+ }
117
+
118
+ // Main function body
119
+ let body = generator.statementToCode(block, 'BODY');
120
+
121
+ // Construct the func_def call with inputs and outputs
122
+ let code = `${name}(inputs(${inputParams.join(', ')}), outputs(${outputParams.join(', ')}))\n`;
123
+
124
+ // Add the function body
125
+ if (body) {
126
+ code += body;
127
+ }
128
+
129
+ return code;
130
+ };
131
+
132
+ // Handler for input reference blocks
133
+ forBlock['input_reference'] = function(block, generator) {
134
+ const varName = block.getFieldValue('VARNAME') ||
135
+ block.type.replace('input_reference_', '') ||
136
+ 'unnamed_arg';
137
+ // Value blocks must return a tuple: [code, order]
138
+ return [varName, chatGenerator.ORDER_ATOMIC];
139
+ };
140
+
141
+ // Register the forBlock definitions with the chat generator
142
+ Object.assign(chatGenerator.forBlock, forBlock);
143
+
144
+ // Override blockToCode to provide a catch-all handler
145
+ const originalBlockToCode = chatGenerator.blockToCode.bind(chatGenerator);
146
+ chatGenerator.blockToCode = function(block, opt_thisOnly) {
147
+ // Null check
148
+ if (!block) {
149
+ return '';
150
+ }
151
+
152
+ // Check if it's an input reference block type
153
+ if (block.type.startsWith('input_reference_')) {
154
+ const varName = block.getFieldValue('VARNAME') ||
155
+ block.type.replace('input_reference_', '') ||
156
+ 'unnamed_arg';
157
+ // Value blocks must return a tuple: [code, order]
158
+ return [varName, this.ORDER_ATOMIC];
159
+ }
160
+
161
+ // Try the normal generation first
162
+ try {
163
+ return originalBlockToCode(block, opt_thisOnly);
164
+ } catch (e) {
165
+ // Catch-all handler for blocks without specific generators
166
+ const blockType = block.type;
167
+ const inputs = [];
168
+
169
+ // Special handling for common blocks with field values
170
+ if (blockType === 'text') {
171
+ const text = block.getFieldValue('TEXT');
172
+ if (text !== null && text !== undefined) {
173
+ inputs.push(`TEXT: "${text}"`);
174
+ }
175
+ } else if (blockType === 'math_number') {
176
+ const num = block.getFieldValue('NUM');
177
+ if (num !== null && num !== undefined) {
178
+ inputs.push(`NUM: ${num}`);
179
+ }
180
+ } else {
181
+ // Generic field value extraction for other blocks
182
+ // Get all inputs to check for fields
183
+ const inputList = block.inputList || [];
184
+ for (const input of inputList) {
185
+ // Check fields in each input
186
+ if (input.fieldRow) {
187
+ for (const field of input.fieldRow) {
188
+ if (field && field.name && field.getValue) {
189
+ const value = field.getValue();
190
+ if (value !== null && value !== undefined && value !== '') {
191
+ // Format the value appropriately
192
+ const formattedValue = typeof value === 'string' ? `"${value}"` : value;
193
+ inputs.push(`${field.name}: ${formattedValue}`);
194
+ }
195
+ }
196
+ }
197
+ }
198
+ }
199
+ }
200
+
201
+ // Then get all value inputs (connected blocks)
202
+ const inputList = block.inputList || [];
203
+ for (const input of inputList) {
204
+ if (input.type === Blockly.inputs.inputTypes.VALUE && input.connection) {
205
+ const inputName = input.name;
206
+ const inputValue = this.valueToCode(block, inputName, this.ORDER_ATOMIC);
207
+
208
+ if (inputValue) {
209
+ inputs.push(`${inputName}: ${inputValue}`);
210
+ }
211
+ }
212
+ }
213
+
214
+ // Generate the standard format: name(inputs(...))
215
+ const code = `${blockType}(inputs(${inputs.join(', ')}))`;
216
+
217
+ // Handle statement inputs (for blocks that have a body)
218
+ let statements = '';
219
+ for (const input of inputList) {
220
+ if (input.type === Blockly.inputs.inputTypes.STATEMENT && input.connection) {
221
+ const statementCode = this.statementToCode(block, input.name);
222
+ if (statementCode) {
223
+ statements += statementCode;
224
+ }
225
+ }
226
+ }
227
+
228
+ // Return appropriate format based on whether it's a value or statement block
229
+ if (block.outputConnection) {
230
+ // This is a value block (can be plugged into inputs)
231
+ return [code, this.ORDER_ATOMIC];
232
+ } else {
233
+ // This is a statement block (has prev/next connections)
234
+ const fullCode = code + (statements ? '\n' + statements : '');
235
+
236
+ // Handle the next block in the sequence if not opt_thisOnly
237
+ if (!opt_thisOnly) {
238
+ const nextCode = this.scrub_(block, fullCode, opt_thisOnly);
239
+ return nextCode;
240
+ }
241
+
242
+ return fullCode + '\n';
243
+ }
244
+ }
245
+ };
project/src/index.js CHANGED
@@ -2,6 +2,7 @@ import * as Blockly from 'blockly';
2
  import { blocks } from './blocks/text';
3
  import { forBlock } from './generators/python';
4
  import { pythonGenerator } from 'blockly/python';
 
5
  import { save, load } from './serialization';
6
  import { toolbox } from './toolbox';
7
  import '@blockly/toolbox-search';
@@ -12,6 +13,9 @@ import './index.css';
12
  Blockly.common.defineBlocks(blocks);
13
  Object.assign(pythonGenerator.forBlock, forBlock);
14
 
 
 
 
15
  // Set up UI elements and inject Blockly
16
  const blocklyDiv = document.getElementById('blocklyDiv');
17
 
@@ -187,6 +191,26 @@ const updateCode = () => {
187
  });
188
  };
189
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
  try {
191
  load(ws);
192
 
@@ -250,6 +274,7 @@ if (existingMcpBlocks.length === 0) {
250
  }
251
 
252
  updateCode();
 
253
 
254
  ws.addChangeListener((e) => {
255
  if (e.isUiEvent) return;
@@ -318,4 +343,5 @@ ws.addChangeListener((e) => {
318
  return;
319
  }
320
  updateCode();
 
321
  });
 
2
  import { blocks } from './blocks/text';
3
  import { forBlock } from './generators/python';
4
  import { pythonGenerator } from 'blockly/python';
5
+ import { chatGenerator, forBlock as chatForBlock } from './generators/chat';
6
  import { save, load } from './serialization';
7
  import { toolbox } from './toolbox';
8
  import '@blockly/toolbox-search';
 
13
  Blockly.common.defineBlocks(blocks);
14
  Object.assign(pythonGenerator.forBlock, forBlock);
15
 
16
+ // Register chat generator blocks
17
+ Object.assign(chatGenerator.forBlock, chatForBlock);
18
+
19
  // Set up UI elements and inject Blockly
20
  const blocklyDiv = document.getElementById('blocklyDiv');
21
 
 
191
  });
192
  };
193
 
194
+ // Update function for the Chat generator (AI Chat tab)
195
+ const updateChatCode = () => {
196
+ let code = chatGenerator.workspaceToCode(ws);
197
+ const codeEl = document.querySelector('#aichatCode code');
198
+
199
+ // You can add any chat-specific preprocessing here
200
+ // For example, adding headers or formatting
201
+
202
+ if (codeEl) {
203
+ codeEl.textContent = code;
204
+ }
205
+
206
+ // Optionally send to a different endpoint or process differently
207
+ // fetch("http://127.0.0.1:7860/update_chat_code", {
208
+ // method: "POST",
209
+ // headers: { "Content-Type": "application/json" },
210
+ // body: JSON.stringify({ code }),
211
+ // });
212
+ };
213
+
214
  try {
215
  load(ws);
216
 
 
274
  }
275
 
276
  updateCode();
277
+ updateChatCode();
278
 
279
  ws.addChangeListener((e) => {
280
  if (e.isUiEvent) return;
 
343
  return;
344
  }
345
  updateCode();
346
+ updateChatCode();
347
  });