Read native plugin task output files on the execution host (#17285)

This commit is contained in:
Nicky Leach authored and GitHub committed 2026-10-22 23:38:09 -07:00
1 parent d69631b01b
commit 412914cfa7
15 files changed
+202 -24

No files matched your search

@@ -1,3 +1,4 @@
import { createHash } from "node:crypto";
import { setTimeout as delay } from "node:timers/promises";
import { environmentTaskOperationSchema, environmentTaskResultSchema, type PluginEnvironmentTaskOperation, type PluginEnvironmentTaskResult, type PluginEnvironmentTaskCredential } from "@paperclipai/plugin-sdk";
import type { RunnerIngressEndpoint } from "@paperclipai/adapter-utils/runner-connectivity";
@@ -44,7 +45,7 @@ export function createPluginRunnerTaskOwner(input: {
void running.catch(() => undefined);
const call = async (operation: PluginEnvironmentTaskOperation) => {
const result = environmentTaskResultSchema.parse(await input.task(operation));
if (result.kind !== (operation.kind === "describe" ? "description" : operation.kind === "prepare" ? "prepared" : operation.kind === "check_project_auth" ? "project_auth" : ["read_state", "archive_state"].includes(operation.kind) ? "state" : ["status", "connection", "credentials"].includes(operation.kind) ? operation.kind : "accepted")) {
if (result.kind !== (operation.kind === "read_file" ? "file" : operation.kind === "describe" ? "description" : operation.kind === "prepare" ? "prepared" : operation.kind === "check_project_auth" ? "project_auth" : ["read_state", "archive_state"].includes(operation.kind) ? "state" : ["status", "connection", "credentials"].includes(operation.kind) ? operation.kind : "accepted")) {
throw new Error("Plugin Runner returned an invalid operation result");
}
return result;
@@ -247,5 +248,15 @@ export function createPluginRunnerTaskOwner(input: {
},
controlPlaneRegistration: (authority, identity, signal) => registration(authority, identity?.runId ?? "", signal),
};
return { launcher, registration, driver };
const readWorkspaceFile = async (path: string, maxBytes: number): Promise<Buffer> => {
if (!submitted || !preparedIdentity || released || stopRequested) throw new Error("Plugin Runner file access unavailable");
const result = await call(environmentTaskOperationSchema.parse({ kind: "read_file", identity: preparedIdentity,
projectIds: [...input.projectIds], path, maxBytes }));
if (released || stopRequested || result.kind !== "file" || result.byteSize > maxBytes) throw new Error("Plugin Runner file access unavailable");
const bytes = Buffer.from(result.base64, "base64");
if (bytes.length !== result.byteSize || bytes.toString("base64") !== result.base64 ||
createHash("sha256").update(bytes).digest("hex") !== result.sha256) throw new Error("Plugin Runner file integrity check failed");
return bytes;
};
return { launcher, registration, driver, readWorkspaceFile };
}