@sandboxrouter/sdk 0.6.0 → 0.7.0
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 +9 -9
- package/dist/cli.js +23 -10
- package/dist/router.d.ts +18 -0
- package/dist/router.js +22 -3
- package/dist/verified.js +8 -8
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -44,8 +44,8 @@ List price while running, 2 vCPU / 4 GB, cheapest first; waitlisted sign-ups fol
|
|
|
44
44
|
|---|---|---|---|---|
|
|
45
45
|
| [Agent37](https://sandboxrouter.vercel.app/providers/agent37) | $0.007 | none | passed (2026-11-11) | [pricing](https://www.agent37.com/docs/agents-api/billing) |
|
|
46
46
|
| [Boat](https://sandboxrouter.vercel.app/providers/boat) | $0.018 | $20/mo (credited) | not run yet | [pricing](https://docs.boat.dev/pricing.md) |
|
|
47
|
-
| [Maritime](https://sandboxrouter.vercel.app/providers/maritime) | $0.022 | $20/mo (credited) | passed (2026-11-
|
|
48
|
-
| [Sailboxes (Sail Research)](https://sandboxrouter.vercel.app/providers/sail) | up to $0.062 | none | passed (2026-11-
|
|
47
|
+
| [Maritime](https://sandboxrouter.vercel.app/providers/maritime) | $0.022 | $20/mo (credited) | passed (2026-11-13) | [pricing](https://maritime.sh/pricing) |
|
|
48
|
+
| [Sailboxes (Sail Research)](https://sandboxrouter.vercel.app/providers/sail) | up to $0.062 | none | passed (2026-11-13) | [pricing](https://docs.sailresearch.com/sailboxes-pricing.md) |
|
|
49
49
|
| [Northflank](https://sandboxrouter.vercel.app/providers/northflank) | $0.067 | none | not run yet | [pricing](https://northflank.com/pricing) |
|
|
50
50
|
| [Morph Cloud](https://sandboxrouter.vercel.app/providers/morph) | $0.100 | none | not run yet | [pricing](https://cloud.morph.so/web/pricing) |
|
|
51
51
|
| [exe.dev](https://sandboxrouter.vercel.app/providers/exedev) | $0.105 | $15/mo | not run yet | [pricing](https://exe.dev/docs/standalone-vms.md) |
|
|
@@ -54,15 +54,15 @@ List price while running, 2 vCPU / 4 GB, cheapest first; waitlisted sign-ups fol
|
|
|
54
54
|
| [Beam](https://sandboxrouter.vercel.app/providers/beam) | $0.140 | $20/mo (credited) | not run yet | [pricing](https://www.beam.cloud/pricing) |
|
|
55
55
|
| [CodeSandbox SDK (Together)](https://sandboxrouter.vercel.app/providers/codesandbox) | $0.149 | none | not run yet | [pricing](https://docs.together.ai/docs/together-code-sandbox-legacy) |
|
|
56
56
|
| [Fly.io Sprites](https://sandboxrouter.vercel.app/providers/sprites) | up to $0.164 | none | passed (2026-11-11) | [pricing](https://fly.io/sprites) |
|
|
57
|
-
| [Blaxel](https://sandboxrouter.vercel.app/providers/blaxel) | $0.166 | none | passed (2026-11-
|
|
57
|
+
| [Blaxel](https://sandboxrouter.vercel.app/providers/blaxel) | $0.166 | none | passed (2026-11-13) | [pricing](https://blaxel.ai/pricing) |
|
|
58
58
|
| [HOPX](https://sandboxrouter.vercel.app/providers/hopx) | $0.166 | none | not run yet | [pricing](https://hopx.ai/pricing) |
|
|
59
59
|
| [Superserve](https://sandboxrouter.vercel.app/providers/superserve) | $0.166 | maybe $20/mo (credited) | passed (2026-11-11) | [pricing](https://superserve.ai/pricing) |
|
|
60
60
|
| [Tensorlake](https://sandboxrouter.vercel.app/providers/tensorlake) | up to $0.200 | none | not run yet | [pricing](https://www.tensorlake.ai/pricing) |
|
|
61
61
|
| [Upstash Box](https://sandboxrouter.vercel.app/providers/upstash) | up to $0.200 | none | not run yet | [pricing](https://upstash.com/pricing/box) |
|
|
62
62
|
| [Cloudflare Sandbox](https://sandboxrouter.vercel.app/providers/cloudflare) | up to $0.216 | $5/mo | passed (2026-11-11) | [pricing](https://developers.cloudflare.com/containers/platform/pricing/) |
|
|
63
|
-
| [Amazon Bedrock AgentCore Code Interpreter](https://sandboxrouter.vercel.app/providers/agentcore) | up to $0.217 | none | passed (2026-11-
|
|
63
|
+
| [Amazon Bedrock AgentCore Code Interpreter](https://sandboxrouter.vercel.app/providers/agentcore) | up to $0.217 | none | passed (2026-11-13) | [pricing](https://aws.amazon.com/bedrock/agentcore/pricing/) |
|
|
64
64
|
| [Modal](https://sandboxrouter.vercel.app/providers/modal) | up to $0.238 | none | passed (2026-11-11) | [pricing](https://modal.com/pricing) |
|
|
65
|
-
| [AWS Lambda MicroVMs](https://sandboxrouter.vercel.app/providers/lambda) | $0.252 | none | passed (2026-11-
|
|
65
|
+
| [AWS Lambda MicroVMs](https://sandboxrouter.vercel.app/providers/lambda) | $0.252 | none | passed (2026-11-13) | [pricing](https://aws.amazon.com/lambda/pricing/) |
|
|
66
66
|
| [Deno Sandbox](https://sandboxrouter.vercel.app/providers/deno) | up to $0.300 | $20/mo | not run yet | [pricing](https://deno.com/sandbox) |
|
|
67
67
|
| [Runloop](https://sandboxrouter.vercel.app/providers/runloop) | $0.317 | none | not run yet | [pricing](https://www.runloop.ai/pricing) |
|
|
68
68
|
| [Vercel Sandbox](https://sandboxrouter.vercel.app/providers/vercel) | up to $0.341 | none | passed (2026-11-11) | [pricing](https://vercel.com/docs/vercel-sandbox/pricing) |
|
|
@@ -70,12 +70,12 @@ List price while running, 2 vCPU / 4 GB, cheapest first; waitlisted sign-ups fol
|
|
|
70
70
|
| [Koyeb Sandboxes (not taking new accounts)](https://sandboxrouter.vercel.app/providers/koyeb) | $0.058 | $29/mo | not run yet | [pricing](https://www.koyeb.com/docs/reference/instances) |
|
|
71
71
|
| [Dedalus Machines (sign-up waitlisted)](https://sandboxrouter.vercel.app/providers/dedalus) | $0.149 | none | not run yet | [pricing](https://docs.dedaluslabs.ai/dcs/dm/pricing) |
|
|
72
72
|
| [LangSmith Sandboxes (sign-up waitlisted)](https://sandboxrouter.vercel.app/providers/langsmith) | $0.189 | none | not run yet | [pricing](https://www.langchain.com/pricing) |
|
|
73
|
-
| [OpenScale Sandboxes](https://sandboxrouter.vercel.app/providers/openscale) | skipped (default image is 2 vCPU / 1 GB; a bigger size needs image.openscale) | none | passed (2026-11-
|
|
73
|
+
| [OpenScale Sandboxes](https://sandboxrouter.vercel.app/providers/openscale) | skipped (default image is 2 vCPU / 1 GB; a bigger size needs image.openscale) | none | passed (2026-11-13) | [pricing](https://openscale.so/sandboxes) |
|
|
74
74
|
| [Azure Container Apps dynamic sessions](https://sandboxrouter.vercel.app/providers/azure) | skipped (max 1 vCPU) | none | not run yet | [pricing](https://learn.microsoft.com/en-us/azure/container-apps/billing#dynamic-sessions) |
|
|
75
|
-
| [Daytona](https://sandboxrouter.vercel.app/providers/daytona) | skipped (default image is 1 vCPU / 1 GB; a bigger size needs image.daytona) | none | passed (2026-11-
|
|
75
|
+
| [Daytona](https://sandboxrouter.vercel.app/providers/daytona) | skipped (default image is 1 vCPU / 1 GB; a bigger size needs image.daytona) | none | passed (2026-11-13) | [pricing](https://www.daytona.io/pricing) |
|
|
76
76
|
| [Alibaba Cloud Agent Sandbox](https://sandboxrouter.vercel.app/providers/alibaba) | skipped (max 2 GB memory) | none | not run yet | [pricing](https://www.alibabacloud.com/help/en/agent-sandbox/product-overview/billing-overview) |
|
|
77
|
-
| [E2B](https://sandboxrouter.vercel.app/providers/e2b) | skipped (default image is 2 vCPU / 0.5 GB; a bigger size needs image.e2b) | none | passed (2026-11-
|
|
78
|
-
| [Docker (local)](https://sandboxrouter.vercel.app/providers/docker) | free | none | passed (2026-11-
|
|
77
|
+
| [E2B](https://sandboxrouter.vercel.app/providers/e2b) | skipped (default image is 2 vCPU / 0.5 GB; a bigger size needs image.e2b) | none | passed (2026-11-13) | [pricing](https://e2b.dev/pricing) |
|
|
78
|
+
| [Docker (local)](https://sandboxrouter.vercel.app/providers/docker) | free | none | passed (2026-11-13) | [pricing](https://docs.docker.com/engine/) |
|
|
79
79
|
|
|
80
80
|
Checked 2026-11-04 to 2026-11-06.
|
|
81
81
|
|
package/dist/cli.js
CHANGED
|
@@ -18,10 +18,12 @@ Usage:
|
|
|
18
18
|
sandboxrouter providers [--vcpu N] [--memory GB] price table + which keys are set
|
|
19
19
|
sandboxrouter route [spec flags] [route flags] dry run: the order providers would be tried
|
|
20
20
|
sandboxrouter run "<cmd>" [spec flags] [route flags] [--keep]
|
|
21
|
-
sandboxrouter check --provider ID[,ID] | --all [--json] [--save [dir]] [--by GITHUB_USER]
|
|
21
|
+
sandboxrouter check --provider ID[,ID] | --all [--json] [--save [dir]] [--retry] [--out FILE] [--by GITHUB_USER]
|
|
22
22
|
test providers for real: exec, env, UTF-8, streaming, files, timeout, pause,
|
|
23
23
|
kill; exits 1 if any step fails. --all = every configured provider;
|
|
24
|
-
--save writes results/conformance/<id>.json for the compatibility table
|
|
24
|
+
--save writes results/conformance/<id>.json for the compatibility table;
|
|
25
|
+
--retry runs a failed provider once more and keeps that result;
|
|
26
|
+
--out writes every report as JSON (with the first try's failure, if retried)
|
|
25
27
|
sandboxrouter ls [--json] sandboxes this machine started that weren't killed
|
|
26
28
|
sandboxrouter gc [--all | --older-than MIN] [--dry-run]
|
|
27
29
|
kill leaked sandboxes: by default those past their lifetime
|
|
@@ -73,6 +75,7 @@ const { values, positionals } = parseArgs({
|
|
|
73
75
|
label: { type: "string" },
|
|
74
76
|
all: { type: "boolean" },
|
|
75
77
|
save: { type: "boolean" },
|
|
78
|
+
retry: { type: "boolean" },
|
|
76
79
|
"older-than": { type: "string" },
|
|
77
80
|
"dry-run": { type: "boolean" },
|
|
78
81
|
minutes: { type: "string" },
|
|
@@ -208,16 +211,23 @@ async function main() {
|
|
|
208
211
|
const saveDir = values.save ? (rest[0] ?? "results/conformance") : undefined;
|
|
209
212
|
const mark = { pass: "ok ", fail: "FAIL", skip: "skip", info: "note" };
|
|
210
213
|
const reports = [];
|
|
214
|
+
const run = (p) => checkProvider(router, p, {
|
|
215
|
+
spec,
|
|
216
|
+
onStep: (r) => {
|
|
217
|
+
if (!values.json)
|
|
218
|
+
console.log(` ${mark[r.status]} ${r.step.padEnd(32)} ${String(r.ms).padStart(6)} ms ${r.detail ?? ""}`);
|
|
219
|
+
},
|
|
220
|
+
});
|
|
211
221
|
for (const p of ids) {
|
|
212
222
|
if (!values.json)
|
|
213
223
|
console.log(`\n${p}`);
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
}
|
|
220
|
-
}
|
|
224
|
+
let report = await run(p);
|
|
225
|
+
if (values.retry && !report.ok && !report.inconclusive) {
|
|
226
|
+
const failed = report.results.find((r) => r.status === "fail");
|
|
227
|
+
if (!values.json)
|
|
228
|
+
console.log(` failed; trying ${p} once more`);
|
|
229
|
+
report = { ...(await run(p)), firstTry: failed ? `${failed.step}: ${failed.detail ?? "failed"}` : "failed" };
|
|
230
|
+
}
|
|
221
231
|
reports.push(report);
|
|
222
232
|
if (report.inconclusive) {
|
|
223
233
|
if (!values.json)
|
|
@@ -226,10 +236,13 @@ async function main() {
|
|
|
226
236
|
}
|
|
227
237
|
if (saveDir) {
|
|
228
238
|
mkdirSync(saveDir, { recursive: true });
|
|
229
|
-
const
|
|
239
|
+
const { firstTry: _, ...result } = report;
|
|
240
|
+
const saved = publishableCheck({ tool: "sandboxrouter-check", version, date: new Date().toISOString(), platform: `${platform()}-${arch()}`, ...(by ? { by } : {}), ...result });
|
|
230
241
|
writeFileSync(`${saveDir}/${p}.json`, JSON.stringify(saved, null, 2) + "\n");
|
|
231
242
|
}
|
|
232
243
|
}
|
|
244
|
+
if (values.out)
|
|
245
|
+
writeFileSync(values.out, JSON.stringify(reports, null, 2) + "\n");
|
|
233
246
|
if (values.json)
|
|
234
247
|
console.log(JSON.stringify(reports, null, 2));
|
|
235
248
|
else {
|
package/dist/router.d.ts
CHANGED
|
@@ -63,6 +63,18 @@ export interface RouterOptions {
|
|
|
63
63
|
requireVerified?: boolean;
|
|
64
64
|
/** Billed / list-price ratio per provider, behind `estimatedHourlyUsd`. Default: the ratios in `BILLED_VS_LIST`, from saved cost runs. */
|
|
65
65
|
billedVsList?: Partial<Record<ProviderId, number>>;
|
|
66
|
+
/**
|
|
67
|
+
* When a create runs well past a provider's usual start time, try the next provider sooner than
|
|
68
|
+
* `createTimeoutSeconds`. The wait becomes `factor` x the provider's median start time (or 1.5x the
|
|
69
|
+
* slowest of its recent starts, if longer), at least `minSeconds`. It applies only when the caller
|
|
70
|
+
* didn't set `createTimeoutSeconds`, the router has a start time for the provider (3 of its own creates,
|
|
71
|
+
* or the bench file), and another provider is left to try. Default `{ factor: 5, minSeconds: 10 }`;
|
|
72
|
+
* `false` always waits the full `createTimeoutSeconds`.
|
|
73
|
+
*/
|
|
74
|
+
quickFallback?: false | {
|
|
75
|
+
factor?: number;
|
|
76
|
+
minSeconds?: number;
|
|
77
|
+
};
|
|
66
78
|
}
|
|
67
79
|
/** Desktop-only providers. Filled in as adapters are added. */
|
|
68
80
|
export declare function defaultComputerProviders(): ComputerProvider[];
|
|
@@ -77,6 +89,7 @@ export declare class Router {
|
|
|
77
89
|
/** Create times this router measured, most recent last. */
|
|
78
90
|
private readonly live;
|
|
79
91
|
private computerOnly;
|
|
92
|
+
private readonly quick;
|
|
80
93
|
/** The local record of sandboxes this router created, or undefined when turned off. */
|
|
81
94
|
readonly ledger?: Ledger;
|
|
82
95
|
constructor(opts?: RouterOptions);
|
|
@@ -94,6 +107,11 @@ export declare class Router {
|
|
|
94
107
|
private whyNone;
|
|
95
108
|
/** Start a sandbox on the best available provider, falling back down the list on failure. */
|
|
96
109
|
create(spec?: SandboxSpec, route?: RouteOptions): Promise<RoutedSandbox>;
|
|
110
|
+
/**
|
|
111
|
+
* Seconds to wait for this provider's create: the caller's `createTimeoutSeconds`, or (see
|
|
112
|
+
* `quickFallback`) a few times its usual start time when another provider is left to try.
|
|
113
|
+
*/
|
|
114
|
+
private waitFor;
|
|
97
115
|
/** Remember a successful create's time, for the speed tie-break and strategy "fastest". */
|
|
98
116
|
private observe;
|
|
99
117
|
private record;
|
package/dist/router.js
CHANGED
|
@@ -103,6 +103,7 @@ export class Router {
|
|
|
103
103
|
/** Create times this router measured, most recent last. */
|
|
104
104
|
live = new Map();
|
|
105
105
|
computerOnly;
|
|
106
|
+
quick;
|
|
106
107
|
/** The local record of sandboxes this router created, or undefined when turned off. */
|
|
107
108
|
ledger;
|
|
108
109
|
constructor(opts = {}) {
|
|
@@ -117,6 +118,7 @@ export class Router {
|
|
|
117
118
|
this.billed =
|
|
118
119
|
opts.billedVsList ?? Object.fromEntries(Object.entries(BILLED_VS_LIST).map(([id, b]) => [id, b.ratio]));
|
|
119
120
|
this.computerOnly = opts.computers ?? (opts.providers ? [] : defaultComputerProviders());
|
|
121
|
+
this.quick = opts.quickFallback === false ? false : { factor: 5, minSeconds: 10, ...opts.quickFallback };
|
|
120
122
|
}
|
|
121
123
|
/** Registered and has credentials. False for providers this router doesn't know. */
|
|
122
124
|
isConfigured(id) {
|
|
@@ -233,22 +235,23 @@ export class Router {
|
|
|
233
235
|
}
|
|
234
236
|
const attempts = [];
|
|
235
237
|
const tries = route.fallback === false ? usable.slice(0, 1) : usable;
|
|
236
|
-
const limitS = route.createTimeoutSeconds ?? DEFAULT_CREATE_TIMEOUT_S;
|
|
237
238
|
const deadline = Date.now() + (route.deadlineSeconds ?? DEFAULT_CREATE_DEADLINE_S) * 1000;
|
|
238
|
-
for (const c of tries) {
|
|
239
|
+
for (const [i, c] of tries.entries()) {
|
|
239
240
|
const left = deadline - Date.now();
|
|
240
241
|
if (left <= 0) {
|
|
241
242
|
throw new RouterError(`create ran out of time (deadlineSeconds) after trying ${attempts.map((a) => a.provider).join(", ")}: ${attempts.map((a) => `${a.provider}: ${a.error}`).join(" | ")}`, attempts, "timeout");
|
|
242
243
|
}
|
|
243
244
|
const t0 = Date.now();
|
|
244
245
|
const pending = this.provider(c.provider).create(spec);
|
|
246
|
+
const { limitS, typicalMs } = this.waitFor(c.provider, route, i === tries.length - 1);
|
|
245
247
|
const waitS = Math.min(limitS, left / 1000);
|
|
246
248
|
const price = { estimatedHourlyUsd: c.estimatedHourlyUsd, listHourlyUsd: c.listHourlyUsd, size: c.size };
|
|
247
249
|
let timedOut = false;
|
|
248
250
|
try {
|
|
249
251
|
const box = await withDeadline(pending, waitS * 1000, () => {
|
|
250
252
|
timedOut = true;
|
|
251
|
-
|
|
253
|
+
const usual = typicalMs !== undefined && waitS < (route.createTimeoutSeconds ?? DEFAULT_CREATE_TIMEOUT_S) ? `; it usually starts in ${Number((typicalMs / 1000).toFixed(1))}s` : "";
|
|
254
|
+
return new ProviderError(c.provider, `create timed out after ${Number(waitS.toFixed(1))}s${usual}`);
|
|
252
255
|
});
|
|
253
256
|
attempts.push({ provider: c.provider, ok: true, ms: Date.now() - t0 });
|
|
254
257
|
this.observe(c.provider, Date.now() - t0);
|
|
@@ -273,6 +276,22 @@ export class Router {
|
|
|
273
276
|
}
|
|
274
277
|
throw new RouterError(`all providers failed: ${attempts.map((a) => `${a.provider}: ${a.error}`).join(" | ")}`, attempts, "all_failed");
|
|
275
278
|
}
|
|
279
|
+
/**
|
|
280
|
+
* Seconds to wait for this provider's create: the caller's `createTimeoutSeconds`, or (see
|
|
281
|
+
* `quickFallback`) a few times its usual start time when another provider is left to try.
|
|
282
|
+
*/
|
|
283
|
+
waitFor(id, route, last) {
|
|
284
|
+
const full = route.createTimeoutSeconds ?? DEFAULT_CREATE_TIMEOUT_S;
|
|
285
|
+
if (!this.quick || last || route.createTimeoutSeconds !== undefined)
|
|
286
|
+
return { limitS: full };
|
|
287
|
+
const live = this.live.get(id);
|
|
288
|
+
const samples = live && live.length >= LIVE_MIN_SAMPLES ? live : loadBench(this.benchFile)[id]?.createMs;
|
|
289
|
+
const typicalMs = median(samples);
|
|
290
|
+
if (typicalMs === undefined || !samples?.length)
|
|
291
|
+
return { limitS: full };
|
|
292
|
+
const s = Math.max(this.quick.factor * typicalMs, 1.5 * Math.max(...samples)) / 1000;
|
|
293
|
+
return { limitS: Math.min(full, Math.max(this.quick.minSeconds, s)), typicalMs };
|
|
294
|
+
}
|
|
276
295
|
/** Remember a successful create's time, for the speed tie-break and strategy "fastest". */
|
|
277
296
|
observe(id, ms) {
|
|
278
297
|
const xs = this.live.get(id) ?? [];
|
package/dist/verified.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
export const VERIFIED = {
|
|
2
2
|
agent37: "2026-11-11",
|
|
3
|
-
agentcore: "2026-11-
|
|
4
|
-
lambda: "2026-11-
|
|
5
|
-
blaxel: "2026-11-
|
|
3
|
+
agentcore: "2026-11-13",
|
|
4
|
+
lambda: "2026-11-13",
|
|
5
|
+
blaxel: "2026-11-13",
|
|
6
6
|
cloudflare: "2026-11-11",
|
|
7
|
-
daytona: "2026-11-
|
|
8
|
-
e2b: "2026-11-
|
|
7
|
+
daytona: "2026-11-13",
|
|
8
|
+
e2b: "2026-11-13",
|
|
9
9
|
sprites: "2026-11-11",
|
|
10
10
|
freestyle: "2026-11-11",
|
|
11
|
-
maritime: "2026-11-
|
|
11
|
+
maritime: "2026-11-13",
|
|
12
12
|
modal: "2026-11-11",
|
|
13
13
|
novita: "2026-11-11",
|
|
14
|
-
openscale: "2026-11-
|
|
15
|
-
sail: "2026-11-
|
|
14
|
+
openscale: "2026-11-13",
|
|
15
|
+
sail: "2026-11-13",
|
|
16
16
|
superserve: "2026-11-11",
|
|
17
17
|
vercel: "2026-11-11",
|
|
18
18
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sandboxrouter/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "One API for every sandbox provider: route AI agents' code by price, speed or capability, with automatic fallback. Free and open source.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -175,7 +175,7 @@
|
|
|
175
175
|
"@aws-sdk/client-appstream": "^3.1162.0",
|
|
176
176
|
"@aws-sdk/credential-provider-node": "^3.972.93",
|
|
177
177
|
"@blaxel/core": "^0.3.34",
|
|
178
|
-
"@daytonaio/sdk": "^0.
|
|
178
|
+
"@daytonaio/sdk": "^0.230.0",
|
|
179
179
|
"@e2b/desktop": "^2.5.0",
|
|
180
180
|
"@fly/sprites": "^0.2.4",
|
|
181
181
|
"@hopx-ai/sdk": "^0.5.1",
|