Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"@runt/pyodide-runtime-agent": "./packages/pyodide-runtime-agent/src/mod.ts",
"@runt/python-runtime-agent": "./packages/python-runtime-agent/mod.ts",
"@runt/tui": "./packages/tui/src/cli.tsx",
"jsr:@runtimed/schema": "jsr:@runtimed/schema@0.1.12",
"jsr:@runtimed/schema": "jsr:@runtimed/schema@0.3.0",
"jsr:@std/cli": "jsr:@std/cli@^1.0.22",
"jsr:@std/testing": "jsr:@std/testing@^1.0.15"
},
Expand Down
14 changes: 14 additions & 0 deletions packages/pyodide-runtime-agent/src/pyodide-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,20 @@ export class PyodideRuntimeAgent extends RuntimeAgent {
mountData,
});

// Send uploaded files to worker
const files = this.store.query(tables.files.select());
// This is a bit of a hack because we don't have access to the artifact client in the worker.
// We send the base URL to the worker for now.
const artifactBaseUrl = this.config.artifactClient.getArtifactUrl("");

if (files.length > 0) {
this.sendWorkerMessage("files", { files, artifactBaseUrl });
}

this.onFilesUpload((files) => {
this.sendWorkerMessage("files", { files, artifactBaseUrl });
});

this.isInitialized = true;
logger.info("Pyodide worker initialized successfully");
} catch (error) {
Expand Down
71 changes: 71 additions & 0 deletions packages/pyodide-runtime-agent/src/pyodide-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
getEssentialPackages,
isFirstRun,
} from "./cache-utils.ts";
import type { FileData } from "jsr:@runtimed/schema";

declare const self: DedicatedWorkerGlobalScope;

Expand Down Expand Up @@ -112,6 +113,76 @@ await run_registered_tool("${data.toolName}", kwargs_string)
break;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this code shared with the intheloop packages which we could be importing here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally we'd share the code. I know there's a lot that similar between run and intheloop now


case "files": {
if (!pyodide) {
throw new Error("Pyodide not initialized");
}

try {
// Cast the files to the expected type
const files = data.files as readonly FileData[];
// Cast the artifact base URL to the expected type
const artifactBaseUrl = data.artifactBaseUrl as string;

if (!artifactBaseUrl) {
throw new Error("Artifact base URL is required");
}

const filesInDirectory = pyodide.FS.readdir("./");

// Write/delete the new files
for (const file of files) {
if (file.deletedAt) {
if (!filesInDirectory.includes(file.fileName)) {
continue;
}
console.log("worker deleting file", { file });
// Just in case we couldn't match the file, we want to put a try/catch
// to avoid the worker crashing
try {
pyodide.FS.unlink(`./${file.fileName}`);
} catch (error) {
// File doesn't exist, nothing to delete
console.log("file does not exist, skipping deletion", {
fileName: file.fileName,
error,
});
}
} else {
console.log("worker fetching file", { file });
console.log("artifactBaseUrl", artifactBaseUrl);
const response = await fetch(
artifactBaseUrl + file.artifactId,
);

// Handle different file types based on mimeType
if (file.mimeType && file.mimeType.startsWith("text/")) {
// Text files
const content = await response.text();
pyodide.FS.writeFile(`./${file.fileName}`, content);
} else {
// Binary files (images, etc.)
const arrayBuffer = await response.arrayBuffer();
const uint8Array = new Uint8Array(arrayBuffer);
pyodide.FS.writeFile(`./${file.fileName}`, uint8Array);
}
}
}

console.log("worker wrote files and cleaned up old files", { data });

self.postMessage({ id, type: "response", data: { success: true } });
} catch (error) {
console.error("Error in files message handler", error);
self.postMessage({
id,
type: "response",
error: error instanceof Error ? error.message : String(error),
});
}
break;
}

case "shutdown": {
await shutdownWorker();
self.postMessage({ id, type: "response", data: { success: true } });
Expand Down
2 changes: 1 addition & 1 deletion packages/schema/deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
},
"imports": {
"fractional-indexing": "npm:fractional-indexing@^3.2.0",
"@runtimed/schema": "jsr:@runtimed/schema@0.1.12",
"@runtimed/schema": "jsr:@runtimed/schema@0.3.0",
"jsr:@std/testing": "jsr:@std/testing@^1.0.15"
},
"lint": {
Expand Down