@aiden-ade/sandbox-agent 0.1.67 → 0.1.69
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 +795 -65
- package/package.json +2 -2
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.69";
|
|
22091
22091
|
|
|
22092
22092
|
// src/daemon-worktree.ts
|
|
22093
22093
|
var import_node_child_process3 = require("child_process");
|
|
@@ -23508,16 +23508,128 @@ async function collectClaudeLimits() {
|
|
|
23508
23508
|
].filter((window2) => Boolean(window2));
|
|
23509
23509
|
})().catch(() => []), 4e3, []);
|
|
23510
23510
|
}
|
|
23511
|
+
function antigravityWindowMinutes(window2) {
|
|
23512
|
+
if (window2 === "5h")
|
|
23513
|
+
return 5 * 60;
|
|
23514
|
+
if (window2 === "weekly")
|
|
23515
|
+
return 7 * 24 * 60;
|
|
23516
|
+
return null;
|
|
23517
|
+
}
|
|
23518
|
+
function antigravityGroupLabel(groupName) {
|
|
23519
|
+
if (typeof groupName !== "string" || !groupName.trim())
|
|
23520
|
+
return "Antigravity";
|
|
23521
|
+
return groupName.replace(/\s*models?$/i, "").trim() || groupName.trim();
|
|
23522
|
+
}
|
|
23523
|
+
function antigravityWindow(groupLabel, raw) {
|
|
23524
|
+
if (!raw)
|
|
23525
|
+
return null;
|
|
23526
|
+
const remainingFraction = numericValue(raw.remaining_fraction);
|
|
23527
|
+
if (remainingFraction === null)
|
|
23528
|
+
return null;
|
|
23529
|
+
const windowMinutes = antigravityWindowMinutes(raw.window);
|
|
23530
|
+
const resetAt = typeof raw.reset_time === "string" && raw.reset_time.trim() ? raw.reset_time : null;
|
|
23531
|
+
const windowShortLabel = limitLabel(windowMinutes, typeof raw.name === "string" && raw.name.trim() ? raw.name.trim() : "Limit");
|
|
23532
|
+
const remaining = Math.max(0, Math.min(100, remainingFraction * 100));
|
|
23533
|
+
return {
|
|
23534
|
+
label: windowShortLabel,
|
|
23535
|
+
group: groupLabel,
|
|
23536
|
+
remaining,
|
|
23537
|
+
limit: 100,
|
|
23538
|
+
usedPercent: Math.max(0, Math.min(100, 100 - remaining)),
|
|
23539
|
+
...windowMinutes !== null ? { windowMinutes } : {},
|
|
23540
|
+
...resetAt ? { resetAt } : {},
|
|
23541
|
+
source: "antigravity-cli-json"
|
|
23542
|
+
};
|
|
23543
|
+
}
|
|
23544
|
+
function runOneShotCli(command, args, env, timeoutMs) {
|
|
23545
|
+
return new Promise((resolve14) => {
|
|
23546
|
+
const child = (0, import_node_child_process4.spawn)(command, args, { env, stdio: ["ignore", "pipe", "ignore"] });
|
|
23547
|
+
let stdout = "";
|
|
23548
|
+
let settled = false;
|
|
23549
|
+
const settle = (value2) => {
|
|
23550
|
+
if (settled)
|
|
23551
|
+
return;
|
|
23552
|
+
settled = true;
|
|
23553
|
+
clearTimeout(timer);
|
|
23554
|
+
resolve14(value2);
|
|
23555
|
+
};
|
|
23556
|
+
const timer = setTimeout(() => {
|
|
23557
|
+
if (!child.killed)
|
|
23558
|
+
child.kill();
|
|
23559
|
+
settle(null);
|
|
23560
|
+
}, timeoutMs);
|
|
23561
|
+
child.stdout.on("data", (chunk) => {
|
|
23562
|
+
stdout += chunk.toString("utf8");
|
|
23563
|
+
});
|
|
23564
|
+
child.on("error", () => settle(null));
|
|
23565
|
+
child.on("close", () => settle(stdout));
|
|
23566
|
+
});
|
|
23567
|
+
}
|
|
23568
|
+
async function collectAntigravityLimits(env) {
|
|
23569
|
+
const runtimeEnv = augmentCliPath2(env);
|
|
23570
|
+
const agyCommand = resolveExecutable("agy", runtimeEnv, "ALAN_ANTIGRAVITY_PATH");
|
|
23571
|
+
if (!agyCommand)
|
|
23572
|
+
return [];
|
|
23573
|
+
const stdout = await runOneShotCli(agyCommand, ["-p", "/usage", "--output-format", "json"], runtimeEnv, 15e3);
|
|
23574
|
+
if (stdout === null)
|
|
23575
|
+
return [];
|
|
23576
|
+
try {
|
|
23577
|
+
const parsed = JSON.parse(stdout);
|
|
23578
|
+
const groups = parsed.command?.data?.groups;
|
|
23579
|
+
if (!Array.isArray(groups))
|
|
23580
|
+
return [];
|
|
23581
|
+
return groups.flatMap((group) => {
|
|
23582
|
+
const groupLabel = antigravityGroupLabel(group.name);
|
|
23583
|
+
const buckets = Array.isArray(group.buckets) ? group.buckets : [];
|
|
23584
|
+
return buckets.map((bucket) => antigravityWindow(groupLabel, bucket)).filter((window2) => Boolean(window2));
|
|
23585
|
+
});
|
|
23586
|
+
} catch {
|
|
23587
|
+
return [];
|
|
23588
|
+
}
|
|
23589
|
+
}
|
|
23590
|
+
var OPENCODE_TOTAL_COST_PATTERN = /Total Cost\s+\$([\d,]+\.\d{2})/;
|
|
23591
|
+
function parseOpenCodeTotalCost(stdout) {
|
|
23592
|
+
const match = OPENCODE_TOTAL_COST_PATTERN.exec(stdout);
|
|
23593
|
+
if (!match)
|
|
23594
|
+
return null;
|
|
23595
|
+
return {
|
|
23596
|
+
label: "Spend",
|
|
23597
|
+
summary: `$${match[1]} all-time`,
|
|
23598
|
+
source: "opencode-cli-stats"
|
|
23599
|
+
};
|
|
23600
|
+
}
|
|
23601
|
+
async function collectOpenCodeLimits(env) {
|
|
23602
|
+
const runtimeEnv = augmentCliPath2(env);
|
|
23603
|
+
const opencodeCommand = resolveExecutable("opencode", runtimeEnv, "ALAN_OPENCODE_PATH");
|
|
23604
|
+
if (!opencodeCommand)
|
|
23605
|
+
return [];
|
|
23606
|
+
const stdout = await runOneShotCli(opencodeCommand, ["stats"], runtimeEnv, 4e3);
|
|
23607
|
+
if (stdout === null)
|
|
23608
|
+
return [];
|
|
23609
|
+
const window2 = parseOpenCodeTotalCost(stdout);
|
|
23610
|
+
return window2 ? [window2] : [];
|
|
23611
|
+
}
|
|
23511
23612
|
async function collectLocalAgentProviderLimits(env = process.env) {
|
|
23512
23613
|
if (cachedLimits && Object.keys(cachedLimits.value).length > 0 && Date.now() - cachedLimits.collectedAt < CACHE_TTL_MS) {
|
|
23513
23614
|
return cachedLimits.value;
|
|
23514
23615
|
}
|
|
23515
|
-
const [codex, claude] = await Promise.all([
|
|
23616
|
+
const [codex, claude, antigravity, opencode] = await Promise.all([
|
|
23617
|
+
collectCodexLimits(env),
|
|
23618
|
+
collectClaudeLimits(),
|
|
23619
|
+
collectAntigravityLimits(env),
|
|
23620
|
+
collectOpenCodeLimits(env)
|
|
23621
|
+
]);
|
|
23516
23622
|
const limits = {};
|
|
23517
23623
|
if (codex.length > 0)
|
|
23518
23624
|
limits.codex_app_server = codex;
|
|
23519
23625
|
if (claude.length > 0)
|
|
23520
23626
|
limits.claude_cli = claude;
|
|
23627
|
+
if (antigravity.length > 0)
|
|
23628
|
+
limits.antigravity_cli = antigravity;
|
|
23629
|
+
if (opencode.length > 0) {
|
|
23630
|
+
limits.opencode_cli = opencode;
|
|
23631
|
+
limits.opencode_serve = opencode;
|
|
23632
|
+
}
|
|
23521
23633
|
if (Object.keys(limits).length > 0) {
|
|
23522
23634
|
cachedLimits = { value: limits, collectedAt: Date.now() };
|
|
23523
23635
|
} else {
|
|
@@ -32313,12 +32425,30 @@ function extractText(parsed) {
|
|
|
32313
32425
|
return "";
|
|
32314
32426
|
}
|
|
32315
32427
|
function extractToolInput(parsed) {
|
|
32316
|
-
|
|
32428
|
+
const rawInput = parsed.parameters ?? parsed.input ?? parsed.args ?? parsed.arguments ?? {};
|
|
32429
|
+
if (typeof rawInput === "object" && rawInput !== null && !Array.isArray(rawInput) && ("Arguments" in rawInput || "arguments" in rawInput)) {
|
|
32430
|
+
const record2 = rawInput;
|
|
32431
|
+
const nested = record2.Arguments ?? record2.arguments;
|
|
32432
|
+
if (typeof nested === "object" && nested !== null) {
|
|
32433
|
+
return nested;
|
|
32434
|
+
}
|
|
32435
|
+
}
|
|
32436
|
+
return rawInput;
|
|
32317
32437
|
}
|
|
32318
32438
|
function extractToolName(parsed) {
|
|
32319
32439
|
for (const key of ["tool_name", "toolName", "name"]) {
|
|
32320
32440
|
const value2 = parsed[key];
|
|
32321
|
-
if (typeof value2 === "string" && value2.trim())
|
|
32441
|
+
if (typeof value2 === "string" && value2.trim()) {
|
|
32442
|
+
const trimmed = value2.trim();
|
|
32443
|
+
if (trimmed === "call_mcp_tool" || trimmed === "callMcpTool") {
|
|
32444
|
+
const input = parsed.parameters ?? parsed.input ?? parsed.args ?? parsed.arguments ?? {};
|
|
32445
|
+
const server2 = typeof input.ServerName === "string" ? input.ServerName.trim() : typeof input.serverName === "string" ? input.serverName.trim() : "";
|
|
32446
|
+
const tool = typeof input.ToolName === "string" ? input.ToolName.trim() : typeof input.toolName === "string" ? input.toolName.trim() : "";
|
|
32447
|
+
if (server2 && tool) return `mcp__${server2}__${tool}`;
|
|
32448
|
+
if (tool) return tool;
|
|
32449
|
+
}
|
|
32450
|
+
return trimmed;
|
|
32451
|
+
}
|
|
32322
32452
|
}
|
|
32323
32453
|
const server = typeof parsed.server === "string" ? parsed.server.trim() : "";
|
|
32324
32454
|
const method = typeof parsed.method === "string" ? parsed.method.trim() : "";
|
|
@@ -32427,17 +32557,14 @@ function syncAntigravitySubagentTranscript(transcriptPath, parentToolUseId, pres
|
|
|
32427
32557
|
const toolCalls = Array.isArray(entry.tool_calls) ? entry.tool_calls : [];
|
|
32428
32558
|
toolCalls.forEach((rawToolCall, toolIndex) => {
|
|
32429
32559
|
const toolCall = asRecord(rawToolCall);
|
|
32430
|
-
|
|
32560
|
+
if (!toolCall) return;
|
|
32561
|
+
const toolName = extractToolName(toolCall);
|
|
32431
32562
|
if (!toolName) return;
|
|
32563
|
+
const toolInput = extractToolInput(toolCall);
|
|
32432
32564
|
const toolId = antigravityTranscriptToolId(parentToolUseId, lineIndex, toolIndex);
|
|
32433
32565
|
pendingToolIds.push(toolId);
|
|
32434
32566
|
emittedEventCount += 1;
|
|
32435
|
-
void presenter.onToolUse(
|
|
32436
|
-
toolName,
|
|
32437
|
-
toolCall?.args ?? toolCall?.parameters ?? {},
|
|
32438
|
-
toolId,
|
|
32439
|
-
parentToolUseId
|
|
32440
|
-
);
|
|
32567
|
+
void presenter.onToolUse(toolName, toolInput, toolId, parentToolUseId);
|
|
32441
32568
|
});
|
|
32442
32569
|
const content = stringField2(entry, "content");
|
|
32443
32570
|
if (content && isAntigravityToolResultEntry(entry)) {
|
|
@@ -35042,7 +35169,7 @@ function handleCopilotStructuredEvent(parsed, context, state) {
|
|
|
35042
35169
|
case "tool.execution_complete": {
|
|
35043
35170
|
const toolId = typeof data.toolCallId === "string" ? data.toolCallId : `copilot-tool-${Date.now()}`;
|
|
35044
35171
|
const result = typeof data.result === "object" && data.result !== null ? data.result : {};
|
|
35045
|
-
const content = typeof result.content === "string" ? result.content : typeof result.detailedContent === "string" ? result.detailedContent : typeof data.error === "string" ? data.error : "";
|
|
35172
|
+
const content = result.codeContext !== void 0 || result.structuredContent !== void 0 || result.content !== void 0 && Array.isArray(result.content) ? JSON.stringify(result, null, 2) : typeof result.content === "string" ? result.content : typeof result.detailedContent === "string" ? result.detailedContent : typeof data.error === "string" ? data.error : "";
|
|
35046
35173
|
const success2 = typeof data.success === "boolean" ? data.success : true;
|
|
35047
35174
|
const trackedLauncher = state.activeBackgroundTaskIds?.has(toolId) === true;
|
|
35048
35175
|
const linkedBackground = state.backgroundTaskIdsByToolId?.has(toolId) === true;
|
|
@@ -35253,6 +35380,9 @@ function buildCursorToolResultText(result) {
|
|
|
35253
35380
|
const resultRecord = result;
|
|
35254
35381
|
const success2 = typeof resultRecord.success === "object" && resultRecord.success !== null ? resultRecord.success : null;
|
|
35255
35382
|
if (success2) {
|
|
35383
|
+
if (success2.codeContext !== void 0 || success2.structuredContent !== void 0 || success2.content !== void 0 && Array.isArray(success2.content)) {
|
|
35384
|
+
return JSON.stringify(success2, null, 2);
|
|
35385
|
+
}
|
|
35256
35386
|
if (typeof success2.content === "string" && success2.content.trim().length > 0)
|
|
35257
35387
|
return success2.content;
|
|
35258
35388
|
if (typeof success2.output === "string" && success2.output.trim().length > 0)
|
|
@@ -43094,11 +43224,11 @@ var SocketWithoutUpgrade = class _SocketWithoutUpgrade extends Emitter {
|
|
|
43094
43224
|
*/
|
|
43095
43225
|
_resetPingTimeout() {
|
|
43096
43226
|
this.clearTimeoutFn(this._pingTimeoutTimer);
|
|
43097
|
-
const
|
|
43098
|
-
this._pingTimeoutTime = Date.now() +
|
|
43227
|
+
const delay3 = this._pingInterval + this._pingTimeout;
|
|
43228
|
+
this._pingTimeoutTime = Date.now() + delay3;
|
|
43099
43229
|
this._pingTimeoutTimer = this.setTimeoutFn(() => {
|
|
43100
43230
|
this._onClose("ping timeout");
|
|
43101
|
-
},
|
|
43231
|
+
}, delay3);
|
|
43102
43232
|
if (this.opts.autoUnref) {
|
|
43103
43233
|
this._pingTimeoutTimer.unref();
|
|
43104
43234
|
}
|
|
@@ -45079,8 +45209,8 @@ var Manager = class extends Emitter {
|
|
|
45079
45209
|
this.emitReserved("reconnect_failed");
|
|
45080
45210
|
this._reconnecting = false;
|
|
45081
45211
|
} else {
|
|
45082
|
-
const
|
|
45083
|
-
debug10("will wait %dms before reconnect attempt",
|
|
45212
|
+
const delay3 = this.backoff.duration();
|
|
45213
|
+
debug10("will wait %dms before reconnect attempt", delay3);
|
|
45084
45214
|
this._reconnecting = true;
|
|
45085
45215
|
const timer = this.setTimeoutFn(() => {
|
|
45086
45216
|
if (self.skipReconnect)
|
|
@@ -45100,7 +45230,7 @@ var Manager = class extends Emitter {
|
|
|
45100
45230
|
self.onreconnect();
|
|
45101
45231
|
}
|
|
45102
45232
|
});
|
|
45103
|
-
},
|
|
45233
|
+
}, delay3);
|
|
45104
45234
|
if (this.opts.autoUnref) {
|
|
45105
45235
|
timer.unref();
|
|
45106
45236
|
}
|
|
@@ -61929,13 +62059,13 @@ var StreamableHTTPClientTransport = class {
|
|
|
61929
62059
|
this.onerror?.(new Error(`Maximum reconnection attempts (${maxRetries}) exceeded.`));
|
|
61930
62060
|
return;
|
|
61931
62061
|
}
|
|
61932
|
-
const
|
|
62062
|
+
const delay3 = this._getNextReconnectionDelay(attemptCount);
|
|
61933
62063
|
this._reconnectionTimeout = setTimeout(() => {
|
|
61934
62064
|
this._startOrAuthSse(options).catch((error2) => {
|
|
61935
62065
|
this.onerror?.(new Error(`Failed to reconnect SSE stream: ${error2 instanceof Error ? error2.message : String(error2)}`));
|
|
61936
62066
|
this._scheduleReconnection(options, attemptCount + 1);
|
|
61937
62067
|
});
|
|
61938
|
-
},
|
|
62068
|
+
}, delay3);
|
|
61939
62069
|
}
|
|
61940
62070
|
_handleSseStream(stream, options, isReconnectable) {
|
|
61941
62071
|
if (!stream) {
|
|
@@ -64748,38 +64878,103 @@ var publishSkillInputSchema = defineWireSchema()(external_exports.object({
|
|
|
64748
64878
|
expectedContentHash: sha256Schema,
|
|
64749
64879
|
uploadGrant: runtimeUploadGrantSchema
|
|
64750
64880
|
}));
|
|
64751
|
-
var
|
|
64752
|
-
|
|
64753
|
-
|
|
64754
|
-
|
|
64755
|
-
|
|
64756
|
-
|
|
64757
|
-
|
|
64758
|
-
|
|
64759
|
-
|
|
64760
|
-
|
|
64761
|
-
|
|
64762
|
-
|
|
64763
|
-
|
|
64764
|
-
|
|
64881
|
+
var skillFrontmatterAdmissionSchema = external_exports.object({
|
|
64882
|
+
name: external_exports.string().min(1).max(64).regex(SKILL_NAME_PATTERN),
|
|
64883
|
+
description: external_exports.string().trim().min(1).max(1024)
|
|
64884
|
+
}).passthrough();
|
|
64885
|
+
var PROJECTED_VALUE_MAX_BYTES = 16384;
|
|
64886
|
+
function formatKeys(keys) {
|
|
64887
|
+
const shown = keys.slice(0, 3).map((key) => `metadata.${key}`);
|
|
64888
|
+
const remaining = keys.length - shown.length;
|
|
64889
|
+
const listed = shown.join(", ");
|
|
64890
|
+
return remaining > 0 ? `${listed} and ${remaining} more` : listed;
|
|
64891
|
+
}
|
|
64892
|
+
function unsupported(message) {
|
|
64893
|
+
return { severity: "warning", code: "UNSUPPORTED_FRONTMATTER", message, path: "SKILL.md" };
|
|
64894
|
+
}
|
|
64895
|
+
function projectSkillFrontmatter(admitted) {
|
|
64896
|
+
const conformance = [];
|
|
64897
|
+
const raw = admitted;
|
|
64898
|
+
const optionalText = (key, max) => {
|
|
64899
|
+
const value2 = raw[key];
|
|
64900
|
+
if (value2 === void 0)
|
|
64901
|
+
return void 0;
|
|
64902
|
+
if (typeof value2 !== "string") {
|
|
64903
|
+
conformance.push(unsupported(`${key} is not a string; the Agent Skills spec expects text`));
|
|
64904
|
+
return void 0;
|
|
64905
|
+
}
|
|
64906
|
+
const trimmed = value2.trim();
|
|
64907
|
+
if (!trimmed)
|
|
64908
|
+
return void 0;
|
|
64909
|
+
if (trimmed.length > max) {
|
|
64910
|
+
conformance.push(unsupported(`${key} exceeds ${max} characters and was not indexed`));
|
|
64911
|
+
return void 0;
|
|
64912
|
+
}
|
|
64913
|
+
return trimmed;
|
|
64914
|
+
};
|
|
64915
|
+
const optionalToolList = (key, max) => {
|
|
64916
|
+
const value2 = raw[key];
|
|
64917
|
+
if (Array.isArray(value2) && value2.every((entry) => typeof entry === "string")) {
|
|
64918
|
+
raw[key] = value2.join(", ");
|
|
64919
|
+
}
|
|
64920
|
+
return optionalText(key, max);
|
|
64921
|
+
};
|
|
64922
|
+
const license = optionalText("license", 1024);
|
|
64923
|
+
const compatibility = optionalText("compatibility", 500);
|
|
64924
|
+
const allowedTools = optionalToolList("allowed-tools", 1024);
|
|
64925
|
+
const metadata = {};
|
|
64926
|
+
const rawMetadata = raw.metadata;
|
|
64927
|
+
if (rawMetadata !== void 0) {
|
|
64928
|
+
if (typeof rawMetadata !== "object" || rawMetadata === null || Array.isArray(rawMetadata)) {
|
|
64929
|
+
conformance.push(unsupported("metadata is not a mapping and was not indexed"));
|
|
64930
|
+
} else {
|
|
64931
|
+
const encoder = new TextEncoder();
|
|
64932
|
+
const notStrings = [];
|
|
64933
|
+
const selfReferential = [];
|
|
64934
|
+
const tooLarge = [];
|
|
64935
|
+
for (const [key, value2] of Object.entries(rawMetadata)) {
|
|
64936
|
+
if (typeof value2 !== "string")
|
|
64937
|
+
notStrings.push(key);
|
|
64938
|
+
let encoded;
|
|
64939
|
+
if (typeof value2 === "string") {
|
|
64940
|
+
encoded = value2;
|
|
64941
|
+
} else {
|
|
64942
|
+
try {
|
|
64943
|
+
encoded = JSON.stringify(value2) ?? "";
|
|
64944
|
+
} catch {
|
|
64945
|
+
selfReferential.push(key);
|
|
64946
|
+
continue;
|
|
64947
|
+
}
|
|
64948
|
+
}
|
|
64949
|
+
if (encoder.encode(encoded).byteLength > PROJECTED_VALUE_MAX_BYTES) {
|
|
64950
|
+
tooLarge.push(key);
|
|
64951
|
+
continue;
|
|
64952
|
+
}
|
|
64953
|
+
metadata[key] = value2;
|
|
64954
|
+
}
|
|
64955
|
+
if (notStrings.length > 0) {
|
|
64956
|
+
conformance.push(unsupported(`${formatKeys(notStrings)} ${notStrings.length === 1 ? "is" : "are"} not ${notStrings.length === 1 ? "a string" : "strings"}; the Agent Skills spec expects text`));
|
|
64957
|
+
}
|
|
64958
|
+
if (selfReferential.length > 0) {
|
|
64959
|
+
conformance.push(unsupported(`${formatKeys(selfReferential)} ${selfReferential.length === 1 ? "refers" : "refer"} to itself and ${selfReferential.length === 1 ? "was" : "were"} not indexed`));
|
|
64960
|
+
}
|
|
64961
|
+
if (tooLarge.length > 0) {
|
|
64962
|
+
conformance.push(unsupported(`${formatKeys(tooLarge)} ${tooLarge.length === 1 ? "is" : "are"} too large to index`));
|
|
64963
|
+
}
|
|
64765
64964
|
}
|
|
64766
64965
|
}
|
|
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
|
-
}));
|
|
64966
|
+
return {
|
|
64967
|
+
metadata: {
|
|
64968
|
+
name: admitted.name,
|
|
64969
|
+
description: admitted.description,
|
|
64970
|
+
...license ? { license } : {},
|
|
64971
|
+
...compatibility ? { compatibility } : {},
|
|
64972
|
+
metadata,
|
|
64973
|
+
...allowedTools ? { allowedTools } : {}
|
|
64974
|
+
},
|
|
64975
|
+
conformance
|
|
64976
|
+
};
|
|
64977
|
+
}
|
|
64783
64978
|
var skillPackageDiagnosticSchema = external_exports.object({
|
|
64784
64979
|
severity: external_exports.literal("warning"),
|
|
64785
64980
|
code: external_exports.enum(["BROKEN_REFERENCE", "UNSUPPORTED_FRONTMATTER"]),
|
|
@@ -65052,7 +65247,10 @@ async function inspectSkillPackage(packageRoot, options = {}) {
|
|
|
65052
65247
|
inspectedFiles.sort(comparePackageFiles);
|
|
65053
65248
|
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
65249
|
const manifestFiles = inspectedFiles.map((file2) => file2.manifest);
|
|
65055
|
-
const diagnostics =
|
|
65250
|
+
const diagnostics = [
|
|
65251
|
+
...parsedMetadata.conformance,
|
|
65252
|
+
...collectDiagnostics(inspectedFiles.find((file2) => file2.manifest.path === "SKILL.md")?.bytes, parsedMetadata.metadata.license, new Set(manifestFiles.map((file2) => file2.path)))
|
|
65253
|
+
];
|
|
65056
65254
|
return {
|
|
65057
65255
|
schemaVersion: 1,
|
|
65058
65256
|
entrypoint: "SKILL.md",
|
|
@@ -65294,14 +65492,14 @@ function parseSkillMetadata(bytes, expectedName) {
|
|
|
65294
65492
|
if (!isRecord2(parsed)) {
|
|
65295
65493
|
throw new SkillPackageError("INVALID_FRONTMATTER", "SKILL.md frontmatter must be a YAML mapping", "SKILL.md");
|
|
65296
65494
|
}
|
|
65297
|
-
const
|
|
65298
|
-
if (!
|
|
65299
|
-
throw new SkillPackageError("INVALID_FRONTMATTER", `SKILL.md frontmatter is invalid: ${
|
|
65495
|
+
const admitted = skillFrontmatterAdmissionSchema.safeParse(parsed);
|
|
65496
|
+
if (!admitted.success) {
|
|
65497
|
+
throw new SkillPackageError("INVALID_FRONTMATTER", `SKILL.md frontmatter is invalid: ${admitted.error.issues.map(formatFrontmatterIssue).join("; ")}`, "SKILL.md");
|
|
65300
65498
|
}
|
|
65301
|
-
if (expectedName !== null &&
|
|
65302
|
-
throw new SkillPackageError("DIRECTORY_NAME_MISMATCH", `Skill name ${
|
|
65499
|
+
if (expectedName !== null && admitted.data.name !== expectedName.normalize("NFC")) {
|
|
65500
|
+
throw new SkillPackageError("DIRECTORY_NAME_MISMATCH", `Skill name ${admitted.data.name} must match its directory ${expectedName}`, "SKILL.md");
|
|
65303
65501
|
}
|
|
65304
|
-
return
|
|
65502
|
+
return projectSkillFrontmatter(admitted.data);
|
|
65305
65503
|
}
|
|
65306
65504
|
function formatFrontmatterIssue(issue2) {
|
|
65307
65505
|
const field = issue2.path.map(String).join(".");
|
|
@@ -68694,6 +68892,332 @@ function decodeResumeFallbackContext(encoded) {
|
|
|
68694
68892
|
// src/sandbox.ts
|
|
68695
68893
|
var import_node_os12 = require("os");
|
|
68696
68894
|
|
|
68895
|
+
// src/execution-activity-tracker.ts
|
|
68896
|
+
var ExecutionActivityTracker = class {
|
|
68897
|
+
constructor(onChange) {
|
|
68898
|
+
this.onChange = onChange;
|
|
68899
|
+
}
|
|
68900
|
+
activities = /* @__PURE__ */ new Map();
|
|
68901
|
+
register(input) {
|
|
68902
|
+
const normalized = normalizeRegistration(input);
|
|
68903
|
+
const existing = this.activities.get(normalized.ownerId);
|
|
68904
|
+
if (existing) {
|
|
68905
|
+
if (!sameRegistration(existing.input, normalized)) {
|
|
68906
|
+
throw new Error(`Execution activity owner ${normalized.ownerId} changed identity`);
|
|
68907
|
+
}
|
|
68908
|
+
existing.refCount += 1;
|
|
68909
|
+
} else {
|
|
68910
|
+
const activeLease = this.firstActivity()?.input.leaseRunId;
|
|
68911
|
+
if (activeLease && activeLease !== normalized.leaseRunId) {
|
|
68912
|
+
throw new Error(
|
|
68913
|
+
`Cannot track execution leases ${activeLease} and ${normalized.leaseRunId} concurrently`
|
|
68914
|
+
);
|
|
68915
|
+
}
|
|
68916
|
+
this.activities.set(normalized.ownerId, { input: normalized, refCount: 1 });
|
|
68917
|
+
}
|
|
68918
|
+
this.emitChange();
|
|
68919
|
+
let released = false;
|
|
68920
|
+
return {
|
|
68921
|
+
release: () => {
|
|
68922
|
+
if (released) return;
|
|
68923
|
+
released = true;
|
|
68924
|
+
const tracked = this.activities.get(normalized.ownerId);
|
|
68925
|
+
if (!tracked) return;
|
|
68926
|
+
tracked.refCount -= 1;
|
|
68927
|
+
if (tracked.refCount <= 0) this.activities.delete(normalized.ownerId);
|
|
68928
|
+
this.emitChange();
|
|
68929
|
+
}
|
|
68930
|
+
};
|
|
68931
|
+
}
|
|
68932
|
+
snapshot() {
|
|
68933
|
+
const first = this.firstActivity();
|
|
68934
|
+
if (!first) return null;
|
|
68935
|
+
const activeRunIds = /* @__PURE__ */ new Set([first.input.leaseRunId]);
|
|
68936
|
+
let trackedChildCount = 0;
|
|
68937
|
+
let trackedWorkCount = 0;
|
|
68938
|
+
let childAlive = false;
|
|
68939
|
+
let phase;
|
|
68940
|
+
for (const { input, refCount } of this.activities.values()) {
|
|
68941
|
+
activeRunIds.add(input.activeRunId ?? input.leaseRunId);
|
|
68942
|
+
trackedWorkCount += refCount;
|
|
68943
|
+
if (input.kind === "child") trackedChildCount += refCount;
|
|
68944
|
+
childAlive ||= input.childAlive === true;
|
|
68945
|
+
phase ??= input.phase;
|
|
68946
|
+
}
|
|
68947
|
+
return {
|
|
68948
|
+
runId: first.input.leaseRunId,
|
|
68949
|
+
conversationId: first.input.conversationId,
|
|
68950
|
+
taskId: first.input.taskId,
|
|
68951
|
+
sandboxId: first.input.sandboxId,
|
|
68952
|
+
activeRunIds: [...activeRunIds].sort(),
|
|
68953
|
+
phase,
|
|
68954
|
+
childAlive,
|
|
68955
|
+
trackedChildCount,
|
|
68956
|
+
trackedWorkCount
|
|
68957
|
+
};
|
|
68958
|
+
}
|
|
68959
|
+
firstActivity() {
|
|
68960
|
+
return this.activities.values().next().value;
|
|
68961
|
+
}
|
|
68962
|
+
emitChange() {
|
|
68963
|
+
this.onChange(this.snapshot());
|
|
68964
|
+
}
|
|
68965
|
+
};
|
|
68966
|
+
function normalizeRegistration(input) {
|
|
68967
|
+
const ownerId = input.ownerId.trim();
|
|
68968
|
+
const leaseRunId = input.leaseRunId.trim();
|
|
68969
|
+
const activeRunId = input.activeRunId?.trim() || void 0;
|
|
68970
|
+
const conversationId = input.conversationId.trim();
|
|
68971
|
+
const taskId = input.taskId.trim();
|
|
68972
|
+
const sandboxId = input.sandboxId.trim();
|
|
68973
|
+
if (!ownerId || !leaseRunId || !conversationId || !taskId || !sandboxId) {
|
|
68974
|
+
throw new Error("Execution activity identity fields must be non-empty");
|
|
68975
|
+
}
|
|
68976
|
+
return {
|
|
68977
|
+
...input,
|
|
68978
|
+
ownerId,
|
|
68979
|
+
leaseRunId,
|
|
68980
|
+
activeRunId,
|
|
68981
|
+
conversationId,
|
|
68982
|
+
taskId,
|
|
68983
|
+
sandboxId
|
|
68984
|
+
};
|
|
68985
|
+
}
|
|
68986
|
+
function sameRegistration(left, right) {
|
|
68987
|
+
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;
|
|
68988
|
+
}
|
|
68989
|
+
|
|
68990
|
+
// src/execution-lease-client.ts
|
|
68991
|
+
var EXECUTION_LEASE_RENEW_INTERVAL_MS = 3e4;
|
|
68992
|
+
var EXECUTION_LEASE_REQUEST_TIMEOUT_MS = 1e4;
|
|
68993
|
+
var DEFAULT_RETRY_DELAYS_MS = [250, 1e3];
|
|
68994
|
+
var ExecutionLeaseClient = class {
|
|
68995
|
+
constructor(options) {
|
|
68996
|
+
this.options = options;
|
|
68997
|
+
this.apiUrl = options.apiUrl.replace(/\/+$/, "");
|
|
68998
|
+
this.fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
68999
|
+
this.renewIntervalMs = options.renewIntervalMs ?? EXECUTION_LEASE_RENEW_INTERVAL_MS;
|
|
69000
|
+
this.requestTimeoutMs = options.requestTimeoutMs ?? EXECUTION_LEASE_REQUEST_TIMEOUT_MS;
|
|
69001
|
+
this.retryDelaysMs = options.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS;
|
|
69002
|
+
this.enabled = options.enabled !== false;
|
|
69003
|
+
}
|
|
69004
|
+
apiUrl;
|
|
69005
|
+
fetchImpl;
|
|
69006
|
+
renewIntervalMs;
|
|
69007
|
+
requestTimeoutMs;
|
|
69008
|
+
retryDelaysMs;
|
|
69009
|
+
activity = null;
|
|
69010
|
+
activityGeneration = 0;
|
|
69011
|
+
interval = null;
|
|
69012
|
+
inFlight = null;
|
|
69013
|
+
trailingRenewal = false;
|
|
69014
|
+
nextSequence = 1;
|
|
69015
|
+
enabled;
|
|
69016
|
+
closed = false;
|
|
69017
|
+
terminalSessionFailure = false;
|
|
69018
|
+
terminalRunIds = /* @__PURE__ */ new Set();
|
|
69019
|
+
setActivity(activity) {
|
|
69020
|
+
if (this.closed || this.terminalSessionFailure) return;
|
|
69021
|
+
const previousRunId = this.activity?.runId ?? null;
|
|
69022
|
+
const nextRunId = activity?.runId ?? null;
|
|
69023
|
+
if (previousRunId !== nextRunId) this.activityGeneration += 1;
|
|
69024
|
+
this.activity = activity;
|
|
69025
|
+
if (!activity) {
|
|
69026
|
+
this.stopInterval();
|
|
69027
|
+
this.trailingRenewal = false;
|
|
69028
|
+
this.options.lifecycle?.debug("sandbox_agent_execution_lease_stopped", {
|
|
69029
|
+
reason: "idle"
|
|
69030
|
+
});
|
|
69031
|
+
return;
|
|
69032
|
+
}
|
|
69033
|
+
if (this.terminalRunIds.has(activity.runId)) {
|
|
69034
|
+
this.stopInterval();
|
|
69035
|
+
return;
|
|
69036
|
+
}
|
|
69037
|
+
if (!this.enabled) return;
|
|
69038
|
+
this.startInterval();
|
|
69039
|
+
if (previousRunId !== activity.runId || !this.inFlight) this.requestRenewal();
|
|
69040
|
+
else this.trailingRenewal = true;
|
|
69041
|
+
}
|
|
69042
|
+
/** Enable renewals after the connected WS server proves route support. */
|
|
69043
|
+
enable() {
|
|
69044
|
+
if (this.enabled || this.closed || this.terminalSessionFailure) return;
|
|
69045
|
+
this.enabled = true;
|
|
69046
|
+
this.options.lifecycle?.info("sandbox_agent_execution_lease_enabled");
|
|
69047
|
+
if (!this.activity || this.terminalRunIds.has(this.activity.runId)) return;
|
|
69048
|
+
this.startInterval();
|
|
69049
|
+
this.requestRenewal();
|
|
69050
|
+
}
|
|
69051
|
+
close() {
|
|
69052
|
+
this.closed = true;
|
|
69053
|
+
this.activityGeneration += 1;
|
|
69054
|
+
this.activity = null;
|
|
69055
|
+
this.trailingRenewal = false;
|
|
69056
|
+
this.stopInterval();
|
|
69057
|
+
}
|
|
69058
|
+
startInterval() {
|
|
69059
|
+
if (this.interval) return;
|
|
69060
|
+
this.interval = setInterval(() => this.requestRenewal(), this.renewIntervalMs);
|
|
69061
|
+
this.interval.unref?.();
|
|
69062
|
+
}
|
|
69063
|
+
stopInterval() {
|
|
69064
|
+
if (!this.interval) return;
|
|
69065
|
+
clearInterval(this.interval);
|
|
69066
|
+
this.interval = null;
|
|
69067
|
+
}
|
|
69068
|
+
loseAuthority(activity, seq, status, code) {
|
|
69069
|
+
this.terminalSessionFailure = true;
|
|
69070
|
+
this.stopInterval();
|
|
69071
|
+
this.options.lifecycle?.error("sandbox_agent_execution_lease_authority_lost", {
|
|
69072
|
+
runId: activity.runId,
|
|
69073
|
+
seq,
|
|
69074
|
+
status,
|
|
69075
|
+
code
|
|
69076
|
+
});
|
|
69077
|
+
this.options.onAuthorityLost?.({ runId: activity.runId, code, status });
|
|
69078
|
+
}
|
|
69079
|
+
requestRenewal() {
|
|
69080
|
+
if (this.closed || !this.enabled || this.terminalSessionFailure || !this.activity || this.terminalRunIds.has(this.activity.runId)) {
|
|
69081
|
+
return;
|
|
69082
|
+
}
|
|
69083
|
+
if (this.inFlight) {
|
|
69084
|
+
this.trailingRenewal = true;
|
|
69085
|
+
return;
|
|
69086
|
+
}
|
|
69087
|
+
const activity = this.activity;
|
|
69088
|
+
const activityGeneration = this.activityGeneration;
|
|
69089
|
+
const seq = this.nextSequence;
|
|
69090
|
+
this.nextSequence += 1;
|
|
69091
|
+
this.inFlight = this.renewWithRetry(activity, activityGeneration, seq).finally(() => {
|
|
69092
|
+
this.inFlight = null;
|
|
69093
|
+
if (!this.trailingRenewal) return;
|
|
69094
|
+
this.trailingRenewal = false;
|
|
69095
|
+
if (this.activity) this.requestRenewal();
|
|
69096
|
+
});
|
|
69097
|
+
}
|
|
69098
|
+
isCurrentRun(activity, generation) {
|
|
69099
|
+
return !this.closed && this.activityGeneration === generation && this.activity?.runId === activity.runId;
|
|
69100
|
+
}
|
|
69101
|
+
async renewWithRetry(activity, activityGeneration, seq) {
|
|
69102
|
+
const body = {
|
|
69103
|
+
conversationId: activity.conversationId,
|
|
69104
|
+
taskId: activity.taskId,
|
|
69105
|
+
sandboxId: activity.sandboxId,
|
|
69106
|
+
agentSessionId: this.options.agentSessionId,
|
|
69107
|
+
seq,
|
|
69108
|
+
activeRunIds: activity.activeRunIds,
|
|
69109
|
+
agentVersion: this.options.agentVersion,
|
|
69110
|
+
phase: activity.phase,
|
|
69111
|
+
childAlive: activity.childAlive,
|
|
69112
|
+
trackedChildCount: activity.trackedChildCount
|
|
69113
|
+
};
|
|
69114
|
+
const url3 = `${this.apiUrl}/public/agent-runs/${encodeURIComponent(activity.runId)}/execution-lease`;
|
|
69115
|
+
for (let attempt = 0; attempt <= this.retryDelaysMs.length; attempt += 1) {
|
|
69116
|
+
if (!this.isCurrentRun(activity, activityGeneration)) return;
|
|
69117
|
+
try {
|
|
69118
|
+
const response = await this.fetchImpl(url3, {
|
|
69119
|
+
method: "POST",
|
|
69120
|
+
headers: {
|
|
69121
|
+
authorization: `Bearer ${this.options.sessionToken}`,
|
|
69122
|
+
"content-type": "application/json"
|
|
69123
|
+
},
|
|
69124
|
+
body: JSON.stringify(body),
|
|
69125
|
+
signal: AbortSignal.timeout(this.requestTimeoutMs)
|
|
69126
|
+
});
|
|
69127
|
+
if (response.ok) {
|
|
69128
|
+
this.options.lifecycle?.debug("sandbox_agent_execution_lease_renewed", {
|
|
69129
|
+
runId: activity.runId,
|
|
69130
|
+
seq,
|
|
69131
|
+
attempt: attempt + 1
|
|
69132
|
+
});
|
|
69133
|
+
return;
|
|
69134
|
+
}
|
|
69135
|
+
const errorBody = await readErrorBody(response);
|
|
69136
|
+
const code = errorBody.code;
|
|
69137
|
+
const sessionAuthorityLost = response.status === 409 && code === "EXECUTION_LEASE_FENCED" || response.status === 401 && code === "EXECUTION_LEASE_INVALID_TOKEN";
|
|
69138
|
+
if (sessionAuthorityLost && code) {
|
|
69139
|
+
this.loseAuthority(activity, seq, response.status, code);
|
|
69140
|
+
return;
|
|
69141
|
+
}
|
|
69142
|
+
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";
|
|
69143
|
+
if (runAuthorityLost && code) {
|
|
69144
|
+
if (!this.isCurrentRun(activity, activityGeneration)) {
|
|
69145
|
+
this.options.lifecycle?.debug("sandbox_agent_execution_lease_stale_response_ignored", {
|
|
69146
|
+
runId: activity.runId,
|
|
69147
|
+
seq,
|
|
69148
|
+
status: response.status,
|
|
69149
|
+
code
|
|
69150
|
+
});
|
|
69151
|
+
return;
|
|
69152
|
+
}
|
|
69153
|
+
this.loseAuthority(activity, seq, response.status, code);
|
|
69154
|
+
return;
|
|
69155
|
+
}
|
|
69156
|
+
if (response.status === 409 && code === "EXECUTION_LEASE_PROVIDER_UNRESOLVED") {
|
|
69157
|
+
this.terminalRunIds.add(activity.runId);
|
|
69158
|
+
if (this.activity?.runId === activity.runId) this.stopInterval();
|
|
69159
|
+
this.options.lifecycle?.warn("sandbox_agent_execution_lease_run_rejected", {
|
|
69160
|
+
runId: activity.runId,
|
|
69161
|
+
seq,
|
|
69162
|
+
code
|
|
69163
|
+
});
|
|
69164
|
+
return;
|
|
69165
|
+
}
|
|
69166
|
+
const takeoverPending = response.status === 409 && code === "EXECUTION_LEASE_TAKEOVER_PENDING";
|
|
69167
|
+
const mixedVersionUnavailable = (response.status === 401 || response.status === 403 || response.status === 404) && !code?.startsWith("EXECUTION_LEASE_");
|
|
69168
|
+
const retryable = takeoverPending || mixedVersionUnavailable || isRetryableStatus(response.status);
|
|
69169
|
+
if (!retryable || attempt === this.retryDelaysMs.length) {
|
|
69170
|
+
this.options.lifecycle?.warn("sandbox_agent_execution_lease_renew_failed", {
|
|
69171
|
+
runId: activity.runId,
|
|
69172
|
+
seq,
|
|
69173
|
+
status: response.status,
|
|
69174
|
+
code,
|
|
69175
|
+
attempt: attempt + 1
|
|
69176
|
+
});
|
|
69177
|
+
return;
|
|
69178
|
+
}
|
|
69179
|
+
if (takeoverPending) {
|
|
69180
|
+
this.options.lifecycle?.debug("sandbox_agent_execution_lease_takeover_pending", {
|
|
69181
|
+
runId: activity.runId,
|
|
69182
|
+
seq,
|
|
69183
|
+
attempt: attempt + 1
|
|
69184
|
+
});
|
|
69185
|
+
}
|
|
69186
|
+
} catch (error2) {
|
|
69187
|
+
if (attempt === this.retryDelaysMs.length) {
|
|
69188
|
+
this.options.lifecycle?.warn("sandbox_agent_execution_lease_renew_failed", {
|
|
69189
|
+
runId: activity.runId,
|
|
69190
|
+
seq,
|
|
69191
|
+
attempt: attempt + 1,
|
|
69192
|
+
error: error2 instanceof Error ? error2 : new Error(String(error2))
|
|
69193
|
+
});
|
|
69194
|
+
return;
|
|
69195
|
+
}
|
|
69196
|
+
}
|
|
69197
|
+
await delay2(this.retryDelaysMs[attempt] ?? 0);
|
|
69198
|
+
}
|
|
69199
|
+
}
|
|
69200
|
+
};
|
|
69201
|
+
function isRetryableStatus(status) {
|
|
69202
|
+
return status === 408 || status === 429 || status >= 500;
|
|
69203
|
+
}
|
|
69204
|
+
async function readErrorBody(response) {
|
|
69205
|
+
try {
|
|
69206
|
+
const body = await response.json();
|
|
69207
|
+
if (!body || typeof body !== "object") return {};
|
|
69208
|
+
const record2 = body;
|
|
69209
|
+
return {
|
|
69210
|
+
code: typeof record2.code === "string" ? record2.code : void 0,
|
|
69211
|
+
message: typeof record2.message === "string" ? record2.message : void 0
|
|
69212
|
+
};
|
|
69213
|
+
} catch {
|
|
69214
|
+
return {};
|
|
69215
|
+
}
|
|
69216
|
+
}
|
|
69217
|
+
function delay2(ms) {
|
|
69218
|
+
return new Promise((resolve14) => setTimeout(resolve14, ms));
|
|
69219
|
+
}
|
|
69220
|
+
|
|
68697
69221
|
// src/web-presenter.ts
|
|
68698
69222
|
var import_node_crypto15 = require("crypto");
|
|
68699
69223
|
var WebPresenter = class {
|
|
@@ -69086,6 +69610,21 @@ var SandboxEventDispatcher = class {
|
|
|
69086
69610
|
|
|
69087
69611
|
// src/ws-client.ts
|
|
69088
69612
|
var ACCEPTED_MESSAGE_ID_CACHE_SIZE = 200;
|
|
69613
|
+
var SUPERVISED_RECONNECT_BASE_DELAY_MS = 1e3;
|
|
69614
|
+
var SUPERVISED_RECONNECT_MAX_DELAY_MS = 5e3;
|
|
69615
|
+
var SUPERVISED_RECONNECT_MAX_JITTER_MS = 500;
|
|
69616
|
+
function parseConnectionDirective(data) {
|
|
69617
|
+
if (typeof data !== "object" || data === null || typeof data.code !== "string" || typeof data.retryable !== "boolean") {
|
|
69618
|
+
return null;
|
|
69619
|
+
}
|
|
69620
|
+
const candidate = data;
|
|
69621
|
+
return {
|
|
69622
|
+
code: candidate.code,
|
|
69623
|
+
retryable: candidate.retryable,
|
|
69624
|
+
reason: typeof candidate.reason === "string" ? candidate.reason : void 0,
|
|
69625
|
+
retryAfterMs: typeof candidate.retryAfterMs === "number" && Number.isFinite(candidate.retryAfterMs) && candidate.retryAfterMs >= 0 ? candidate.retryAfterMs : void 0
|
|
69626
|
+
};
|
|
69627
|
+
}
|
|
69089
69628
|
var WSClient = class {
|
|
69090
69629
|
constructor(wsUrl, sessionId, taskId, token, callbacks, agentVersion, lifecycle) {
|
|
69091
69630
|
this.lifecycle = lifecycle;
|
|
@@ -69094,7 +69633,7 @@ var WSClient = class {
|
|
|
69094
69633
|
this.getRunState = callbacks.getRunState;
|
|
69095
69634
|
this.socket = lookup(wsUrl, {
|
|
69096
69635
|
query: { type: "agent", sessionId, taskId, agentVersion: agentVersion ?? "" },
|
|
69097
|
-
auth: { token },
|
|
69636
|
+
auth: { token, agentSessionId: this.agentSessionId },
|
|
69098
69637
|
transports: ["websocket"],
|
|
69099
69638
|
reconnection: true,
|
|
69100
69639
|
reconnectionAttempts: Infinity,
|
|
@@ -69126,6 +69665,10 @@ var WSClient = class {
|
|
|
69126
69665
|
/** Monotonic heartbeat sequence — advances on every hello + heartbeat. */
|
|
69127
69666
|
heartbeatSeq = 0;
|
|
69128
69667
|
heartbeatTimer = null;
|
|
69668
|
+
supervisedReconnectTimer = null;
|
|
69669
|
+
supervisedReconnectAttempt = 0;
|
|
69670
|
+
connectionDirective = null;
|
|
69671
|
+
intentionalClose = false;
|
|
69129
69672
|
agentVersion;
|
|
69130
69673
|
getRunState;
|
|
69131
69674
|
/**
|
|
@@ -69232,16 +69775,82 @@ var WSClient = class {
|
|
|
69232
69775
|
get connected() {
|
|
69233
69776
|
return this.socket.connected;
|
|
69234
69777
|
}
|
|
69778
|
+
getAgentSessionId() {
|
|
69779
|
+
return this.agentSessionId;
|
|
69780
|
+
}
|
|
69235
69781
|
setLifecycleContext(context) {
|
|
69236
69782
|
this.lifecycle?.setContext(context);
|
|
69237
69783
|
}
|
|
69238
69784
|
close() {
|
|
69239
69785
|
this.lifecycle?.info("sandbox_agent_ws_close_requested");
|
|
69786
|
+
this.intentionalClose = true;
|
|
69787
|
+
this.clearSupervisedReconnect();
|
|
69240
69788
|
this.stopHeartbeat();
|
|
69241
69789
|
this.socket.disconnect();
|
|
69242
69790
|
}
|
|
69791
|
+
clearSupervisedReconnect() {
|
|
69792
|
+
if (this.supervisedReconnectTimer) {
|
|
69793
|
+
clearTimeout(this.supervisedReconnectTimer);
|
|
69794
|
+
this.supervisedReconnectTimer = null;
|
|
69795
|
+
}
|
|
69796
|
+
}
|
|
69797
|
+
/**
|
|
69798
|
+
* Socket.IO reconnects transport failures through its Manager. It does not
|
|
69799
|
+
* reconnect an `io server disconnect`, where `socket.active` is false. Only
|
|
69800
|
+
* supervise that terminal transport state, and only after the server has
|
|
69801
|
+
* explicitly classified the disconnect as retryable (including the legacy
|
|
69802
|
+
* `server_shutdown` advisory emitted by older WS servers).
|
|
69803
|
+
*/
|
|
69804
|
+
scheduleSupervisedReconnect(reason) {
|
|
69805
|
+
if (this.intentionalClose || this.socket.connected || this.socket.active || this.supervisedReconnectTimer || this.connectionDirective?.retryable !== true) {
|
|
69806
|
+
return;
|
|
69807
|
+
}
|
|
69808
|
+
const attempt = this.supervisedReconnectAttempt + 1;
|
|
69809
|
+
this.supervisedReconnectAttempt = attempt;
|
|
69810
|
+
const exponentialDelay = Math.min(
|
|
69811
|
+
SUPERVISED_RECONNECT_BASE_DELAY_MS * 2 ** (attempt - 1),
|
|
69812
|
+
SUPERVISED_RECONNECT_MAX_DELAY_MS
|
|
69813
|
+
);
|
|
69814
|
+
const requestedDelay = Math.max(exponentialDelay, this.connectionDirective.retryAfterMs ?? 0);
|
|
69815
|
+
const jitterRange = Math.min(SUPERVISED_RECONNECT_MAX_JITTER_MS, requestedDelay / 2);
|
|
69816
|
+
const delayMs = requestedDelay + Math.floor(Math.random() * jitterRange);
|
|
69817
|
+
this.lifecycle?.warn("sandbox_agent_ws_supervised_reconnect_scheduled", {
|
|
69818
|
+
reason,
|
|
69819
|
+
directiveCode: this.connectionDirective.code,
|
|
69820
|
+
attempt,
|
|
69821
|
+
delayMs
|
|
69822
|
+
});
|
|
69823
|
+
this.supervisedReconnectTimer = setTimeout(() => {
|
|
69824
|
+
this.supervisedReconnectTimer = null;
|
|
69825
|
+
if (this.intentionalClose || this.socket.connected || this.socket.active) return;
|
|
69826
|
+
this.lifecycle?.info("sandbox_agent_ws_supervised_reconnect_attempt", {
|
|
69827
|
+
directiveCode: this.connectionDirective?.code,
|
|
69828
|
+
attempt
|
|
69829
|
+
});
|
|
69830
|
+
this.connectionDirective = null;
|
|
69831
|
+
this.socket.connect();
|
|
69832
|
+
}, delayMs);
|
|
69833
|
+
this.supervisedReconnectTimer.unref?.();
|
|
69834
|
+
}
|
|
69243
69835
|
setupListeners(callbacks) {
|
|
69836
|
+
this.socket.io.on("reconnect_attempt", (attempt) => {
|
|
69837
|
+
this.lifecycle?.info("sandbox_agent_ws_manager_reconnect_attempt", { attempt });
|
|
69838
|
+
});
|
|
69839
|
+
this.socket.io.on("reconnect", (attempt) => {
|
|
69840
|
+
this.lifecycle?.info("sandbox_agent_ws_manager_reconnected", { attempt });
|
|
69841
|
+
});
|
|
69842
|
+
this.socket.io.on("reconnect_error", (error2) => {
|
|
69843
|
+
this.lifecycle?.warn("sandbox_agent_ws_manager_reconnect_error", {
|
|
69844
|
+
error: error2 instanceof Error ? error2 : new Error(String(error2))
|
|
69845
|
+
});
|
|
69846
|
+
});
|
|
69847
|
+
this.socket.io.on("reconnect_failed", () => {
|
|
69848
|
+
this.lifecycle?.error("sandbox_agent_ws_manager_reconnect_failed");
|
|
69849
|
+
});
|
|
69244
69850
|
this.socket.on("connect", () => {
|
|
69851
|
+
this.clearSupervisedReconnect();
|
|
69852
|
+
this.supervisedReconnectAttempt = 0;
|
|
69853
|
+
this.connectionDirective = null;
|
|
69245
69854
|
this.lifecycle?.info("sandbox_agent_ws_socket_connected", { socketId: this.socket.id });
|
|
69246
69855
|
this.startHeartbeat();
|
|
69247
69856
|
this.eventDispatcher.flush();
|
|
@@ -69252,6 +69861,36 @@ var WSClient = class {
|
|
|
69252
69861
|
this.stopHeartbeat();
|
|
69253
69862
|
this.eventDispatcher.disconnect();
|
|
69254
69863
|
callbacks.onDisconnect?.(reason);
|
|
69864
|
+
this.scheduleSupervisedReconnect(reason);
|
|
69865
|
+
});
|
|
69866
|
+
this.socket.on("server_shutdown", (data) => {
|
|
69867
|
+
this.connectionDirective = {
|
|
69868
|
+
code: "server_shutdown",
|
|
69869
|
+
reason: data?.reason,
|
|
69870
|
+
retryable: true,
|
|
69871
|
+
retryAfterMs: data?.retryAfterMs ?? 1e3
|
|
69872
|
+
};
|
|
69873
|
+
});
|
|
69874
|
+
this.socket.on("agent.capabilities", (data) => {
|
|
69875
|
+
if (typeof data !== "object" || data === null || typeof data.executionLeaseV1 !== "boolean") {
|
|
69876
|
+
return;
|
|
69877
|
+
}
|
|
69878
|
+
const capabilities = {
|
|
69879
|
+
executionLeaseV1: data.executionLeaseV1
|
|
69880
|
+
};
|
|
69881
|
+
this.lifecycle?.info("sandbox_agent_ws_capabilities_received", {
|
|
69882
|
+
executionLeaseV1: capabilities.executionLeaseV1
|
|
69883
|
+
});
|
|
69884
|
+
callbacks.onCapabilities?.(capabilities);
|
|
69885
|
+
});
|
|
69886
|
+
this.socket.on("connection_directive", (data) => {
|
|
69887
|
+
const directive = parseConnectionDirective(data);
|
|
69888
|
+
if (!directive) return;
|
|
69889
|
+
this.connectionDirective = directive;
|
|
69890
|
+
if (!directive.retryable) {
|
|
69891
|
+
this.clearSupervisedReconnect();
|
|
69892
|
+
callbacks.onTerminalDirective?.({ code: directive.code, reason: directive.reason });
|
|
69893
|
+
}
|
|
69255
69894
|
});
|
|
69256
69895
|
this.socket.on("agent.probe", (_data, ack) => {
|
|
69257
69896
|
ack?.({
|
|
@@ -69261,9 +69900,24 @@ var WSClient = class {
|
|
|
69261
69900
|
});
|
|
69262
69901
|
});
|
|
69263
69902
|
this.socket.on("connect_error", (error2) => {
|
|
69903
|
+
const directive = parseConnectionDirective(
|
|
69904
|
+
error2?.data
|
|
69905
|
+
);
|
|
69906
|
+
if (directive) {
|
|
69907
|
+
this.connectionDirective = directive;
|
|
69908
|
+
if (!directive.retryable) {
|
|
69909
|
+
this.clearSupervisedReconnect();
|
|
69910
|
+
callbacks.onTerminalDirective?.({ code: directive.code, reason: directive.reason });
|
|
69911
|
+
}
|
|
69912
|
+
} else {
|
|
69913
|
+
this.connectionDirective = null;
|
|
69914
|
+
}
|
|
69264
69915
|
this.lifecycle?.warn("sandbox_agent_ws_socket_connect_error", {
|
|
69265
|
-
error: error2 instanceof Error ? error2 : new Error(String(error2))
|
|
69916
|
+
error: error2 instanceof Error ? error2 : new Error(String(error2)),
|
|
69917
|
+
directiveCode: directive?.code,
|
|
69918
|
+
retryable: directive?.retryable
|
|
69266
69919
|
});
|
|
69920
|
+
this.scheduleSupervisedReconnect("connect_error");
|
|
69267
69921
|
});
|
|
69268
69922
|
this.socket.on(
|
|
69269
69923
|
"user_message",
|
|
@@ -69367,10 +70021,14 @@ async function runSandbox(config2) {
|
|
|
69367
70021
|
let currentImages = [];
|
|
69368
70022
|
let currentFiles = [];
|
|
69369
70023
|
let currentParsedAttachments = [];
|
|
69370
|
-
|
|
70024
|
+
let stopped = false;
|
|
69371
70025
|
let pendingMessageResolve = null;
|
|
69372
70026
|
const queuedMessages = [];
|
|
69373
70027
|
let currentAgent = null;
|
|
70028
|
+
let executionLeaseClient = null;
|
|
70029
|
+
let executionLeaseV1Supported = false;
|
|
70030
|
+
let activeRootExecutionActivity = null;
|
|
70031
|
+
let reportActiveRun = false;
|
|
69374
70032
|
let currentTaskMeta;
|
|
69375
70033
|
let currentPrMeta;
|
|
69376
70034
|
let currentWorkflowTools;
|
|
@@ -69398,6 +70056,32 @@ async function runSandbox(config2) {
|
|
|
69398
70056
|
lifecycle.info("sandbox_agent_ws_connect_attempt", {
|
|
69399
70057
|
wsUrl: config2.wsUrl
|
|
69400
70058
|
});
|
|
70059
|
+
const stopActiveAgent = () => {
|
|
70060
|
+
reportActiveRun = false;
|
|
70061
|
+
activeRootExecutionActivity?.release();
|
|
70062
|
+
activeRootExecutionActivity = null;
|
|
70063
|
+
const agent = currentAgent;
|
|
70064
|
+
if (!agent) return;
|
|
70065
|
+
const killed = agent.kill();
|
|
70066
|
+
if (!killed) {
|
|
70067
|
+
agent.abort();
|
|
70068
|
+
return;
|
|
70069
|
+
}
|
|
70070
|
+
const abortDeadline = setTimeout(() => {
|
|
70071
|
+
if (currentAgent === agent) agent.abort();
|
|
70072
|
+
}, 5e3);
|
|
70073
|
+
abortDeadline.unref?.();
|
|
70074
|
+
};
|
|
70075
|
+
const terminateAgentProcess = (reason) => {
|
|
70076
|
+
if (stopped) return;
|
|
70077
|
+
lifecycle.warn("sandbox_agent_process_fenced", reason);
|
|
70078
|
+
stopped = true;
|
|
70079
|
+
executionLeaseClient?.close();
|
|
70080
|
+
stopActiveAgent();
|
|
70081
|
+
const resolvePendingMessage = pendingMessageResolve;
|
|
70082
|
+
pendingMessageResolve = null;
|
|
70083
|
+
resolvePendingMessage?.(null);
|
|
70084
|
+
};
|
|
69401
70085
|
const wsClient = new WSClient(
|
|
69402
70086
|
config2.wsUrl,
|
|
69403
70087
|
config2.sessionId,
|
|
@@ -69440,10 +70124,7 @@ async function runSandbox(config2) {
|
|
|
69440
70124
|
},
|
|
69441
70125
|
onStop: () => {
|
|
69442
70126
|
lifecycle.info("sandbox_agent_stop_received");
|
|
69443
|
-
|
|
69444
|
-
const killed = currentAgent.kill();
|
|
69445
|
-
if (!killed) currentAgent.abort();
|
|
69446
|
-
}
|
|
70127
|
+
stopActiveAgent();
|
|
69447
70128
|
},
|
|
69448
70129
|
onToolResponse: (toolId, response) => {
|
|
69449
70130
|
if (currentAgent) {
|
|
@@ -69457,12 +70138,40 @@ async function runSandbox(config2) {
|
|
|
69457
70138
|
},
|
|
69458
70139
|
onConnect: () => lifecycle.info("sandbox_agent_ws_connected"),
|
|
69459
70140
|
onDisconnect: (reason) => lifecycle.info("sandbox_agent_ws_disconnected", { reason }),
|
|
70141
|
+
onCapabilities: (capabilities) => {
|
|
70142
|
+
if (!capabilities.executionLeaseV1) return;
|
|
70143
|
+
executionLeaseV1Supported = true;
|
|
70144
|
+
executionLeaseClient?.enable();
|
|
70145
|
+
},
|
|
70146
|
+
onTerminalDirective: terminateAgentProcess,
|
|
69460
70147
|
// Liveness heartbeat run state: a run is active while CoreAgent is executing.
|
|
69461
|
-
getRunState: () =>
|
|
70148
|
+
getRunState: () => {
|
|
70149
|
+
const activeRunId = currentRunId ?? config2.runId;
|
|
70150
|
+
return currentAgent && reportActiveRun ? { idle: false, activeRunIds: activeRunId ? [activeRunId] : [] } : { idle: true, activeRunIds: [] };
|
|
70151
|
+
}
|
|
69462
70152
|
},
|
|
69463
70153
|
AGENT_VERSION,
|
|
69464
70154
|
lifecycle
|
|
69465
70155
|
);
|
|
70156
|
+
const agentSessionId = wsClient.getAgentSessionId();
|
|
70157
|
+
executionLeaseClient = config2.apiUrl && config2.sandboxId && agentSessionId ? new ExecutionLeaseClient({
|
|
70158
|
+
apiUrl: config2.apiUrl,
|
|
70159
|
+
sessionToken: config2.sessionToken,
|
|
70160
|
+
agentSessionId,
|
|
70161
|
+
agentVersion: AGENT_VERSION,
|
|
70162
|
+
lifecycle,
|
|
70163
|
+
enabled: false,
|
|
70164
|
+
onAuthorityLost: ({ code }) => terminateAgentProcess({ code })
|
|
70165
|
+
}) : null;
|
|
70166
|
+
if (executionLeaseV1Supported) executionLeaseClient?.enable();
|
|
70167
|
+
const executionActivityTracker = executionLeaseClient ? new ExecutionActivityTracker((activity) => executionLeaseClient.setActivity(activity)) : null;
|
|
70168
|
+
if (!executionLeaseClient && (currentRunId ?? config2.runId)) {
|
|
70169
|
+
lifecycle.warn("sandbox_agent_execution_lease_unavailable", {
|
|
70170
|
+
hasApiUrl: Boolean(config2.apiUrl),
|
|
70171
|
+
hasSandboxId: Boolean(config2.sandboxId),
|
|
70172
|
+
hasAgentSessionId: Boolean(agentSessionId)
|
|
70173
|
+
});
|
|
70174
|
+
}
|
|
69466
70175
|
try {
|
|
69467
70176
|
await wsClient.waitForConnection();
|
|
69468
70177
|
} catch (error2) {
|
|
@@ -69490,6 +70199,18 @@ async function runSandbox(config2) {
|
|
|
69490
70199
|
backendKind: activeBackendKind
|
|
69491
70200
|
});
|
|
69492
70201
|
currentAgent = agent;
|
|
70202
|
+
const activeRunId = currentRunId ?? config2.runId;
|
|
70203
|
+
const rootExecutionActivity = executionActivityTracker && activeRunId && currentTaskId ? executionActivityTracker.register({
|
|
70204
|
+
ownerId: `root:${activeRunId}`,
|
|
70205
|
+
leaseRunId: activeRunId,
|
|
70206
|
+
conversationId: currentConversationId,
|
|
70207
|
+
taskId: currentTaskId,
|
|
70208
|
+
sandboxId: config2.sandboxId,
|
|
70209
|
+
kind: "root",
|
|
70210
|
+
phase: "agent_run"
|
|
70211
|
+
}) : null;
|
|
70212
|
+
activeRootExecutionActivity = rootExecutionActivity;
|
|
70213
|
+
reportActiveRun = true;
|
|
69493
70214
|
wsClient.setCurrentRunId(currentRunId ?? config2.runId);
|
|
69494
70215
|
presenter.setRunContext?.(currentRunId ?? config2.runId, activeBackendKind);
|
|
69495
70216
|
const correlation = correlationLogFields2({
|
|
@@ -69642,6 +70363,12 @@ async function runSandbox(config2) {
|
|
|
69642
70363
|
presenter.onError(errorMessage, false);
|
|
69643
70364
|
}
|
|
69644
70365
|
presenter.onComplete(result);
|
|
70366
|
+
} finally {
|
|
70367
|
+
reportActiveRun = false;
|
|
70368
|
+
rootExecutionActivity?.release();
|
|
70369
|
+
if (activeRootExecutionActivity === rootExecutionActivity) {
|
|
70370
|
+
activeRootExecutionActivity = null;
|
|
70371
|
+
}
|
|
69645
70372
|
}
|
|
69646
70373
|
currentAgent = null;
|
|
69647
70374
|
resumeFallbackContext = void 0;
|
|
@@ -69733,6 +70460,7 @@ async function runSandbox(config2) {
|
|
|
69733
70460
|
}
|
|
69734
70461
|
presenter.setSuppressSessionLifecycle(false);
|
|
69735
70462
|
lifecycle.info("sandbox_agent_process_exit");
|
|
70463
|
+
executionLeaseClient?.close();
|
|
69736
70464
|
wsClient.close();
|
|
69737
70465
|
}
|
|
69738
70466
|
|
|
@@ -70098,6 +70826,7 @@ function logEffectiveGitIdentity(lifecycle, projectPath) {
|
|
|
70098
70826
|
}
|
|
70099
70827
|
async function runSessionFromEnv() {
|
|
70100
70828
|
const wsUrl = process.env.ALAN_WS_URL;
|
|
70829
|
+
const apiUrl = process.env.ALAN_API_URL || void 0;
|
|
70101
70830
|
const sessionId = process.env.ALAN_SESSION_ID;
|
|
70102
70831
|
const taskId = process.env.ALAN_TASK_ID;
|
|
70103
70832
|
const sessionToken = process.env.ALAN_SESSION_TOKEN;
|
|
@@ -70143,6 +70872,7 @@ async function runSessionFromEnv() {
|
|
|
70143
70872
|
logEffectiveGitIdentity(lifecycle, projectPath);
|
|
70144
70873
|
await runSandbox({
|
|
70145
70874
|
wsUrl,
|
|
70875
|
+
apiUrl,
|
|
70146
70876
|
sessionId,
|
|
70147
70877
|
taskId,
|
|
70148
70878
|
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.69",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Alan agent runtime — cloud sandbox and local daemon (alan-agent CLI)",
|
|
6
6
|
"bin": {
|
|
@@ -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",
|