mirror of
https://github.com/andrewyng/openworker.git
synced 2026-11-04 13:27:11 +00:00
199 lines
5.8 KiB
JavaScript
199 lines
5.8 KiB
JavaScript
// Optional single live task in a separate pinned cohort. Key arrives on stdin.
|
|
// Existing fixture/variant pools and their saved sessions are never relabelled.
|
|
import assert from "node:assert/strict";
|
|
import { readFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { randomUUID, createHash } from "node:crypto";
|
|
import { repo, run, kubectl, apply } from "../helm/local.mjs";
|
|
import {
|
|
root,
|
|
context,
|
|
save,
|
|
wait,
|
|
pods,
|
|
forward,
|
|
client,
|
|
permitPodIdentity,
|
|
} from "./qualification-lib.mjs";
|
|
const m = await context(),
|
|
k = (args) => kubectl(m, ["-n", "ow-app", ...args]);
|
|
const proof = JSON.parse(
|
|
await readFile(join(root, "current-http-qualification.json"), "utf8"),
|
|
);
|
|
assert.equal(proof.status, "completed");
|
|
let key = "";
|
|
for await (const b of process.stdin) {
|
|
key += b;
|
|
if (key.length > 4096) throw Error("Key input limit");
|
|
}
|
|
key = key.trim();
|
|
assert.ok(key && !/\s/.test(key));
|
|
const model = "gpt-6-sol";
|
|
const check = await fetch("https://api.openai.com/v1/models/" + model, {
|
|
headers: { Authorization: "Bearer " + key },
|
|
redirect: "error",
|
|
signal: AbortSignal.timeout(20000),
|
|
});
|
|
assert.equal(check.status, 200, "Selected model unavailable");
|
|
await check.body?.cancel();
|
|
await apply(m, [
|
|
{
|
|
apiVersion: "v1",
|
|
kind: "Secret",
|
|
metadata: {
|
|
name: "openai-model",
|
|
namespace: "ow-app",
|
|
labels: { "openworker.dev/experiment": m.context },
|
|
},
|
|
stringData: { OPENAI_API_KEY: key },
|
|
},
|
|
]);
|
|
key = "";
|
|
const v = JSON.parse(await readFile(join(root, "values.json"), "utf8"));
|
|
v.api.replicas = 1;
|
|
v.worker.replicas = 1;
|
|
v.taskDesk.enabled = false;
|
|
v.config.scripted = false;
|
|
v.config.model = model;
|
|
v.secrets.model = "openai-model";
|
|
await permitPodIdentity(m, "live");
|
|
await save("live-values.json", v);
|
|
await run(m.helm, [
|
|
"upgrade",
|
|
"--install",
|
|
"live",
|
|
join(repo, "deploy/helm/openworker"),
|
|
"--kubeconfig",
|
|
m.kubeconfig,
|
|
"--kube-context",
|
|
m.context,
|
|
"-n",
|
|
"ow-app",
|
|
"-f",
|
|
join(root, "live-values.json"),
|
|
]);
|
|
for (const role of ["api", "worker"])
|
|
await k([
|
|
"rollout",
|
|
"status",
|
|
"deployment/live-openworker-" + role,
|
|
"--timeout=180s",
|
|
]);
|
|
const f = await forward(m, (await pods(m, "api", "live"))[0].metadata.name),
|
|
a = await client(f.port);
|
|
let sid,
|
|
finished = false;
|
|
try {
|
|
const environment = JSON.parse(
|
|
await readFile(join(root, "environment.json"), "utf8"),
|
|
),
|
|
path = "packing-" + randomUUID() + ".md";
|
|
sid = (
|
|
await a.json("/sessions", {
|
|
request_id: randomUUID(),
|
|
parameters: {
|
|
name: "Live cloud packing checklist",
|
|
coworker: "task-desk",
|
|
workspace: "/sandbox",
|
|
environment_id: environment.id,
|
|
},
|
|
})
|
|
).session_id;
|
|
await a.json(`/sessions/${sid}/turns`, {
|
|
submission_id: randomUUID(),
|
|
text: `Write exactly five practical Markdown checklist bullets for a weekend trip to ${path}. Use write_file then read_file to verify it. Do not use run_shell or any other tools. Include the checklist in your final answer.`,
|
|
});
|
|
const approved = new Set();
|
|
const result = await wait(async () => {
|
|
const s = await a.snapshot(sid);
|
|
assert.ok(
|
|
!["failed", "cancelled", "interrupted", "truncated"].includes(
|
|
s.turn?.status,
|
|
),
|
|
);
|
|
for (const i of s.interactions) {
|
|
if (approved.has(i.id)) continue;
|
|
assert.equal(i.kind, "approval");
|
|
assert.ok(
|
|
["write_file", "read_file"].includes(i.call.name),
|
|
"Unexpected tool: not approved",
|
|
);
|
|
const args = JSON.parse(i.call.arguments);
|
|
assert.equal(args.path, path);
|
|
if (i.call.name === "write_file")
|
|
assert.ok(
|
|
typeof args.content === "string" && args.content.length < 4096,
|
|
);
|
|
assert.ok(approved.size < 2);
|
|
await a.approve(sid, s, i.call.name);
|
|
approved.add(i.id);
|
|
}
|
|
return s.turn?.status === "completed" && s;
|
|
}, 180000);
|
|
assert.equal(result.mode, "live");
|
|
assert.equal(result.session.model, model);
|
|
assert.equal(approved.size, 2);
|
|
const events = await a.events(sid, result.cursor),
|
|
tools = events.filter((e) => e.type === "tool_finished");
|
|
assert.deepEqual(
|
|
tools.map((e) => e.data.name),
|
|
["write_file", "read_file"],
|
|
);
|
|
for (const t of tools) assert.notEqual(t.data.result.isError, true);
|
|
const bytes = Buffer.from(JSON.stringify(result.messages)),
|
|
sha = createHash("sha256").update(bytes).digest("hex");
|
|
const artifact = await a.json(`/sessions/${sid}/artifacts`, {
|
|
request_id: randomUUID(),
|
|
name: "live-checklist.json",
|
|
turn_id: result.turn.id,
|
|
content_type: "application/json",
|
|
size: bytes.length,
|
|
sha256: sha,
|
|
});
|
|
assert.equal(
|
|
(
|
|
await a.request(`/sessions/${sid}/artifacts/${artifact.id}/content`, {
|
|
method: "PUT",
|
|
raw: bytes,
|
|
})
|
|
).status,
|
|
200,
|
|
);
|
|
assert.deepEqual(
|
|
(await a.request(`/sessions/${sid}/artifacts/${artifact.id}/content`))
|
|
.bytes,
|
|
bytes,
|
|
);
|
|
finished = true;
|
|
await save("current-live-qualification.json", {
|
|
status: "completed",
|
|
time: new Date().toISOString(),
|
|
session: sid,
|
|
model,
|
|
approvals: approved.size,
|
|
artifact: artifact.id,
|
|
sha256: sha,
|
|
checks: [
|
|
"Live model calls real sandbox write/read under two bounded exact approvals",
|
|
"Final response published and downloaded through real S3",
|
|
"Separate model cohort leaves existing fixture sessions and pools intact",
|
|
],
|
|
});
|
|
console.log(
|
|
"PASS live Sol, two exact approvals, sandbox write/read and verified S3 output",
|
|
);
|
|
} finally {
|
|
if (sid && !finished) {
|
|
const s = await a.snapshot(sid).catch(() => null);
|
|
if (s?.turn)
|
|
await a
|
|
.json(`/sessions/${sid}/controls`, {
|
|
request_id: randomUUID(),
|
|
turn_id: s.turn.id,
|
|
action: { kind: "cancel" },
|
|
})
|
|
.catch(() => {});
|
|
}
|
|
f.close();
|
|
}
|