@tangle-network/agent-app 0.46.59 → 0.47.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/dist/VaultPane-QZC3YKQG.js +7 -0
- package/dist/chat-routes/index.js +1 -1
- package/dist/{chunk-WSRECTKA.js → chunk-P6YXUGNA.js} +29 -47
- package/dist/chunk-P6YXUGNA.js.map +1 -0
- package/dist/{chunk-ICLUEQYX.js → chunk-ZNLASEO3.js} +34 -12
- package/dist/chunk-ZNLASEO3.js.map +1 -0
- package/dist/sandbox/index.d.ts +4 -11
- package/dist/sandbox/index.js +1 -3
- package/dist/vault/index.js +1 -1
- package/dist/vault/lazy.js +1 -1
- package/package.json +1 -1
- package/dist/VaultPane-YKZ6YJGI.js +0 -7
- package/dist/chunk-ICLUEQYX.js.map +0 -1
- package/dist/chunk-WSRECTKA.js.map +0 -1
- /package/dist/{VaultPane-YKZ6YJGI.js.map → VaultPane-QZC3YKQG.js.map} +0 -0
package/README.md
CHANGED
|
@@ -173,6 +173,18 @@ Two `createMissionService` seams adopters hit on day one:
|
|
|
173
173
|
- **`generateId`** (on `MissionServiceOptions`) defaults to `crypto.randomUUID()` — a 36-char dashed UUID. If your mission table has an existing id shape (e.g. 32-hex to match D1 row defaults), inject your own generator; the service stamps it verbatim on the inserted record.
|
|
174
174
|
- **`CreateMissionInput.extras`** carries opaque product-column values (a `workflowId` FK, a source-turn pointer) verbatim to `MissionStorePort.insert(record, extras)`, so creation is a single write — no post-insert stamp. The service never reads them.
|
|
175
175
|
|
|
176
|
+
### Sandbox reuse
|
|
177
|
+
|
|
178
|
+
Set `livenessProbe: {}` to verify a reused runtime with `echo alive`.
|
|
179
|
+
The command must exit successfully and return only `alive`, allowing surrounding whitespace.
|
|
180
|
+
A healthy idle runtime does not need a running CLI process.
|
|
181
|
+
Remove `sidecarProcessPattern`, `psTimeoutMs`, and imports of `DEFAULT_SIDECAR_PROCESS_PATTERN` when upgrading.
|
|
182
|
+
|
|
183
|
+
`execTimeoutMs` sets the SDK command timeout, from 100 to 600,000 milliseconds; the default is 5,000.
|
|
184
|
+
SDK readiness and transport deadlines apply separately, so this value is not an end-to-end provisioning deadline.
|
|
185
|
+
Recovery waits for the SDK request to settle before restarting the sandbox.
|
|
186
|
+
Failures retain their SDK cause for the redacted diagnostic serializer and preserve the workspace.
|
|
187
|
+
|
|
176
188
|
## Compatibility
|
|
177
189
|
|
|
178
190
|
- **ESM only.** Ships `import` + `types` conditions per subpath.
|
|
@@ -112,7 +112,7 @@ import {
|
|
|
112
112
|
flattenHistory,
|
|
113
113
|
readSandboxBinaryBytes,
|
|
114
114
|
statSandboxFileSize
|
|
115
|
-
} from "../chunk-
|
|
115
|
+
} from "../chunk-P6YXUGNA.js";
|
|
116
116
|
import "../chunk-MCYJON3F.js";
|
|
117
117
|
import "../chunk-LWSJK546.js";
|
|
118
118
|
import "../chunk-P5PIAQVS.js";
|
|
@@ -1093,7 +1093,6 @@ function buildProductEgressPolicy(publicOrigin, extraDomains = []) {
|
|
|
1093
1093
|
includeImplicitDomains: false
|
|
1094
1094
|
};
|
|
1095
1095
|
}
|
|
1096
|
-
var DEFAULT_SIDECAR_PROCESS_PATTERN = "opencode|claude|codex";
|
|
1097
1096
|
var DEFAULT_SANDBOX_RESOURCES = {
|
|
1098
1097
|
image: "universal",
|
|
1099
1098
|
cpuCores: 2,
|
|
@@ -1590,39 +1589,16 @@ function assertEnvWithinLimits(env) {
|
|
|
1590
1589
|
);
|
|
1591
1590
|
}
|
|
1592
1591
|
}
|
|
1593
|
-
function
|
|
1594
|
-
|
|
1595
|
-
if (pattern.includes("\\|")) {
|
|
1596
|
-
throw new Error(
|
|
1597
|
-
'Invalid livenessProbe.sidecarProcessPattern: pgrep -f uses extended regular expressions; use a bare "|" for alternation, not "\\|".'
|
|
1598
|
-
);
|
|
1599
|
-
}
|
|
1600
|
-
return pattern;
|
|
1601
|
-
}
|
|
1602
|
-
async function isBoxAlive(box, harness, probe) {
|
|
1603
|
-
if (!probe) return true;
|
|
1604
|
-
const execTimeout = probe.execTimeoutMs ?? 5e3;
|
|
1605
|
-
const psTimeout = probe.psTimeoutMs ?? 3e3;
|
|
1606
|
-
const pattern = resolveSidecarProcessPattern(probe, harness);
|
|
1607
|
-
const race = (p, ms, label) => Promise.race([
|
|
1608
|
-
p,
|
|
1609
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error(label)), ms))
|
|
1610
|
-
]);
|
|
1592
|
+
async function isBoxAlive(box, probe) {
|
|
1593
|
+
if (!probe) return ok(void 0);
|
|
1611
1594
|
try {
|
|
1612
|
-
const alive = await
|
|
1613
|
-
if (
|
|
1614
|
-
|
|
1615
|
-
const ps = await race(
|
|
1616
|
-
box.exec(`pgrep -f ${shellSingleQuote(pattern)} || echo no-sidecar`),
|
|
1617
|
-
psTimeout,
|
|
1618
|
-
"ps check timeout"
|
|
1619
|
-
);
|
|
1620
|
-
if (ps.stdout.includes("no-sidecar")) return false;
|
|
1621
|
-
} catch {
|
|
1595
|
+
const alive = await box.exec("echo alive", { timeoutMs: probe.execTimeoutMs ?? 5e3 });
|
|
1596
|
+
if (alive.exitCode !== 0 || alive.stdout.trim() !== "alive") {
|
|
1597
|
+
return fail(new Error("alive check did not return a successful alive marker"));
|
|
1622
1598
|
}
|
|
1623
|
-
return
|
|
1624
|
-
} catch {
|
|
1625
|
-
return
|
|
1599
|
+
return ok(void 0);
|
|
1600
|
+
} catch (cause) {
|
|
1601
|
+
return fail(new Error("alive check failed", { cause }));
|
|
1626
1602
|
}
|
|
1627
1603
|
}
|
|
1628
1604
|
var DEFAULT_LIVENESS_CACHE_TTL_MS = 5e3;
|
|
@@ -1755,15 +1731,15 @@ async function writeDeferredFilesWithRuntimeAuthRefresh(client, box, files, stag
|
|
|
1755
1731
|
)
|
|
1756
1732
|
);
|
|
1757
1733
|
}
|
|
1758
|
-
async function isReusableBox(box,
|
|
1734
|
+
async function isReusableBox(box, probe) {
|
|
1759
1735
|
if (sandboxEdgeFailed(box) || !sandboxRuntimeUrl(box)) {
|
|
1760
1736
|
livenessVerifiedAt.delete(box.id);
|
|
1761
|
-
return
|
|
1737
|
+
return fail(new Error(sandboxEdgeFailed(box) ? "runtime edge readiness failed" : "runtime URL is missing"));
|
|
1762
1738
|
}
|
|
1763
|
-
if (!probe) return
|
|
1764
|
-
if (hasRecentLivenessVerification(box, probe)) return
|
|
1765
|
-
const alive = await isBoxAlive(box,
|
|
1766
|
-
if (alive) livenessVerifiedAt.set(box.id, Date.now());
|
|
1739
|
+
if (!probe) return ok(void 0);
|
|
1740
|
+
if (hasRecentLivenessVerification(box, probe)) return ok(void 0);
|
|
1741
|
+
const alive = await isBoxAlive(box, probe);
|
|
1742
|
+
if (alive.succeeded) livenessVerifiedAt.set(box.id, Date.now());
|
|
1767
1743
|
else livenessVerifiedAt.delete(box.id);
|
|
1768
1744
|
return alive;
|
|
1769
1745
|
}
|
|
@@ -1794,7 +1770,7 @@ async function resumeStoppedBox(box, timeoutMs, onProgress) {
|
|
|
1794
1770
|
return fail(stoppedBoxResumeError(box, cause));
|
|
1795
1771
|
}
|
|
1796
1772
|
}
|
|
1797
|
-
async function recoverUnresponsiveBox(client, box,
|
|
1773
|
+
async function recoverUnresponsiveBox(client, box, probe, stage, name, resumeTimeout, onProgress) {
|
|
1798
1774
|
try {
|
|
1799
1775
|
await box.stop();
|
|
1800
1776
|
} catch (err) {
|
|
@@ -1817,12 +1793,14 @@ async function recoverUnresponsiveBox(client, box, harness, probe, stage, name,
|
|
|
1817
1793
|
);
|
|
1818
1794
|
}
|
|
1819
1795
|
const recovered = await refreshRuntimeConnection(client, resumed.value);
|
|
1820
|
-
|
|
1796
|
+
const reusable = await isReusableBox(recovered, probe);
|
|
1797
|
+
if (!reusable.succeeded) {
|
|
1821
1798
|
throw new SandboxRecoveryFailedError(
|
|
1822
1799
|
stage,
|
|
1823
1800
|
name,
|
|
1824
1801
|
"probe",
|
|
1825
|
-
|
|
1802
|
+
`the box is still unresponsive after a state-preserving restart: ${reusable.error.message}`,
|
|
1803
|
+
reusable.error
|
|
1826
1804
|
);
|
|
1827
1805
|
}
|
|
1828
1806
|
return recovered;
|
|
@@ -1993,6 +1971,9 @@ async function requestSandboxReplacement(recover, failure, label) {
|
|
|
1993
1971
|
return { ...recovery.value, replacementBoxKey };
|
|
1994
1972
|
}
|
|
1995
1973
|
async function requestMissingSandboxReplacement(shell, failure) {
|
|
1974
|
+
if (failure.error instanceof SandboxRecoveryFailedError && failure.error.phase === "probe") {
|
|
1975
|
+
throw failure.error;
|
|
1976
|
+
}
|
|
1996
1977
|
const diagnostics = serializeSandboxProvisioningError(failure.error);
|
|
1997
1978
|
if (!isSandboxApiSandboxMissingFailure(diagnostics)) throw failure.error;
|
|
1998
1979
|
return requestSandboxReplacement(
|
|
@@ -2002,6 +1983,10 @@ async function requestMissingSandboxReplacement(shell, failure) {
|
|
|
2002
1983
|
);
|
|
2003
1984
|
}
|
|
2004
1985
|
async function provisionWorkspaceSandbox(shell, options) {
|
|
1986
|
+
const execTimeoutMs = shell.livenessProbe?.execTimeoutMs;
|
|
1987
|
+
if (execTimeoutMs !== void 0 && (!Number.isInteger(execTimeoutMs) || execTimeoutMs < 100 || execTimeoutMs > 6e5)) {
|
|
1988
|
+
throw new Error("livenessProbe.execTimeoutMs must be an integer between 100 and 600000");
|
|
1989
|
+
}
|
|
2005
1990
|
const { workspaceId, userId, harness, forceNew, onProgress, billingOwnerId } = options;
|
|
2006
1991
|
const resolved = await resolveWorkspaceSandboxClient(shell, workspaceId, userId);
|
|
2007
1992
|
const { scope, client } = resolved;
|
|
@@ -2021,13 +2006,12 @@ async function provisionWorkspaceSandbox(shell, options) {
|
|
|
2021
2006
|
} else if (found.metadata?.harness === harness) {
|
|
2022
2007
|
try {
|
|
2023
2008
|
const ready = await refreshRuntimeConnection(client, found);
|
|
2024
|
-
if (await isReusableBox(ready,
|
|
2009
|
+
if ((await isReusableBox(ready, shell.livenessProbe)).succeeded) {
|
|
2025
2010
|
return await finalizeExistingBox(shell, client, ready, "reused", name, workspaceId, userId, harness, scope);
|
|
2026
2011
|
}
|
|
2027
2012
|
const recovered = await recoverUnresponsiveBox(
|
|
2028
2013
|
client,
|
|
2029
2014
|
ready,
|
|
2030
|
-
harness,
|
|
2031
2015
|
shell.livenessProbe,
|
|
2032
2016
|
"reused",
|
|
2033
2017
|
name,
|
|
@@ -2074,13 +2058,12 @@ async function provisionWorkspaceSandbox(shell, options) {
|
|
|
2074
2058
|
} else {
|
|
2075
2059
|
try {
|
|
2076
2060
|
const box2 = await refreshRuntimeConnection(client, resumed.value);
|
|
2077
|
-
if (await isReusableBox(box2,
|
|
2061
|
+
if ((await isReusableBox(box2, shell.livenessProbe)).succeeded) {
|
|
2078
2062
|
return await finalizeExistingBox(shell, client, box2, "resumed", name, workspaceId, userId, harness, scope);
|
|
2079
2063
|
}
|
|
2080
2064
|
const recovered = await recoverUnresponsiveBox(
|
|
2081
2065
|
client,
|
|
2082
2066
|
box2,
|
|
2083
|
-
harness,
|
|
2084
2067
|
shell.livenessProbe,
|
|
2085
2068
|
"resumed",
|
|
2086
2069
|
name,
|
|
@@ -2785,7 +2768,6 @@ export {
|
|
|
2785
2768
|
resolveSandboxClientCredentials,
|
|
2786
2769
|
PYPI_EGRESS_DOMAINS,
|
|
2787
2770
|
buildProductEgressPolicy,
|
|
2788
|
-
DEFAULT_SIDECAR_PROCESS_PATTERN,
|
|
2789
2771
|
DEFAULT_SANDBOX_RESOURCES,
|
|
2790
2772
|
getClient,
|
|
2791
2773
|
resetClientCache,
|
|
@@ -2834,4 +2816,4 @@ export {
|
|
|
2834
2816
|
isTerminalPromptEvent,
|
|
2835
2817
|
detectInteractiveQuestion
|
|
2836
2818
|
};
|
|
2837
|
-
//# sourceMappingURL=chunk-
|
|
2819
|
+
//# sourceMappingURL=chunk-P6YXUGNA.js.map
|