mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-16 23:01:56 +00:00
iframe and Firefox fixes
This commit is contained in:
parent
4b0703cd5b
commit
faefc63309
11 changed files with 472 additions and 380 deletions
|
|
@ -1,174 +1,15 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script>
|
||||
// Store files and console output for current execution
|
||||
let returnedFiles = [];
|
||||
let consoleOutput = [];
|
||||
|
||||
// Store attachments with helper methods
|
||||
window.attachments = [];
|
||||
|
||||
// Helper function to list available files
|
||||
window.listFiles = function() {
|
||||
return window.attachments.map(a => ({
|
||||
id: a.id,
|
||||
fileName: a.fileName,
|
||||
mimeType: a.mimeType,
|
||||
size: a.size
|
||||
}));
|
||||
};
|
||||
|
||||
// Helper function to read text file by ID
|
||||
window.readTextFile = function(attachmentId) {
|
||||
const attachment = window.attachments.find(a => a.id === attachmentId);
|
||||
if (!attachment) {
|
||||
throw new Error('Attachment not found: ' + attachmentId);
|
||||
}
|
||||
// If extractedText exists, return it
|
||||
if (attachment.extractedText) {
|
||||
return attachment.extractedText;
|
||||
}
|
||||
// Otherwise decode base64 content
|
||||
try {
|
||||
return atob(attachment.content);
|
||||
} catch (e) {
|
||||
throw new Error('Failed to decode text content for: ' + attachmentId);
|
||||
}
|
||||
};
|
||||
|
||||
// Helper function to read binary file as Uint8Array
|
||||
window.readBinaryFile = function(attachmentId) {
|
||||
const attachment = window.attachments.find(a => a.id === attachmentId);
|
||||
if (!attachment) {
|
||||
throw new Error('Attachment not found: ' + attachmentId);
|
||||
}
|
||||
const binaryString = atob(attachment.content);
|
||||
const bytes = new Uint8Array(binaryString.length);
|
||||
for (let i = 0; i < binaryString.length; i++) {
|
||||
bytes[i] = binaryString.charCodeAt(i);
|
||||
}
|
||||
return bytes;
|
||||
};
|
||||
|
||||
// Override console
|
||||
['log', 'error', 'warn', 'info', 'debug', 'table'].forEach(method => {
|
||||
const original = console[method];
|
||||
console[method] = (...args) => {
|
||||
// Convert args to strings for plain text output
|
||||
const stringArgs = args.map(arg => {
|
||||
try {
|
||||
if (arg === undefined) return 'undefined';
|
||||
if (arg === null) return 'null';
|
||||
if (typeof arg === 'function') return arg.toString();
|
||||
if (typeof arg === 'symbol') return arg.toString();
|
||||
if (arg instanceof Error) return arg.stack || arg.message;
|
||||
if (typeof arg === 'object') return JSON.stringify(arg, null, 2);
|
||||
return String(arg);
|
||||
} catch {
|
||||
return String(arg);
|
||||
}
|
||||
});
|
||||
consoleOutput.push({ type: method, args: stringArgs });
|
||||
original.apply(console, args);
|
||||
};
|
||||
});
|
||||
|
||||
// Single return function for files only
|
||||
window.returnFile = async (fileName, content, mimeType) => {
|
||||
// Validate mimeType for binary-like content to guide the LLM
|
||||
const isBinaryLike = (val) => val instanceof Blob || val instanceof Uint8Array;
|
||||
if (isBinaryLike(content) && (!mimeType || typeof mimeType !== 'string' || !mimeType.includes('/'))) {
|
||||
const err = new Error('returnFile: mimeType is required for Blob/Uint8Array content (e.g., "image/png").');
|
||||
throw err;
|
||||
}
|
||||
|
||||
// Default for plain string content when not specified
|
||||
if (typeof content === 'string' && (!mimeType || typeof mimeType !== 'string' || mimeType === '')) {
|
||||
mimeType = 'text/plain';
|
||||
}
|
||||
|
||||
// Handle data URLs - extract the data and mime type
|
||||
if (typeof content === 'string' && content.startsWith('data:')) {
|
||||
const matches = content.match(/^data:([^;,]+)(;base64)?,(.*)$/);
|
||||
if (matches) {
|
||||
if (mimeType === 'text/plain' && matches[1]) {
|
||||
mimeType = matches[1];
|
||||
}
|
||||
const isBase64 = !!matches[2];
|
||||
const data = matches[3];
|
||||
if (isBase64) {
|
||||
const binaryString = atob(data);
|
||||
const bytes = new Uint8Array(binaryString.length);
|
||||
for (let i = 0; i < binaryString.length; i++) {
|
||||
bytes[i] = binaryString.charCodeAt(i);
|
||||
}
|
||||
content = bytes;
|
||||
} else {
|
||||
content = decodeURIComponent(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Convert Blob to Uint8Array for postMessage
|
||||
else if (content instanceof Blob) {
|
||||
const arrayBuffer = await content.arrayBuffer();
|
||||
content = new Uint8Array(arrayBuffer);
|
||||
}
|
||||
// Handle different content types
|
||||
else if (typeof content === 'object' && !(content instanceof Uint8Array)) {
|
||||
content = JSON.stringify(content, null, 2);
|
||||
if (!mimeType || mimeType === 'text/plain') {
|
||||
mimeType = 'application/json';
|
||||
}
|
||||
}
|
||||
returnedFiles.push({ fileName, content, mimeType });
|
||||
};
|
||||
|
||||
// Message handler
|
||||
window.addEventListener('message', async (e) => {
|
||||
if (e.data.type === 'setAttachments') {
|
||||
window.attachments = e.data.attachments;
|
||||
parent.postMessage({ type: 'ready' }, '*');
|
||||
} else if (e.data.type === 'execute') {
|
||||
// Reset for new execution
|
||||
returnedFiles = [];
|
||||
consoleOutput = [];
|
||||
|
||||
try {
|
||||
// Execute code in global scope to persist variables
|
||||
const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
|
||||
const func = new AsyncFunction(e.data.code);
|
||||
const result = await func();
|
||||
|
||||
// If there was a direct return value, log it
|
||||
if (result !== undefined) {
|
||||
console.log('Return value:', result);
|
||||
}
|
||||
|
||||
parent.postMessage({
|
||||
type: 'result',
|
||||
success: true,
|
||||
files: returnedFiles,
|
||||
console: consoleOutput
|
||||
}, '*');
|
||||
} catch (error) {
|
||||
parent.postMessage({
|
||||
type: 'error',
|
||||
success: false,
|
||||
error: {
|
||||
message: error.message,
|
||||
stack: error.stack,
|
||||
name: error.name
|
||||
},
|
||||
console: consoleOutput
|
||||
}, '*');
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Sandboxed Content</title>
|
||||
<style>
|
||||
html { height: 100%; }
|
||||
body { min-height: 100%; margin: 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script src="sandbox.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue