@themoltnet/pi-extension 0.22.5 → 0.23.1
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/dist/index.d.ts +10 -3
- package/dist/index.js +529 -40
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -718,9 +718,8 @@ declare const Task: Type.TObject<{
|
|
|
718
718
|
acceptedAttemptN: Type.TUnion<[Type.TNumber, Type.TNull]>;
|
|
719
719
|
claimCondition: Type.TUnion<[Type.TUnsafe<ClaimCondition>, Type.TNull]>;
|
|
720
720
|
requiredExecutorTrustLevel: Type.TUnion<[Type.TLiteral<"selfDeclared">, Type.TLiteral<"agentSigned">, Type.TLiteral<"releaseVerifiedTool">, Type.TLiteral<"sandboxAttested">]>;
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
model: Type.TString;
|
|
721
|
+
allowedProfiles: Type.TArray<Type.TObject<{
|
|
722
|
+
profileId: Type.TString;
|
|
724
723
|
}>>;
|
|
725
724
|
status: Type.TUnion<[Type.TLiteral<"waiting">, Type.TLiteral<"queued">, Type.TLiteral<"dispatched">, Type.TLiteral<"running">, Type.TLiteral<"completed">, Type.TLiteral<"failed">, Type.TLiteral<"cancelled">, Type.TLiteral<"expired">]>;
|
|
726
725
|
queuedAt: Type.TString;
|
|
@@ -844,6 +843,12 @@ declare interface TaskReporter {
|
|
|
844
843
|
* cancellation has been observed. Null until `cancelSignal` aborts.
|
|
845
844
|
*/
|
|
846
845
|
readonly cancelReason: string | null;
|
|
846
|
+
/**
|
|
847
|
+
* Request local cancellation of the in-flight task. Runtime shutdown uses
|
|
848
|
+
* this to trip the same executor-facing signal as proposer cancellation,
|
|
849
|
+
* without waiting for the next server heartbeat.
|
|
850
|
+
*/
|
|
851
|
+
requestCancel?(reason: string): void;
|
|
847
852
|
}
|
|
848
853
|
|
|
849
854
|
declare const TaskStatus: Type.TUnion<[Type.TLiteral<"waiting">, Type.TLiteral<"queued">, Type.TLiteral<"dispatched">, Type.TLiteral<"running">, Type.TLiteral<"completed">, Type.TLiteral<"failed">, Type.TLiteral<"cancelled">, Type.TLiteral<"expired">]>;
|
|
@@ -902,6 +907,8 @@ export declare interface VmConfig {
|
|
|
902
907
|
extraAllowedHosts?: string[];
|
|
903
908
|
/** Full sandbox config (vfs shadows, env overrides). */
|
|
904
909
|
sandboxConfig?: SandboxConfig;
|
|
910
|
+
/** Abort resume/setup work, closing any live VM owned by resumeVm. */
|
|
911
|
+
signal?: AbortSignal;
|
|
905
912
|
}
|
|
906
913
|
|
|
907
914
|
export declare interface VmCredentials {
|
package/dist/index.js
CHANGED
|
@@ -1674,6 +1674,124 @@ var updateRenderedPack = (options) => (options.client ?? client).patch({
|
|
|
1674
1674
|
}
|
|
1675
1675
|
});
|
|
1676
1676
|
/**
|
|
1677
|
+
* List runtime profiles for the active team context.
|
|
1678
|
+
*/
|
|
1679
|
+
var listRuntimeProfiles = (options) => (options?.client ?? client).get({
|
|
1680
|
+
security: [
|
|
1681
|
+
{
|
|
1682
|
+
scheme: "bearer",
|
|
1683
|
+
type: "http"
|
|
1684
|
+
},
|
|
1685
|
+
{
|
|
1686
|
+
name: "X-Moltnet-Session-Token",
|
|
1687
|
+
type: "apiKey"
|
|
1688
|
+
},
|
|
1689
|
+
{
|
|
1690
|
+
in: "cookie",
|
|
1691
|
+
name: "ory_kratos_session",
|
|
1692
|
+
type: "apiKey"
|
|
1693
|
+
}
|
|
1694
|
+
],
|
|
1695
|
+
url: "/runtime-profiles",
|
|
1696
|
+
...options
|
|
1697
|
+
});
|
|
1698
|
+
/**
|
|
1699
|
+
* Create a runtime profile for the active team context.
|
|
1700
|
+
*/
|
|
1701
|
+
var createRuntimeProfile = (options) => (options?.client ?? client).post({
|
|
1702
|
+
security: [
|
|
1703
|
+
{
|
|
1704
|
+
scheme: "bearer",
|
|
1705
|
+
type: "http"
|
|
1706
|
+
},
|
|
1707
|
+
{
|
|
1708
|
+
name: "X-Moltnet-Session-Token",
|
|
1709
|
+
type: "apiKey"
|
|
1710
|
+
},
|
|
1711
|
+
{
|
|
1712
|
+
in: "cookie",
|
|
1713
|
+
name: "ory_kratos_session",
|
|
1714
|
+
type: "apiKey"
|
|
1715
|
+
}
|
|
1716
|
+
],
|
|
1717
|
+
url: "/runtime-profiles",
|
|
1718
|
+
...options,
|
|
1719
|
+
headers: {
|
|
1720
|
+
"Content-Type": "application/json",
|
|
1721
|
+
...options?.headers
|
|
1722
|
+
}
|
|
1723
|
+
});
|
|
1724
|
+
/**
|
|
1725
|
+
* Delete one runtime profile.
|
|
1726
|
+
*/
|
|
1727
|
+
var deleteRuntimeProfile = (options) => (options.client ?? client).delete({
|
|
1728
|
+
security: [
|
|
1729
|
+
{
|
|
1730
|
+
scheme: "bearer",
|
|
1731
|
+
type: "http"
|
|
1732
|
+
},
|
|
1733
|
+
{
|
|
1734
|
+
name: "X-Moltnet-Session-Token",
|
|
1735
|
+
type: "apiKey"
|
|
1736
|
+
},
|
|
1737
|
+
{
|
|
1738
|
+
in: "cookie",
|
|
1739
|
+
name: "ory_kratos_session",
|
|
1740
|
+
type: "apiKey"
|
|
1741
|
+
}
|
|
1742
|
+
],
|
|
1743
|
+
url: "/runtime-profiles/{profileId}",
|
|
1744
|
+
...options
|
|
1745
|
+
});
|
|
1746
|
+
/**
|
|
1747
|
+
* Get one runtime profile.
|
|
1748
|
+
*/
|
|
1749
|
+
var getRuntimeProfile = (options) => (options.client ?? client).get({
|
|
1750
|
+
security: [
|
|
1751
|
+
{
|
|
1752
|
+
scheme: "bearer",
|
|
1753
|
+
type: "http"
|
|
1754
|
+
},
|
|
1755
|
+
{
|
|
1756
|
+
name: "X-Moltnet-Session-Token",
|
|
1757
|
+
type: "apiKey"
|
|
1758
|
+
},
|
|
1759
|
+
{
|
|
1760
|
+
in: "cookie",
|
|
1761
|
+
name: "ory_kratos_session",
|
|
1762
|
+
type: "apiKey"
|
|
1763
|
+
}
|
|
1764
|
+
],
|
|
1765
|
+
url: "/runtime-profiles/{profileId}",
|
|
1766
|
+
...options
|
|
1767
|
+
});
|
|
1768
|
+
/**
|
|
1769
|
+
* Update one runtime profile.
|
|
1770
|
+
*/
|
|
1771
|
+
var updateRuntimeProfile = (options) => (options.client ?? client).patch({
|
|
1772
|
+
security: [
|
|
1773
|
+
{
|
|
1774
|
+
scheme: "bearer",
|
|
1775
|
+
type: "http"
|
|
1776
|
+
},
|
|
1777
|
+
{
|
|
1778
|
+
name: "X-Moltnet-Session-Token",
|
|
1779
|
+
type: "apiKey"
|
|
1780
|
+
},
|
|
1781
|
+
{
|
|
1782
|
+
in: "cookie",
|
|
1783
|
+
name: "ory_kratos_session",
|
|
1784
|
+
type: "apiKey"
|
|
1785
|
+
}
|
|
1786
|
+
],
|
|
1787
|
+
url: "/runtime-profiles/{profileId}",
|
|
1788
|
+
...options,
|
|
1789
|
+
headers: {
|
|
1790
|
+
"Content-Type": "application/json",
|
|
1791
|
+
...options.headers
|
|
1792
|
+
}
|
|
1793
|
+
});
|
|
1794
|
+
/**
|
|
1677
1795
|
* List tasks for a team with optional filters.
|
|
1678
1796
|
*/
|
|
1679
1797
|
var listTasks = (options) => (options.client ?? client).get({
|
|
@@ -1788,6 +1906,32 @@ var listTaskAttempts = (options) => (options.client ?? client).get({
|
|
|
1788
1906
|
...options
|
|
1789
1907
|
});
|
|
1790
1908
|
/**
|
|
1909
|
+
* Claimant intentionally abandons this attempt (e.g. daemon shutdown). The attempt becomes aborted and the task requeues for another claim (or fails when retries are exhausted). Does NOT cancel the task.
|
|
1910
|
+
*/
|
|
1911
|
+
var abortTaskAttempt = (options) => (options.client ?? client).post({
|
|
1912
|
+
security: [
|
|
1913
|
+
{
|
|
1914
|
+
scheme: "bearer",
|
|
1915
|
+
type: "http"
|
|
1916
|
+
},
|
|
1917
|
+
{
|
|
1918
|
+
name: "X-Moltnet-Session-Token",
|
|
1919
|
+
type: "apiKey"
|
|
1920
|
+
},
|
|
1921
|
+
{
|
|
1922
|
+
in: "cookie",
|
|
1923
|
+
name: "ory_kratos_session",
|
|
1924
|
+
type: "apiKey"
|
|
1925
|
+
}
|
|
1926
|
+
],
|
|
1927
|
+
url: "/tasks/{id}/attempts/{n}/abort",
|
|
1928
|
+
...options,
|
|
1929
|
+
headers: {
|
|
1930
|
+
"Content-Type": "application/json",
|
|
1931
|
+
...options.headers
|
|
1932
|
+
}
|
|
1933
|
+
});
|
|
1934
|
+
/**
|
|
1791
1935
|
* Mark an attempt as completed with output.
|
|
1792
1936
|
*/
|
|
1793
1937
|
var completeTask = (options) => (options.client ?? client).post({
|
|
@@ -4696,6 +4840,54 @@ function createRecoveryNamespace(context) {
|
|
|
4696
4840
|
};
|
|
4697
4841
|
}
|
|
4698
4842
|
//#endregion
|
|
4843
|
+
//#region ../sdk/src/namespaces/runtime-profiles.ts
|
|
4844
|
+
function createRuntimeProfilesNamespace(context) {
|
|
4845
|
+
const { client, auth } = context;
|
|
4846
|
+
return {
|
|
4847
|
+
async list(options) {
|
|
4848
|
+
return unwrapResult(await listRuntimeProfiles({
|
|
4849
|
+
client,
|
|
4850
|
+
auth,
|
|
4851
|
+
headers: teamHeaders(options)
|
|
4852
|
+
}));
|
|
4853
|
+
},
|
|
4854
|
+
async create(body, options) {
|
|
4855
|
+
return unwrapResult(await createRuntimeProfile({
|
|
4856
|
+
client,
|
|
4857
|
+
auth,
|
|
4858
|
+
headers: teamHeaders(options),
|
|
4859
|
+
body
|
|
4860
|
+
}));
|
|
4861
|
+
},
|
|
4862
|
+
async get(profileId) {
|
|
4863
|
+
return unwrapResult(await getRuntimeProfile({
|
|
4864
|
+
client,
|
|
4865
|
+
auth,
|
|
4866
|
+
path: { profileId }
|
|
4867
|
+
}));
|
|
4868
|
+
},
|
|
4869
|
+
async update(profileId, body) {
|
|
4870
|
+
return unwrapResult(await updateRuntimeProfile({
|
|
4871
|
+
client,
|
|
4872
|
+
auth,
|
|
4873
|
+
path: { profileId },
|
|
4874
|
+
body
|
|
4875
|
+
}));
|
|
4876
|
+
},
|
|
4877
|
+
async delete(profileId) {
|
|
4878
|
+
const result = await deleteRuntimeProfile({
|
|
4879
|
+
client,
|
|
4880
|
+
auth,
|
|
4881
|
+
path: { profileId }
|
|
4882
|
+
});
|
|
4883
|
+
if (result.error) unwrapResult(result);
|
|
4884
|
+
}
|
|
4885
|
+
};
|
|
4886
|
+
}
|
|
4887
|
+
function teamHeaders(options) {
|
|
4888
|
+
return options?.teamId ? { "x-moltnet-team-id": options.teamId } : void 0;
|
|
4889
|
+
}
|
|
4890
|
+
//#endregion
|
|
4699
4891
|
//#region ../sdk/src/namespaces/signing-requests.ts
|
|
4700
4892
|
function createSigningRequestsNamespace(context) {
|
|
4701
4893
|
const { client, auth } = context;
|
|
@@ -4816,6 +5008,17 @@ function createTasksNamespace(context) {
|
|
|
4816
5008
|
body
|
|
4817
5009
|
}));
|
|
4818
5010
|
},
|
|
5011
|
+
async abortAttempt(id, n, body) {
|
|
5012
|
+
return unwrapResult(await abortTaskAttempt({
|
|
5013
|
+
client,
|
|
5014
|
+
auth,
|
|
5015
|
+
path: {
|
|
5016
|
+
id,
|
|
5017
|
+
n
|
|
5018
|
+
},
|
|
5019
|
+
body
|
|
5020
|
+
}));
|
|
5021
|
+
},
|
|
4819
5022
|
async cancel(id, body) {
|
|
4820
5023
|
return unwrapResult(await cancelTask({
|
|
4821
5024
|
client,
|
|
@@ -4999,6 +5202,7 @@ function createAgent(options) {
|
|
|
4999
5202
|
legreffier: createLegreffierNamespace(context),
|
|
5000
5203
|
problems: createProblemsNamespace(context),
|
|
5001
5204
|
teams: createTeamsNamespace(context),
|
|
5205
|
+
runtimeProfiles: createRuntimeProfilesNamespace(context),
|
|
5002
5206
|
tasks: createTasksNamespace(context),
|
|
5003
5207
|
client,
|
|
5004
5208
|
getToken: () => tokenManager.getToken()
|
|
@@ -8310,6 +8514,63 @@ function pruneOldSnapshots(maxCached, currentDir) {
|
|
|
8310
8514
|
});
|
|
8311
8515
|
}
|
|
8312
8516
|
//#endregion
|
|
8517
|
+
//#region src/abort-utils.ts
|
|
8518
|
+
function throwIfAborted(signal, label) {
|
|
8519
|
+
if (!signal?.aborted) return;
|
|
8520
|
+
throw abortError(label, signal);
|
|
8521
|
+
}
|
|
8522
|
+
function abortError(label, signal) {
|
|
8523
|
+
const reason = signal.reason;
|
|
8524
|
+
const suffix = reason instanceof Error ? reason.message : reason === void 0 ? "aborted" : String(reason);
|
|
8525
|
+
const err = /* @__PURE__ */ new Error(`${label} aborted: ${suffix}`);
|
|
8526
|
+
err.name = "AbortError";
|
|
8527
|
+
return err;
|
|
8528
|
+
}
|
|
8529
|
+
function cleanupLateResource(resourcePromise, opts) {
|
|
8530
|
+
resourcePromise.then(async (resource) => {
|
|
8531
|
+
try {
|
|
8532
|
+
await opts.cleanup(resource);
|
|
8533
|
+
} catch (err) {
|
|
8534
|
+
opts.onCleanupError?.(err);
|
|
8535
|
+
}
|
|
8536
|
+
}, () => {});
|
|
8537
|
+
}
|
|
8538
|
+
async function abortableResource(opts) {
|
|
8539
|
+
const { signal } = opts;
|
|
8540
|
+
if (!signal) return opts.promise;
|
|
8541
|
+
throwIfAborted(signal, opts.label);
|
|
8542
|
+
const resourcePromise = Promise.resolve(opts.promise);
|
|
8543
|
+
const abortPromise = new Promise((_, reject) => {
|
|
8544
|
+
const abort = () => {
|
|
8545
|
+
cleanupLateResource(resourcePromise, opts);
|
|
8546
|
+
reject(abortError(opts.label, signal));
|
|
8547
|
+
};
|
|
8548
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
8549
|
+
resourcePromise.then(() => signal.removeEventListener("abort", abort), () => signal.removeEventListener("abort", abort));
|
|
8550
|
+
});
|
|
8551
|
+
return Promise.race([resourcePromise, abortPromise]);
|
|
8552
|
+
}
|
|
8553
|
+
async function delay(ms, signal, label) {
|
|
8554
|
+
if (!signal) {
|
|
8555
|
+
await new Promise((resolve) => {
|
|
8556
|
+
setTimeout(resolve, ms);
|
|
8557
|
+
});
|
|
8558
|
+
return;
|
|
8559
|
+
}
|
|
8560
|
+
throwIfAborted(signal, label);
|
|
8561
|
+
await new Promise((resolve, reject) => {
|
|
8562
|
+
const listener = () => {
|
|
8563
|
+
clearTimeout(timeout);
|
|
8564
|
+
reject(abortError(label, signal));
|
|
8565
|
+
};
|
|
8566
|
+
const timeout = setTimeout(() => {
|
|
8567
|
+
signal.removeEventListener("abort", listener);
|
|
8568
|
+
resolve();
|
|
8569
|
+
}, ms);
|
|
8570
|
+
signal.addEventListener("abort", listener, { once: true });
|
|
8571
|
+
});
|
|
8572
|
+
}
|
|
8573
|
+
//#endregion
|
|
8313
8574
|
//#region src/vm-manager.ts
|
|
8314
8575
|
/**
|
|
8315
8576
|
* Memory-backed VFS mount used by the daemon to inject task-context
|
|
@@ -8426,23 +8687,33 @@ var BASE_ALLOWED_HOSTS = [
|
|
|
8426
8687
|
* surface immediately rather than fall through to cryptic agent
|
|
8427
8688
|
* errors later.
|
|
8428
8689
|
*/
|
|
8429
|
-
async function vmRun(vm, label, command) {
|
|
8690
|
+
async function vmRun(vm, label, command, signal) {
|
|
8430
8691
|
const wrapped = `set -eu\nset -o pipefail\n${command}`;
|
|
8692
|
+
throwIfAborted(signal, `resume step "${label}"`);
|
|
8431
8693
|
const r = await vm.exec([
|
|
8432
8694
|
"sh",
|
|
8433
8695
|
"-c",
|
|
8434
8696
|
wrapped
|
|
8435
|
-
]);
|
|
8697
|
+
], { signal });
|
|
8436
8698
|
if (r.exitCode !== 0) {
|
|
8437
8699
|
const tail = [r.stderr, r.stdout].filter(Boolean).join("\n").slice(-800);
|
|
8438
8700
|
throw new Error(`resume step "${label}" failed (exit ${r.exitCode}):\n${tail}`);
|
|
8439
8701
|
}
|
|
8440
8702
|
}
|
|
8703
|
+
function nonErrorMessage(err) {
|
|
8704
|
+
if (typeof err === "string") return err;
|
|
8705
|
+
try {
|
|
8706
|
+
return JSON.stringify(err) ?? "unknown error";
|
|
8707
|
+
} catch {
|
|
8708
|
+
return "unknown error";
|
|
8709
|
+
}
|
|
8710
|
+
}
|
|
8441
8711
|
/**
|
|
8442
8712
|
* Resume a VM from a checkpoint, inject credentials, configure egress +
|
|
8443
8713
|
* TLS. Returns the managed VM handle.
|
|
8444
8714
|
*/
|
|
8445
8715
|
async function resumeVm(config) {
|
|
8716
|
+
throwIfAborted(config.signal, "VM resume");
|
|
8446
8717
|
const mainRepo = findMainWorktree();
|
|
8447
8718
|
const agentDir = path.join(mainRepo, ".moltnet", config.agentName);
|
|
8448
8719
|
const guestWorkspace = path.resolve(config.mountPath);
|
|
@@ -8486,24 +8757,33 @@ async function resumeVm(config) {
|
|
|
8486
8757
|
};
|
|
8487
8758
|
const resources = config.sandboxConfig?.resources;
|
|
8488
8759
|
const workspaceMode = config.workspaceMode ?? "shared_mount";
|
|
8489
|
-
const vm = await
|
|
8490
|
-
|
|
8491
|
-
|
|
8492
|
-
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
|
|
8760
|
+
const vm = await abortableResource({
|
|
8761
|
+
promise: VmCheckpoint.load(config.checkpointPath).resume({
|
|
8762
|
+
httpHooks,
|
|
8763
|
+
env: vmEnv,
|
|
8764
|
+
...resources?.memory && { memory: resources.memory },
|
|
8765
|
+
...resources?.cpus && { cpus: resources.cpus },
|
|
8766
|
+
vfs: { mounts: {
|
|
8767
|
+
[guestWorkspace]: workspaceProvider,
|
|
8768
|
+
[GUEST_TASK_SKILLS_MOUNT]: new MemoryProvider()
|
|
8769
|
+
} }
|
|
8770
|
+
}),
|
|
8771
|
+
signal: config.signal,
|
|
8772
|
+
label: "VM resume",
|
|
8773
|
+
cleanup: (resumedVm) => resumedVm.close(),
|
|
8774
|
+
onCleanupError: (err) => {
|
|
8775
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
8776
|
+
process.stderr.write(`[vm] aborted resume late vm.close() failed: ${message}\n`);
|
|
8777
|
+
}
|
|
8498
8778
|
});
|
|
8499
8779
|
try {
|
|
8500
|
-
await vm
|
|
8780
|
+
await vmRun(vm, "TLS certificates", `
|
|
8501
8781
|
cp /etc/gondolin/mitm/ca.crt /usr/local/share/ca-certificates/gondolin-mitm.crt
|
|
8502
8782
|
update-ca-certificates 2>/dev/null
|
|
8503
8783
|
cat /etc/gondolin/mitm/ca.crt >> /etc/ssl/certs/ca-certificates.crt
|
|
8504
|
-
|
|
8505
|
-
await vmRun(vm, "DNS resolvers", `printf 'nameserver 8.8.8.8\\nnameserver 1.1.1.1\\n' > /etc/resolv.conf
|
|
8506
|
-
await vmRun(vm, "git safe.directory", `git config --system --add safe.directory '*'
|
|
8784
|
+
`, config.signal);
|
|
8785
|
+
await vmRun(vm, "DNS resolvers", `printf 'nameserver 8.8.8.8\\nnameserver 1.1.1.1\\n' > /etc/resolv.conf`, config.signal);
|
|
8786
|
+
await vmRun(vm, "git safe.directory", `git config --system --add safe.directory '*'`, config.signal);
|
|
8507
8787
|
for (const [i, entry] of (config.sandboxConfig?.resumeCommands ?? []).entries()) {
|
|
8508
8788
|
if (!shouldRunResumeCommand(entry, { workspaceMode })) continue;
|
|
8509
8789
|
const { run, retries, backoffMs } = typeof entry === "string" ? {
|
|
@@ -8518,34 +8798,67 @@ async function resumeVm(config) {
|
|
|
8518
8798
|
const label = `resumeCommands[${i}]`;
|
|
8519
8799
|
let lastErr;
|
|
8520
8800
|
for (let attempt = 0; attempt <= retries; attempt++) try {
|
|
8521
|
-
await vmRun(vm, label, run);
|
|
8801
|
+
await vmRun(vm, label, run, config.signal);
|
|
8522
8802
|
lastErr = void 0;
|
|
8523
8803
|
break;
|
|
8524
8804
|
} catch (err) {
|
|
8525
8805
|
lastErr = err;
|
|
8526
8806
|
if (attempt === retries) break;
|
|
8527
|
-
await
|
|
8528
|
-
setTimeout(resolve, (attempt + 1) * backoffMs);
|
|
8529
|
-
});
|
|
8807
|
+
await delay((attempt + 1) * backoffMs, config.signal, label);
|
|
8530
8808
|
}
|
|
8531
|
-
if (lastErr) throw lastErr instanceof Error ? lastErr : new Error(
|
|
8809
|
+
if (lastErr) throw lastErr instanceof Error ? lastErr : new Error(nonErrorMessage(lastErr));
|
|
8532
8810
|
}
|
|
8533
8811
|
const vmSshDir = `${vmAgentDir}/ssh`;
|
|
8534
|
-
await vm.exec(`mkdir -p ${vmAgentDir}/ssh /home/agent/.pi/agent
|
|
8535
|
-
if (creds.piAuthJson !== null) await vm.fs.writeFile("/home/agent/.pi/agent/auth.json", creds.piAuthJson, {
|
|
8812
|
+
await vm.exec(`mkdir -p ${vmAgentDir}/ssh /home/agent/.pi/agent`, { signal: config.signal });
|
|
8813
|
+
if (creds.piAuthJson !== null) await vm.fs.writeFile("/home/agent/.pi/agent/auth.json", creds.piAuthJson, {
|
|
8814
|
+
mode: 384,
|
|
8815
|
+
signal: config.signal
|
|
8816
|
+
});
|
|
8536
8817
|
const vmMoltnetJson = rewriteMoltnetJsonPaths(creds.moltnetJson, vmAgentDir, vmSshDir, creds.githubAppPemFilename);
|
|
8537
|
-
await vm.fs.writeFile(`${vmAgentDir}/moltnet.json`, vmMoltnetJson, {
|
|
8538
|
-
|
|
8818
|
+
await vm.fs.writeFile(`${vmAgentDir}/moltnet.json`, vmMoltnetJson, {
|
|
8819
|
+
mode: 384,
|
|
8820
|
+
signal: config.signal
|
|
8821
|
+
});
|
|
8822
|
+
await vm.fs.writeFile(`${vmAgentDir}/env`, creds.agentEnvRaw, {
|
|
8823
|
+
mode: 384,
|
|
8824
|
+
signal: config.signal
|
|
8825
|
+
});
|
|
8539
8826
|
if (creds.gitconfig) {
|
|
8540
8827
|
const vmSigningKey = `${vmSshDir}/id_ed25519`;
|
|
8541
8828
|
const vmGitconfig = creds.gitconfig.replace(/signingKey\s*=\s*.+/g, `signingKey = ${vmSigningKey}`);
|
|
8542
|
-
await vm.fs.writeFile(`${vmAgentDir}/gitconfig`, vmGitconfig, {
|
|
8829
|
+
await vm.fs.writeFile(`${vmAgentDir}/gitconfig`, vmGitconfig, {
|
|
8830
|
+
mode: 420,
|
|
8831
|
+
signal: config.signal
|
|
8832
|
+
});
|
|
8543
8833
|
}
|
|
8544
|
-
if (creds.sshPrivateKey) await vm.fs.writeFile(`${vmSshDir}/id_ed25519`, creds.sshPrivateKey, {
|
|
8545
|
-
|
|
8546
|
-
|
|
8547
|
-
|
|
8548
|
-
await vm.
|
|
8834
|
+
if (creds.sshPrivateKey) await vm.fs.writeFile(`${vmSshDir}/id_ed25519`, creds.sshPrivateKey, {
|
|
8835
|
+
mode: 384,
|
|
8836
|
+
signal: config.signal
|
|
8837
|
+
});
|
|
8838
|
+
if (creds.sshPublicKey) await vm.fs.writeFile(`${vmSshDir}/id_ed25519.pub`, creds.sshPublicKey, {
|
|
8839
|
+
mode: 420,
|
|
8840
|
+
signal: config.signal
|
|
8841
|
+
});
|
|
8842
|
+
if (creds.allowedSigners) await vm.fs.writeFile(`${vmSshDir}/allowed_signers`, creds.allowedSigners, {
|
|
8843
|
+
mode: 420,
|
|
8844
|
+
signal: config.signal
|
|
8845
|
+
});
|
|
8846
|
+
if (creds.githubAppPem && creds.githubAppPemFilename) await vm.fs.writeFile(`${vmAgentDir}/${creds.githubAppPemFilename}`, creds.githubAppPem, {
|
|
8847
|
+
mode: 384,
|
|
8848
|
+
signal: config.signal
|
|
8849
|
+
});
|
|
8850
|
+
await vm.exec("chown -R agent:agent /home/agent/.pi /home/agent/.moltnet", { signal: config.signal });
|
|
8851
|
+
const gitCredHelperPath = `${vmSshDir}/git-credential-moltnet`;
|
|
8852
|
+
const credHelperScript = `#!/bin/sh
|
|
8853
|
+
echo "username=x-access-token"
|
|
8854
|
+
echo "password=$(moltnet github token --credentials ${vmSshDir}/moltnet.json)"
|
|
8855
|
+
`;
|
|
8856
|
+
await vm.fs.writeFile(gitCredHelperPath, credHelperScript, {
|
|
8857
|
+
mode: 493,
|
|
8858
|
+
signal: config.signal
|
|
8859
|
+
});
|
|
8860
|
+
await vmRun(vm, "git credential helper", `git config --global credential.helper ${gitCredHelperPath} && \
|
|
8861
|
+
git config --global url."https://github.com/".insteadOf "git@github.com:"`, config.signal);
|
|
8549
8862
|
return {
|
|
8550
8863
|
vm,
|
|
8551
8864
|
credentials: creds,
|
|
@@ -13157,6 +13470,170 @@ function validateRubricWeights(rubric) {
|
|
|
13157
13470
|
return null;
|
|
13158
13471
|
}
|
|
13159
13472
|
//#endregion
|
|
13473
|
+
//#region ../tasks/src/runtime-profiles.ts
|
|
13474
|
+
var RuntimeProfileName = String$1({
|
|
13475
|
+
minLength: 1,
|
|
13476
|
+
maxLength: 100,
|
|
13477
|
+
pattern: "^[a-zA-Z0-9][a-zA-Z0-9_-]{0,99}$"
|
|
13478
|
+
});
|
|
13479
|
+
var RuntimeProfileEnvName = String$1({
|
|
13480
|
+
minLength: 1,
|
|
13481
|
+
maxLength: 128,
|
|
13482
|
+
pattern: "^[A-Z_][A-Z0-9_]*$"
|
|
13483
|
+
});
|
|
13484
|
+
var RuntimeProfileToolName = String$1({
|
|
13485
|
+
minLength: 1,
|
|
13486
|
+
maxLength: 128,
|
|
13487
|
+
pattern: "^[a-zA-Z0-9._/-]+$"
|
|
13488
|
+
});
|
|
13489
|
+
var SandboxResumeCommandWhenSchema = _Object_({ workspaceMode: Optional(_Array_(Union([
|
|
13490
|
+
Literal("shared_mount"),
|
|
13491
|
+
Literal("dedicated_worktree"),
|
|
13492
|
+
Literal("scratch_mount")
|
|
13493
|
+
]), {
|
|
13494
|
+
minItems: 1,
|
|
13495
|
+
maxItems: 3
|
|
13496
|
+
})) }, { additionalProperties: false });
|
|
13497
|
+
var RuntimeProfileSandboxResumeCommand = Union([String$1({
|
|
13498
|
+
minLength: 1,
|
|
13499
|
+
maxLength: 4096
|
|
13500
|
+
}), _Object_({
|
|
13501
|
+
run: String$1({
|
|
13502
|
+
minLength: 1,
|
|
13503
|
+
maxLength: 4096
|
|
13504
|
+
}),
|
|
13505
|
+
when: Optional(SandboxResumeCommandWhenSchema),
|
|
13506
|
+
retries: Optional(Integer({
|
|
13507
|
+
minimum: 0,
|
|
13508
|
+
maximum: 5
|
|
13509
|
+
})),
|
|
13510
|
+
retryBackoffMs: Optional(Integer({
|
|
13511
|
+
minimum: 0,
|
|
13512
|
+
maximum: 6e4
|
|
13513
|
+
}))
|
|
13514
|
+
}, { additionalProperties: false })]);
|
|
13515
|
+
var RuntimeProfileSandbox = _Object_({
|
|
13516
|
+
snapshot: Optional(_Object_({
|
|
13517
|
+
setupCommands: Optional(_Array_(String$1({
|
|
13518
|
+
minLength: 1,
|
|
13519
|
+
maxLength: 4096
|
|
13520
|
+
}), { maxItems: 20 })),
|
|
13521
|
+
allowedHosts: Optional(_Array_(String$1({
|
|
13522
|
+
minLength: 1,
|
|
13523
|
+
maxLength: 255
|
|
13524
|
+
}), { maxItems: 50 })),
|
|
13525
|
+
overlaySize: Optional(String$1({
|
|
13526
|
+
minLength: 2,
|
|
13527
|
+
maxLength: 16,
|
|
13528
|
+
pattern: "^[0-9]+[KMGTP]?$"
|
|
13529
|
+
}))
|
|
13530
|
+
}, { additionalProperties: false })),
|
|
13531
|
+
resumeCommands: Optional(_Array_(RuntimeProfileSandboxResumeCommand, { maxItems: 30 })),
|
|
13532
|
+
vfs: Optional(_Object_({
|
|
13533
|
+
shadow: Optional(_Array_(String$1({
|
|
13534
|
+
minLength: 1,
|
|
13535
|
+
maxLength: 255
|
|
13536
|
+
}), { maxItems: 100 })),
|
|
13537
|
+
shadowMode: Optional(Union([Literal("deny"), Literal("tmpfs")]))
|
|
13538
|
+
}, { additionalProperties: false })),
|
|
13539
|
+
env: Optional(Record(RuntimeProfileEnvName, String$1({ maxLength: 4096 }))),
|
|
13540
|
+
hostExec: Optional(_Object_({ autoApprove: Optional(Literal(false)) }, { additionalProperties: false })),
|
|
13541
|
+
resources: Optional(_Object_({
|
|
13542
|
+
memory: Optional(String$1({
|
|
13543
|
+
minLength: 2,
|
|
13544
|
+
maxLength: 16,
|
|
13545
|
+
pattern: "^[0-9]+[KMG]?$"
|
|
13546
|
+
})),
|
|
13547
|
+
cpus: Optional(Integer({
|
|
13548
|
+
minimum: 1,
|
|
13549
|
+
maximum: 32
|
|
13550
|
+
}))
|
|
13551
|
+
}, { additionalProperties: false }))
|
|
13552
|
+
}, {
|
|
13553
|
+
$id: "RuntimeProfileSandbox",
|
|
13554
|
+
additionalProperties: false
|
|
13555
|
+
});
|
|
13556
|
+
var RuntimeProfileContext = _Object_({
|
|
13557
|
+
slug: String$1({
|
|
13558
|
+
minLength: 1,
|
|
13559
|
+
maxLength: 64,
|
|
13560
|
+
pattern: "^[a-zA-Z0-9_-]+$"
|
|
13561
|
+
}),
|
|
13562
|
+
binding: Union([
|
|
13563
|
+
Literal("skill"),
|
|
13564
|
+
Literal("context_inline"),
|
|
13565
|
+
Literal("prompt_prefix"),
|
|
13566
|
+
Literal("user_inline")
|
|
13567
|
+
]),
|
|
13568
|
+
content: String$1({
|
|
13569
|
+
minLength: 1,
|
|
13570
|
+
maxLength: 65536
|
|
13571
|
+
})
|
|
13572
|
+
}, {
|
|
13573
|
+
$id: "RuntimeProfileContext",
|
|
13574
|
+
additionalProperties: false
|
|
13575
|
+
});
|
|
13576
|
+
var RuntimeProfileRef = _Object_({ profileId: String$1({ format: "uuid" }) }, {
|
|
13577
|
+
$id: "RuntimeProfileRef",
|
|
13578
|
+
additionalProperties: false
|
|
13579
|
+
});
|
|
13580
|
+
var RuntimeProfileLeaseTtlSec = Integer({
|
|
13581
|
+
minimum: 1,
|
|
13582
|
+
maximum: 86400
|
|
13583
|
+
});
|
|
13584
|
+
var RuntimeProfileHeartbeatIntervalMs = Integer({
|
|
13585
|
+
minimum: 0,
|
|
13586
|
+
maximum: 36e5
|
|
13587
|
+
});
|
|
13588
|
+
var RuntimeProfileMaxBatchSize = Integer({
|
|
13589
|
+
minimum: 1,
|
|
13590
|
+
maximum: 1e3
|
|
13591
|
+
});
|
|
13592
|
+
_Object_({
|
|
13593
|
+
id: String$1({ format: "uuid" }),
|
|
13594
|
+
teamId: String$1({ format: "uuid" }),
|
|
13595
|
+
name: RuntimeProfileName,
|
|
13596
|
+
description: Union([String$1({ maxLength: 4096 }), Null()]),
|
|
13597
|
+
provider: String$1({
|
|
13598
|
+
minLength: 1,
|
|
13599
|
+
maxLength: 100
|
|
13600
|
+
}),
|
|
13601
|
+
model: String$1({
|
|
13602
|
+
minLength: 1,
|
|
13603
|
+
maxLength: 200
|
|
13604
|
+
}),
|
|
13605
|
+
runtimeKind: Literal("gondolin_pi"),
|
|
13606
|
+
sandbox: RuntimeProfileSandbox,
|
|
13607
|
+
sessionStorageMode: Literal("local"),
|
|
13608
|
+
workspaceStorageMode: Literal("local"),
|
|
13609
|
+
sessionTtlSec: Integer({
|
|
13610
|
+
minimum: 1,
|
|
13611
|
+
maximum: 86400
|
|
13612
|
+
}),
|
|
13613
|
+
workspaceTtlSec: Integer({
|
|
13614
|
+
minimum: 1,
|
|
13615
|
+
maximum: 86400
|
|
13616
|
+
}),
|
|
13617
|
+
leaseTtlSec: RuntimeProfileLeaseTtlSec,
|
|
13618
|
+
heartbeatIntervalMs: RuntimeProfileHeartbeatIntervalMs,
|
|
13619
|
+
maxBatchSize: RuntimeProfileMaxBatchSize,
|
|
13620
|
+
requiredEnv: _Array_(RuntimeProfileEnvName, { maxItems: 100 }),
|
|
13621
|
+
requiredTools: _Array_(RuntimeProfileToolName, { maxItems: 100 }),
|
|
13622
|
+
context: _Array_(RuntimeProfileContext, { maxItems: 5 }),
|
|
13623
|
+
revision: Integer({ minimum: 1 }),
|
|
13624
|
+
definitionCid: String$1({
|
|
13625
|
+
minLength: 1,
|
|
13626
|
+
maxLength: 100
|
|
13627
|
+
}),
|
|
13628
|
+
createdByAgentId: Union([String$1({ format: "uuid" }), Null()]),
|
|
13629
|
+
createdByHumanId: Union([String$1({ format: "uuid" }), Null()]),
|
|
13630
|
+
createdAt: String$1({ format: "date-time" }),
|
|
13631
|
+
updatedAt: String$1({ format: "date-time" })
|
|
13632
|
+
}, {
|
|
13633
|
+
$id: "RuntimeProfile",
|
|
13634
|
+
additionalProperties: false
|
|
13635
|
+
});
|
|
13636
|
+
//#endregion
|
|
13160
13637
|
//#region ../tasks/src/success-criteria.ts
|
|
13161
13638
|
/**
|
|
13162
13639
|
* SuccessCriteria — proposer-stated acceptance criteria, evaluated in two
|
|
@@ -16848,6 +17325,7 @@ var TaskAttemptStatus = Union([
|
|
|
16848
17325
|
Literal("completed"),
|
|
16849
17326
|
Literal("failed"),
|
|
16850
17327
|
Literal("cancelled"),
|
|
17328
|
+
Literal("aborted"),
|
|
16851
17329
|
Literal("timed_out")
|
|
16852
17330
|
], { $id: "TaskAttemptStatus" });
|
|
16853
17331
|
var ExecutorTrustLevel = Union([
|
|
@@ -16856,14 +17334,6 @@ var ExecutorTrustLevel = Union([
|
|
|
16856
17334
|
Literal("releaseVerifiedTool"),
|
|
16857
17335
|
Literal("sandboxAttested")
|
|
16858
17336
|
], { $id: "ExecutorTrustLevel" });
|
|
16859
|
-
/** Identifies a (provider, model) daemon pair allowed to claim a task. */
|
|
16860
|
-
var ExecutorRef = _Object_({
|
|
16861
|
-
provider: String$1({ minLength: 1 }),
|
|
16862
|
-
model: String$1({ minLength: 1 })
|
|
16863
|
-
}, {
|
|
16864
|
-
$id: "ExecutorRef",
|
|
16865
|
-
additionalProperties: false
|
|
16866
|
-
});
|
|
16867
17337
|
var OutputKind = Union([Literal("artifact"), Literal("judgment")], { $id: "OutputKind" });
|
|
16868
17338
|
var TaskMessageKind = Union([
|
|
16869
17339
|
Literal("text_delta"),
|
|
@@ -17008,7 +17478,7 @@ _Object_({
|
|
|
17008
17478
|
acceptedAttemptN: Union([Number$1(), Null()]),
|
|
17009
17479
|
claimCondition: Union([Unsafe(Ref$1("ClaimCondition")), Null()]),
|
|
17010
17480
|
requiredExecutorTrustLevel: ExecutorTrustLevel,
|
|
17011
|
-
|
|
17481
|
+
allowedProfiles: _Array_(RuntimeProfileRef, { maxItems: 16 }),
|
|
17012
17482
|
status: TaskStatus,
|
|
17013
17483
|
queuedAt: IsoTimestamp,
|
|
17014
17484
|
completedAt: Union([IsoTimestamp, Null()]),
|
|
@@ -22988,6 +23458,20 @@ async function executePiTask(claimedTask, reporter, opts) {
|
|
|
22988
23458
|
retryable: false
|
|
22989
23459
|
}
|
|
22990
23460
|
});
|
|
23461
|
+
const makeCancelledOutput = (message) => ({
|
|
23462
|
+
taskId: task.id,
|
|
23463
|
+
attemptN,
|
|
23464
|
+
status: "cancelled",
|
|
23465
|
+
output: null,
|
|
23466
|
+
outputCid: null,
|
|
23467
|
+
usage: finalUsage,
|
|
23468
|
+
durationMs: Date.now() - startTime,
|
|
23469
|
+
error: {
|
|
23470
|
+
code: "task_cancelled",
|
|
23471
|
+
message,
|
|
23472
|
+
retryable: false
|
|
23473
|
+
}
|
|
23474
|
+
});
|
|
22991
23475
|
let onTurnEvent;
|
|
22992
23476
|
if (opts.makeOnTurnEvent) try {
|
|
22993
23477
|
onTurnEvent = opts.makeOnTurnEvent(claimedTask);
|
|
@@ -23050,10 +23534,15 @@ async function executePiTask(claimedTask, reporter, opts) {
|
|
|
23050
23534
|
mountPath,
|
|
23051
23535
|
workspaceMode: workspace.mode,
|
|
23052
23536
|
extraAllowedHosts: opts.extraAllowedHosts,
|
|
23053
|
-
sandboxConfig
|
|
23537
|
+
sandboxConfig,
|
|
23538
|
+
signal: reporter.cancelSignal
|
|
23054
23539
|
});
|
|
23055
23540
|
} catch (err) {
|
|
23056
23541
|
const message = err instanceof Error ? err.message : String(err);
|
|
23542
|
+
if (reporter.cancelSignal.aborted) {
|
|
23543
|
+
await emitError("vm_resume", message, { cancelled: true });
|
|
23544
|
+
return makeCancelledOutput(reporter.cancelReason ?? "Task cancelled during VM resume.");
|
|
23545
|
+
}
|
|
23057
23546
|
await emitError("vm_resume", message);
|
|
23058
23547
|
return makeFailedOutput("vm_resume_failed", message);
|
|
23059
23548
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@themoltnet/pi-extension",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MoltNet pi extension — sandboxed tool execution in Gondolin VMs with MoltNet identity and persistent memory",
|
|
6
6
|
"keywords": [
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"@earendil-works/gondolin": "^0.9.1",
|
|
37
37
|
"@opentelemetry/api": "^1.9.0",
|
|
38
38
|
"typebox": "^1.2.8",
|
|
39
|
-
"@themoltnet/
|
|
40
|
-
"@themoltnet/
|
|
39
|
+
"@themoltnet/sdk": "0.108.0",
|
|
40
|
+
"@themoltnet/agent-runtime": "0.24.0"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"@earendil-works/pi-coding-agent": ">=0.74.0",
|