@pushpalsdev/cli 1.1.31 → 1.1.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/runtime/sandbox/apps/workerpals/src/backends/openai_codex/test_openai_codex_runtime_config.py +22 -0
- package/runtime/sandbox/apps/workerpals/src/backends/openhands_task_execute.ts +8 -1
- package/runtime/sandbox/apps/workerpals/src/backends/shared/executor_base.py +15 -4
- package/runtime/sandbox/apps/workerpals/src/common/generic_python_executor.ts +14 -6
- package/runtime/sandbox/apps/workerpals/src/common/python_payload_transport.ts +26 -0
- package/runtime/sandbox/package.json +1 -0
package/package.json
CHANGED
|
@@ -350,6 +350,28 @@ class OpenAICodexRuntimeConfigTests(unittest.TestCase):
|
|
|
350
350
|
self.assertIn("Home shell startup is assertable", guidance)
|
|
351
351
|
self.assertIn("bun run web:e2e", guidance)
|
|
352
352
|
|
|
353
|
+
def test_parse_payload_accepts_file_backed_payload_transport(self) -> None:
|
|
354
|
+
with tempfile.TemporaryDirectory(prefix="pushpals-payload-file-") as temp_dir:
|
|
355
|
+
repo = Path(temp_dir) / "repo"
|
|
356
|
+
repo.mkdir(parents=True, exist_ok=True)
|
|
357
|
+
payload = {
|
|
358
|
+
"kind": "task.execute",
|
|
359
|
+
"repo": str(repo),
|
|
360
|
+
"params": {"instruction": "Make one small publishable change"},
|
|
361
|
+
}
|
|
362
|
+
encoded = base64.b64encode(json.dumps(payload).encode("utf-8")).decode("ascii")
|
|
363
|
+
payload_file = Path(temp_dir) / "payload.b64"
|
|
364
|
+
payload_file.write_text(encoded, encoding="utf-8")
|
|
365
|
+
|
|
366
|
+
task = parse_task_execute_payload(
|
|
367
|
+
["executor", "--payload-file", str(payload_file)],
|
|
368
|
+
logger=Logger("[test]"),
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
self.assertEqual(task.kind, "task.execute")
|
|
372
|
+
self.assertEqual(task.repo, str(repo.resolve()))
|
|
373
|
+
self.assertEqual(task.instruction, "Make one small publishable change")
|
|
374
|
+
|
|
353
375
|
def test_parse_payload_prefers_helper_tests_for_visual_derivation_tasks(self) -> None:
|
|
354
376
|
with tempfile.TemporaryDirectory(prefix="pushpals-visual-guidance-") as temp_dir:
|
|
355
377
|
repo = Path(temp_dir) / "repo"
|
|
@@ -17,6 +17,10 @@ import {
|
|
|
17
17
|
filterResultLines,
|
|
18
18
|
} from "../common/execution_utils.js";
|
|
19
19
|
import { buildWorkerSandboxWritableEnv } from "../common/sandbox_env.js";
|
|
20
|
+
import {
|
|
21
|
+
createPythonPayloadTransport,
|
|
22
|
+
type PythonPayloadTransport,
|
|
23
|
+
} from "../common/python_payload_transport.js";
|
|
20
24
|
import { computeTimeoutWarningWindow } from "../timeout_policy.js";
|
|
21
25
|
|
|
22
26
|
// ---- Script path (resolved relative to this file) ----------------------------
|
|
@@ -274,6 +278,7 @@ export async function executeWithOpenHands(
|
|
|
274
278
|
let timeoutTimer: ReturnType<typeof setTimeout> | null = null;
|
|
275
279
|
let stuckNudgeStartTimer: ReturnType<typeof setTimeout> | null = null;
|
|
276
280
|
let stuckNudgeTimer: ReturnType<typeof setInterval> | null = null;
|
|
281
|
+
let payloadTransport: PythonPayloadTransport | null = null;
|
|
277
282
|
const outputPolicy = {
|
|
278
283
|
maxOutputChars: runtimeConfig.workerpals.outputMaxChars,
|
|
279
284
|
maxOutputLines: runtimeConfig.workerpals.outputMaxLines,
|
|
@@ -282,7 +287,8 @@ export async function executeWithOpenHands(
|
|
|
282
287
|
};
|
|
283
288
|
|
|
284
289
|
try {
|
|
285
|
-
|
|
290
|
+
payloadTransport = createPythonPayloadTransport(payload);
|
|
291
|
+
const proc = Bun.spawn([pythonBin, scriptPath, ...payloadTransport.args], {
|
|
286
292
|
cwd: repo,
|
|
287
293
|
stdout: "pipe",
|
|
288
294
|
stderr: "pipe",
|
|
@@ -623,5 +629,6 @@ export async function executeWithOpenHands(
|
|
|
623
629
|
if (stuckNudgeTimer) {
|
|
624
630
|
clearInterval(stuckNudgeTimer);
|
|
625
631
|
}
|
|
632
|
+
payloadTransport?.cleanup();
|
|
626
633
|
}
|
|
627
634
|
}
|
|
@@ -163,6 +163,20 @@ def decode_payload(raw: str) -> Dict[str, Any]:
|
|
|
163
163
|
return payload
|
|
164
164
|
|
|
165
165
|
|
|
166
|
+
def read_encoded_payload_arg(argv: List[str]) -> str:
|
|
167
|
+
if len(argv) < 2:
|
|
168
|
+
raise ValueError("missing base64 job payload")
|
|
169
|
+
mode = argv[1]
|
|
170
|
+
if mode == "--payload-file":
|
|
171
|
+
if len(argv) < 3 or not str(argv[2] or "").strip():
|
|
172
|
+
raise ValueError("missing payload file path")
|
|
173
|
+
path = Path(str(argv[2])).expanduser()
|
|
174
|
+
return path.read_text(encoding="utf-8").strip()
|
|
175
|
+
if mode == "--payload-stdin":
|
|
176
|
+
return sys.stdin.read().strip()
|
|
177
|
+
return mode
|
|
178
|
+
|
|
179
|
+
|
|
166
180
|
def resolve_repo_within_assigned_root(repo: str) -> Tuple[Optional[str], Optional[str]]:
|
|
167
181
|
raw_repo = str(repo or "").strip()
|
|
168
182
|
if not raw_repo:
|
|
@@ -968,11 +982,8 @@ def parse_task_execute_payload(
|
|
|
968
982
|
don't need to handle them.
|
|
969
983
|
"""
|
|
970
984
|
log = logger or Logger("[Executor]")
|
|
971
|
-
if len(argv) < 2:
|
|
972
|
-
raise SystemExit(fail("Missing base64 job payload", exit_code=2))
|
|
973
|
-
|
|
974
985
|
try:
|
|
975
|
-
payload = decode_payload(argv
|
|
986
|
+
payload = decode_payload(read_encoded_payload_arg(argv))
|
|
976
987
|
except Exception as exc:
|
|
977
988
|
raise SystemExit(fail(f"Failed to decode job payload: {exc}", exit_code=2))
|
|
978
989
|
|
|
@@ -19,6 +19,10 @@ import {
|
|
|
19
19
|
streamLines,
|
|
20
20
|
} from "./execution_utils.js";
|
|
21
21
|
import { buildWorkerSandboxWritableEnv } from "./sandbox_env.js";
|
|
22
|
+
import {
|
|
23
|
+
createPythonPayloadTransport,
|
|
24
|
+
type PythonPayloadTransport,
|
|
25
|
+
} from "./python_payload_transport.js";
|
|
22
26
|
|
|
23
27
|
interface GenericPythonExecutorConfig {
|
|
24
28
|
backendName: string;
|
|
@@ -357,7 +361,6 @@ export function createGenericPythonExecutor(
|
|
|
357
361
|
}),
|
|
358
362
|
"utf-8",
|
|
359
363
|
).toString("base64");
|
|
360
|
-
const args = [pythonBin, scriptPath, payloadBase64];
|
|
361
364
|
const childTimeoutMs = resolveGenericPythonExecutorChildTimeoutMs({
|
|
362
365
|
backendName,
|
|
363
366
|
hostTimeoutMs: timeoutMs,
|
|
@@ -379,12 +382,15 @@ export function createGenericPythonExecutor(
|
|
|
379
382
|
)}ms`
|
|
380
383
|
: "";
|
|
381
384
|
|
|
382
|
-
|
|
383
|
-
"stdout",
|
|
384
|
-
`[${backendLabel}Executor] Spawning ${backendName} executor (timeout=${timeoutMs}ms; ${timeoutDetail}${childTimeoutDetail})`,
|
|
385
|
-
);
|
|
386
|
-
|
|
385
|
+
let payloadTransport: PythonPayloadTransport | null = null;
|
|
387
386
|
try {
|
|
387
|
+
payloadTransport = createPythonPayloadTransport(payloadBase64);
|
|
388
|
+
const args = [pythonBin, scriptPath, ...payloadTransport.args];
|
|
389
|
+
onLog?.(
|
|
390
|
+
"stdout",
|
|
391
|
+
`[${backendLabel}Executor] Spawning ${backendName} executor (timeout=${timeoutMs}ms; ${timeoutDetail}${childTimeoutDetail})`,
|
|
392
|
+
);
|
|
393
|
+
|
|
388
394
|
const outputPolicy = {
|
|
389
395
|
maxOutputChars: runtimeConfig.workerpals.outputMaxChars,
|
|
390
396
|
maxOutputLines: runtimeConfig.workerpals.outputMaxLines,
|
|
@@ -539,6 +545,8 @@ export function createGenericPythonExecutor(
|
|
|
539
545
|
"",
|
|
540
546
|
),
|
|
541
547
|
};
|
|
548
|
+
} finally {
|
|
549
|
+
payloadTransport?.cleanup();
|
|
542
550
|
}
|
|
543
551
|
};
|
|
544
552
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { mkdtempSync, rmSync, writeFileSync } from "fs";
|
|
2
|
+
import { tmpdir } from "os";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
|
|
5
|
+
export interface PythonPayloadTransport {
|
|
6
|
+
args: string[];
|
|
7
|
+
filePath: string;
|
|
8
|
+
cleanup: () => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function createPythonPayloadTransport(payloadBase64: string): PythonPayloadTransport {
|
|
12
|
+
const dir = mkdtempSync(join(tmpdir(), "pushpals-python-payload-"));
|
|
13
|
+
const filePath = join(dir, "payload.b64");
|
|
14
|
+
writeFileSync(filePath, payloadBase64, { encoding: "utf8", mode: 0o600 });
|
|
15
|
+
|
|
16
|
+
let cleaned = false;
|
|
17
|
+
return {
|
|
18
|
+
args: ["--payload-file", filePath],
|
|
19
|
+
filePath,
|
|
20
|
+
cleanup: () => {
|
|
21
|
+
if (cleaned) return;
|
|
22
|
+
cleaned = true;
|
|
23
|
+
rmSync(dir, { recursive: true, force: true });
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"cli": "bun run scripts/pushpals-cli.ts",
|
|
10
10
|
"cli:integration": "bun run scripts/cli-integration.ts",
|
|
11
11
|
"cli:bundle": "bun run --cwd packages/cli build",
|
|
12
|
+
"cli:verify-package-payload": "bun run scripts/verify-cli-package-payload.ts",
|
|
12
13
|
"cli:monitor:export": "bun run scripts/sync-cli-monitor-ui.ts",
|
|
13
14
|
"replay:worker-job": "bun run scripts/replay-worker-job.ts",
|
|
14
15
|
"protocol:build": "bun --cwd packages/protocol build",
|