@aiden-ade/sandbox-agent 0.1.67 → 0.1.68
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.cjs +647 -54
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -22087,7 +22087,7 @@ function describeError(error2) {
|
|
|
22087
22087
|
}
|
|
22088
22088
|
|
|
22089
22089
|
// src/version.ts
|
|
22090
|
-
var AGENT_VERSION = "0.1.
|
|
22090
|
+
var AGENT_VERSION = "0.1.68";
|
|
22091
22091
|
|
|
22092
22092
|
// src/daemon-worktree.ts
|
|
22093
22093
|
var import_node_child_process3 = require("child_process");
|
|
@@ -43094,11 +43094,11 @@ var SocketWithoutUpgrade = class _SocketWithoutUpgrade extends Emitter {
|
|
|
43094
43094
|
*/
|
|
43095
43095
|
_resetPingTimeout() {
|
|
43096
43096
|
this.clearTimeoutFn(this._pingTimeoutTimer);
|
|
43097
|
-
const
|
|
43098
|
-
this._pingTimeoutTime = Date.now() +
|
|
43097
|
+
const delay3 = this._pingInterval + this._pingTimeout;
|
|
43098
|
+
this._pingTimeoutTime = Date.now() + delay3;
|
|
43099
43099
|
this._pingTimeoutTimer = this.setTimeoutFn(() => {
|
|
43100
43100
|
this._onClose("ping timeout");
|
|
43101
|
-
},
|
|
43101
|
+
}, delay3);
|
|
43102
43102
|
if (this.opts.autoUnref) {
|
|
43103
43103
|
this._pingTimeoutTimer.unref();
|
|
43104
43104
|
}
|
|
@@ -45079,8 +45079,8 @@ var Manager = class extends Emitter {
|
|
|
45079
45079
|
this.emitReserved("reconnect_failed");
|
|
45080
45080
|
this._reconnecting = false;
|
|
45081
45081
|
} else {
|
|
45082
|
-
const
|
|
45083
|
-
debug10("will wait %dms before reconnect attempt",
|
|
45082
|
+
const delay3 = this.backoff.duration();
|
|
45083
|
+
debug10("will wait %dms before reconnect attempt", delay3);
|
|
45084
45084
|
this._reconnecting = true;
|
|
45085
45085
|
const timer = this.setTimeoutFn(() => {
|
|
45086
45086
|
if (self.skipReconnect)
|
|
@@ -45100,7 +45100,7 @@ var Manager = class extends Emitter {
|
|
|
45100
45100
|
self.onreconnect();
|
|
45101
45101
|
}
|
|
45102
45102
|
});
|
|
45103
|
-
},
|
|
45103
|
+
}, delay3);
|
|
45104
45104
|
if (this.opts.autoUnref) {
|
|
45105
45105
|
timer.unref();
|
|
45106
45106
|
}
|
|
@@ -61929,13 +61929,13 @@ var StreamableHTTPClientTransport = class {
|
|
|
61929
61929
|
this.onerror?.(new Error(`Maximum reconnection attempts (${maxRetries}) exceeded.`));
|
|
61930
61930
|
return;
|
|
61931
61931
|
}
|
|
61932
|
-
const
|
|
61932
|
+
const delay3 = this._getNextReconnectionDelay(attemptCount);
|
|
61933
61933
|
this._reconnectionTimeout = setTimeout(() => {
|
|
61934
61934
|
this._startOrAuthSse(options).catch((error2) => {
|
|
61935
61935
|
this.onerror?.(new Error(`Failed to reconnect SSE stream: ${error2 instanceof Error ? error2.message : String(error2)}`));
|
|
61936
61936
|
this._scheduleReconnection(options, attemptCount + 1);
|
|
61937
61937
|
});
|
|
61938
|
-
},
|
|
61938
|
+
}, delay3);
|
|
61939
61939
|
}
|
|
61940
61940
|
_handleSseStream(stream, options, isReconnectable) {
|
|
61941
61941
|
if (!stream) {
|
|
@@ -64748,38 +64748,96 @@ var publishSkillInputSchema = defineWireSchema()(external_exports.object({
|
|
|
64748
64748
|
expectedContentHash: sha256Schema,
|
|
64749
64749
|
uploadGrant: runtimeUploadGrantSchema
|
|
64750
64750
|
}));
|
|
64751
|
-
var
|
|
64752
|
-
|
|
64753
|
-
|
|
64754
|
-
|
|
64755
|
-
|
|
64756
|
-
|
|
64757
|
-
|
|
64758
|
-
|
|
64759
|
-
|
|
64760
|
-
|
|
64761
|
-
|
|
64762
|
-
|
|
64763
|
-
|
|
64764
|
-
|
|
64751
|
+
var skillFrontmatterAdmissionSchema = external_exports.object({
|
|
64752
|
+
name: external_exports.string().min(1).max(64).regex(SKILL_NAME_PATTERN),
|
|
64753
|
+
description: external_exports.string().trim().min(1).max(1024)
|
|
64754
|
+
}).passthrough();
|
|
64755
|
+
var PROJECTED_VALUE_MAX_BYTES = 16384;
|
|
64756
|
+
function formatKeys(keys) {
|
|
64757
|
+
const shown = keys.slice(0, 3).map((key) => `metadata.${key}`);
|
|
64758
|
+
const remaining = keys.length - shown.length;
|
|
64759
|
+
const listed = shown.join(", ");
|
|
64760
|
+
return remaining > 0 ? `${listed} and ${remaining} more` : listed;
|
|
64761
|
+
}
|
|
64762
|
+
function unsupported(message) {
|
|
64763
|
+
return { severity: "warning", code: "UNSUPPORTED_FRONTMATTER", message, path: "SKILL.md" };
|
|
64764
|
+
}
|
|
64765
|
+
function projectSkillFrontmatter(admitted) {
|
|
64766
|
+
const conformance = [];
|
|
64767
|
+
const raw = admitted;
|
|
64768
|
+
const optionalText = (key, max) => {
|
|
64769
|
+
const value2 = raw[key];
|
|
64770
|
+
if (value2 === void 0)
|
|
64771
|
+
return void 0;
|
|
64772
|
+
if (typeof value2 !== "string") {
|
|
64773
|
+
conformance.push(unsupported(`${key} is not a string; the Agent Skills spec expects text`));
|
|
64774
|
+
return void 0;
|
|
64775
|
+
}
|
|
64776
|
+
const trimmed = value2.trim();
|
|
64777
|
+
if (!trimmed)
|
|
64778
|
+
return void 0;
|
|
64779
|
+
if (trimmed.length > max) {
|
|
64780
|
+
conformance.push(unsupported(`${key} exceeds ${max} characters and was not indexed`));
|
|
64781
|
+
return void 0;
|
|
64782
|
+
}
|
|
64783
|
+
return trimmed;
|
|
64784
|
+
};
|
|
64785
|
+
const license = optionalText("license", 1024);
|
|
64786
|
+
const compatibility = optionalText("compatibility", 500);
|
|
64787
|
+
const allowedTools = optionalText("allowed-tools", 1024);
|
|
64788
|
+
const metadata = {};
|
|
64789
|
+
const rawMetadata = raw.metadata;
|
|
64790
|
+
if (rawMetadata !== void 0) {
|
|
64791
|
+
if (typeof rawMetadata !== "object" || rawMetadata === null || Array.isArray(rawMetadata)) {
|
|
64792
|
+
conformance.push(unsupported("metadata is not a mapping and was not indexed"));
|
|
64793
|
+
} else {
|
|
64794
|
+
const encoder = new TextEncoder();
|
|
64795
|
+
const notStrings = [];
|
|
64796
|
+
const selfReferential = [];
|
|
64797
|
+
const tooLarge = [];
|
|
64798
|
+
for (const [key, value2] of Object.entries(rawMetadata)) {
|
|
64799
|
+
if (typeof value2 !== "string")
|
|
64800
|
+
notStrings.push(key);
|
|
64801
|
+
let encoded;
|
|
64802
|
+
if (typeof value2 === "string") {
|
|
64803
|
+
encoded = value2;
|
|
64804
|
+
} else {
|
|
64805
|
+
try {
|
|
64806
|
+
encoded = JSON.stringify(value2) ?? "";
|
|
64807
|
+
} catch {
|
|
64808
|
+
selfReferential.push(key);
|
|
64809
|
+
continue;
|
|
64810
|
+
}
|
|
64811
|
+
}
|
|
64812
|
+
if (encoder.encode(encoded).byteLength > PROJECTED_VALUE_MAX_BYTES) {
|
|
64813
|
+
tooLarge.push(key);
|
|
64814
|
+
continue;
|
|
64815
|
+
}
|
|
64816
|
+
metadata[key] = value2;
|
|
64817
|
+
}
|
|
64818
|
+
if (notStrings.length > 0) {
|
|
64819
|
+
conformance.push(unsupported(`${formatKeys(notStrings)} ${notStrings.length === 1 ? "is" : "are"} not ${notStrings.length === 1 ? "a string" : "strings"}; the Agent Skills spec expects text`));
|
|
64820
|
+
}
|
|
64821
|
+
if (selfReferential.length > 0) {
|
|
64822
|
+
conformance.push(unsupported(`${formatKeys(selfReferential)} ${selfReferential.length === 1 ? "refers" : "refer"} to itself and ${selfReferential.length === 1 ? "was" : "were"} not indexed`));
|
|
64823
|
+
}
|
|
64824
|
+
if (tooLarge.length > 0) {
|
|
64825
|
+
conformance.push(unsupported(`${formatKeys(tooLarge)} ${tooLarge.length === 1 ? "is" : "are"} too large to index`));
|
|
64826
|
+
}
|
|
64765
64827
|
}
|
|
64766
64828
|
}
|
|
64767
|
-
|
|
64768
|
-
|
|
64769
|
-
|
|
64770
|
-
|
|
64771
|
-
|
|
64772
|
-
|
|
64773
|
-
|
|
64774
|
-
|
|
64775
|
-
}
|
|
64776
|
-
|
|
64777
|
-
|
|
64778
|
-
|
|
64779
|
-
...value2.compatibility ? { compatibility: value2.compatibility } : {},
|
|
64780
|
-
metadata: value2.metadata,
|
|
64781
|
-
...value2["allowed-tools"] ? { allowedTools: value2["allowed-tools"] } : {}
|
|
64782
|
-
}));
|
|
64829
|
+
return {
|
|
64830
|
+
metadata: {
|
|
64831
|
+
name: admitted.name,
|
|
64832
|
+
description: admitted.description,
|
|
64833
|
+
...license ? { license } : {},
|
|
64834
|
+
...compatibility ? { compatibility } : {},
|
|
64835
|
+
metadata,
|
|
64836
|
+
...allowedTools ? { allowedTools } : {}
|
|
64837
|
+
},
|
|
64838
|
+
conformance
|
|
64839
|
+
};
|
|
64840
|
+
}
|
|
64783
64841
|
var skillPackageDiagnosticSchema = external_exports.object({
|
|
64784
64842
|
severity: external_exports.literal("warning"),
|
|
64785
64843
|
code: external_exports.enum(["BROKEN_REFERENCE", "UNSUPPORTED_FRONTMATTER"]),
|
|
@@ -65052,7 +65110,10 @@ async function inspectSkillPackage(packageRoot, options = {}) {
|
|
|
65052
65110
|
inspectedFiles.sort(comparePackageFiles);
|
|
65053
65111
|
const parsedMetadata = parseSkillMetadata(inspectedFiles.find((file2) => file2.manifest.path === "SKILL.md")?.bytes, options.expectedName === void 0 ? (0, import_node_path15.basename)(root) : options.expectedName);
|
|
65054
65112
|
const manifestFiles = inspectedFiles.map((file2) => file2.manifest);
|
|
65055
|
-
const diagnostics =
|
|
65113
|
+
const diagnostics = [
|
|
65114
|
+
...parsedMetadata.conformance,
|
|
65115
|
+
...collectDiagnostics(inspectedFiles.find((file2) => file2.manifest.path === "SKILL.md")?.bytes, parsedMetadata.metadata.license, new Set(manifestFiles.map((file2) => file2.path)))
|
|
65116
|
+
];
|
|
65056
65117
|
return {
|
|
65057
65118
|
schemaVersion: 1,
|
|
65058
65119
|
entrypoint: "SKILL.md",
|
|
@@ -65294,14 +65355,14 @@ function parseSkillMetadata(bytes, expectedName) {
|
|
|
65294
65355
|
if (!isRecord2(parsed)) {
|
|
65295
65356
|
throw new SkillPackageError("INVALID_FRONTMATTER", "SKILL.md frontmatter must be a YAML mapping", "SKILL.md");
|
|
65296
65357
|
}
|
|
65297
|
-
const
|
|
65298
|
-
if (!
|
|
65299
|
-
throw new SkillPackageError("INVALID_FRONTMATTER", `SKILL.md frontmatter is invalid: ${
|
|
65358
|
+
const admitted = skillFrontmatterAdmissionSchema.safeParse(parsed);
|
|
65359
|
+
if (!admitted.success) {
|
|
65360
|
+
throw new SkillPackageError("INVALID_FRONTMATTER", `SKILL.md frontmatter is invalid: ${admitted.error.issues.map(formatFrontmatterIssue).join("; ")}`, "SKILL.md");
|
|
65300
65361
|
}
|
|
65301
|
-
if (expectedName !== null &&
|
|
65302
|
-
throw new SkillPackageError("DIRECTORY_NAME_MISMATCH", `Skill name ${
|
|
65362
|
+
if (expectedName !== null && admitted.data.name !== expectedName.normalize("NFC")) {
|
|
65363
|
+
throw new SkillPackageError("DIRECTORY_NAME_MISMATCH", `Skill name ${admitted.data.name} must match its directory ${expectedName}`, "SKILL.md");
|
|
65303
65364
|
}
|
|
65304
|
-
return
|
|
65365
|
+
return projectSkillFrontmatter(admitted.data);
|
|
65305
65366
|
}
|
|
65306
65367
|
function formatFrontmatterIssue(issue2) {
|
|
65307
65368
|
const field = issue2.path.map(String).join(".");
|
|
@@ -68694,6 +68755,332 @@ function decodeResumeFallbackContext(encoded) {
|
|
|
68694
68755
|
// src/sandbox.ts
|
|
68695
68756
|
var import_node_os12 = require("os");
|
|
68696
68757
|
|
|
68758
|
+
// src/execution-activity-tracker.ts
|
|
68759
|
+
var ExecutionActivityTracker = class {
|
|
68760
|
+
constructor(onChange) {
|
|
68761
|
+
this.onChange = onChange;
|
|
68762
|
+
}
|
|
68763
|
+
activities = /* @__PURE__ */ new Map();
|
|
68764
|
+
register(input) {
|
|
68765
|
+
const normalized = normalizeRegistration(input);
|
|
68766
|
+
const existing = this.activities.get(normalized.ownerId);
|
|
68767
|
+
if (existing) {
|
|
68768
|
+
if (!sameRegistration(existing.input, normalized)) {
|
|
68769
|
+
throw new Error(`Execution activity owner ${normalized.ownerId} changed identity`);
|
|
68770
|
+
}
|
|
68771
|
+
existing.refCount += 1;
|
|
68772
|
+
} else {
|
|
68773
|
+
const activeLease = this.firstActivity()?.input.leaseRunId;
|
|
68774
|
+
if (activeLease && activeLease !== normalized.leaseRunId) {
|
|
68775
|
+
throw new Error(
|
|
68776
|
+
`Cannot track execution leases ${activeLease} and ${normalized.leaseRunId} concurrently`
|
|
68777
|
+
);
|
|
68778
|
+
}
|
|
68779
|
+
this.activities.set(normalized.ownerId, { input: normalized, refCount: 1 });
|
|
68780
|
+
}
|
|
68781
|
+
this.emitChange();
|
|
68782
|
+
let released = false;
|
|
68783
|
+
return {
|
|
68784
|
+
release: () => {
|
|
68785
|
+
if (released) return;
|
|
68786
|
+
released = true;
|
|
68787
|
+
const tracked = this.activities.get(normalized.ownerId);
|
|
68788
|
+
if (!tracked) return;
|
|
68789
|
+
tracked.refCount -= 1;
|
|
68790
|
+
if (tracked.refCount <= 0) this.activities.delete(normalized.ownerId);
|
|
68791
|
+
this.emitChange();
|
|
68792
|
+
}
|
|
68793
|
+
};
|
|
68794
|
+
}
|
|
68795
|
+
snapshot() {
|
|
68796
|
+
const first = this.firstActivity();
|
|
68797
|
+
if (!first) return null;
|
|
68798
|
+
const activeRunIds = /* @__PURE__ */ new Set([first.input.leaseRunId]);
|
|
68799
|
+
let trackedChildCount = 0;
|
|
68800
|
+
let trackedWorkCount = 0;
|
|
68801
|
+
let childAlive = false;
|
|
68802
|
+
let phase;
|
|
68803
|
+
for (const { input, refCount } of this.activities.values()) {
|
|
68804
|
+
activeRunIds.add(input.activeRunId ?? input.leaseRunId);
|
|
68805
|
+
trackedWorkCount += refCount;
|
|
68806
|
+
if (input.kind === "child") trackedChildCount += refCount;
|
|
68807
|
+
childAlive ||= input.childAlive === true;
|
|
68808
|
+
phase ??= input.phase;
|
|
68809
|
+
}
|
|
68810
|
+
return {
|
|
68811
|
+
runId: first.input.leaseRunId,
|
|
68812
|
+
conversationId: first.input.conversationId,
|
|
68813
|
+
taskId: first.input.taskId,
|
|
68814
|
+
sandboxId: first.input.sandboxId,
|
|
68815
|
+
activeRunIds: [...activeRunIds].sort(),
|
|
68816
|
+
phase,
|
|
68817
|
+
childAlive,
|
|
68818
|
+
trackedChildCount,
|
|
68819
|
+
trackedWorkCount
|
|
68820
|
+
};
|
|
68821
|
+
}
|
|
68822
|
+
firstActivity() {
|
|
68823
|
+
return this.activities.values().next().value;
|
|
68824
|
+
}
|
|
68825
|
+
emitChange() {
|
|
68826
|
+
this.onChange(this.snapshot());
|
|
68827
|
+
}
|
|
68828
|
+
};
|
|
68829
|
+
function normalizeRegistration(input) {
|
|
68830
|
+
const ownerId = input.ownerId.trim();
|
|
68831
|
+
const leaseRunId = input.leaseRunId.trim();
|
|
68832
|
+
const activeRunId = input.activeRunId?.trim() || void 0;
|
|
68833
|
+
const conversationId = input.conversationId.trim();
|
|
68834
|
+
const taskId = input.taskId.trim();
|
|
68835
|
+
const sandboxId = input.sandboxId.trim();
|
|
68836
|
+
if (!ownerId || !leaseRunId || !conversationId || !taskId || !sandboxId) {
|
|
68837
|
+
throw new Error("Execution activity identity fields must be non-empty");
|
|
68838
|
+
}
|
|
68839
|
+
return {
|
|
68840
|
+
...input,
|
|
68841
|
+
ownerId,
|
|
68842
|
+
leaseRunId,
|
|
68843
|
+
activeRunId,
|
|
68844
|
+
conversationId,
|
|
68845
|
+
taskId,
|
|
68846
|
+
sandboxId
|
|
68847
|
+
};
|
|
68848
|
+
}
|
|
68849
|
+
function sameRegistration(left, right) {
|
|
68850
|
+
return left.ownerId === right.ownerId && left.leaseRunId === right.leaseRunId && left.activeRunId === right.activeRunId && left.conversationId === right.conversationId && left.taskId === right.taskId && left.sandboxId === right.sandboxId && left.kind === right.kind;
|
|
68851
|
+
}
|
|
68852
|
+
|
|
68853
|
+
// src/execution-lease-client.ts
|
|
68854
|
+
var EXECUTION_LEASE_RENEW_INTERVAL_MS = 3e4;
|
|
68855
|
+
var EXECUTION_LEASE_REQUEST_TIMEOUT_MS = 1e4;
|
|
68856
|
+
var DEFAULT_RETRY_DELAYS_MS = [250, 1e3];
|
|
68857
|
+
var ExecutionLeaseClient = class {
|
|
68858
|
+
constructor(options) {
|
|
68859
|
+
this.options = options;
|
|
68860
|
+
this.apiUrl = options.apiUrl.replace(/\/+$/, "");
|
|
68861
|
+
this.fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
68862
|
+
this.renewIntervalMs = options.renewIntervalMs ?? EXECUTION_LEASE_RENEW_INTERVAL_MS;
|
|
68863
|
+
this.requestTimeoutMs = options.requestTimeoutMs ?? EXECUTION_LEASE_REQUEST_TIMEOUT_MS;
|
|
68864
|
+
this.retryDelaysMs = options.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS;
|
|
68865
|
+
this.enabled = options.enabled !== false;
|
|
68866
|
+
}
|
|
68867
|
+
apiUrl;
|
|
68868
|
+
fetchImpl;
|
|
68869
|
+
renewIntervalMs;
|
|
68870
|
+
requestTimeoutMs;
|
|
68871
|
+
retryDelaysMs;
|
|
68872
|
+
activity = null;
|
|
68873
|
+
activityGeneration = 0;
|
|
68874
|
+
interval = null;
|
|
68875
|
+
inFlight = null;
|
|
68876
|
+
trailingRenewal = false;
|
|
68877
|
+
nextSequence = 1;
|
|
68878
|
+
enabled;
|
|
68879
|
+
closed = false;
|
|
68880
|
+
terminalSessionFailure = false;
|
|
68881
|
+
terminalRunIds = /* @__PURE__ */ new Set();
|
|
68882
|
+
setActivity(activity) {
|
|
68883
|
+
if (this.closed || this.terminalSessionFailure) return;
|
|
68884
|
+
const previousRunId = this.activity?.runId ?? null;
|
|
68885
|
+
const nextRunId = activity?.runId ?? null;
|
|
68886
|
+
if (previousRunId !== nextRunId) this.activityGeneration += 1;
|
|
68887
|
+
this.activity = activity;
|
|
68888
|
+
if (!activity) {
|
|
68889
|
+
this.stopInterval();
|
|
68890
|
+
this.trailingRenewal = false;
|
|
68891
|
+
this.options.lifecycle?.debug("sandbox_agent_execution_lease_stopped", {
|
|
68892
|
+
reason: "idle"
|
|
68893
|
+
});
|
|
68894
|
+
return;
|
|
68895
|
+
}
|
|
68896
|
+
if (this.terminalRunIds.has(activity.runId)) {
|
|
68897
|
+
this.stopInterval();
|
|
68898
|
+
return;
|
|
68899
|
+
}
|
|
68900
|
+
if (!this.enabled) return;
|
|
68901
|
+
this.startInterval();
|
|
68902
|
+
if (previousRunId !== activity.runId || !this.inFlight) this.requestRenewal();
|
|
68903
|
+
else this.trailingRenewal = true;
|
|
68904
|
+
}
|
|
68905
|
+
/** Enable renewals after the connected WS server proves route support. */
|
|
68906
|
+
enable() {
|
|
68907
|
+
if (this.enabled || this.closed || this.terminalSessionFailure) return;
|
|
68908
|
+
this.enabled = true;
|
|
68909
|
+
this.options.lifecycle?.info("sandbox_agent_execution_lease_enabled");
|
|
68910
|
+
if (!this.activity || this.terminalRunIds.has(this.activity.runId)) return;
|
|
68911
|
+
this.startInterval();
|
|
68912
|
+
this.requestRenewal();
|
|
68913
|
+
}
|
|
68914
|
+
close() {
|
|
68915
|
+
this.closed = true;
|
|
68916
|
+
this.activityGeneration += 1;
|
|
68917
|
+
this.activity = null;
|
|
68918
|
+
this.trailingRenewal = false;
|
|
68919
|
+
this.stopInterval();
|
|
68920
|
+
}
|
|
68921
|
+
startInterval() {
|
|
68922
|
+
if (this.interval) return;
|
|
68923
|
+
this.interval = setInterval(() => this.requestRenewal(), this.renewIntervalMs);
|
|
68924
|
+
this.interval.unref?.();
|
|
68925
|
+
}
|
|
68926
|
+
stopInterval() {
|
|
68927
|
+
if (!this.interval) return;
|
|
68928
|
+
clearInterval(this.interval);
|
|
68929
|
+
this.interval = null;
|
|
68930
|
+
}
|
|
68931
|
+
loseAuthority(activity, seq, status, code) {
|
|
68932
|
+
this.terminalSessionFailure = true;
|
|
68933
|
+
this.stopInterval();
|
|
68934
|
+
this.options.lifecycle?.error("sandbox_agent_execution_lease_authority_lost", {
|
|
68935
|
+
runId: activity.runId,
|
|
68936
|
+
seq,
|
|
68937
|
+
status,
|
|
68938
|
+
code
|
|
68939
|
+
});
|
|
68940
|
+
this.options.onAuthorityLost?.({ runId: activity.runId, code, status });
|
|
68941
|
+
}
|
|
68942
|
+
requestRenewal() {
|
|
68943
|
+
if (this.closed || !this.enabled || this.terminalSessionFailure || !this.activity || this.terminalRunIds.has(this.activity.runId)) {
|
|
68944
|
+
return;
|
|
68945
|
+
}
|
|
68946
|
+
if (this.inFlight) {
|
|
68947
|
+
this.trailingRenewal = true;
|
|
68948
|
+
return;
|
|
68949
|
+
}
|
|
68950
|
+
const activity = this.activity;
|
|
68951
|
+
const activityGeneration = this.activityGeneration;
|
|
68952
|
+
const seq = this.nextSequence;
|
|
68953
|
+
this.nextSequence += 1;
|
|
68954
|
+
this.inFlight = this.renewWithRetry(activity, activityGeneration, seq).finally(() => {
|
|
68955
|
+
this.inFlight = null;
|
|
68956
|
+
if (!this.trailingRenewal) return;
|
|
68957
|
+
this.trailingRenewal = false;
|
|
68958
|
+
if (this.activity) this.requestRenewal();
|
|
68959
|
+
});
|
|
68960
|
+
}
|
|
68961
|
+
isCurrentRun(activity, generation) {
|
|
68962
|
+
return !this.closed && this.activityGeneration === generation && this.activity?.runId === activity.runId;
|
|
68963
|
+
}
|
|
68964
|
+
async renewWithRetry(activity, activityGeneration, seq) {
|
|
68965
|
+
const body = {
|
|
68966
|
+
conversationId: activity.conversationId,
|
|
68967
|
+
taskId: activity.taskId,
|
|
68968
|
+
sandboxId: activity.sandboxId,
|
|
68969
|
+
agentSessionId: this.options.agentSessionId,
|
|
68970
|
+
seq,
|
|
68971
|
+
activeRunIds: activity.activeRunIds,
|
|
68972
|
+
agentVersion: this.options.agentVersion,
|
|
68973
|
+
phase: activity.phase,
|
|
68974
|
+
childAlive: activity.childAlive,
|
|
68975
|
+
trackedChildCount: activity.trackedChildCount
|
|
68976
|
+
};
|
|
68977
|
+
const url3 = `${this.apiUrl}/public/agent-runs/${encodeURIComponent(activity.runId)}/execution-lease`;
|
|
68978
|
+
for (let attempt = 0; attempt <= this.retryDelaysMs.length; attempt += 1) {
|
|
68979
|
+
if (!this.isCurrentRun(activity, activityGeneration)) return;
|
|
68980
|
+
try {
|
|
68981
|
+
const response = await this.fetchImpl(url3, {
|
|
68982
|
+
method: "POST",
|
|
68983
|
+
headers: {
|
|
68984
|
+
authorization: `Bearer ${this.options.sessionToken}`,
|
|
68985
|
+
"content-type": "application/json"
|
|
68986
|
+
},
|
|
68987
|
+
body: JSON.stringify(body),
|
|
68988
|
+
signal: AbortSignal.timeout(this.requestTimeoutMs)
|
|
68989
|
+
});
|
|
68990
|
+
if (response.ok) {
|
|
68991
|
+
this.options.lifecycle?.debug("sandbox_agent_execution_lease_renewed", {
|
|
68992
|
+
runId: activity.runId,
|
|
68993
|
+
seq,
|
|
68994
|
+
attempt: attempt + 1
|
|
68995
|
+
});
|
|
68996
|
+
return;
|
|
68997
|
+
}
|
|
68998
|
+
const errorBody = await readErrorBody(response);
|
|
68999
|
+
const code = errorBody.code;
|
|
69000
|
+
const sessionAuthorityLost = response.status === 409 && code === "EXECUTION_LEASE_FENCED" || response.status === 401 && code === "EXECUTION_LEASE_INVALID_TOKEN";
|
|
69001
|
+
if (sessionAuthorityLost && code) {
|
|
69002
|
+
this.loseAuthority(activity, seq, response.status, code);
|
|
69003
|
+
return;
|
|
69004
|
+
}
|
|
69005
|
+
const runAuthorityLost = response.status === 409 && code === "EXECUTION_LEASE_INACTIVE_RUN" || response.status === 403 && code === "EXECUTION_LEASE_BINDING_MISMATCH" || response.status === 404 && code === "EXECUTION_LEASE_RUN_NOT_FOUND";
|
|
69006
|
+
if (runAuthorityLost && code) {
|
|
69007
|
+
if (!this.isCurrentRun(activity, activityGeneration)) {
|
|
69008
|
+
this.options.lifecycle?.debug("sandbox_agent_execution_lease_stale_response_ignored", {
|
|
69009
|
+
runId: activity.runId,
|
|
69010
|
+
seq,
|
|
69011
|
+
status: response.status,
|
|
69012
|
+
code
|
|
69013
|
+
});
|
|
69014
|
+
return;
|
|
69015
|
+
}
|
|
69016
|
+
this.loseAuthority(activity, seq, response.status, code);
|
|
69017
|
+
return;
|
|
69018
|
+
}
|
|
69019
|
+
if (response.status === 409 && code === "EXECUTION_LEASE_PROVIDER_UNRESOLVED") {
|
|
69020
|
+
this.terminalRunIds.add(activity.runId);
|
|
69021
|
+
if (this.activity?.runId === activity.runId) this.stopInterval();
|
|
69022
|
+
this.options.lifecycle?.warn("sandbox_agent_execution_lease_run_rejected", {
|
|
69023
|
+
runId: activity.runId,
|
|
69024
|
+
seq,
|
|
69025
|
+
code
|
|
69026
|
+
});
|
|
69027
|
+
return;
|
|
69028
|
+
}
|
|
69029
|
+
const takeoverPending = response.status === 409 && code === "EXECUTION_LEASE_TAKEOVER_PENDING";
|
|
69030
|
+
const mixedVersionUnavailable = (response.status === 401 || response.status === 403 || response.status === 404) && !code?.startsWith("EXECUTION_LEASE_");
|
|
69031
|
+
const retryable = takeoverPending || mixedVersionUnavailable || isRetryableStatus(response.status);
|
|
69032
|
+
if (!retryable || attempt === this.retryDelaysMs.length) {
|
|
69033
|
+
this.options.lifecycle?.warn("sandbox_agent_execution_lease_renew_failed", {
|
|
69034
|
+
runId: activity.runId,
|
|
69035
|
+
seq,
|
|
69036
|
+
status: response.status,
|
|
69037
|
+
code,
|
|
69038
|
+
attempt: attempt + 1
|
|
69039
|
+
});
|
|
69040
|
+
return;
|
|
69041
|
+
}
|
|
69042
|
+
if (takeoverPending) {
|
|
69043
|
+
this.options.lifecycle?.debug("sandbox_agent_execution_lease_takeover_pending", {
|
|
69044
|
+
runId: activity.runId,
|
|
69045
|
+
seq,
|
|
69046
|
+
attempt: attempt + 1
|
|
69047
|
+
});
|
|
69048
|
+
}
|
|
69049
|
+
} catch (error2) {
|
|
69050
|
+
if (attempt === this.retryDelaysMs.length) {
|
|
69051
|
+
this.options.lifecycle?.warn("sandbox_agent_execution_lease_renew_failed", {
|
|
69052
|
+
runId: activity.runId,
|
|
69053
|
+
seq,
|
|
69054
|
+
attempt: attempt + 1,
|
|
69055
|
+
error: error2 instanceof Error ? error2 : new Error(String(error2))
|
|
69056
|
+
});
|
|
69057
|
+
return;
|
|
69058
|
+
}
|
|
69059
|
+
}
|
|
69060
|
+
await delay2(this.retryDelaysMs[attempt] ?? 0);
|
|
69061
|
+
}
|
|
69062
|
+
}
|
|
69063
|
+
};
|
|
69064
|
+
function isRetryableStatus(status) {
|
|
69065
|
+
return status === 408 || status === 429 || status >= 500;
|
|
69066
|
+
}
|
|
69067
|
+
async function readErrorBody(response) {
|
|
69068
|
+
try {
|
|
69069
|
+
const body = await response.json();
|
|
69070
|
+
if (!body || typeof body !== "object") return {};
|
|
69071
|
+
const record2 = body;
|
|
69072
|
+
return {
|
|
69073
|
+
code: typeof record2.code === "string" ? record2.code : void 0,
|
|
69074
|
+
message: typeof record2.message === "string" ? record2.message : void 0
|
|
69075
|
+
};
|
|
69076
|
+
} catch {
|
|
69077
|
+
return {};
|
|
69078
|
+
}
|
|
69079
|
+
}
|
|
69080
|
+
function delay2(ms) {
|
|
69081
|
+
return new Promise((resolve14) => setTimeout(resolve14, ms));
|
|
69082
|
+
}
|
|
69083
|
+
|
|
68697
69084
|
// src/web-presenter.ts
|
|
68698
69085
|
var import_node_crypto15 = require("crypto");
|
|
68699
69086
|
var WebPresenter = class {
|
|
@@ -69086,6 +69473,21 @@ var SandboxEventDispatcher = class {
|
|
|
69086
69473
|
|
|
69087
69474
|
// src/ws-client.ts
|
|
69088
69475
|
var ACCEPTED_MESSAGE_ID_CACHE_SIZE = 200;
|
|
69476
|
+
var SUPERVISED_RECONNECT_BASE_DELAY_MS = 1e3;
|
|
69477
|
+
var SUPERVISED_RECONNECT_MAX_DELAY_MS = 5e3;
|
|
69478
|
+
var SUPERVISED_RECONNECT_MAX_JITTER_MS = 500;
|
|
69479
|
+
function parseConnectionDirective(data) {
|
|
69480
|
+
if (typeof data !== "object" || data === null || typeof data.code !== "string" || typeof data.retryable !== "boolean") {
|
|
69481
|
+
return null;
|
|
69482
|
+
}
|
|
69483
|
+
const candidate = data;
|
|
69484
|
+
return {
|
|
69485
|
+
code: candidate.code,
|
|
69486
|
+
retryable: candidate.retryable,
|
|
69487
|
+
reason: typeof candidate.reason === "string" ? candidate.reason : void 0,
|
|
69488
|
+
retryAfterMs: typeof candidate.retryAfterMs === "number" && Number.isFinite(candidate.retryAfterMs) && candidate.retryAfterMs >= 0 ? candidate.retryAfterMs : void 0
|
|
69489
|
+
};
|
|
69490
|
+
}
|
|
69089
69491
|
var WSClient = class {
|
|
69090
69492
|
constructor(wsUrl, sessionId, taskId, token, callbacks, agentVersion, lifecycle) {
|
|
69091
69493
|
this.lifecycle = lifecycle;
|
|
@@ -69094,7 +69496,7 @@ var WSClient = class {
|
|
|
69094
69496
|
this.getRunState = callbacks.getRunState;
|
|
69095
69497
|
this.socket = lookup(wsUrl, {
|
|
69096
69498
|
query: { type: "agent", sessionId, taskId, agentVersion: agentVersion ?? "" },
|
|
69097
|
-
auth: { token },
|
|
69499
|
+
auth: { token, agentSessionId: this.agentSessionId },
|
|
69098
69500
|
transports: ["websocket"],
|
|
69099
69501
|
reconnection: true,
|
|
69100
69502
|
reconnectionAttempts: Infinity,
|
|
@@ -69126,6 +69528,10 @@ var WSClient = class {
|
|
|
69126
69528
|
/** Monotonic heartbeat sequence — advances on every hello + heartbeat. */
|
|
69127
69529
|
heartbeatSeq = 0;
|
|
69128
69530
|
heartbeatTimer = null;
|
|
69531
|
+
supervisedReconnectTimer = null;
|
|
69532
|
+
supervisedReconnectAttempt = 0;
|
|
69533
|
+
connectionDirective = null;
|
|
69534
|
+
intentionalClose = false;
|
|
69129
69535
|
agentVersion;
|
|
69130
69536
|
getRunState;
|
|
69131
69537
|
/**
|
|
@@ -69232,16 +69638,82 @@ var WSClient = class {
|
|
|
69232
69638
|
get connected() {
|
|
69233
69639
|
return this.socket.connected;
|
|
69234
69640
|
}
|
|
69641
|
+
getAgentSessionId() {
|
|
69642
|
+
return this.agentSessionId;
|
|
69643
|
+
}
|
|
69235
69644
|
setLifecycleContext(context) {
|
|
69236
69645
|
this.lifecycle?.setContext(context);
|
|
69237
69646
|
}
|
|
69238
69647
|
close() {
|
|
69239
69648
|
this.lifecycle?.info("sandbox_agent_ws_close_requested");
|
|
69649
|
+
this.intentionalClose = true;
|
|
69650
|
+
this.clearSupervisedReconnect();
|
|
69240
69651
|
this.stopHeartbeat();
|
|
69241
69652
|
this.socket.disconnect();
|
|
69242
69653
|
}
|
|
69654
|
+
clearSupervisedReconnect() {
|
|
69655
|
+
if (this.supervisedReconnectTimer) {
|
|
69656
|
+
clearTimeout(this.supervisedReconnectTimer);
|
|
69657
|
+
this.supervisedReconnectTimer = null;
|
|
69658
|
+
}
|
|
69659
|
+
}
|
|
69660
|
+
/**
|
|
69661
|
+
* Socket.IO reconnects transport failures through its Manager. It does not
|
|
69662
|
+
* reconnect an `io server disconnect`, where `socket.active` is false. Only
|
|
69663
|
+
* supervise that terminal transport state, and only after the server has
|
|
69664
|
+
* explicitly classified the disconnect as retryable (including the legacy
|
|
69665
|
+
* `server_shutdown` advisory emitted by older WS servers).
|
|
69666
|
+
*/
|
|
69667
|
+
scheduleSupervisedReconnect(reason) {
|
|
69668
|
+
if (this.intentionalClose || this.socket.connected || this.socket.active || this.supervisedReconnectTimer || this.connectionDirective?.retryable !== true) {
|
|
69669
|
+
return;
|
|
69670
|
+
}
|
|
69671
|
+
const attempt = this.supervisedReconnectAttempt + 1;
|
|
69672
|
+
this.supervisedReconnectAttempt = attempt;
|
|
69673
|
+
const exponentialDelay = Math.min(
|
|
69674
|
+
SUPERVISED_RECONNECT_BASE_DELAY_MS * 2 ** (attempt - 1),
|
|
69675
|
+
SUPERVISED_RECONNECT_MAX_DELAY_MS
|
|
69676
|
+
);
|
|
69677
|
+
const requestedDelay = Math.max(exponentialDelay, this.connectionDirective.retryAfterMs ?? 0);
|
|
69678
|
+
const jitterRange = Math.min(SUPERVISED_RECONNECT_MAX_JITTER_MS, requestedDelay / 2);
|
|
69679
|
+
const delayMs = requestedDelay + Math.floor(Math.random() * jitterRange);
|
|
69680
|
+
this.lifecycle?.warn("sandbox_agent_ws_supervised_reconnect_scheduled", {
|
|
69681
|
+
reason,
|
|
69682
|
+
directiveCode: this.connectionDirective.code,
|
|
69683
|
+
attempt,
|
|
69684
|
+
delayMs
|
|
69685
|
+
});
|
|
69686
|
+
this.supervisedReconnectTimer = setTimeout(() => {
|
|
69687
|
+
this.supervisedReconnectTimer = null;
|
|
69688
|
+
if (this.intentionalClose || this.socket.connected || this.socket.active) return;
|
|
69689
|
+
this.lifecycle?.info("sandbox_agent_ws_supervised_reconnect_attempt", {
|
|
69690
|
+
directiveCode: this.connectionDirective?.code,
|
|
69691
|
+
attempt
|
|
69692
|
+
});
|
|
69693
|
+
this.connectionDirective = null;
|
|
69694
|
+
this.socket.connect();
|
|
69695
|
+
}, delayMs);
|
|
69696
|
+
this.supervisedReconnectTimer.unref?.();
|
|
69697
|
+
}
|
|
69243
69698
|
setupListeners(callbacks) {
|
|
69699
|
+
this.socket.io.on("reconnect_attempt", (attempt) => {
|
|
69700
|
+
this.lifecycle?.info("sandbox_agent_ws_manager_reconnect_attempt", { attempt });
|
|
69701
|
+
});
|
|
69702
|
+
this.socket.io.on("reconnect", (attempt) => {
|
|
69703
|
+
this.lifecycle?.info("sandbox_agent_ws_manager_reconnected", { attempt });
|
|
69704
|
+
});
|
|
69705
|
+
this.socket.io.on("reconnect_error", (error2) => {
|
|
69706
|
+
this.lifecycle?.warn("sandbox_agent_ws_manager_reconnect_error", {
|
|
69707
|
+
error: error2 instanceof Error ? error2 : new Error(String(error2))
|
|
69708
|
+
});
|
|
69709
|
+
});
|
|
69710
|
+
this.socket.io.on("reconnect_failed", () => {
|
|
69711
|
+
this.lifecycle?.error("sandbox_agent_ws_manager_reconnect_failed");
|
|
69712
|
+
});
|
|
69244
69713
|
this.socket.on("connect", () => {
|
|
69714
|
+
this.clearSupervisedReconnect();
|
|
69715
|
+
this.supervisedReconnectAttempt = 0;
|
|
69716
|
+
this.connectionDirective = null;
|
|
69245
69717
|
this.lifecycle?.info("sandbox_agent_ws_socket_connected", { socketId: this.socket.id });
|
|
69246
69718
|
this.startHeartbeat();
|
|
69247
69719
|
this.eventDispatcher.flush();
|
|
@@ -69252,6 +69724,36 @@ var WSClient = class {
|
|
|
69252
69724
|
this.stopHeartbeat();
|
|
69253
69725
|
this.eventDispatcher.disconnect();
|
|
69254
69726
|
callbacks.onDisconnect?.(reason);
|
|
69727
|
+
this.scheduleSupervisedReconnect(reason);
|
|
69728
|
+
});
|
|
69729
|
+
this.socket.on("server_shutdown", (data) => {
|
|
69730
|
+
this.connectionDirective = {
|
|
69731
|
+
code: "server_shutdown",
|
|
69732
|
+
reason: data?.reason,
|
|
69733
|
+
retryable: true,
|
|
69734
|
+
retryAfterMs: data?.retryAfterMs ?? 1e3
|
|
69735
|
+
};
|
|
69736
|
+
});
|
|
69737
|
+
this.socket.on("agent.capabilities", (data) => {
|
|
69738
|
+
if (typeof data !== "object" || data === null || typeof data.executionLeaseV1 !== "boolean") {
|
|
69739
|
+
return;
|
|
69740
|
+
}
|
|
69741
|
+
const capabilities = {
|
|
69742
|
+
executionLeaseV1: data.executionLeaseV1
|
|
69743
|
+
};
|
|
69744
|
+
this.lifecycle?.info("sandbox_agent_ws_capabilities_received", {
|
|
69745
|
+
executionLeaseV1: capabilities.executionLeaseV1
|
|
69746
|
+
});
|
|
69747
|
+
callbacks.onCapabilities?.(capabilities);
|
|
69748
|
+
});
|
|
69749
|
+
this.socket.on("connection_directive", (data) => {
|
|
69750
|
+
const directive = parseConnectionDirective(data);
|
|
69751
|
+
if (!directive) return;
|
|
69752
|
+
this.connectionDirective = directive;
|
|
69753
|
+
if (!directive.retryable) {
|
|
69754
|
+
this.clearSupervisedReconnect();
|
|
69755
|
+
callbacks.onTerminalDirective?.({ code: directive.code, reason: directive.reason });
|
|
69756
|
+
}
|
|
69255
69757
|
});
|
|
69256
69758
|
this.socket.on("agent.probe", (_data, ack) => {
|
|
69257
69759
|
ack?.({
|
|
@@ -69261,9 +69763,24 @@ var WSClient = class {
|
|
|
69261
69763
|
});
|
|
69262
69764
|
});
|
|
69263
69765
|
this.socket.on("connect_error", (error2) => {
|
|
69766
|
+
const directive = parseConnectionDirective(
|
|
69767
|
+
error2?.data
|
|
69768
|
+
);
|
|
69769
|
+
if (directive) {
|
|
69770
|
+
this.connectionDirective = directive;
|
|
69771
|
+
if (!directive.retryable) {
|
|
69772
|
+
this.clearSupervisedReconnect();
|
|
69773
|
+
callbacks.onTerminalDirective?.({ code: directive.code, reason: directive.reason });
|
|
69774
|
+
}
|
|
69775
|
+
} else {
|
|
69776
|
+
this.connectionDirective = null;
|
|
69777
|
+
}
|
|
69264
69778
|
this.lifecycle?.warn("sandbox_agent_ws_socket_connect_error", {
|
|
69265
|
-
error: error2 instanceof Error ? error2 : new Error(String(error2))
|
|
69779
|
+
error: error2 instanceof Error ? error2 : new Error(String(error2)),
|
|
69780
|
+
directiveCode: directive?.code,
|
|
69781
|
+
retryable: directive?.retryable
|
|
69266
69782
|
});
|
|
69783
|
+
this.scheduleSupervisedReconnect("connect_error");
|
|
69267
69784
|
});
|
|
69268
69785
|
this.socket.on(
|
|
69269
69786
|
"user_message",
|
|
@@ -69367,10 +69884,14 @@ async function runSandbox(config2) {
|
|
|
69367
69884
|
let currentImages = [];
|
|
69368
69885
|
let currentFiles = [];
|
|
69369
69886
|
let currentParsedAttachments = [];
|
|
69370
|
-
|
|
69887
|
+
let stopped = false;
|
|
69371
69888
|
let pendingMessageResolve = null;
|
|
69372
69889
|
const queuedMessages = [];
|
|
69373
69890
|
let currentAgent = null;
|
|
69891
|
+
let executionLeaseClient = null;
|
|
69892
|
+
let executionLeaseV1Supported = false;
|
|
69893
|
+
let activeRootExecutionActivity = null;
|
|
69894
|
+
let reportActiveRun = false;
|
|
69374
69895
|
let currentTaskMeta;
|
|
69375
69896
|
let currentPrMeta;
|
|
69376
69897
|
let currentWorkflowTools;
|
|
@@ -69398,6 +69919,32 @@ async function runSandbox(config2) {
|
|
|
69398
69919
|
lifecycle.info("sandbox_agent_ws_connect_attempt", {
|
|
69399
69920
|
wsUrl: config2.wsUrl
|
|
69400
69921
|
});
|
|
69922
|
+
const stopActiveAgent = () => {
|
|
69923
|
+
reportActiveRun = false;
|
|
69924
|
+
activeRootExecutionActivity?.release();
|
|
69925
|
+
activeRootExecutionActivity = null;
|
|
69926
|
+
const agent = currentAgent;
|
|
69927
|
+
if (!agent) return;
|
|
69928
|
+
const killed = agent.kill();
|
|
69929
|
+
if (!killed) {
|
|
69930
|
+
agent.abort();
|
|
69931
|
+
return;
|
|
69932
|
+
}
|
|
69933
|
+
const abortDeadline = setTimeout(() => {
|
|
69934
|
+
if (currentAgent === agent) agent.abort();
|
|
69935
|
+
}, 5e3);
|
|
69936
|
+
abortDeadline.unref?.();
|
|
69937
|
+
};
|
|
69938
|
+
const terminateAgentProcess = (reason) => {
|
|
69939
|
+
if (stopped) return;
|
|
69940
|
+
lifecycle.warn("sandbox_agent_process_fenced", reason);
|
|
69941
|
+
stopped = true;
|
|
69942
|
+
executionLeaseClient?.close();
|
|
69943
|
+
stopActiveAgent();
|
|
69944
|
+
const resolvePendingMessage = pendingMessageResolve;
|
|
69945
|
+
pendingMessageResolve = null;
|
|
69946
|
+
resolvePendingMessage?.(null);
|
|
69947
|
+
};
|
|
69401
69948
|
const wsClient = new WSClient(
|
|
69402
69949
|
config2.wsUrl,
|
|
69403
69950
|
config2.sessionId,
|
|
@@ -69440,10 +69987,7 @@ async function runSandbox(config2) {
|
|
|
69440
69987
|
},
|
|
69441
69988
|
onStop: () => {
|
|
69442
69989
|
lifecycle.info("sandbox_agent_stop_received");
|
|
69443
|
-
|
|
69444
|
-
const killed = currentAgent.kill();
|
|
69445
|
-
if (!killed) currentAgent.abort();
|
|
69446
|
-
}
|
|
69990
|
+
stopActiveAgent();
|
|
69447
69991
|
},
|
|
69448
69992
|
onToolResponse: (toolId, response) => {
|
|
69449
69993
|
if (currentAgent) {
|
|
@@ -69457,12 +70001,40 @@ async function runSandbox(config2) {
|
|
|
69457
70001
|
},
|
|
69458
70002
|
onConnect: () => lifecycle.info("sandbox_agent_ws_connected"),
|
|
69459
70003
|
onDisconnect: (reason) => lifecycle.info("sandbox_agent_ws_disconnected", { reason }),
|
|
70004
|
+
onCapabilities: (capabilities) => {
|
|
70005
|
+
if (!capabilities.executionLeaseV1) return;
|
|
70006
|
+
executionLeaseV1Supported = true;
|
|
70007
|
+
executionLeaseClient?.enable();
|
|
70008
|
+
},
|
|
70009
|
+
onTerminalDirective: terminateAgentProcess,
|
|
69460
70010
|
// Liveness heartbeat run state: a run is active while CoreAgent is executing.
|
|
69461
|
-
getRunState: () =>
|
|
70011
|
+
getRunState: () => {
|
|
70012
|
+
const activeRunId = currentRunId ?? config2.runId;
|
|
70013
|
+
return currentAgent && reportActiveRun ? { idle: false, activeRunIds: activeRunId ? [activeRunId] : [] } : { idle: true, activeRunIds: [] };
|
|
70014
|
+
}
|
|
69462
70015
|
},
|
|
69463
70016
|
AGENT_VERSION,
|
|
69464
70017
|
lifecycle
|
|
69465
70018
|
);
|
|
70019
|
+
const agentSessionId = wsClient.getAgentSessionId();
|
|
70020
|
+
executionLeaseClient = config2.apiUrl && config2.sandboxId && agentSessionId ? new ExecutionLeaseClient({
|
|
70021
|
+
apiUrl: config2.apiUrl,
|
|
70022
|
+
sessionToken: config2.sessionToken,
|
|
70023
|
+
agentSessionId,
|
|
70024
|
+
agentVersion: AGENT_VERSION,
|
|
70025
|
+
lifecycle,
|
|
70026
|
+
enabled: false,
|
|
70027
|
+
onAuthorityLost: ({ code }) => terminateAgentProcess({ code })
|
|
70028
|
+
}) : null;
|
|
70029
|
+
if (executionLeaseV1Supported) executionLeaseClient?.enable();
|
|
70030
|
+
const executionActivityTracker = executionLeaseClient ? new ExecutionActivityTracker((activity) => executionLeaseClient.setActivity(activity)) : null;
|
|
70031
|
+
if (!executionLeaseClient && (currentRunId ?? config2.runId)) {
|
|
70032
|
+
lifecycle.warn("sandbox_agent_execution_lease_unavailable", {
|
|
70033
|
+
hasApiUrl: Boolean(config2.apiUrl),
|
|
70034
|
+
hasSandboxId: Boolean(config2.sandboxId),
|
|
70035
|
+
hasAgentSessionId: Boolean(agentSessionId)
|
|
70036
|
+
});
|
|
70037
|
+
}
|
|
69466
70038
|
try {
|
|
69467
70039
|
await wsClient.waitForConnection();
|
|
69468
70040
|
} catch (error2) {
|
|
@@ -69490,6 +70062,18 @@ async function runSandbox(config2) {
|
|
|
69490
70062
|
backendKind: activeBackendKind
|
|
69491
70063
|
});
|
|
69492
70064
|
currentAgent = agent;
|
|
70065
|
+
const activeRunId = currentRunId ?? config2.runId;
|
|
70066
|
+
const rootExecutionActivity = executionActivityTracker && activeRunId && currentTaskId ? executionActivityTracker.register({
|
|
70067
|
+
ownerId: `root:${activeRunId}`,
|
|
70068
|
+
leaseRunId: activeRunId,
|
|
70069
|
+
conversationId: currentConversationId,
|
|
70070
|
+
taskId: currentTaskId,
|
|
70071
|
+
sandboxId: config2.sandboxId,
|
|
70072
|
+
kind: "root",
|
|
70073
|
+
phase: "agent_run"
|
|
70074
|
+
}) : null;
|
|
70075
|
+
activeRootExecutionActivity = rootExecutionActivity;
|
|
70076
|
+
reportActiveRun = true;
|
|
69493
70077
|
wsClient.setCurrentRunId(currentRunId ?? config2.runId);
|
|
69494
70078
|
presenter.setRunContext?.(currentRunId ?? config2.runId, activeBackendKind);
|
|
69495
70079
|
const correlation = correlationLogFields2({
|
|
@@ -69642,6 +70226,12 @@ async function runSandbox(config2) {
|
|
|
69642
70226
|
presenter.onError(errorMessage, false);
|
|
69643
70227
|
}
|
|
69644
70228
|
presenter.onComplete(result);
|
|
70229
|
+
} finally {
|
|
70230
|
+
reportActiveRun = false;
|
|
70231
|
+
rootExecutionActivity?.release();
|
|
70232
|
+
if (activeRootExecutionActivity === rootExecutionActivity) {
|
|
70233
|
+
activeRootExecutionActivity = null;
|
|
70234
|
+
}
|
|
69645
70235
|
}
|
|
69646
70236
|
currentAgent = null;
|
|
69647
70237
|
resumeFallbackContext = void 0;
|
|
@@ -69733,6 +70323,7 @@ async function runSandbox(config2) {
|
|
|
69733
70323
|
}
|
|
69734
70324
|
presenter.setSuppressSessionLifecycle(false);
|
|
69735
70325
|
lifecycle.info("sandbox_agent_process_exit");
|
|
70326
|
+
executionLeaseClient?.close();
|
|
69736
70327
|
wsClient.close();
|
|
69737
70328
|
}
|
|
69738
70329
|
|
|
@@ -70098,6 +70689,7 @@ function logEffectiveGitIdentity(lifecycle, projectPath) {
|
|
|
70098
70689
|
}
|
|
70099
70690
|
async function runSessionFromEnv() {
|
|
70100
70691
|
const wsUrl = process.env.ALAN_WS_URL;
|
|
70692
|
+
const apiUrl = process.env.ALAN_API_URL || void 0;
|
|
70101
70693
|
const sessionId = process.env.ALAN_SESSION_ID;
|
|
70102
70694
|
const taskId = process.env.ALAN_TASK_ID;
|
|
70103
70695
|
const sessionToken = process.env.ALAN_SESSION_TOKEN;
|
|
@@ -70143,6 +70735,7 @@ async function runSessionFromEnv() {
|
|
|
70143
70735
|
logEffectiveGitIdentity(lifecycle, projectPath);
|
|
70144
70736
|
await runSandbox({
|
|
70145
70737
|
wsUrl,
|
|
70738
|
+
apiUrl,
|
|
70146
70739
|
sessionId,
|
|
70147
70740
|
taskId,
|
|
70148
70741
|
sessionToken,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiden-ade/sandbox-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.68",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Alan agent runtime — cloud sandbox and local daemon (alan-agent CLI)",
|
|
6
6
|
"bin": {
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"tsup": "^8.5.1",
|
|
26
26
|
"tsx": "^4.19.0",
|
|
27
27
|
"typescript": "~5.9.3",
|
|
28
|
-
"@alan-ai/
|
|
29
|
-
"@alan-ai/
|
|
28
|
+
"@alan-ai/shared": "0.1.0",
|
|
29
|
+
"@alan-ai/agent-core": "0.1.0"
|
|
30
30
|
},
|
|
31
31
|
"deprecated": "Use @alan-ai-hq/agent-manager instead.",
|
|
32
32
|
"scripts": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"lint": "biome check .",
|
|
36
36
|
"lint:fix": "biome check --write .",
|
|
37
37
|
"format": "biome format --write .",
|
|
38
|
-
"test": "vitest run
|
|
38
|
+
"test": "vitest run",
|
|
39
39
|
"test:coverage": "vitest run --coverage",
|
|
40
40
|
"test:watch": "vitest",
|
|
41
41
|
"type-check": "tsc --noEmit",
|