@ash-cloud/ash-ai 0.1.17 → 0.1.19
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 +593 -80
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +222 -12
- package/dist/index.d.ts +222 -12
- package/dist/index.js +592 -81
- package/dist/index.js.map +1 -1
- package/dist/playground/components/NormalizedMessageList.d.ts +7 -1
- package/dist/playground/components/NormalizedMessageList.d.ts.map +1 -1
- package/dist/playground.js +1241 -1181
- package/dist/{schema-dr_7pxIB.d.cts → schema-CAoHu2Rx.d.cts} +21 -2
- package/dist/{schema-dr_7pxIB.d.ts → schema-CAoHu2Rx.d.ts} +21 -2
- package/dist/schema.cjs +11 -0
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.d.cts +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +11 -1
- package/dist/schema.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -108,7 +108,7 @@ var init_normalized = __esm({
|
|
|
108
108
|
"src/types/normalized.ts"() {
|
|
109
109
|
}
|
|
110
110
|
});
|
|
111
|
-
exports.SessionStatus = void 0; exports.AgentStatus = void 0; exports.MessageRole = void 0; exports.messageContentSchema = void 0; exports.messageSchema = void 0; exports.sessionSchema = void 0; exports.attachmentSchema = void 0; exports.DEFAULT_SANDBOX_PROVIDER_CONFIG = void 0; exports.StreamEventType = void 0; exports.QueueItemStatus = void 0; exports.EventCategory = void 0;
|
|
111
|
+
exports.SessionStatus = void 0; exports.AgentStatus = void 0; exports.MessageRole = void 0; exports.messageContentSchema = void 0; exports.messageSchema = void 0; exports.sessionSchema = void 0; exports.attachmentSchema = void 0; exports.DEFAULT_SANDBOX_PROVIDER_CONFIG = void 0; exports.StreamEventType = void 0; exports.QueueItemStatus = void 0; exports.EventCategory = void 0; exports.EventSource = void 0;
|
|
112
112
|
var init_types = __esm({
|
|
113
113
|
"src/types/index.ts"() {
|
|
114
114
|
init_normalized();
|
|
@@ -233,6 +233,14 @@ var init_types = __esm({
|
|
|
233
233
|
WEBHOOK: "webhook"
|
|
234
234
|
// webhook_delivery, webhook_failure (outbound webhook events)
|
|
235
235
|
};
|
|
236
|
+
exports.EventSource = {
|
|
237
|
+
AGENT: "agent",
|
|
238
|
+
// Directly from the agent SDK
|
|
239
|
+
SYSTEM: "system",
|
|
240
|
+
// Generated by execution layer (lifecycle, user input)
|
|
241
|
+
DERIVED: "derived"
|
|
242
|
+
// Transformed/aggregated from agent events
|
|
243
|
+
};
|
|
236
244
|
}
|
|
237
245
|
});
|
|
238
246
|
|
|
@@ -2595,6 +2603,11 @@ var init_memory = __esm({
|
|
|
2595
2603
|
if (options.status) {
|
|
2596
2604
|
sessions2 = sessions2.filter((s) => s.status === options.status);
|
|
2597
2605
|
}
|
|
2606
|
+
if (options.resourceId) {
|
|
2607
|
+
sessions2 = sessions2.filter(
|
|
2608
|
+
(s) => s.metadata && s.metadata["resourceId"] === options.resourceId
|
|
2609
|
+
);
|
|
2610
|
+
}
|
|
2598
2611
|
const orderBy = options.orderBy ?? "createdAt";
|
|
2599
2612
|
const order = options.order ?? "desc";
|
|
2600
2613
|
sessions2.sort((a, b) => {
|
|
@@ -4526,13 +4539,13 @@ function getSandboxPool() {
|
|
|
4526
4539
|
return globalPool;
|
|
4527
4540
|
}
|
|
4528
4541
|
function isPoolEnabled() {
|
|
4529
|
-
if (!process.env.VERCEL) {
|
|
4530
|
-
return false;
|
|
4531
|
-
}
|
|
4532
4542
|
if (process.env.SANDBOX_POOL_ENABLED === "false") {
|
|
4533
4543
|
return false;
|
|
4534
4544
|
}
|
|
4535
|
-
|
|
4545
|
+
if (process.env.SANDBOX_POOL_ENABLED === "true") {
|
|
4546
|
+
return true;
|
|
4547
|
+
}
|
|
4548
|
+
return !!process.env.VERCEL;
|
|
4536
4549
|
}
|
|
4537
4550
|
async function ensureSandboxPoolInitialized() {
|
|
4538
4551
|
if (globalPool && globalPool.isRunning()) {
|
|
@@ -4617,7 +4630,7 @@ node -e "require('@anthropic-ai/claude-agent-sdk'); console.log('[warmup] SDK ve
|
|
|
4617
4630
|
|
|
4618
4631
|
echo "[warmup] Warmup complete!"
|
|
4619
4632
|
`;
|
|
4620
|
-
exports.SandboxPool = class {
|
|
4633
|
+
exports.SandboxPool = class _SandboxPool {
|
|
4621
4634
|
config;
|
|
4622
4635
|
pool = /* @__PURE__ */ new Map();
|
|
4623
4636
|
warmingInProgress = /* @__PURE__ */ new Set();
|
|
@@ -4626,6 +4639,16 @@ echo "[warmup] Warmup complete!"
|
|
|
4626
4639
|
lastMaintenanceAt = null;
|
|
4627
4640
|
metricsCallback;
|
|
4628
4641
|
startPromise = null;
|
|
4642
|
+
/** Registered warmup specs by tag (e.g. agentId -> spec) */
|
|
4643
|
+
warmupSpecs = /* @__PURE__ */ new Map();
|
|
4644
|
+
/** Consecutive warmup failure count (reset on success) */
|
|
4645
|
+
consecutiveFailures = 0;
|
|
4646
|
+
/** Timestamp of last warmup attempt — used for backoff */
|
|
4647
|
+
lastWarmupAttemptAt = 0;
|
|
4648
|
+
/** Max consecutive failures before stopping attempts entirely until manual restart */
|
|
4649
|
+
static MAX_CONSECUTIVE_FAILURES = 10;
|
|
4650
|
+
/** Base backoff delay in ms (doubles each failure: 30s, 60s, 120s, 240s…) */
|
|
4651
|
+
static BACKOFF_BASE_MS = 3e4;
|
|
4629
4652
|
constructor(config = {}) {
|
|
4630
4653
|
this.config = {
|
|
4631
4654
|
minPoolSize: config.minPoolSize ?? parseInt(process.env.SANDBOX_POOL_MIN_SIZE ?? "2"),
|
|
@@ -4674,11 +4697,13 @@ echo "[warmup] Warmup complete!"
|
|
|
4674
4697
|
if (this.maintenanceIntervalId.unref) {
|
|
4675
4698
|
this.maintenanceIntervalId.unref();
|
|
4676
4699
|
}
|
|
4700
|
+
const initialSpecs = this.selectSpecsForReplenishment(this.config.minPoolSize);
|
|
4677
4701
|
console.log(`[POOL] Spawning ${this.config.minPoolSize} initial sandbox(es)...`);
|
|
4678
4702
|
const warmupPromises = [];
|
|
4679
4703
|
for (let i = 0; i < this.config.minPoolSize; i++) {
|
|
4704
|
+
const spec = initialSpecs[i];
|
|
4680
4705
|
warmupPromises.push(
|
|
4681
|
-
this.warmSandbox().then((sandbox) => {
|
|
4706
|
+
this.warmSandbox(spec).then((sandbox) => {
|
|
4682
4707
|
this.pool.set(sandbox.sandboxId, sandbox);
|
|
4683
4708
|
console.log(`[POOL] Initial sandbox ready: ${sandbox.sandboxId}`);
|
|
4684
4709
|
}).catch((error) => {
|
|
@@ -4722,9 +4747,11 @@ echo "[warmup] Warmup complete!"
|
|
|
4722
4747
|
}
|
|
4723
4748
|
/**
|
|
4724
4749
|
* Acquire a pre-warmed sandbox for a session.
|
|
4750
|
+
* If preferTag is provided, tries to find a sandbox warmed for that tag first.
|
|
4751
|
+
* Falls back to a generic (untagged) sandbox if no tag match is found.
|
|
4725
4752
|
* If no eligible sandbox is available, creates one on-demand.
|
|
4726
4753
|
*/
|
|
4727
|
-
async acquire(sessionId) {
|
|
4754
|
+
async acquire(sessionId, preferTag) {
|
|
4728
4755
|
if (!this.running) {
|
|
4729
4756
|
throw new Error("Sandbox pool is not running");
|
|
4730
4757
|
}
|
|
@@ -4734,26 +4761,34 @@ echo "[warmup] Warmup complete!"
|
|
|
4734
4761
|
return pooled;
|
|
4735
4762
|
}
|
|
4736
4763
|
}
|
|
4737
|
-
const available = this.getAvailableSandbox();
|
|
4764
|
+
const available = this.getAvailableSandbox(preferTag);
|
|
4738
4765
|
if (available) {
|
|
4739
4766
|
available.assignedTo = sessionId;
|
|
4740
|
-
|
|
4767
|
+
const tagInfo = available.warmupTag ? ` [tag=${available.warmupTag}, agentSetupComplete=${available.agentSetupComplete}]` : " [generic]";
|
|
4768
|
+
console.log(`[POOL] Acquired sandbox ${available.sandboxId} for session ${sessionId}${tagInfo}`);
|
|
4741
4769
|
this.emitMetric("sandbox_assigned", {
|
|
4742
4770
|
sandboxId: available.sandboxId,
|
|
4743
4771
|
sessionId,
|
|
4744
|
-
poolAvailable: this.getAvailableCount()
|
|
4772
|
+
poolAvailable: this.getAvailableCount(),
|
|
4773
|
+
warmupTag: available.warmupTag,
|
|
4774
|
+
agentSetupComplete: available.agentSetupComplete,
|
|
4775
|
+
preferTag
|
|
4745
4776
|
});
|
|
4746
4777
|
this.triggerReplenishment();
|
|
4747
4778
|
return available;
|
|
4748
4779
|
}
|
|
4749
|
-
|
|
4750
|
-
|
|
4780
|
+
const spec = preferTag ? this.warmupSpecs.get(preferTag) : void 0;
|
|
4781
|
+
console.log(`[POOL] No available sandbox, creating on-demand for session ${sessionId}${spec ? ` [spec=${preferTag}]` : ""}...`);
|
|
4782
|
+
const sandbox = await this.warmSandbox(spec);
|
|
4751
4783
|
sandbox.assignedTo = sessionId;
|
|
4752
4784
|
this.pool.set(sandbox.sandboxId, sandbox);
|
|
4753
4785
|
this.emitMetric("sandbox_assigned", {
|
|
4754
4786
|
sandboxId: sandbox.sandboxId,
|
|
4755
4787
|
sessionId,
|
|
4756
|
-
onDemand: true
|
|
4788
|
+
onDemand: true,
|
|
4789
|
+
warmupTag: sandbox.warmupTag,
|
|
4790
|
+
agentSetupComplete: sandbox.agentSetupComplete,
|
|
4791
|
+
preferTag
|
|
4757
4792
|
});
|
|
4758
4793
|
return sandbox;
|
|
4759
4794
|
}
|
|
@@ -4784,11 +4819,14 @@ echo "[warmup] Warmup complete!"
|
|
|
4784
4819
|
let available = 0;
|
|
4785
4820
|
let assigned = 0;
|
|
4786
4821
|
let ineligible = 0;
|
|
4822
|
+
const availableByTag = {};
|
|
4787
4823
|
for (const pooled of this.pool.values()) {
|
|
4788
4824
|
if (pooled.assignedTo) {
|
|
4789
4825
|
assigned++;
|
|
4790
4826
|
} else if (pooled.eligible) {
|
|
4791
4827
|
available++;
|
|
4828
|
+
const tagKey = pooled.warmupTag || "generic";
|
|
4829
|
+
availableByTag[tagKey] = (availableByTag[tagKey] || 0) + 1;
|
|
4792
4830
|
} else {
|
|
4793
4831
|
ineligible++;
|
|
4794
4832
|
}
|
|
@@ -4801,6 +4839,10 @@ echo "[warmup] Warmup complete!"
|
|
|
4801
4839
|
warming: this.warmingInProgress.size,
|
|
4802
4840
|
running: this.running,
|
|
4803
4841
|
lastMaintenanceAt: this.lastMaintenanceAt,
|
|
4842
|
+
consecutiveFailures: this.consecutiveFailures,
|
|
4843
|
+
warmupSuspended: this.consecutiveFailures >= _SandboxPool.MAX_CONSECUTIVE_FAILURES,
|
|
4844
|
+
registeredSpecs: this.warmupSpecs.size,
|
|
4845
|
+
availableByTag,
|
|
4804
4846
|
config: {
|
|
4805
4847
|
minPoolSize: this.config.minPoolSize,
|
|
4806
4848
|
maxPoolSize: this.config.maxPoolSize,
|
|
@@ -4815,17 +4857,56 @@ echo "[warmup] Warmup complete!"
|
|
|
4815
4857
|
onMetrics(callback) {
|
|
4816
4858
|
this.metricsCallback = callback;
|
|
4817
4859
|
}
|
|
4860
|
+
/**
|
|
4861
|
+
* Register a warmup spec so the pool can pre-warm agent-specific sandboxes.
|
|
4862
|
+
* If a spec with the same tag already exists, it is replaced.
|
|
4863
|
+
* Triggers replenishment to warm a sandbox for this spec.
|
|
4864
|
+
*/
|
|
4865
|
+
registerWarmupSpec(spec) {
|
|
4866
|
+
const isNew = !this.warmupSpecs.has(spec.tag);
|
|
4867
|
+
this.warmupSpecs.set(spec.tag, spec);
|
|
4868
|
+
console.log(`[POOL] ${isNew ? "Registered" : "Updated"} warmup spec: ${spec.tag} (priority=${spec.priority})`);
|
|
4869
|
+
this.emitMetric("spec_registered", {
|
|
4870
|
+
tag: spec.tag,
|
|
4871
|
+
priority: spec.priority,
|
|
4872
|
+
isNew,
|
|
4873
|
+
totalSpecs: this.warmupSpecs.size
|
|
4874
|
+
});
|
|
4875
|
+
if (this.running) {
|
|
4876
|
+
this.triggerReplenishment();
|
|
4877
|
+
}
|
|
4878
|
+
}
|
|
4879
|
+
/**
|
|
4880
|
+
* Remove a warmup spec. Existing tagged sandboxes remain but won't be replaced.
|
|
4881
|
+
*/
|
|
4882
|
+
unregisterWarmupSpec(tag) {
|
|
4883
|
+
this.warmupSpecs.delete(tag);
|
|
4884
|
+
console.log(`[POOL] Unregistered warmup spec: ${tag}`);
|
|
4885
|
+
}
|
|
4886
|
+
/**
|
|
4887
|
+
* Update the priority of a warmup spec (e.g. for MRU tracking).
|
|
4888
|
+
* Higher priority = more likely to get a warm sandbox during replenishment.
|
|
4889
|
+
*/
|
|
4890
|
+
updateSpecPriority(tag, priority) {
|
|
4891
|
+
const spec = this.warmupSpecs.get(tag);
|
|
4892
|
+
if (spec) {
|
|
4893
|
+
spec.priority = priority;
|
|
4894
|
+
}
|
|
4895
|
+
}
|
|
4818
4896
|
// ===========================================================================
|
|
4819
4897
|
// PRIVATE METHODS
|
|
4820
4898
|
// ===========================================================================
|
|
4821
4899
|
/**
|
|
4822
|
-
* Create and warm a new sandbox
|
|
4900
|
+
* Create and warm a new sandbox.
|
|
4901
|
+
* If a spec is provided, runs the spec's setup function after SDK installation.
|
|
4902
|
+
* On spec setup failure, the sandbox remains generic (graceful degradation).
|
|
4823
4903
|
*/
|
|
4824
|
-
async warmSandbox() {
|
|
4904
|
+
async warmSandbox(spec) {
|
|
4825
4905
|
const warmupId = `warming-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
4826
4906
|
this.warmingInProgress.add(warmupId);
|
|
4827
4907
|
this.emitMetric("warmup_started", { warmupId });
|
|
4828
4908
|
const startTime = Date.now();
|
|
4909
|
+
this.lastWarmupAttemptAt = startTime;
|
|
4829
4910
|
const useTarball = !!this.config.baseTarballUrl;
|
|
4830
4911
|
try {
|
|
4831
4912
|
const { Sandbox } = await import('@vercel/sandbox');
|
|
@@ -4914,6 +4995,37 @@ echo "[warmup] Warmup complete!"
|
|
|
4914
4995
|
throw new Error(`Warmup failed: ${stderr}`);
|
|
4915
4996
|
}
|
|
4916
4997
|
}
|
|
4998
|
+
let warmupTag;
|
|
4999
|
+
let agentSetupComplete = false;
|
|
5000
|
+
if (spec) {
|
|
5001
|
+
console.log(`[POOL] Running spec setup for tag=${spec.tag} on sandbox ${sandbox.sandboxId}...`);
|
|
5002
|
+
this.emitMetric("spec_setup_started", { tag: spec.tag, sandboxId: sandbox.sandboxId });
|
|
5003
|
+
const specStartTime = Date.now();
|
|
5004
|
+
try {
|
|
5005
|
+
await spec.setup(sandbox);
|
|
5006
|
+
warmupTag = spec.tag;
|
|
5007
|
+
agentSetupComplete = true;
|
|
5008
|
+
const specDuration = Date.now() - specStartTime;
|
|
5009
|
+
console.log(`[POOL] Spec setup completed for tag=${spec.tag} on sandbox ${sandbox.sandboxId} (${specDuration}ms)`);
|
|
5010
|
+
this.emitMetric("spec_setup_completed", {
|
|
5011
|
+
tag: spec.tag,
|
|
5012
|
+
sandboxId: sandbox.sandboxId,
|
|
5013
|
+
durationMs: specDuration
|
|
5014
|
+
});
|
|
5015
|
+
} catch (specError) {
|
|
5016
|
+
const specDuration = Date.now() - specStartTime;
|
|
5017
|
+
const specErrorMessage = specError instanceof Error ? specError.message : "Unknown";
|
|
5018
|
+
console.warn(
|
|
5019
|
+
`[POOL] Spec setup failed for tag=${spec.tag} on sandbox ${sandbox.sandboxId} (${specDuration}ms): ${specErrorMessage}. Sandbox stays generic.`
|
|
5020
|
+
);
|
|
5021
|
+
this.emitMetric("spec_setup_failed", {
|
|
5022
|
+
tag: spec.tag,
|
|
5023
|
+
sandboxId: sandbox.sandboxId,
|
|
5024
|
+
durationMs: specDuration,
|
|
5025
|
+
error: specErrorMessage
|
|
5026
|
+
});
|
|
5027
|
+
}
|
|
5028
|
+
}
|
|
4917
5029
|
const warmupTime = Date.now() - startTime;
|
|
4918
5030
|
const now = Date.now();
|
|
4919
5031
|
const pooled = {
|
|
@@ -4923,22 +5035,38 @@ echo "[warmup] Warmup complete!"
|
|
|
4923
5035
|
expiresAt: now + this.config.sandboxTimeout * 1e3,
|
|
4924
5036
|
sdkInstalled: true,
|
|
4925
5037
|
eligible: true,
|
|
4926
|
-
lastHeartbeat: now
|
|
5038
|
+
lastHeartbeat: now,
|
|
5039
|
+
warmupTag,
|
|
5040
|
+
agentSetupComplete
|
|
4927
5041
|
};
|
|
4928
|
-
|
|
5042
|
+
const tagInfo = warmupTag ? ` [tag=${warmupTag}]` : "";
|
|
5043
|
+
console.log(`[POOL] Warmup completed for ${sandbox.sandboxId} (took ${warmupTime}ms)${useTarball ? " [tarball]" : ""}${tagInfo}`);
|
|
5044
|
+
this.consecutiveFailures = 0;
|
|
4929
5045
|
this.emitMetric("warmup_completed", {
|
|
4930
5046
|
sandboxId: pooled.sandboxId,
|
|
4931
5047
|
warmupTimeMs: warmupTime,
|
|
4932
|
-
usedTarball: useTarball
|
|
5048
|
+
usedTarball: useTarball,
|
|
5049
|
+
warmupTag,
|
|
5050
|
+
agentSetupComplete
|
|
4933
5051
|
});
|
|
4934
5052
|
this.emitMetric("sandbox_created", { sandboxId: pooled.sandboxId });
|
|
4935
5053
|
return pooled;
|
|
4936
5054
|
} catch (error) {
|
|
4937
5055
|
const warmupTime = Date.now() - startTime;
|
|
5056
|
+
this.consecutiveFailures++;
|
|
5057
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown";
|
|
5058
|
+
if (this.consecutiveFailures === 1) {
|
|
5059
|
+
console.error(`[POOL] Warmup failed: ${errorMessage}`);
|
|
5060
|
+
} else {
|
|
5061
|
+
console.error(
|
|
5062
|
+
`[POOL] Warmup failed (${this.consecutiveFailures} consecutive). Next attempt in ${Math.min(_SandboxPool.BACKOFF_BASE_MS * Math.pow(2, this.consecutiveFailures - 1), 3e5) / 1e3}s. Error: ${errorMessage}`
|
|
5063
|
+
);
|
|
5064
|
+
}
|
|
4938
5065
|
this.emitMetric("warmup_failed", {
|
|
4939
|
-
error:
|
|
5066
|
+
error: errorMessage,
|
|
4940
5067
|
warmupTimeMs: warmupTime,
|
|
4941
|
-
usedTarball: useTarball
|
|
5068
|
+
usedTarball: useTarball,
|
|
5069
|
+
consecutiveFailures: this.consecutiveFailures
|
|
4942
5070
|
});
|
|
4943
5071
|
throw error;
|
|
4944
5072
|
} finally {
|
|
@@ -5000,18 +5128,29 @@ echo "[warmup] Warmup complete!"
|
|
|
5000
5128
|
}
|
|
5001
5129
|
}
|
|
5002
5130
|
/**
|
|
5003
|
-
* Get an available eligible sandbox for assignment
|
|
5131
|
+
* Get an available eligible sandbox for assignment.
|
|
5132
|
+
* If preferTag is provided:
|
|
5133
|
+
* - First tries to find a sandbox tagged for that specific agent
|
|
5134
|
+
* - Falls back to a generic (untagged) sandbox
|
|
5135
|
+
* - Tagged sandboxes for OTHER agents are NOT used as fallback (reserved)
|
|
5004
5136
|
*/
|
|
5005
|
-
getAvailableSandbox() {
|
|
5006
|
-
let
|
|
5137
|
+
getAvailableSandbox(preferTag) {
|
|
5138
|
+
let bestTagged = null;
|
|
5139
|
+
let bestGeneric = null;
|
|
5007
5140
|
for (const pooled of this.pool.values()) {
|
|
5008
5141
|
if (!pooled.assignedTo && pooled.eligible) {
|
|
5009
|
-
if (
|
|
5010
|
-
|
|
5142
|
+
if (preferTag && pooled.warmupTag === preferTag) {
|
|
5143
|
+
if (!bestTagged || pooled.expiresAt > bestTagged.expiresAt) {
|
|
5144
|
+
bestTagged = pooled;
|
|
5145
|
+
}
|
|
5146
|
+
} else if (!pooled.warmupTag) {
|
|
5147
|
+
if (!bestGeneric || pooled.expiresAt > bestGeneric.expiresAt) {
|
|
5148
|
+
bestGeneric = pooled;
|
|
5149
|
+
}
|
|
5011
5150
|
}
|
|
5012
5151
|
}
|
|
5013
5152
|
}
|
|
5014
|
-
return
|
|
5153
|
+
return bestTagged || bestGeneric;
|
|
5015
5154
|
}
|
|
5016
5155
|
/**
|
|
5017
5156
|
* Get count of available sandboxes
|
|
@@ -5046,9 +5185,30 @@ echo "[warmup] Warmup complete!"
|
|
|
5046
5185
|
});
|
|
5047
5186
|
}
|
|
5048
5187
|
/**
|
|
5049
|
-
* Replenish pool if below min size
|
|
5188
|
+
* Replenish pool if below min size.
|
|
5189
|
+
* Applies exponential backoff when warmups keep failing to avoid
|
|
5190
|
+
* a tight failure loop that wastes resources and floods metrics.
|
|
5050
5191
|
*/
|
|
5051
5192
|
async replenishPool() {
|
|
5193
|
+
if (this.consecutiveFailures >= _SandboxPool.MAX_CONSECUTIVE_FAILURES) {
|
|
5194
|
+
if (Math.random() < 0.2) {
|
|
5195
|
+
console.warn(
|
|
5196
|
+
`[POOL] Warmup suspended after ${this.consecutiveFailures} consecutive failures. Check SANDBOX_BASE_TARBALL_URL or Vercel API status. Pool will retry on next acquire().`
|
|
5197
|
+
);
|
|
5198
|
+
}
|
|
5199
|
+
return;
|
|
5200
|
+
}
|
|
5201
|
+
if (this.consecutiveFailures > 0) {
|
|
5202
|
+
const backoffMs = Math.min(
|
|
5203
|
+
_SandboxPool.BACKOFF_BASE_MS * Math.pow(2, this.consecutiveFailures - 1),
|
|
5204
|
+
5 * 6e4
|
|
5205
|
+
// Cap at 5 minutes
|
|
5206
|
+
);
|
|
5207
|
+
const timeSinceLastAttempt = Date.now() - this.lastWarmupAttemptAt;
|
|
5208
|
+
if (timeSinceLastAttempt < backoffMs) {
|
|
5209
|
+
return;
|
|
5210
|
+
}
|
|
5211
|
+
}
|
|
5052
5212
|
const eligibleCount = this.getEligibleCount();
|
|
5053
5213
|
const warmingCount = this.warmingInProgress.size;
|
|
5054
5214
|
const totalProjected = eligibleCount + warmingCount;
|
|
@@ -5057,13 +5217,16 @@ echo "[warmup] Warmup complete!"
|
|
|
5057
5217
|
this.config.maxPoolSize - this.pool.size - warmingCount
|
|
5058
5218
|
);
|
|
5059
5219
|
if (needed <= 0) return;
|
|
5220
|
+
const specAssignments = this.selectSpecsForReplenishment(needed);
|
|
5060
5221
|
console.log(`[POOL] Spawning ${needed} sandbox(es) to maintain pool...`);
|
|
5061
5222
|
const promises = [];
|
|
5062
5223
|
for (let i = 0; i < needed; i++) {
|
|
5224
|
+
const spec = specAssignments[i];
|
|
5063
5225
|
promises.push(
|
|
5064
|
-
this.warmSandbox().then((sandbox) => {
|
|
5226
|
+
this.warmSandbox(spec).then((sandbox) => {
|
|
5065
5227
|
this.pool.set(sandbox.sandboxId, sandbox);
|
|
5066
|
-
|
|
5228
|
+
const tagInfo = sandbox.warmupTag ? ` [tag=${sandbox.warmupTag}]` : "";
|
|
5229
|
+
console.log(`[POOL] Replenishment sandbox ready: ${sandbox.sandboxId}${tagInfo}`);
|
|
5067
5230
|
}).catch((error) => {
|
|
5068
5231
|
console.error("[POOL] Failed to warm replenishment sandbox:", error);
|
|
5069
5232
|
})
|
|
@@ -5074,6 +5237,39 @@ echo "[warmup] Warmup complete!"
|
|
|
5074
5237
|
}
|
|
5075
5238
|
await Promise.all(promises);
|
|
5076
5239
|
}
|
|
5240
|
+
/**
|
|
5241
|
+
* Decide which specs to apply to new sandboxes during replenishment.
|
|
5242
|
+
* Strategy: cover uncovered specs first (highest priority), then fill remaining as generic.
|
|
5243
|
+
* Returns an array of length `needed`, where each element is a spec or undefined (generic).
|
|
5244
|
+
*/
|
|
5245
|
+
selectSpecsForReplenishment(needed) {
|
|
5246
|
+
if (this.warmupSpecs.size === 0) {
|
|
5247
|
+
return new Array(needed).fill(void 0);
|
|
5248
|
+
}
|
|
5249
|
+
const uncoveredSpecs = [];
|
|
5250
|
+
for (const spec of this.warmupSpecs.values()) {
|
|
5251
|
+
let hasCoverage = false;
|
|
5252
|
+
for (const pooled of this.pool.values()) {
|
|
5253
|
+
if (pooled.warmupTag === spec.tag && pooled.eligible && !pooled.assignedTo) {
|
|
5254
|
+
hasCoverage = true;
|
|
5255
|
+
break;
|
|
5256
|
+
}
|
|
5257
|
+
}
|
|
5258
|
+
if (!hasCoverage) {
|
|
5259
|
+
uncoveredSpecs.push(spec);
|
|
5260
|
+
}
|
|
5261
|
+
}
|
|
5262
|
+
uncoveredSpecs.sort((a, b) => b.priority - a.priority);
|
|
5263
|
+
const assignments = [];
|
|
5264
|
+
for (const spec of uncoveredSpecs) {
|
|
5265
|
+
if (assignments.length >= needed) break;
|
|
5266
|
+
assignments.push(spec);
|
|
5267
|
+
}
|
|
5268
|
+
while (assignments.length < needed) {
|
|
5269
|
+
assignments.push(void 0);
|
|
5270
|
+
}
|
|
5271
|
+
return assignments;
|
|
5272
|
+
}
|
|
5077
5273
|
/**
|
|
5078
5274
|
* Destroy a sandbox and clean up
|
|
5079
5275
|
*/
|
|
@@ -5305,7 +5501,7 @@ function removeExpiredSandbox(sessionId) {
|
|
|
5305
5501
|
}
|
|
5306
5502
|
}
|
|
5307
5503
|
async function getOrCreateSandbox(options) {
|
|
5308
|
-
const { sessionId, runtime = "node22", timeout = 300, vcpus = 4, existingSandboxId } = options;
|
|
5504
|
+
const { sessionId, runtime = "node22", timeout = 300, vcpus = 4, existingSandboxId, preferTag } = options;
|
|
5309
5505
|
ensureCleanupRunning();
|
|
5310
5506
|
ensureHeartbeatRunning();
|
|
5311
5507
|
const { Sandbox } = await import('@vercel/sandbox');
|
|
@@ -5322,6 +5518,8 @@ async function getOrCreateSandbox(options) {
|
|
|
5322
5518
|
sdkInstalled: cached.sdkInstalled,
|
|
5323
5519
|
startupScriptRan: cached.startupScriptRan,
|
|
5324
5520
|
startupScriptHash: cached.startupScriptHash,
|
|
5521
|
+
installScriptRan: cached.installScriptRan,
|
|
5522
|
+
installScriptHash: cached.installScriptHash,
|
|
5325
5523
|
isNew: false,
|
|
5326
5524
|
configFileUrl: cached.configFileUrl,
|
|
5327
5525
|
configInstalledAt: cached.configInstalledAt
|
|
@@ -5330,41 +5528,6 @@ async function getOrCreateSandbox(options) {
|
|
|
5330
5528
|
console.log("[SANDBOX] Cached sandbox has expired (HTTP 410 or similar), creating new sandbox");
|
|
5331
5529
|
removeExpiredSandbox(sessionId);
|
|
5332
5530
|
}
|
|
5333
|
-
const pool = await ensureSandboxPoolInitialized();
|
|
5334
|
-
if (pool && pool.isRunning()) {
|
|
5335
|
-
try {
|
|
5336
|
-
console.log("[SANDBOX] Attempting to acquire from pre-warmed pool...");
|
|
5337
|
-
const pooled = await pool.acquire(sessionId);
|
|
5338
|
-
console.log("[SANDBOX] Acquired pre-warmed sandbox:", pooled.sandboxId);
|
|
5339
|
-
const now2 = Date.now();
|
|
5340
|
-
const entry2 = {
|
|
5341
|
-
sandbox: pooled.sandbox,
|
|
5342
|
-
sessionId,
|
|
5343
|
-
createdAt: pooled.createdAt,
|
|
5344
|
-
lastUsedAt: now2,
|
|
5345
|
-
sdkInstalled: pooled.sdkInstalled,
|
|
5346
|
-
startupScriptRan: false
|
|
5347
|
-
// User script hasn't run yet
|
|
5348
|
-
};
|
|
5349
|
-
sandboxCache.set(sessionId, entry2);
|
|
5350
|
-
return {
|
|
5351
|
-
sandbox: pooled.sandbox,
|
|
5352
|
-
sandboxId: pooled.sandboxId,
|
|
5353
|
-
sdkInstalled: pooled.sdkInstalled,
|
|
5354
|
-
startupScriptRan: false,
|
|
5355
|
-
startupScriptHash: void 0,
|
|
5356
|
-
isNew: false,
|
|
5357
|
-
// Not new - came from pool
|
|
5358
|
-
configFileUrl: void 0,
|
|
5359
|
-
configInstalledAt: void 0
|
|
5360
|
-
};
|
|
5361
|
-
} catch (error) {
|
|
5362
|
-
console.warn(
|
|
5363
|
-
"[SANDBOX] Failed to acquire from pool, falling back to on-demand creation:",
|
|
5364
|
-
error instanceof Error ? error.message : "Unknown error"
|
|
5365
|
-
);
|
|
5366
|
-
}
|
|
5367
|
-
}
|
|
5368
5531
|
if (existingSandboxId) {
|
|
5369
5532
|
console.log("[SANDBOX] Attempting to reconnect to existing sandbox:", existingSandboxId);
|
|
5370
5533
|
try {
|
|
@@ -5385,7 +5548,9 @@ async function getOrCreateSandbox(options) {
|
|
|
5385
5548
|
// We assume SDK is installed since this is an existing sandbox
|
|
5386
5549
|
// The caller can verify and re-mark if needed
|
|
5387
5550
|
sdkInstalled: true,
|
|
5388
|
-
startupScriptRan: true
|
|
5551
|
+
startupScriptRan: true,
|
|
5552
|
+
installScriptRan: true
|
|
5553
|
+
// Assume ran for reconnected sandboxes
|
|
5389
5554
|
};
|
|
5390
5555
|
sandboxCache.set(sessionId, entry2);
|
|
5391
5556
|
return {
|
|
@@ -5397,13 +5562,17 @@ async function getOrCreateSandbox(options) {
|
|
|
5397
5562
|
// Assume ran for reconnected sandboxes
|
|
5398
5563
|
startupScriptHash: void 0,
|
|
5399
5564
|
// Unknown — caller should not re-run based on hash mismatch alone
|
|
5565
|
+
installScriptRan: true,
|
|
5566
|
+
// Assume ran for reconnected sandboxes
|
|
5567
|
+
installScriptHash: void 0,
|
|
5568
|
+
// Unknown — same logic as startup script
|
|
5400
5569
|
isNew: false,
|
|
5401
5570
|
configFileUrl: void 0,
|
|
5402
5571
|
configInstalledAt: now2
|
|
5403
5572
|
// Assume config was installed — prevents unnecessary re-install on reconnection
|
|
5404
5573
|
};
|
|
5405
5574
|
} else {
|
|
5406
|
-
console.log("[SANDBOX] Reconnected sandbox failed health check, will create new");
|
|
5575
|
+
console.log("[SANDBOX] Reconnected sandbox failed health check, will try pool or create new");
|
|
5407
5576
|
}
|
|
5408
5577
|
} catch (error) {
|
|
5409
5578
|
console.log(
|
|
@@ -5413,6 +5582,47 @@ async function getOrCreateSandbox(options) {
|
|
|
5413
5582
|
);
|
|
5414
5583
|
}
|
|
5415
5584
|
}
|
|
5585
|
+
const pool = await ensureSandboxPoolInitialized();
|
|
5586
|
+
if (pool && pool.isRunning()) {
|
|
5587
|
+
try {
|
|
5588
|
+
console.log(`[SANDBOX] Attempting to acquire from pre-warmed pool...${preferTag ? ` [preferTag=${preferTag}]` : ""}`);
|
|
5589
|
+
const pooled = await pool.acquire(sessionId, preferTag);
|
|
5590
|
+
const tagInfo = pooled.warmupTag ? ` [tag=${pooled.warmupTag}, agentSetup=${pooled.agentSetupComplete}]` : "";
|
|
5591
|
+
console.log(`[SANDBOX] Acquired pre-warmed sandbox: ${pooled.sandboxId}${tagInfo}`);
|
|
5592
|
+
const agentSetupDone = pooled.agentSetupComplete === true;
|
|
5593
|
+
const now2 = Date.now();
|
|
5594
|
+
const entry2 = {
|
|
5595
|
+
sandbox: pooled.sandbox,
|
|
5596
|
+
sessionId,
|
|
5597
|
+
createdAt: pooled.createdAt,
|
|
5598
|
+
lastUsedAt: now2,
|
|
5599
|
+
sdkInstalled: pooled.sdkInstalled,
|
|
5600
|
+
startupScriptRan: agentSetupDone,
|
|
5601
|
+
installScriptRan: agentSetupDone
|
|
5602
|
+
};
|
|
5603
|
+
sandboxCache.set(sessionId, entry2);
|
|
5604
|
+
return {
|
|
5605
|
+
sandbox: pooled.sandbox,
|
|
5606
|
+
sandboxId: pooled.sandboxId,
|
|
5607
|
+
sdkInstalled: pooled.sdkInstalled,
|
|
5608
|
+
startupScriptRan: agentSetupDone,
|
|
5609
|
+
startupScriptHash: void 0,
|
|
5610
|
+
installScriptRan: agentSetupDone,
|
|
5611
|
+
installScriptHash: void 0,
|
|
5612
|
+
isNew: false,
|
|
5613
|
+
// Not new - came from pool
|
|
5614
|
+
configFileUrl: void 0,
|
|
5615
|
+
configInstalledAt: agentSetupDone ? now2 : void 0,
|
|
5616
|
+
warmupTag: pooled.warmupTag,
|
|
5617
|
+
agentSetupComplete: pooled.agentSetupComplete
|
|
5618
|
+
};
|
|
5619
|
+
} catch (error) {
|
|
5620
|
+
console.warn(
|
|
5621
|
+
"[SANDBOX] Failed to acquire from pool, falling back to on-demand creation:",
|
|
5622
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
5623
|
+
);
|
|
5624
|
+
}
|
|
5625
|
+
}
|
|
5416
5626
|
console.log("[SANDBOX] Creating new sandbox for session:", sessionId);
|
|
5417
5627
|
const baseTarballUrl = process.env.SANDBOX_BASE_TARBALL_URL;
|
|
5418
5628
|
const useTarball = !!baseTarballUrl;
|
|
@@ -5446,7 +5656,8 @@ async function getOrCreateSandbox(options) {
|
|
|
5446
5656
|
lastUsedAt: now,
|
|
5447
5657
|
// If we used tarball, SDK is pre-installed
|
|
5448
5658
|
sdkInstalled: useTarball,
|
|
5449
|
-
startupScriptRan: false
|
|
5659
|
+
startupScriptRan: false,
|
|
5660
|
+
installScriptRan: false
|
|
5450
5661
|
};
|
|
5451
5662
|
sandboxCache.set(sessionId, entry);
|
|
5452
5663
|
return {
|
|
@@ -5456,6 +5667,8 @@ async function getOrCreateSandbox(options) {
|
|
|
5456
5667
|
sdkInstalled: useTarball,
|
|
5457
5668
|
startupScriptRan: false,
|
|
5458
5669
|
startupScriptHash: void 0,
|
|
5670
|
+
installScriptRan: false,
|
|
5671
|
+
installScriptHash: void 0,
|
|
5459
5672
|
isNew: true,
|
|
5460
5673
|
configFileUrl: void 0,
|
|
5461
5674
|
configInstalledAt: void 0
|
|
@@ -5495,6 +5708,14 @@ function markStartupScriptRan(sessionId, scriptHash) {
|
|
|
5495
5708
|
cached.lastUsedAt = Date.now();
|
|
5496
5709
|
}
|
|
5497
5710
|
}
|
|
5711
|
+
function markInstallScriptRan(sessionId, scriptHash) {
|
|
5712
|
+
const cached = sandboxCache.get(sessionId);
|
|
5713
|
+
if (cached) {
|
|
5714
|
+
cached.installScriptRan = true;
|
|
5715
|
+
cached.installScriptHash = scriptHash;
|
|
5716
|
+
cached.lastUsedAt = Date.now();
|
|
5717
|
+
}
|
|
5718
|
+
}
|
|
5498
5719
|
function needsStartupScriptRerun(sessionId, newScript) {
|
|
5499
5720
|
const cached = sandboxCache.get(sessionId);
|
|
5500
5721
|
if (!cached) return true;
|
|
@@ -5562,6 +5783,8 @@ function getCachedSandbox(sessionId) {
|
|
|
5562
5783
|
sdkInstalled: cached.sdkInstalled,
|
|
5563
5784
|
startupScriptRan: cached.startupScriptRan,
|
|
5564
5785
|
startupScriptHash: cached.startupScriptHash,
|
|
5786
|
+
installScriptRan: cached.installScriptRan,
|
|
5787
|
+
installScriptHash: cached.installScriptHash,
|
|
5565
5788
|
isNew: false,
|
|
5566
5789
|
configFileUrl: cached.configFileUrl,
|
|
5567
5790
|
configInstalledAt: cached.configInstalledAt
|
|
@@ -6154,6 +6377,85 @@ SCRIPT_EOF`]
|
|
|
6154
6377
|
}
|
|
6155
6378
|
}
|
|
6156
6379
|
}
|
|
6380
|
+
async function warmSandboxForSession(options) {
|
|
6381
|
+
const {
|
|
6382
|
+
sessionId,
|
|
6383
|
+
runtime = "node22",
|
|
6384
|
+
timeout = 600,
|
|
6385
|
+
vcpus = 4,
|
|
6386
|
+
startupScript,
|
|
6387
|
+
configFileUrl,
|
|
6388
|
+
envVars = {}
|
|
6389
|
+
} = options;
|
|
6390
|
+
console.log(`[WARM] Pre-warming sandbox for session: ${sessionId}`);
|
|
6391
|
+
const startTime = Date.now();
|
|
6392
|
+
const result = await getOrCreateSandbox({
|
|
6393
|
+
sessionId,
|
|
6394
|
+
runtime,
|
|
6395
|
+
timeout,
|
|
6396
|
+
vcpus
|
|
6397
|
+
});
|
|
6398
|
+
const { sandbox, sdkInstalled } = result;
|
|
6399
|
+
if (!sdkInstalled) {
|
|
6400
|
+
console.log("[WARM] Installing SDK...");
|
|
6401
|
+
await sandbox.runCommand({
|
|
6402
|
+
cmd: "bash",
|
|
6403
|
+
args: ["-c", "which jq || (sudo dnf install -y jq 2>/dev/null || sudo apt-get update && sudo apt-get install -y jq 2>/dev/null || sudo apk add jq 2>/dev/null) || true"]
|
|
6404
|
+
});
|
|
6405
|
+
await sandbox.runCommand({
|
|
6406
|
+
cmd: "bash",
|
|
6407
|
+
args: ["-c", "which ffmpeg || (sudo dnf install -y ffmpeg 2>/dev/null || sudo apt-get update && sudo apt-get install -y ffmpeg 2>/dev/null || sudo apk add ffmpeg 2>/dev/null) || true"]
|
|
6408
|
+
});
|
|
6409
|
+
const sdkResult = await sandbox.runCommand({
|
|
6410
|
+
cmd: "bash",
|
|
6411
|
+
args: ["-c", "npm init -y && npm install @anthropic-ai/claude-agent-sdk"],
|
|
6412
|
+
env: envVars
|
|
6413
|
+
});
|
|
6414
|
+
if (sdkResult.exitCode !== 0) {
|
|
6415
|
+
const stderr = await sdkResult.stderr();
|
|
6416
|
+
throw new Error(`Failed to install Claude Agent SDK during warmup: ${stderr}`);
|
|
6417
|
+
}
|
|
6418
|
+
markSdkInstalled(sessionId);
|
|
6419
|
+
}
|
|
6420
|
+
if (startupScript) {
|
|
6421
|
+
console.log("[WARM] Running startup script...");
|
|
6422
|
+
const scriptResult = await sandbox.runCommand({
|
|
6423
|
+
cmd: "bash",
|
|
6424
|
+
args: ["-c", startupScript],
|
|
6425
|
+
env: envVars
|
|
6426
|
+
});
|
|
6427
|
+
if (scriptResult.exitCode !== 0) {
|
|
6428
|
+
const stderr = await scriptResult.stderr();
|
|
6429
|
+
throw new Error(`Startup script failed during warmup: ${stderr}`);
|
|
6430
|
+
}
|
|
6431
|
+
markStartupScriptRan(sessionId, hashStartupScript(startupScript));
|
|
6432
|
+
}
|
|
6433
|
+
if (configFileUrl) {
|
|
6434
|
+
console.log("[WARM] Installing config from:", configFileUrl);
|
|
6435
|
+
const configScript = `
|
|
6436
|
+
set -e
|
|
6437
|
+
curl -sSL --fail "${configFileUrl}" -o /tmp/config.zip
|
|
6438
|
+
unzip -o /tmp/config.zip -d .
|
|
6439
|
+
rm -f /tmp/config.zip
|
|
6440
|
+
`;
|
|
6441
|
+
const configResult = await sandbox.runCommand({
|
|
6442
|
+
cmd: "bash",
|
|
6443
|
+
args: ["-c", configScript],
|
|
6444
|
+
env: envVars
|
|
6445
|
+
});
|
|
6446
|
+
if (configResult.exitCode !== 0) {
|
|
6447
|
+
const stderr = await configResult.stderr();
|
|
6448
|
+
throw new Error(`Config installation failed during warmup: ${stderr}`);
|
|
6449
|
+
}
|
|
6450
|
+
markConfigInstalled(sessionId, configFileUrl);
|
|
6451
|
+
}
|
|
6452
|
+
const duration = Date.now() - startTime;
|
|
6453
|
+
console.log(`[WARM] Sandbox pre-warmed for session ${sessionId} in ${duration}ms (sandbox: ${result.sandboxId})`);
|
|
6454
|
+
return {
|
|
6455
|
+
sandboxId: result.sandboxId,
|
|
6456
|
+
ready: true
|
|
6457
|
+
};
|
|
6458
|
+
}
|
|
6157
6459
|
var sandboxCache, DEFAULT_IDLE_TTL, CLEANUP_INTERVAL, HEARTBEAT_INTERVAL, cleanupIntervalId, heartbeatIntervalId, GLOBAL_HEARTBEAT_KEY, heartbeatListeners;
|
|
6158
6460
|
var init_vercel_sandbox_executor = __esm({
|
|
6159
6461
|
"src/runtime/vercel-sandbox-executor.ts"() {
|
|
@@ -6808,6 +7110,31 @@ WATCHER_EOF`;
|
|
|
6808
7110
|
globalInSandboxManager = null;
|
|
6809
7111
|
}
|
|
6810
7112
|
});
|
|
7113
|
+
function matchGlob(pattern, filePath) {
|
|
7114
|
+
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
7115
|
+
const normalizedPattern = pattern.replace(/\\/g, "/");
|
|
7116
|
+
let regexStr = "";
|
|
7117
|
+
let i = 0;
|
|
7118
|
+
while (i < normalizedPattern.length) {
|
|
7119
|
+
if (normalizedPattern[i] === "*" && normalizedPattern[i + 1] === "*") {
|
|
7120
|
+
if (normalizedPattern[i + 2] === "/") {
|
|
7121
|
+
regexStr += "(?:.*/)?";
|
|
7122
|
+
i += 3;
|
|
7123
|
+
} else {
|
|
7124
|
+
regexStr += ".*";
|
|
7125
|
+
i += 2;
|
|
7126
|
+
}
|
|
7127
|
+
} else if (normalizedPattern[i] === "*") {
|
|
7128
|
+
regexStr += "[^/]*";
|
|
7129
|
+
i += 1;
|
|
7130
|
+
} else {
|
|
7131
|
+
const ch = normalizedPattern[i];
|
|
7132
|
+
regexStr += ch.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
7133
|
+
i += 1;
|
|
7134
|
+
}
|
|
7135
|
+
}
|
|
7136
|
+
return new RegExp(`^${regexStr}$`).test(normalizedPath);
|
|
7137
|
+
}
|
|
6811
7138
|
function extractErrorMessage(error) {
|
|
6812
7139
|
if (error === null || error === void 0) {
|
|
6813
7140
|
return "Unknown error (null/undefined)";
|
|
@@ -6850,12 +7177,18 @@ function extractErrorMessage(error) {
|
|
|
6850
7177
|
function createSandboxFileSync(options) {
|
|
6851
7178
|
return new exports.SandboxFileSync(options);
|
|
6852
7179
|
}
|
|
6853
|
-
exports.SandboxFileSync = void 0;
|
|
7180
|
+
var DEFAULT_WEBHOOK_IGNORE; exports.SandboxFileSync = void 0;
|
|
6854
7181
|
var init_sandbox_file_sync = __esm({
|
|
6855
7182
|
"src/runtime/sandbox-file-sync.ts"() {
|
|
6856
7183
|
init_sandbox_file_watcher();
|
|
6857
7184
|
init_in_sandbox_watcher();
|
|
6858
7185
|
init_types();
|
|
7186
|
+
DEFAULT_WEBHOOK_IGNORE = [
|
|
7187
|
+
"**/agent-runner.js",
|
|
7188
|
+
"**/agent-runner.cjs",
|
|
7189
|
+
"**/.file-watcher.js",
|
|
7190
|
+
"**/.file-watcher-output.log"
|
|
7191
|
+
];
|
|
6859
7192
|
exports.SandboxFileSync = class {
|
|
6860
7193
|
fileStore;
|
|
6861
7194
|
sandboxBasePath;
|
|
@@ -6870,6 +7203,10 @@ var init_sandbox_file_sync = __esm({
|
|
|
6870
7203
|
fileChangeSubscribers = /* @__PURE__ */ new Set();
|
|
6871
7204
|
// Sequence number cache per session (for event storage)
|
|
6872
7205
|
sequenceNumbers = /* @__PURE__ */ new Map();
|
|
7206
|
+
// Webhook batching state
|
|
7207
|
+
batchTimer = null;
|
|
7208
|
+
batchQueue = /* @__PURE__ */ new Map();
|
|
7209
|
+
// keyed by file path for dedup
|
|
6873
7210
|
constructor(options) {
|
|
6874
7211
|
this.fileStore = options.fileStore;
|
|
6875
7212
|
this.sandboxBasePath = options.sandboxBasePath ?? ".claude/files";
|
|
@@ -6904,6 +7241,72 @@ var init_sandbox_file_sync = __esm({
|
|
|
6904
7241
|
*/
|
|
6905
7242
|
removeWebhook() {
|
|
6906
7243
|
this.webhookConfig = void 0;
|
|
7244
|
+
if (this.batchTimer) {
|
|
7245
|
+
clearTimeout(this.batchTimer);
|
|
7246
|
+
this.batchTimer = null;
|
|
7247
|
+
}
|
|
7248
|
+
this.batchQueue.clear();
|
|
7249
|
+
}
|
|
7250
|
+
/**
|
|
7251
|
+
* Check if a file path should be excluded from webhook notifications.
|
|
7252
|
+
* Tests against DEFAULT_WEBHOOK_IGNORE patterns and any user-configured ignorePaths.
|
|
7253
|
+
*/
|
|
7254
|
+
shouldIgnorePath(filePath) {
|
|
7255
|
+
if (!filePath) return false;
|
|
7256
|
+
const userPatterns = this.webhookConfig?.ignorePaths ?? [];
|
|
7257
|
+
const allPatterns = [...DEFAULT_WEBHOOK_IGNORE, ...userPatterns];
|
|
7258
|
+
return allPatterns.some((pattern) => matchGlob(pattern, filePath));
|
|
7259
|
+
}
|
|
7260
|
+
/**
|
|
7261
|
+
* Route a webhook payload through batching (if configured) or send immediately.
|
|
7262
|
+
* When batchWindowMs is set, payloads are queued and deduplicated by file path.
|
|
7263
|
+
*/
|
|
7264
|
+
enqueueOrSendWebhook(payload, sessionId) {
|
|
7265
|
+
const batchWindowMs = this.webhookConfig?.batchWindowMs;
|
|
7266
|
+
if (!batchWindowMs || batchWindowMs <= 0) {
|
|
7267
|
+
this.sendWebhook(payload, sessionId);
|
|
7268
|
+
return;
|
|
7269
|
+
}
|
|
7270
|
+
const filePath = payload.fileSyncEvent?.canonicalPath ?? payload.fileChangeEvent?.relativePath ?? `_unknown_${Date.now()}`;
|
|
7271
|
+
this.batchQueue.set(filePath, payload);
|
|
7272
|
+
if (this.batchTimer) {
|
|
7273
|
+
clearTimeout(this.batchTimer);
|
|
7274
|
+
}
|
|
7275
|
+
this.batchTimer = setTimeout(() => {
|
|
7276
|
+
this.flushWebhookBatch(sessionId);
|
|
7277
|
+
}, batchWindowMs);
|
|
7278
|
+
}
|
|
7279
|
+
/**
|
|
7280
|
+
* Flush all queued webhook payloads as a single batch request.
|
|
7281
|
+
*/
|
|
7282
|
+
async flushWebhookBatch(sessionId) {
|
|
7283
|
+
this.batchTimer = null;
|
|
7284
|
+
if (this.batchQueue.size === 0) return;
|
|
7285
|
+
const payloads = Array.from(this.batchQueue.values());
|
|
7286
|
+
this.batchQueue.clear();
|
|
7287
|
+
const fileSyncEvents = [];
|
|
7288
|
+
const fileChangeEvents = [];
|
|
7289
|
+
let batchSessionId = sessionId ?? "";
|
|
7290
|
+
for (const p of payloads) {
|
|
7291
|
+
if (!batchSessionId) {
|
|
7292
|
+
batchSessionId = p.sessionId;
|
|
7293
|
+
}
|
|
7294
|
+
if (p.fileSyncEvent) {
|
|
7295
|
+
fileSyncEvents.push(p.fileSyncEvent);
|
|
7296
|
+
}
|
|
7297
|
+
if (p.fileChangeEvent) {
|
|
7298
|
+
fileChangeEvents.push(p.fileChangeEvent);
|
|
7299
|
+
}
|
|
7300
|
+
}
|
|
7301
|
+
const batchPayload = {
|
|
7302
|
+
event: "file_sync_batch",
|
|
7303
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7304
|
+
sessionId: batchSessionId,
|
|
7305
|
+
metadata: this.webhookConfig?.metadata,
|
|
7306
|
+
fileSyncEvents,
|
|
7307
|
+
fileChangeEvents
|
|
7308
|
+
};
|
|
7309
|
+
await this.sendWebhook(batchPayload, sessionId);
|
|
6907
7310
|
}
|
|
6908
7311
|
/**
|
|
6909
7312
|
* Extract hostname from URL for display (security - don't expose full URL)
|
|
@@ -7045,6 +7448,9 @@ var init_sandbox_file_sync = __esm({
|
|
|
7045
7448
|
* pre-signed S3 download URL when the file exists in storage.
|
|
7046
7449
|
*/
|
|
7047
7450
|
async sendFileSyncWebhook(sessionId, event) {
|
|
7451
|
+
if (this.shouldIgnorePath(event.canonicalPath)) {
|
|
7452
|
+
return;
|
|
7453
|
+
}
|
|
7048
7454
|
let downloadUrl;
|
|
7049
7455
|
if (event.success && event.canonicalPath && !event.operation.startsWith("deleted")) {
|
|
7050
7456
|
try {
|
|
@@ -7070,12 +7476,15 @@ var init_sandbox_file_sync = __esm({
|
|
|
7070
7476
|
metadata: this.webhookConfig?.metadata,
|
|
7071
7477
|
fileSyncEvent: webhookEvent
|
|
7072
7478
|
};
|
|
7073
|
-
|
|
7479
|
+
this.enqueueOrSendWebhook(payload, sessionId);
|
|
7074
7480
|
}
|
|
7075
7481
|
/**
|
|
7076
7482
|
* Send a file change event webhook (from watcher)
|
|
7077
7483
|
*/
|
|
7078
7484
|
async sendFileChangeWebhook(event) {
|
|
7485
|
+
if (this.shouldIgnorePath(event.relativePath)) {
|
|
7486
|
+
return;
|
|
7487
|
+
}
|
|
7079
7488
|
const payload = {
|
|
7080
7489
|
event: "file_change",
|
|
7081
7490
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -7083,7 +7492,7 @@ var init_sandbox_file_sync = __esm({
|
|
|
7083
7492
|
metadata: this.webhookConfig?.metadata,
|
|
7084
7493
|
fileChangeEvent: event
|
|
7085
7494
|
};
|
|
7086
|
-
|
|
7495
|
+
this.enqueueOrSendWebhook(payload, event.sessionId);
|
|
7087
7496
|
}
|
|
7088
7497
|
/**
|
|
7089
7498
|
* Get the next sequence number for a session
|
|
@@ -7747,6 +8156,11 @@ var init_sandbox_file_sync = __esm({
|
|
|
7747
8156
|
await Promise.all([...inSandboxPromises, ...localPromises]);
|
|
7748
8157
|
this.inSandboxWatchers.clear();
|
|
7749
8158
|
this.localWatchers.clear();
|
|
8159
|
+
if (this.batchTimer) {
|
|
8160
|
+
clearTimeout(this.batchTimer);
|
|
8161
|
+
this.batchTimer = null;
|
|
8162
|
+
await this.flushWebhookBatch();
|
|
8163
|
+
}
|
|
7750
8164
|
}
|
|
7751
8165
|
/**
|
|
7752
8166
|
* Get watching status for all sessions
|
|
@@ -9815,6 +10229,58 @@ function createSessionsRouter(options) {
|
|
|
9815
10229
|
}
|
|
9816
10230
|
});
|
|
9817
10231
|
});
|
|
10232
|
+
router.get("/:sessionId/stream-events", async (c) => {
|
|
10233
|
+
const sessionId = c.req.param("sessionId");
|
|
10234
|
+
const afterSequence = Math.max(0, parseInt(c.req.query("afterSequence") || "0", 10) || 0);
|
|
10235
|
+
const limit = Math.min(Math.max(1, parseInt(c.req.query("limit") || "100", 10) || 100), 1e3);
|
|
10236
|
+
const waitMs = Math.min(Math.max(0, parseInt(c.req.query("waitMs") || "0", 10) || 0), 3e4);
|
|
10237
|
+
const session = await sessionManager.getSession(sessionId);
|
|
10238
|
+
if (!session) {
|
|
10239
|
+
return c.json({ error: "Session not found" }, 404);
|
|
10240
|
+
}
|
|
10241
|
+
const agent = agents2.get(session.agentName);
|
|
10242
|
+
if (!agent) {
|
|
10243
|
+
return c.json({ error: `Agent not found: ${session.agentName}` }, 404);
|
|
10244
|
+
}
|
|
10245
|
+
const streamEventStorage = agent.getStreamEventStorage();
|
|
10246
|
+
if (!streamEventStorage) {
|
|
10247
|
+
return c.json({ error: "Stream event storage not configured" }, 501);
|
|
10248
|
+
}
|
|
10249
|
+
let events = await streamEventStorage.readEvents(sessionId, {
|
|
10250
|
+
afterSequence,
|
|
10251
|
+
limit
|
|
10252
|
+
});
|
|
10253
|
+
if (events.length === 0 && waitMs > 0) {
|
|
10254
|
+
const deadline = Date.now() + waitMs;
|
|
10255
|
+
const pollInterval = 200;
|
|
10256
|
+
while (Date.now() < deadline) {
|
|
10257
|
+
events = await streamEventStorage.readEvents(sessionId, {
|
|
10258
|
+
afterSequence,
|
|
10259
|
+
limit
|
|
10260
|
+
});
|
|
10261
|
+
if (events.length > 0) break;
|
|
10262
|
+
const currentSession = await sessionManager.getSession(sessionId);
|
|
10263
|
+
if (currentSession && ["completed", "error", "stopped"].includes(currentSession.status)) {
|
|
10264
|
+
break;
|
|
10265
|
+
}
|
|
10266
|
+
await new Promise((resolve3) => setTimeout(resolve3, pollInterval));
|
|
10267
|
+
}
|
|
10268
|
+
}
|
|
10269
|
+
const nextCursor = events.length > 0 ? Math.max(...events.map((e) => e.sequence)) : afterSequence;
|
|
10270
|
+
return c.json({
|
|
10271
|
+
events: events.map((e) => ({
|
|
10272
|
+
id: e.id,
|
|
10273
|
+
sequence: e.sequence,
|
|
10274
|
+
eventType: e.eventType,
|
|
10275
|
+
payload: e.payload,
|
|
10276
|
+
batchCount: e.batchCount,
|
|
10277
|
+
createdAt: e.createdAt.toISOString()
|
|
10278
|
+
})),
|
|
10279
|
+
nextCursor,
|
|
10280
|
+
hasMore: events.length === limit,
|
|
10281
|
+
sessionStatus: session.status
|
|
10282
|
+
});
|
|
10283
|
+
});
|
|
9818
10284
|
router.get("/:sessionId/stream", async (c) => {
|
|
9819
10285
|
const sessionId = c.req.param("sessionId");
|
|
9820
10286
|
const afterParam = c.req.query("after");
|
|
@@ -10499,7 +10965,8 @@ function createHarnessServer(config) {
|
|
|
10499
10965
|
basePath = "/api",
|
|
10500
10966
|
middleware = [],
|
|
10501
10967
|
hooks = {},
|
|
10502
|
-
queue: queueConfig = {}
|
|
10968
|
+
queue: queueConfig = {},
|
|
10969
|
+
sandbox: sandboxConfig
|
|
10503
10970
|
} = config;
|
|
10504
10971
|
let agentsNeedReload = false;
|
|
10505
10972
|
const sessionManager = new exports.SessionManager(storage);
|
|
@@ -10650,7 +11117,7 @@ function createHarnessServer(config) {
|
|
|
10650
11117
|
return agentStorage.getActiveAgents();
|
|
10651
11118
|
},
|
|
10652
11119
|
/**
|
|
10653
|
-
* Initialize storage, agents,
|
|
11120
|
+
* Initialize storage, agents, start queue processor, and optionally init sandbox pool
|
|
10654
11121
|
*/
|
|
10655
11122
|
async initialize() {
|
|
10656
11123
|
await storage.initialize();
|
|
@@ -10664,12 +11131,20 @@ function createHarnessServer(config) {
|
|
|
10664
11131
|
await agent.initialize();
|
|
10665
11132
|
}
|
|
10666
11133
|
queueProcessor?.start();
|
|
11134
|
+
if (sandboxConfig?.pool && sandboxConfig.autoInitPool !== false) {
|
|
11135
|
+
try {
|
|
11136
|
+
await initializeSandboxPool(sandboxConfig.pool);
|
|
11137
|
+
} catch (error) {
|
|
11138
|
+
console.error("[SERVER] Failed to initialize sandbox pool:", error instanceof Error ? error.message : error);
|
|
11139
|
+
}
|
|
11140
|
+
}
|
|
10667
11141
|
},
|
|
10668
11142
|
/**
|
|
10669
|
-
* Close storage, agents,
|
|
11143
|
+
* Close storage, agents, stop queue processor, and shutdown sandbox pool
|
|
10670
11144
|
*/
|
|
10671
11145
|
async close() {
|
|
10672
11146
|
queueProcessor?.stop();
|
|
11147
|
+
await shutdownSandboxPool();
|
|
10673
11148
|
for (const agent of agents2.values()) {
|
|
10674
11149
|
await agent.close();
|
|
10675
11150
|
}
|
|
@@ -10691,6 +11166,7 @@ var init_server = __esm({
|
|
|
10691
11166
|
init_agents();
|
|
10692
11167
|
init_skills2();
|
|
10693
11168
|
init_queue2();
|
|
11169
|
+
init_sandbox_pool();
|
|
10694
11170
|
}
|
|
10695
11171
|
});
|
|
10696
11172
|
|
|
@@ -13612,7 +14088,8 @@ function createOpenAPIServer(config) {
|
|
|
13612
14088
|
basePath = "/api",
|
|
13613
14089
|
middleware = [],
|
|
13614
14090
|
hooks = {},
|
|
13615
|
-
docs = {}
|
|
14091
|
+
docs = {},
|
|
14092
|
+
sandbox: sandboxConfig
|
|
13616
14093
|
} = config;
|
|
13617
14094
|
const {
|
|
13618
14095
|
enabled: docsEnabled = true,
|
|
@@ -13787,7 +14264,7 @@ Authentication is handled by the hosting application. This API does not enforce
|
|
|
13787
14264
|
return agentStorage.getActiveAgents();
|
|
13788
14265
|
},
|
|
13789
14266
|
/**
|
|
13790
|
-
* Initialize storage and
|
|
14267
|
+
* Initialize storage, agents, and optionally init sandbox pool
|
|
13791
14268
|
*/
|
|
13792
14269
|
async initialize() {
|
|
13793
14270
|
await storage.initialize();
|
|
@@ -13797,11 +14274,19 @@ Authentication is handled by the hosting application. This API does not enforce
|
|
|
13797
14274
|
for (const agent of agents2.values()) {
|
|
13798
14275
|
await agent.initialize();
|
|
13799
14276
|
}
|
|
14277
|
+
if (sandboxConfig?.pool && sandboxConfig.autoInitPool !== false) {
|
|
14278
|
+
try {
|
|
14279
|
+
await initializeSandboxPool(sandboxConfig.pool);
|
|
14280
|
+
} catch (error) {
|
|
14281
|
+
console.error("[SERVER] Failed to initialize sandbox pool:", error instanceof Error ? error.message : error);
|
|
14282
|
+
}
|
|
14283
|
+
}
|
|
13800
14284
|
},
|
|
13801
14285
|
/**
|
|
13802
|
-
* Close storage and
|
|
14286
|
+
* Close storage, agents, and shutdown sandbox pool
|
|
13803
14287
|
*/
|
|
13804
14288
|
async close() {
|
|
14289
|
+
await shutdownSandboxPool();
|
|
13805
14290
|
for (const agent of agents2.values()) {
|
|
13806
14291
|
await agent.close();
|
|
13807
14292
|
}
|
|
@@ -13833,6 +14318,7 @@ var init_server2 = __esm({
|
|
|
13833
14318
|
init_sessions2();
|
|
13834
14319
|
init_agents2();
|
|
13835
14320
|
init_skills3();
|
|
14321
|
+
init_sandbox_pool();
|
|
13836
14322
|
}
|
|
13837
14323
|
});
|
|
13838
14324
|
|
|
@@ -16597,6 +17083,7 @@ __export(schema_exports, {
|
|
|
16597
17083
|
configDeployments: () => configDeployments,
|
|
16598
17084
|
configDeploymentsRelations: () => configDeploymentsRelations,
|
|
16599
17085
|
eventCategoryEnum: () => eventCategoryEnum,
|
|
17086
|
+
eventSourceEnum: () => eventSourceEnum,
|
|
16600
17087
|
messageRoleEnum: () => messageRoleEnum,
|
|
16601
17088
|
messages: () => messages,
|
|
16602
17089
|
messagesRelations: () => messagesRelations,
|
|
@@ -16610,7 +17097,7 @@ __export(schema_exports, {
|
|
|
16610
17097
|
streamEvents: () => streamEvents,
|
|
16611
17098
|
streamEventsRelations: () => streamEventsRelations
|
|
16612
17099
|
});
|
|
16613
|
-
var sessionStatusEnum, messageRoleEnum, agentStatusEnum, agentBackendEnum, queueItemStatusEnum, configDeploymentStatusEnum, configDeploymentTriggerEnum, eventCategoryEnum, sessions, messages, attachments, agents, queueItems, configDeployments, sessionEvents, streamEvents, sessionsRelations, sessionEventsRelations, messagesRelations, attachmentsRelations, configDeploymentsRelations, streamEventsRelations, agentsRelations;
|
|
17100
|
+
var sessionStatusEnum, messageRoleEnum, agentStatusEnum, agentBackendEnum, queueItemStatusEnum, configDeploymentStatusEnum, configDeploymentTriggerEnum, eventSourceEnum, eventCategoryEnum, sessions, messages, attachments, agents, queueItems, configDeployments, sessionEvents, streamEvents, sessionsRelations, sessionEventsRelations, messagesRelations, attachmentsRelations, configDeploymentsRelations, streamEventsRelations, agentsRelations;
|
|
16614
17101
|
var init_schema = __esm({
|
|
16615
17102
|
"src/storage-postgres/schema.ts"() {
|
|
16616
17103
|
sessionStatusEnum = pgCore.pgEnum("session_status", [
|
|
@@ -16652,6 +17139,14 @@ var init_schema = __esm({
|
|
|
16652
17139
|
"initial",
|
|
16653
17140
|
"rollback"
|
|
16654
17141
|
]);
|
|
17142
|
+
eventSourceEnum = pgCore.pgEnum("event_source", [
|
|
17143
|
+
"agent",
|
|
17144
|
+
// Directly from the agent SDK
|
|
17145
|
+
"system",
|
|
17146
|
+
// Generated by execution layer (lifecycle, user input)
|
|
17147
|
+
"derived"
|
|
17148
|
+
// Transformed/aggregated from agent events
|
|
17149
|
+
]);
|
|
16655
17150
|
eventCategoryEnum = pgCore.pgEnum("event_category", [
|
|
16656
17151
|
"lifecycle",
|
|
16657
17152
|
// session_start, session_end, turn_complete
|
|
@@ -16842,6 +17337,8 @@ var init_schema = __esm({
|
|
|
16842
17337
|
// Aggregation fields (for text_stream events)
|
|
16843
17338
|
isAggregated: pgCore.boolean("is_aggregated").default(false),
|
|
16844
17339
|
aggregatedCount: pgCore.integer("aggregated_count"),
|
|
17340
|
+
// Event source tagging
|
|
17341
|
+
eventSource: eventSourceEnum("event_source").notNull().default("agent"),
|
|
16845
17342
|
// Ordering
|
|
16846
17343
|
sequenceNumber: pgCore.integer("sequence_number").notNull(),
|
|
16847
17344
|
createdAt: pgCore.timestamp("created_at", { withTimezone: true }).defaultNow().notNull()
|
|
@@ -17434,6 +17931,11 @@ var init_storage2 = __esm({
|
|
|
17434
17931
|
drizzleOrm.eq(sessions.status, options.status)
|
|
17435
17932
|
);
|
|
17436
17933
|
}
|
|
17934
|
+
if (options.resourceId) {
|
|
17935
|
+
conditions.push(
|
|
17936
|
+
drizzleOrm.sql`${sessions.metadata}->>'resourceId' = ${options.resourceId}`
|
|
17937
|
+
);
|
|
17938
|
+
}
|
|
17437
17939
|
const orderColumn = options.orderBy === "updatedAt" ? sessions.updatedAt : sessions.createdAt;
|
|
17438
17940
|
const orderFn = options.order === "asc" ? drizzleOrm.asc : drizzleOrm.desc;
|
|
17439
17941
|
const limit = options.limit ?? 50;
|
|
@@ -18155,6 +18657,9 @@ var init_storage3 = __esm({
|
|
|
18155
18657
|
if (options.status) {
|
|
18156
18658
|
query = query.eq("status", options.status);
|
|
18157
18659
|
}
|
|
18660
|
+
if (options.resourceId) {
|
|
18661
|
+
query = query.eq("metadata->>resourceId", options.resourceId);
|
|
18662
|
+
}
|
|
18158
18663
|
const orderColumn = options.orderBy === "updatedAt" ? "updated_at" : "created_at";
|
|
18159
18664
|
const ascending = options.order === "asc";
|
|
18160
18665
|
query = query.order(orderColumn, { ascending }).range(offset, offset + limit - 1);
|
|
@@ -18512,6 +19017,7 @@ var init_storage3 = __esm({
|
|
|
18512
19017
|
sessionId: row.session_id,
|
|
18513
19018
|
eventType: row.event_type,
|
|
18514
19019
|
category: row.category,
|
|
19020
|
+
eventSource: row.event_source,
|
|
18515
19021
|
startedAt: new Date(row.started_at),
|
|
18516
19022
|
endedAt: row.ended_at ? new Date(row.ended_at) : void 0,
|
|
18517
19023
|
durationMs: row.duration_ms ?? void 0,
|
|
@@ -18534,6 +19040,7 @@ var init_storage3 = __esm({
|
|
|
18534
19040
|
session_id: sessionId,
|
|
18535
19041
|
event_type: event.eventType,
|
|
18536
19042
|
category: event.category,
|
|
19043
|
+
event_source: event.eventSource || "agent",
|
|
18537
19044
|
started_at: event.startedAt.toISOString(),
|
|
18538
19045
|
ended_at: event.endedAt?.toISOString() ?? null,
|
|
18539
19046
|
duration_ms: event.durationMs ?? null,
|
|
@@ -18560,6 +19067,9 @@ var init_storage3 = __esm({
|
|
|
18560
19067
|
if (options.eventType) {
|
|
18561
19068
|
query = query.eq("event_type", options.eventType);
|
|
18562
19069
|
}
|
|
19070
|
+
if (options.eventSource) {
|
|
19071
|
+
query = query.eq("event_source", options.eventSource);
|
|
19072
|
+
}
|
|
18563
19073
|
if (options.filePath) {
|
|
18564
19074
|
query = query.or(
|
|
18565
19075
|
`event_data->>filePath.eq.${options.filePath},event_data->>canonicalPath.eq.${options.filePath},and(category.eq.tool,tool_name.in.(Read,Write,Edit),event_data->input->>file_path.eq.${options.filePath})`
|
|
@@ -18896,7 +19406,8 @@ var init_storage4 = __esm({
|
|
|
18896
19406
|
limit: options?.limit,
|
|
18897
19407
|
offset: options?.offset,
|
|
18898
19408
|
agentName: options?.agentName,
|
|
18899
|
-
status: options?.status
|
|
19409
|
+
status: options?.status,
|
|
19410
|
+
resourceId: options?.resourceId
|
|
18900
19411
|
}
|
|
18901
19412
|
}
|
|
18902
19413
|
);
|
|
@@ -19642,6 +20153,7 @@ exports.loadWorkspaceState = loadWorkspaceState;
|
|
|
19642
20153
|
exports.mapClaudeOptionsToGemini = mapClaudeOptionsToGemini;
|
|
19643
20154
|
exports.mapToolToActionType = mapToolToActionType;
|
|
19644
20155
|
exports.markConfigInstalled = markConfigInstalled;
|
|
20156
|
+
exports.markInstallScriptRan = markInstallScriptRan;
|
|
19645
20157
|
exports.markSdkInstalled = markSdkInstalled;
|
|
19646
20158
|
exports.markStartupScriptRan = markStartupScriptRan;
|
|
19647
20159
|
exports.mcpAuthToHeaders = mcpAuthToHeaders;
|
|
@@ -19669,6 +20181,7 @@ exports.sseMcpWithAuth = sseMcpWithAuth;
|
|
|
19669
20181
|
exports.startServer = startServer;
|
|
19670
20182
|
exports.streamEventRelay = streamEventRelay;
|
|
19671
20183
|
exports.updateToolCallWithResult = updateToolCallWithResult;
|
|
20184
|
+
exports.warmSandboxForSession = warmSandboxForSession;
|
|
19672
20185
|
exports.writeFileToSandbox = writeFileToSandbox;
|
|
19673
20186
|
//# sourceMappingURL=index.cjs.map
|
|
19674
20187
|
//# sourceMappingURL=index.cjs.map
|