@tangle-network/agent-app 0.60.218 → 0.60.219
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/chat-routes/index.js +1 -1
- package/dist/{chunk-4QUOPWIG.js → chunk-RDLOC7BJ.js} +117 -4
- package/dist/chunk-RDLOC7BJ.js.map +1 -0
- package/dist/sandbox/index.d.ts +11 -0
- package/dist/sandbox/index.js +3 -1
- package/dist/sandbox/reuse-state.d.ts +55 -0
- package/package.json +1 -1
- package/dist/chunk-4QUOPWIG.js.map +0 -1
|
@@ -165,6 +165,57 @@ async function* traceSandboxPromptEvents(events, options) {
|
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
+
// src/sandbox/reuse-state.ts
|
|
169
|
+
var CACHE_NAME = "agent-app-sandbox-reuse";
|
|
170
|
+
var KEY_ORIGIN = "https://sandbox-reuse.agent-app.invalid/";
|
|
171
|
+
var ENTRY_MAX_AGE_SECONDS = 15 * 60;
|
|
172
|
+
function isRecord(value) {
|
|
173
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
174
|
+
}
|
|
175
|
+
function stamped(value, field) {
|
|
176
|
+
if (!isRecord(value) || typeof value.at !== "number" || typeof value[field] !== "string") return void 0;
|
|
177
|
+
return { text: value[field], at: value.at };
|
|
178
|
+
}
|
|
179
|
+
function parseState(value) {
|
|
180
|
+
if (!isRecord(value) || typeof value.boxId !== "string" || !isRecord(value.checks)) return null;
|
|
181
|
+
const checks = value.checks;
|
|
182
|
+
if (typeof checks.identity !== "string") return null;
|
|
183
|
+
const parsed = { identity: checks.identity };
|
|
184
|
+
if (typeof checks.alive === "number") parsed.alive = checks.alive;
|
|
185
|
+
const egress = stamped(checks.egress, "key");
|
|
186
|
+
if (egress) parsed.egress = { key: egress.text, at: egress.at };
|
|
187
|
+
const env = stamped(checks.env, "digest");
|
|
188
|
+
if (env) parsed.env = { digest: env.text, at: env.at };
|
|
189
|
+
const corpus = stamped(checks.corpus, "hash");
|
|
190
|
+
if (corpus) parsed.corpus = { hash: corpus.text, at: corpus.at };
|
|
191
|
+
return { boxId: value.boxId, checks: parsed };
|
|
192
|
+
}
|
|
193
|
+
function createCacheReuseStore(open) {
|
|
194
|
+
let cache;
|
|
195
|
+
const handle = async () => cache ??= await open();
|
|
196
|
+
const request = (name) => new Request(`${KEY_ORIGIN}${encodeURIComponent(name)}`);
|
|
197
|
+
return {
|
|
198
|
+
async load(name) {
|
|
199
|
+
const hit = await (await handle()).match(request(name));
|
|
200
|
+
if (!hit) return null;
|
|
201
|
+
return parseState(await hit.json());
|
|
202
|
+
},
|
|
203
|
+
async save(name, state) {
|
|
204
|
+
await (await handle()).put(request(name), new Response(JSON.stringify(state), {
|
|
205
|
+
headers: { "content-type": "application/json", "cache-control": `public, max-age=${ENTRY_MAX_AGE_SECONDS}` }
|
|
206
|
+
}));
|
|
207
|
+
},
|
|
208
|
+
async drop(name) {
|
|
209
|
+
await (await handle()).delete(request(name));
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
function workersReuseStore() {
|
|
214
|
+
const storage = globalThis.caches;
|
|
215
|
+
if (typeof storage?.open !== "function") return null;
|
|
216
|
+
return createCacheReuseStore(() => storage.open(CACHE_NAME));
|
|
217
|
+
}
|
|
218
|
+
|
|
168
219
|
// src/sandbox/model.ts
|
|
169
220
|
function backendModelFields(model) {
|
|
170
221
|
return {
|
|
@@ -1547,6 +1598,10 @@ var REUSE_CHECKS_MAX = 1e3;
|
|
|
1547
1598
|
var reuseChecks = /* @__PURE__ */ new Map();
|
|
1548
1599
|
var runningBoxIds = /* @__PURE__ */ new Map();
|
|
1549
1600
|
var trustedBoxes = /* @__PURE__ */ new WeakSet();
|
|
1601
|
+
var reuseNames = /* @__PURE__ */ new Map();
|
|
1602
|
+
var savedShared = /* @__PURE__ */ new Map();
|
|
1603
|
+
var defaultReuseStore;
|
|
1604
|
+
var activeReuseStore = null;
|
|
1550
1605
|
function boxIdentity(box) {
|
|
1551
1606
|
const startedAt = box.startedAt instanceof Date ? box.startedAt.getTime() : Number.NaN;
|
|
1552
1607
|
return `${Number.isFinite(startedAt) ? startedAt : ""}|${box.filesystemIncarnationId ?? ""}`;
|
|
@@ -1573,6 +1628,10 @@ function recordCheck(box, patch) {
|
|
|
1573
1628
|
}
|
|
1574
1629
|
function forgetBox(boxId) {
|
|
1575
1630
|
reuseChecks.delete(boxId);
|
|
1631
|
+
const name = reuseNames.get(boxId);
|
|
1632
|
+
if (name === void 0 || !activeReuseStore) return;
|
|
1633
|
+
savedShared.delete(name);
|
|
1634
|
+
void Promise.resolve(activeReuseStore.drop(name)).catch(() => void 0);
|
|
1576
1635
|
}
|
|
1577
1636
|
function isRecent(at, ttlMs, now = Date.now()) {
|
|
1578
1637
|
return at !== void 0 && Number.isFinite(ttlMs) && ttlMs > 0 && now - at < ttlMs;
|
|
@@ -1600,6 +1659,10 @@ function resetClientCache() {
|
|
|
1600
1659
|
_cached = null;
|
|
1601
1660
|
reuseChecks.clear();
|
|
1602
1661
|
runningBoxIds.clear();
|
|
1662
|
+
reuseNames.clear();
|
|
1663
|
+
savedShared.clear();
|
|
1664
|
+
defaultReuseStore = void 0;
|
|
1665
|
+
activeReuseStore = null;
|
|
1603
1666
|
}
|
|
1604
1667
|
function buildAppToolMcpServers(options) {
|
|
1605
1668
|
const entries = {};
|
|
@@ -2075,11 +2138,17 @@ async function listRunning(client, name) {
|
|
|
2075
2138
|
function rememberRunningBox(name, box) {
|
|
2076
2139
|
runningBoxIds.delete(name);
|
|
2077
2140
|
runningBoxIds.set(name, box.id);
|
|
2141
|
+
reuseNames.set(box.id, name);
|
|
2078
2142
|
while (runningBoxIds.size > REUSE_CHECKS_MAX) {
|
|
2079
2143
|
const oldest = runningBoxIds.keys().next().value;
|
|
2080
2144
|
if (oldest === void 0) break;
|
|
2081
2145
|
runningBoxIds.delete(oldest);
|
|
2082
2146
|
}
|
|
2147
|
+
while (reuseNames.size > REUSE_CHECKS_MAX) {
|
|
2148
|
+
const oldest = reuseNames.keys().next().value;
|
|
2149
|
+
if (oldest === void 0) break;
|
|
2150
|
+
reuseNames.delete(oldest);
|
|
2151
|
+
}
|
|
2083
2152
|
return box;
|
|
2084
2153
|
}
|
|
2085
2154
|
async function getRunningBox(client, id, name) {
|
|
@@ -2612,16 +2681,57 @@ async function ensureWorkspaceSandbox(shell, options) {
|
|
|
2612
2681
|
return box;
|
|
2613
2682
|
}
|
|
2614
2683
|
async function reuseWorkspaceSandbox(shell, options) {
|
|
2615
|
-
if (options.forceNew
|
|
2684
|
+
if (options.forceNew) return void 0;
|
|
2685
|
+
await hydrateReuseState(shell, options);
|
|
2686
|
+
if (!hasRecentProbe(shell, options)) return void 0;
|
|
2616
2687
|
return claimWorkspaceSandbox(shell, options, true);
|
|
2617
2688
|
}
|
|
2689
|
+
function boxNameFor(shell, options) {
|
|
2690
|
+
const scope = { workspaceId: options.workspaceId, ...options.userId ? { userId: options.userId } : {} };
|
|
2691
|
+
return shell.boxKey ? shell.boxKey(scope) : shell.name(options.workspaceId);
|
|
2692
|
+
}
|
|
2618
2693
|
function hasRecentProbe(shell, options) {
|
|
2619
2694
|
const probe = shell.livenessProbe;
|
|
2620
2695
|
if (!probe || options.forceNew) return false;
|
|
2621
|
-
const
|
|
2622
|
-
const id = runningBoxIds.get(shell.boxKey ? shell.boxKey(scope) : shell.name(options.workspaceId));
|
|
2696
|
+
const id = runningBoxIds.get(boxNameFor(shell, options));
|
|
2623
2697
|
return isRecent(id === void 0 ? void 0 : reuseChecks.get(id)?.alive, probe.cacheTtlMs ?? TRUSTED_REUSE_TTL_MS);
|
|
2624
2698
|
}
|
|
2699
|
+
function reuseStoreOf(shell) {
|
|
2700
|
+
if (shell.reuseState !== void 0) return shell.reuseState;
|
|
2701
|
+
if (defaultReuseStore === void 0) defaultReuseStore = workersReuseStore();
|
|
2702
|
+
return defaultReuseStore;
|
|
2703
|
+
}
|
|
2704
|
+
async function hydrateReuseState(shell, options) {
|
|
2705
|
+
if (options.forceNew) return;
|
|
2706
|
+
const store = reuseStoreOf(shell);
|
|
2707
|
+
activeReuseStore = store;
|
|
2708
|
+
if (!store) return;
|
|
2709
|
+
const name = boxNameFor(shell, options);
|
|
2710
|
+
if (runningBoxIds.has(name)) return;
|
|
2711
|
+
try {
|
|
2712
|
+
const shared = await store.load(name);
|
|
2713
|
+
if (!shared) return;
|
|
2714
|
+
runningBoxIds.set(name, shared.boxId);
|
|
2715
|
+
reuseNames.set(shared.boxId, name);
|
|
2716
|
+
reuseChecks.set(shared.boxId, shared.checks);
|
|
2717
|
+
savedShared.set(name, JSON.stringify(shared));
|
|
2718
|
+
} catch {
|
|
2719
|
+
}
|
|
2720
|
+
}
|
|
2721
|
+
async function persistReuseState(shell, box) {
|
|
2722
|
+
const store = reuseStoreOf(shell);
|
|
2723
|
+
const name = reuseNames.get(box.id);
|
|
2724
|
+
const checks = reuseChecks.get(box.id);
|
|
2725
|
+
if (!store || name === void 0 || !checks) return;
|
|
2726
|
+
const state = { boxId: box.id, checks };
|
|
2727
|
+
const serialized = JSON.stringify(state);
|
|
2728
|
+
if (savedShared.get(name) === serialized) return;
|
|
2729
|
+
try {
|
|
2730
|
+
await store.save(name, state);
|
|
2731
|
+
savedShared.set(name, serialized);
|
|
2732
|
+
} catch {
|
|
2733
|
+
}
|
|
2734
|
+
}
|
|
2625
2735
|
function spendGate(options) {
|
|
2626
2736
|
let gated;
|
|
2627
2737
|
return () => {
|
|
@@ -2637,6 +2747,7 @@ function spendGate(options) {
|
|
|
2637
2747
|
async function claimWorkspaceSandbox(shell, options, reuseOnly) {
|
|
2638
2748
|
const { trace } = options;
|
|
2639
2749
|
const gate = spendGate(options);
|
|
2750
|
+
await hydrateReuseState(shell, options);
|
|
2640
2751
|
if (!hasRecentProbe(shell, options)) await gate();
|
|
2641
2752
|
const claim = trace?.start("sandbox.claim", "sandbox", { "workspace.harness": options.harness }, options.traceParent);
|
|
2642
2753
|
const traced = trace && claim ? {
|
|
@@ -2654,6 +2765,7 @@ async function claimWorkspaceSandbox(shell, options, reuseOnly) {
|
|
|
2654
2765
|
}
|
|
2655
2766
|
claim?.end({ "sandbox.id": box.id, ...trustedBoxes.has(box) ? { "sandbox.probe_trusted": true } : {} });
|
|
2656
2767
|
if (!trustedBoxes.has(box)) await observeProvisionedBox(shell, options, box);
|
|
2768
|
+
await persistReuseState(shell, box);
|
|
2657
2769
|
return box;
|
|
2658
2770
|
} catch (error) {
|
|
2659
2771
|
claim?.end(void 0, error);
|
|
@@ -3579,6 +3691,7 @@ function firstQuestionText(value) {
|
|
|
3579
3691
|
|
|
3580
3692
|
export {
|
|
3581
3693
|
traceSandboxPromptEvents,
|
|
3694
|
+
createCacheReuseStore,
|
|
3582
3695
|
backendModelFields,
|
|
3583
3696
|
resolveModelSelection,
|
|
3584
3697
|
resolveModel,
|
|
@@ -3680,4 +3793,4 @@ export {
|
|
|
3680
3793
|
isTerminalPromptEvent,
|
|
3681
3794
|
detectInteractiveQuestion
|
|
3682
3795
|
};
|
|
3683
|
-
//# sourceMappingURL=chunk-
|
|
3796
|
+
//# sourceMappingURL=chunk-RDLOC7BJ.js.map
|