tangled
alpha
login
or
join now
dunkirk.sh
/
plastic
2
fork
atom
self modifying website
2
fork
atom
overview
issues
pulls
pipelines
feat: add tool feedback
dunkirk.sh
9 months ago
ffacc84f
99b77929
verified
This commit was signed with the committer's
known signature
.
dunkirk.sh
SSH Key Fingerprint:
SHA256:DqcG0RXYExE26KiWo3VxJnsxswN1QNfTBvB+bdSpk80=
+120
-8
1 changed file
expand all
collapse all
unified
split
index.html
+120
-8
index.html
···
362
362
console.log('Executing tool call:', func, args);
363
363
364
364
if (window.toolCallbacks[func]) {
365
365
-
// Handle parameter name variations
366
366
-
if (func === 'updateStyle' && args.styleObj) {
367
367
-
// Convert styleObj to the expected parameter name
368
368
-
return window.toolCallbacks[func](args.selector, args.styleObj);
369
369
-
} else {
370
370
-
// Use all argument values in order
371
371
-
return window.toolCallbacks[func](...Object.values(args));
365
365
+
try {
366
366
+
// Handle different function signatures
367
367
+
if (func === 'removeElement') {
368
368
+
// removeElement expects just a selector
369
369
+
const selector = args.selector || Object.keys(args)[0] || Object.values(args)[0];
370
370
+
return window.toolCallbacks[func](selector);
371
371
+
} else if (func === 'updateStyle' && args.styleObj) {
372
372
+
return window.toolCallbacks[func](args.selector, args.styleObj);
373
373
+
} else if (func === 'executeJS') {
374
374
+
return window.toolCallbacks[func](args.code);
375
375
+
} else if (func === 'updateElement') {
376
376
+
return window.toolCallbacks[func](args.selector, args.newContent);
377
377
+
} else if (func === 'replaceElement') {
378
378
+
return window.toolCallbacks[func](args.selector, args.newHTML);
379
379
+
} else if (func === 'addElement') {
380
380
+
return window.toolCallbacks[func](args.parentSelector, args.newHTML, args.position);
381
381
+
} else {
382
382
+
// Fallback: use all argument values in order
383
383
+
return window.toolCallbacks[func](...Object.values(args));
384
384
+
}
385
385
+
} catch (error) {
386
386
+
return { success: false, message: `Error executing ${func}: ${error.message}` };
372
387
}
373
388
}
374
389
return { success: false, message: `Unknown tool: ${func}` };
···
399
414
messages: [
400
415
{
401
416
role: "user",
402
402
-
content: `Here is the current HTML page:\n\n${currentPageHTML}\n\nUser request: "${userPrompt}"\n\nIMPORTANT: You must respond with ONLY one of these two formats:\n\nFORMAT 1 - Tool calls (for precise modifications):\n{"tool_calls": [{"function": "functionName", "arguments": {"param": "value"}}]}\n\nFORMAT 2 - Raw HTML (to append to page):\n<div>Your HTML content here</div>\n\nDO NOT include any explanatory text, markdown formatting, or additional commentary. Respond with ONLY the JSON or HTML.\n\nAvailable tools:\n1. replaceElement(selector, newHTML) - Replace an element\n2. updateElement(selector, newContent) - Update element content \n3. addElement(parentSelector, newHTML, position) - Add element\n4. removeElement(selector) - Remove an element\n5. updateStyle(selector, styleObj) - Update CSS styles\n6. executeJS(code) - Run JavaScript code\n\nUse DOS/retro aesthetic with flat colors: #000000 (black), #ffffff (white), #c0c0c0 (gray), #000080 (blue), #ff0000 (red). Use monospace fonts.`,
417
417
+
content: `Here is the current HTML page:\n\n${currentPageHTML}\n\nUser request: "${userPrompt}"\n\nIMPORTANT: You must respond with ONLY one of these two formats:\n\nFORMAT 1 - Tool calls (for precise modifications):\n{"tool_calls": [{"function": "functionName", "arguments": {"param": "value"}}]}\n\nFORMAT 2 - Raw HTML (to append to page):\n<div>Your HTML content here</div>\n\nDO NOT include any explanatory text, markdown formatting, or additional commentary. Respond with ONLY the JSON or HTML.\n\nAvailable tools with correct argument formats:\n1. removeElement: {"function": "removeElement", "arguments": {"selector": ".class-name"}}\n2. updateElement: {"function": "updateElement", "arguments": {"selector": ".class-name", "newContent": "new content"}}\n3. replaceElement: {"function": "replaceElement", "arguments": {"selector": ".class-name", "newHTML": "<div>new html</div>"}}\n4. addElement: {"function": "addElement", "arguments": {"parentSelector": ".parent", "newHTML": "<div>content</div>", "position": "beforeend"}}\n5. updateStyle: {"function": "updateStyle", "arguments": {"selector": ".class-name", "styleObj": {"color": "#000000"}}}\n6. executeJS: {"function": "executeJS", "arguments": {"code": "console.log('hello');"}}\n\nUse DOS/retro aesthetic with flat colors: #000000 (black), #ffffff (white), #c0c0c0 (gray), #000080 (blue), #ff0000 (red). Use monospace fonts.`,
403
418
},
404
419
],
405
420
}),
···
464
479
console.log('Tool call result:', result);
465
480
}
466
481
statusDiv.textContent = `EXECUTED ${results.length} COMMANDS`;
482
482
+
483
483
+
// Send feedback to AI about tool results
484
484
+
setTimeout(() => sendToolFeedback(userPrompt, results), 100);
467
485
} else {
468
486
throw new Error("Invalid tool call format");
469
487
}
···
497
515
function clearEditor() {
498
516
document.getElementById("codeEditor").value = "";
499
517
document.getElementById("statusDisplay").textContent = "";
518
518
+
}
519
519
+
520
520
+
async function sendToolFeedback(originalPrompt, toolResults) {
521
521
+
const statusDiv = document.getElementById("statusDisplay");
522
522
+
523
523
+
try {
524
524
+
statusDiv.textContent = "SENDING FEEDBACK TO AI...";
525
525
+
526
526
+
const currentPageHTML = document.documentElement.outerHTML;
527
527
+
const resultsText = toolResults.map(r =>
528
528
+
`${r.success ? '✓' : '✗'} ${r.message}${r.result ? ` (result: ${r.result})` : ''}`
529
529
+
).join('\n');
530
530
+
531
531
+
const response = await fetch(
532
532
+
"https://ai.hackclub.com/chat/completions",
533
533
+
{
534
534
+
method: "POST",
535
535
+
headers: {
536
536
+
"Content-Type": "application/json",
537
537
+
},
538
538
+
body: JSON.stringify({
539
539
+
messages: [
540
540
+
{
541
541
+
role: "user",
542
542
+
content: `Previous request: "${originalPrompt}"\n\nTool execution results:\n${resultsText}\n\nCurrent page state:\n${currentPageHTML}\n\nBased on the tool results, do you need to make any follow-up modifications? If everything looks good, respond with "COMPLETE". If you need to make adjustments, respond with tool calls or HTML.\n\nIMPORTANT: Respond with ONLY one of these formats:\n- "COMPLETE" (if satisfied)\n- {"tool_calls": [...]} (for modifications)\n- Raw HTML (to append content)\n\nDO NOT include explanatory text.`,
543
543
+
},
544
544
+
],
545
545
+
}),
546
546
+
},
547
547
+
);
548
548
+
549
549
+
if (!response.ok) {
550
550
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
551
551
+
}
552
552
+
553
553
+
const data = await response.json();
554
554
+
let followUpContent;
555
555
+
556
556
+
if (data.choices && data.choices[0] && data.choices[0].message) {
557
557
+
followUpContent = data.choices[0].message.content;
558
558
+
} else if (data.content) {
559
559
+
followUpContent = data.content;
560
560
+
} else if (data.response) {
561
561
+
followUpContent = data.response;
562
562
+
} else {
563
563
+
throw new Error("Unexpected API response format");
564
564
+
}
565
565
+
566
566
+
followUpContent = followUpContent.trim();
567
567
+
console.log('Follow-up response:', followUpContent);
568
568
+
569
569
+
if (followUpContent === "COMPLETE") {
570
570
+
statusDiv.textContent = "AI SATISFIED - TASK COMPLETE";
571
571
+
setTimeout(() => statusDiv.textContent = "", 3000);
572
572
+
return;
573
573
+
}
574
574
+
575
575
+
// Process follow-up commands
576
576
+
statusDiv.textContent = "AI MAKING ADJUSTMENTS...";
577
577
+
578
578
+
// Try to parse as tool calls
579
579
+
try {
580
580
+
const jsonMatch = followUpContent.match(/\{[\s\S]*"tool_calls"[\s\S]*\}/);
581
581
+
if (jsonMatch) {
582
582
+
const toolResponse = JSON.parse(jsonMatch[0]);
583
583
+
if (toolResponse.tool_calls && Array.isArray(toolResponse.tool_calls)) {
584
584
+
const followUpResults = [];
585
585
+
for (const toolCall of toolResponse.tool_calls) {
586
586
+
const result = executeToolCall(toolCall);
587
587
+
followUpResults.push(result);
588
588
+
console.log('Follow-up tool result:', result);
589
589
+
}
590
590
+
statusDiv.textContent = `AI EXECUTED ${followUpResults.length} ADJUSTMENTS`;
591
591
+
}
592
592
+
} else {
593
593
+
// Treat as HTML
594
594
+
let cleanCode = followUpContent
595
595
+
.replace(/```html\n?/g, "")
596
596
+
.replace(/```\n?/g, "");
597
597
+
document.querySelector(".content").innerHTML += cleanCode;
598
598
+
statusDiv.textContent = "AI ADDED FOLLOW-UP CONTENT";
599
599
+
}
600
600
+
} catch (error) {
601
601
+
console.log('Follow-up parsing error:', error);
602
602
+
statusDiv.textContent = "AI FEEDBACK ERROR";
603
603
+
}
604
604
+
605
605
+
setTimeout(() => statusDiv.textContent = "", 4000);
606
606
+
607
607
+
} catch (error) {
608
608
+
statusDiv.textContent = `FEEDBACK ERROR: ${error.message}`;
609
609
+
console.error('Feedback error:', error);
610
610
+
setTimeout(() => statusDiv.textContent = "", 3000);
611
611
+
}
500
612
}
501
613
502
614
// Handle Ctrl+Enter in textarea