experimental-ash 0.3.0-alpha.37 → 0.3.0-alpha.38
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/docs/public/sandbox.md +87 -49
- package/dist/src/chunks/{chunk-2R4UWV4G.js → chunk-5BOA7PVK.js} +2 -2
- package/dist/src/chunks/{chunk-XQMYWUU7.js → chunk-IKHNAPQA.js} +166 -92
- package/dist/src/chunks/{chunk-XQMYWUU7.js.map → chunk-IKHNAPQA.js.map} +2 -2
- package/dist/src/chunks/{chunk-XZHB5N7B.js → chunk-W3JJ5DZF.js} +6 -6
- package/dist/src/chunks/{chunk-XZHB5N7B.js.map → chunk-W3JJ5DZF.js.map} +2 -2
- package/dist/src/chunks/{dev-authored-source-watcher-Y56KM4VR.js → dev-authored-source-watcher-AQSC6QOJ.js} +3 -3
- package/dist/src/chunks/{host-VLLCUGVL.js → host-G4LSBCND.js} +4 -4
- package/dist/src/cli/commands/info.js +1 -1
- package/dist/src/cli/run.js +2 -2
- package/dist/src/compiler/model-catalog.d.ts +33 -0
- package/dist/src/compiler/model-catalog.d.ts.map +1 -1
- package/dist/src/compiler/model-catalog.js +96 -72
- package/dist/src/compiler/model-catalog.js.map +1 -1
- package/dist/src/compiler/normalize-agent-config.js +13 -2
- package/dist/src/compiler/normalize-agent-config.js.map +1 -1
- package/dist/src/evals/cli/eval.js +3 -3
- package/dist/src/execution/sandbox/bindings/local.js +4 -2
- package/dist/src/execution/sandbox/bindings/local.js.map +1 -1
- package/dist/src/execution/sandbox/bindings/vercel.d.ts +4 -4
- package/dist/src/execution/sandbox/bindings/vercel.d.ts.map +1 -1
- package/dist/src/execution/sandbox/bindings/vercel.js +51 -5
- package/dist/src/execution/sandbox/bindings/vercel.js.map +1 -1
- package/dist/src/execution/sandbox/ensure.d.ts.map +1 -1
- package/dist/src/execution/sandbox/ensure.js +2 -4
- package/dist/src/execution/sandbox/ensure.js.map +1 -1
- package/dist/src/execution/sandbox/prewarm.d.ts.map +1 -1
- package/dist/src/execution/sandbox/prewarm.js +2 -2
- package/dist/src/execution/sandbox/prewarm.js.map +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/public/definitions/sandbox-backend.d.ts +7 -6
- package/dist/src/public/definitions/sandbox-backend.d.ts.map +1 -1
- package/dist/src/public/definitions/sandbox.d.ts +29 -9
- package/dist/src/public/definitions/sandbox.d.ts.map +1 -1
- package/dist/src/public/definitions/sandbox.js.map +1 -1
- package/dist/src/public/sandbox/backends/vercel.d.ts +6 -5
- package/dist/src/public/sandbox/backends/vercel.d.ts.map +1 -1
- package/dist/src/public/sandbox/backends/vercel.js +7 -6
- package/dist/src/public/sandbox/backends/vercel.js.map +1 -1
- package/dist/src/public/sandbox/index.d.ts +2 -1
- package/dist/src/public/sandbox/index.d.ts.map +1 -1
- package/dist/src/public/sandbox/index.js.map +1 -1
- package/dist/src/public/sandbox/vercel-sandbox.d.ts +32 -0
- package/dist/src/public/sandbox/vercel-sandbox.d.ts.map +1 -0
- package/dist/src/public/sandbox/vercel-sandbox.js +2 -0
- package/dist/src/public/sandbox/vercel-sandbox.js.map +1 -0
- package/dist/src/public/sandboxes/vercel-sandbox.d.ts +42 -0
- package/dist/src/public/sandboxes/vercel-sandbox.d.ts.map +1 -0
- package/dist/src/public/sandboxes/vercel-sandbox.js +2 -0
- package/dist/src/public/sandboxes/vercel-sandbox.js.map +1 -0
- package/dist/src/runtime/types.d.ts +3 -3
- package/dist/src/runtime/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/src/compiler/rich-model-catalog.d.ts +0 -40
- package/dist/src/compiler/rich-model-catalog.d.ts.map +0 -1
- package/dist/src/compiler/rich-model-catalog.js +0 -66
- package/dist/src/compiler/rich-model-catalog.js.map +0 -1
- /package/dist/src/chunks/{chunk-2R4UWV4G.js.map → chunk-5BOA7PVK.js.map} +0 -0
- /package/dist/src/chunks/{dev-authored-source-watcher-Y56KM4VR.js.map → dev-authored-source-watcher-AQSC6QOJ.js.map} +0 -0
- /package/dist/src/chunks/{host-VLLCUGVL.js.map → host-G4LSBCND.js.map} +0 -0
|
@@ -21,7 +21,7 @@ If you never author a sandbox override, the framework default is what you get.
|
|
|
21
21
|
|
|
22
22
|
## Overriding The Sandbox
|
|
23
23
|
|
|
24
|
-
To customize the sandbox — to add
|
|
24
|
+
To customize the sandbox — to add bootstrap commands or per-session setup —
|
|
25
25
|
author a sandbox definition module:
|
|
26
26
|
|
|
27
27
|
```ts
|
|
@@ -29,7 +29,8 @@ author a sandbox definition module:
|
|
|
29
29
|
import { defineSandbox } from "experimental-ash/sandbox";
|
|
30
30
|
|
|
31
31
|
export default defineSandbox({
|
|
32
|
-
async bootstrap({
|
|
32
|
+
async bootstrap({ use }) {
|
|
33
|
+
const sandbox = await use();
|
|
33
34
|
await sandbox.runCommand("apt-get install -y jq");
|
|
34
35
|
},
|
|
35
36
|
});
|
|
@@ -49,8 +50,10 @@ When both are present, the folder layout wins and the top-level shorthand is ign
|
|
|
49
50
|
|
|
50
51
|
The public lifecycle surface is intentionally small:
|
|
51
52
|
|
|
52
|
-
- `bootstrap` — template-scoped setup (runs once when the template is built)
|
|
53
|
-
|
|
53
|
+
- `bootstrap({ use })` — template-scoped setup (runs once when the template is built). Call `use()`
|
|
54
|
+
to get a `SandboxSession` for filesystem setup. Only filesystem state survives snapshotting.
|
|
55
|
+
- `onSession({ use })` — durable-session-scoped setup (runs once per session). Call `use(opts?)` to
|
|
56
|
+
get the backend-specific sandbox (e.g. `VercelSandbox`) with session-level configuration applied.
|
|
54
57
|
- `sandbox.resolvePath(path)` — translate a logical `/workspace/...` path into the live filesystem
|
|
55
58
|
- `sandbox.runCommand(command)` — run a shell command inside the sandbox
|
|
56
59
|
|
|
@@ -182,6 +185,9 @@ Inside a subagent's authored code, `getSandbox()` binds to the subagent's own sa
|
|
|
182
185
|
- installing dependencies
|
|
183
186
|
- seeding files or directories every later session should start with
|
|
184
187
|
|
|
188
|
+
Call `use()` to get a `SandboxSession`. Only filesystem state survives — configuration changes
|
|
189
|
+
like network policy or resource allocation do not persist into the snapshot.
|
|
190
|
+
|
|
185
191
|
Framework-managed seed files (compiled skills, authored `workspace/` entries) are written into the
|
|
186
192
|
template before the authored `bootstrap` runs, so your bootstrap can read them.
|
|
187
193
|
|
|
@@ -189,10 +195,14 @@ template before the authored `bootstrap` runs, so your bootstrap can read them.
|
|
|
189
195
|
|
|
190
196
|
`onSession` is durable-session-scoped. Use it for one-time setup for the current Ash session:
|
|
191
197
|
|
|
198
|
+
- configuring network policy, resources, or timeout
|
|
192
199
|
- creating a session-specific working copy
|
|
193
200
|
- configuring per-user credentials for CLI tools
|
|
194
201
|
- writing one-time markers
|
|
195
|
-
|
|
202
|
+
|
|
203
|
+
Call `use(opts?)` to get the backend-specific sandbox. When using `vercelBackend()`, this returns
|
|
204
|
+
a `VercelSandbox` with `update()` for session-level configuration. Options passed to `use()` are
|
|
205
|
+
applied immediately; you can call `sandbox.update()` again later if needed.
|
|
196
206
|
|
|
197
207
|
Unlike `bootstrap`, `onSession` runs inside the active Ash runtime context, so user-scoped setup can
|
|
198
208
|
call `getSession()` and derive the current principal without baking credentials into the reusable
|
|
@@ -200,10 +210,12 @@ template:
|
|
|
200
210
|
|
|
201
211
|
```ts
|
|
202
212
|
import { getSession } from "experimental-ash/context";
|
|
203
|
-
import { defineSandbox } from "experimental-ash/sandbox";
|
|
213
|
+
import { defineSandbox, vercelBackend } from "experimental-ash/sandbox";
|
|
204
214
|
|
|
205
215
|
export default defineSandbox({
|
|
206
|
-
|
|
216
|
+
backend: vercelBackend(),
|
|
217
|
+
async onSession({ use }) {
|
|
218
|
+
const sandbox = await use({ networkPolicy: "deny-all" });
|
|
207
219
|
const user = getSession().auth.current;
|
|
208
220
|
if (user === null) return;
|
|
209
221
|
|
|
@@ -219,7 +231,8 @@ export default defineSandbox({
|
|
|
219
231
|
|
|
220
232
|
Ash ships two built-in backends, exposed as factory functions from `experimental-ash/sandbox`:
|
|
221
233
|
|
|
222
|
-
- `vercelBackend(
|
|
234
|
+
- `vercelBackend()` — runs the sandbox on Vercel Sandbox via `@vercel/sandbox`. Returns a
|
|
235
|
+
`VercelSandbox` from `onSession`'s `use()` with full SDK capabilities.
|
|
223
236
|
- `localBackend()` — runs the sandbox locally via `just-bash`. Default for `pnpm ash dev`.
|
|
224
237
|
|
|
225
238
|
Attach a backend via `defineSandbox({ backend })`:
|
|
@@ -229,10 +242,14 @@ Attach a backend via `defineSandbox({ backend })`:
|
|
|
229
242
|
import { defineSandbox, vercelBackend } from "experimental-ash/sandbox";
|
|
230
243
|
|
|
231
244
|
export default defineSandbox({
|
|
232
|
-
backend: vercelBackend(
|
|
233
|
-
async bootstrap({
|
|
245
|
+
backend: vercelBackend(),
|
|
246
|
+
async bootstrap({ use }) {
|
|
247
|
+
const sandbox = await use();
|
|
234
248
|
await sandbox.runCommand("git clone https://example.com/repo.git repo");
|
|
235
249
|
},
|
|
250
|
+
async onSession({ use }) {
|
|
251
|
+
await use({ networkPolicy: "deny-all" });
|
|
252
|
+
},
|
|
236
253
|
});
|
|
237
254
|
```
|
|
238
255
|
|
|
@@ -251,69 +268,90 @@ export default defineSandbox({
|
|
|
251
268
|
});
|
|
252
269
|
```
|
|
253
270
|
|
|
254
|
-
### Vercel Backend
|
|
271
|
+
### Vercel Backend: Session Configuration
|
|
255
272
|
|
|
256
|
-
`vercelBackend(
|
|
257
|
-
|
|
258
|
-
**
|
|
259
|
-
Hover the `options` argument in your editor to see the live set of fields.
|
|
273
|
+
`vercelBackend()` takes no options. All configuration is done through lifecycle hooks:
|
|
274
|
+
|
|
275
|
+
- **Immutable creation config** (runtime, ports, env) — passed via `bootstrap`'s `use()`:
|
|
260
276
|
|
|
261
277
|
```ts
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
ports: [3000],
|
|
267
|
-
env: { NODE_ENV: "production" },
|
|
268
|
-
});
|
|
278
|
+
async bootstrap({ use }) {
|
|
279
|
+
const sandbox = await use({ runtime: "node24", ports: [3000] });
|
|
280
|
+
await sandbox.runCommand("npm install");
|
|
281
|
+
}
|
|
269
282
|
```
|
|
270
283
|
|
|
271
|
-
|
|
284
|
+
- **Session-level config** (networkPolicy, resources, timeout, tags) — passed via `onSession`'s
|
|
285
|
+
`use()` or `sandbox.update()`:
|
|
272
286
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
287
|
+
```ts
|
|
288
|
+
async onSession({ use }) {
|
|
289
|
+
const sandbox = await use({
|
|
290
|
+
networkPolicy: "deny-all",
|
|
291
|
+
resources: { vcpus: 4 },
|
|
292
|
+
timeout: 60 * 60 * 1_000,
|
|
293
|
+
});
|
|
294
|
+
// Can also update later:
|
|
295
|
+
await sandbox.update({ tags: { user: "casey" } });
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
This split ensures that `bootstrap` only does filesystem setup (which survives snapshotting), while
|
|
300
|
+
`onSession` configures the live session (network policy, resources, etc. do not survive snapshots).
|
|
301
|
+
|
|
302
|
+
### Network Policies
|
|
276
303
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
304
|
+
Network policies are set per-session via `onSession`. Three forms are supported:
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
await use({ networkPolicy: "allow-all" }); // default
|
|
308
|
+
await use({ networkPolicy: "deny-all" }); // block all egress, including DNS
|
|
309
|
+
|
|
310
|
+
await use({
|
|
311
|
+
networkPolicy: {
|
|
312
|
+
allow: ["ai-gateway.vercel.sh", "*.github.com"],
|
|
313
|
+
subnets: { deny: ["10.0.0.0/8"] },
|
|
314
|
+
},
|
|
315
|
+
});
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
Since network policy is applied in `onSession` (after the template snapshot), it does not constrain
|
|
319
|
+
`bootstrap`. You can freely `git clone` and `npm install` in bootstrap, then lock down the network
|
|
320
|
+
in `onSession`.
|
|
280
321
|
|
|
281
322
|
### Timeout
|
|
282
323
|
|
|
283
324
|
The `@vercel/sandbox` SDK shuts down idle VMs after a configurable timeout (default 5 minutes). Ash
|
|
284
325
|
raises this default to **30 minutes** so the sandbox survives across workflow step boundaries. You can
|
|
285
|
-
override it
|
|
326
|
+
override it in `onSession`:
|
|
286
327
|
|
|
287
328
|
```ts
|
|
288
|
-
|
|
329
|
+
async onSession({ use }) {
|
|
330
|
+
await use({ timeout: 60 * 60 * 1_000 }); // 1 hour
|
|
331
|
+
}
|
|
289
332
|
```
|
|
290
333
|
|
|
291
334
|
The maximum timeout depends on your Vercel plan: **5 hours** for Pro/Enterprise, **45 minutes** for
|
|
292
335
|
Hobby. If a sandbox expires between steps, the next step will fail with a `410 Gone` error.
|
|
293
336
|
|
|
294
|
-
###
|
|
337
|
+
### Tags
|
|
295
338
|
|
|
296
|
-
|
|
297
|
-
supported:
|
|
339
|
+
Ash attaches Vercel Sandbox tags for runtime attribution:
|
|
298
340
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
341
|
+
- `agent` — the active agent or subagent name
|
|
342
|
+
- `channel` — the active channel adapter kind
|
|
343
|
+
- `sessionId` — the Ash session id
|
|
302
344
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
}
|
|
308
|
-
}
|
|
345
|
+
Custom tags can be set via `onSession`:
|
|
346
|
+
|
|
347
|
+
```ts
|
|
348
|
+
async onSession({ use }) {
|
|
349
|
+
await use({ tags: { team: "infra" } });
|
|
350
|
+
}
|
|
309
351
|
```
|
|
310
352
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
`networkPolicy` will therefore also constrain `bootstrap()`. Make sure your bootstrap works within
|
|
314
|
-
whatever constraints you set — for example, a `deny-all` policy will block `git clone` and
|
|
315
|
-
`npm install`. If you need a less restrictive bootstrap, allowlist only the hosts your bootstrap
|
|
316
|
-
needs (e.g. `["registry.npmjs.org"]`) instead of using `deny-all`.
|
|
353
|
+
Vercel Sandbox supports at most five tags. Ash-owned tags take three slots, leaving two for custom
|
|
354
|
+
tags.
|
|
317
355
|
|
|
318
356
|
### Custom Backends
|
|
319
357
|
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
loadCompiledManifest,
|
|
12
12
|
resolveWorkflowBuildDirectory,
|
|
13
13
|
stringifyEsmImportSpecifier
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-IKHNAPQA.js";
|
|
15
15
|
import {
|
|
16
16
|
resolvePackageSourceFilePath
|
|
17
17
|
} from "./chunk-E7IAIRUB.js";
|
|
@@ -589,4 +589,4 @@ export {
|
|
|
589
589
|
createAuthoredSourceRuntimeCompiledArtifactsSource,
|
|
590
590
|
prepareApplicationHost
|
|
591
591
|
};
|
|
592
|
-
//# sourceMappingURL=chunk-
|
|
592
|
+
//# sourceMappingURL=chunk-5BOA7PVK.js.map
|
|
@@ -4453,7 +4453,7 @@ function createLocalSandboxBackend() {
|
|
|
4453
4453
|
});
|
|
4454
4454
|
const templateSession = buildSandboxSession(createLocalSessionPrimitives(templateSandbox));
|
|
4455
4455
|
if (createInput.bootstrap !== void 0) {
|
|
4456
|
-
await createInput.bootstrap(templateSession);
|
|
4456
|
+
await createInput.bootstrap({ use: async () => templateSession });
|
|
4457
4457
|
}
|
|
4458
4458
|
const templateSeedFiles = await loadSeedFiles();
|
|
4459
4459
|
for (const file of templateSeedFiles) {
|
|
@@ -4592,8 +4592,10 @@ async function createBashSandbox(input) {
|
|
|
4592
4592
|
};
|
|
4593
4593
|
}
|
|
4594
4594
|
function createHandle(sandbox) {
|
|
4595
|
+
const session = buildSandboxSession(createLocalSessionPrimitives(sandbox));
|
|
4595
4596
|
return {
|
|
4596
|
-
session
|
|
4597
|
+
session,
|
|
4598
|
+
useSessionFn: async () => session,
|
|
4597
4599
|
async captureState() {
|
|
4598
4600
|
const metadata = await sandbox.captureSnapshot() ?? {};
|
|
4599
4601
|
return {
|
|
@@ -4716,8 +4718,7 @@ function localBackend() {
|
|
|
4716
4718
|
function createVercelSandboxBackend(input = {}) {
|
|
4717
4719
|
const loadSandboxModule = input.loadSandboxModule ?? (async () => await import("@vercel/sandbox"));
|
|
4718
4720
|
const createOptions = {
|
|
4719
|
-
timeout: DEFAULT_SANDBOX_TIMEOUT_MS
|
|
4720
|
-
...input.createOptions
|
|
4721
|
+
timeout: DEFAULT_SANDBOX_TIMEOUT_MS
|
|
4721
4722
|
};
|
|
4722
4723
|
return {
|
|
4723
4724
|
name: "vercel",
|
|
@@ -4798,7 +4799,7 @@ async function ensureTemplate(input) {
|
|
|
4798
4799
|
createVercelSessionPrimitives(sandbox, input.templateKey)
|
|
4799
4800
|
);
|
|
4800
4801
|
if (input.bootstrap !== void 0) {
|
|
4801
|
-
await input.bootstrap(templateSession);
|
|
4802
|
+
await input.bootstrap({ use: async () => templateSession });
|
|
4802
4803
|
}
|
|
4803
4804
|
const resolvedSeedFiles = input.seedFiles === void 0 ? [] : typeof input.seedFiles === "function" ? await input.seedFiles() : input.seedFiles;
|
|
4804
4805
|
for (const file of resolvedSeedFiles) {
|
|
@@ -4833,6 +4834,19 @@ async function ensureSession(input) {
|
|
|
4833
4834
|
function createHandle2(sandbox, sessionKey) {
|
|
4834
4835
|
return {
|
|
4835
4836
|
session: buildSandboxSession(createVercelSessionPrimitives(sandbox, sessionKey)),
|
|
4837
|
+
useSessionFn: async (options) => {
|
|
4838
|
+
if (options !== void 0) {
|
|
4839
|
+
const updateParams = {};
|
|
4840
|
+
if (options.networkPolicy !== void 0) updateParams.networkPolicy = options.networkPolicy;
|
|
4841
|
+
if (options.resources !== void 0) updateParams.resources = options.resources;
|
|
4842
|
+
if (options.timeout !== void 0) updateParams.timeout = options.timeout;
|
|
4843
|
+
if (options.tags !== void 0) updateParams.tags = options.tags;
|
|
4844
|
+
if (Object.keys(updateParams).length > 0) {
|
|
4845
|
+
await sandbox.update(updateParams);
|
|
4846
|
+
}
|
|
4847
|
+
}
|
|
4848
|
+
return buildVercelSandbox(sandbox, sessionKey);
|
|
4849
|
+
},
|
|
4836
4850
|
async captureState() {
|
|
4837
4851
|
return {
|
|
4838
4852
|
backendName: "vercel",
|
|
@@ -4844,6 +4858,39 @@ function createHandle2(sandbox, sessionKey) {
|
|
|
4844
4858
|
}
|
|
4845
4859
|
};
|
|
4846
4860
|
}
|
|
4861
|
+
function buildVercelSandbox(sandbox, id) {
|
|
4862
|
+
const session = buildSandboxSession(createVercelSessionPrimitives(sandbox, id));
|
|
4863
|
+
return {
|
|
4864
|
+
...session,
|
|
4865
|
+
get name() {
|
|
4866
|
+
return sandbox.name;
|
|
4867
|
+
},
|
|
4868
|
+
get persistent() {
|
|
4869
|
+
return sandbox.persistent;
|
|
4870
|
+
},
|
|
4871
|
+
get status() {
|
|
4872
|
+
return sandbox.status;
|
|
4873
|
+
},
|
|
4874
|
+
get networkPolicy() {
|
|
4875
|
+
return sandbox.networkPolicy;
|
|
4876
|
+
},
|
|
4877
|
+
get tags() {
|
|
4878
|
+
return sandbox.tags;
|
|
4879
|
+
},
|
|
4880
|
+
async update(params) {
|
|
4881
|
+
await sandbox.update(params);
|
|
4882
|
+
},
|
|
4883
|
+
async stop(opts) {
|
|
4884
|
+
await sandbox.stop(opts);
|
|
4885
|
+
},
|
|
4886
|
+
async snapshot(opts) {
|
|
4887
|
+
return await sandbox.snapshot(opts);
|
|
4888
|
+
},
|
|
4889
|
+
domain(port) {
|
|
4890
|
+
return sandbox.domain(port);
|
|
4891
|
+
}
|
|
4892
|
+
};
|
|
4893
|
+
}
|
|
4847
4894
|
function createVercelSessionPrimitives(sandbox, id) {
|
|
4848
4895
|
return {
|
|
4849
4896
|
id,
|
|
@@ -4979,8 +5026,8 @@ var DEFAULT_SANDBOX_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
|
4979
5026
|
var VERCEL_SANDBOX_TAG_LIMIT = 5;
|
|
4980
5027
|
|
|
4981
5028
|
// src/public/sandbox/backends/vercel.ts
|
|
4982
|
-
function vercelBackend(
|
|
4983
|
-
return createVercelSandboxBackend(
|
|
5029
|
+
function vercelBackend() {
|
|
5030
|
+
return createVercelSandboxBackend();
|
|
4984
5031
|
}
|
|
4985
5032
|
|
|
4986
5033
|
// src/public/sandbox/backends/default.ts
|
|
@@ -6723,19 +6770,30 @@ async function normalizeAuthoredModelReference(input) {
|
|
|
6723
6770
|
`Expected the authored agent config export "${source.exportName ?? "default"}" from "${source.logicalPath}" to provide a valid AI SDK language model.`
|
|
6724
6771
|
);
|
|
6725
6772
|
}
|
|
6726
|
-
|
|
6727
|
-
|
|
6728
|
-
|
|
6729
|
-
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
|
|
6733
|
-
sourceId: source.sourceId
|
|
6734
|
-
},
|
|
6735
|
-
providerOptions: input.providerOptions === void 0 ? void 0 : parseJsonObject(input.providerOptions)
|
|
6773
|
+
const sourceBackedModel = {
|
|
6774
|
+
id: formatLanguageModelGatewayId(languageModel),
|
|
6775
|
+
source: {
|
|
6776
|
+
exportName: source.exportName,
|
|
6777
|
+
sourceKind: "module",
|
|
6778
|
+
logicalPath: source.logicalPath,
|
|
6779
|
+
sourceId: source.sourceId
|
|
6736
6780
|
},
|
|
6737
|
-
input
|
|
6738
|
-
|
|
6781
|
+
providerOptions: input.providerOptions === void 0 ? void 0 : parseJsonObject(input.providerOptions)
|
|
6782
|
+
};
|
|
6783
|
+
if (input.contextWindowTokens === void 0) {
|
|
6784
|
+
const providerResult = await input.modelCatalog.getByProviderModelId(
|
|
6785
|
+
languageModel.provider,
|
|
6786
|
+
languageModel.modelId
|
|
6787
|
+
);
|
|
6788
|
+
if (providerResult) {
|
|
6789
|
+
return {
|
|
6790
|
+
...sourceBackedModel,
|
|
6791
|
+
id: providerResult.slug,
|
|
6792
|
+
contextWindowTokens: providerResult.limits.contextWindowTokens
|
|
6793
|
+
};
|
|
6794
|
+
}
|
|
6795
|
+
}
|
|
6796
|
+
return await withCompiledRuntimeModelLimits(sourceBackedModel, input);
|
|
6739
6797
|
}
|
|
6740
6798
|
async function withCompiledRuntimeModelLimits(model, input) {
|
|
6741
6799
|
if (input.contextWindowTokens !== void 0) {
|
|
@@ -8647,20 +8705,24 @@ import { join as join17, relative as relative4, resolve as resolve8 } from "node
|
|
|
8647
8705
|
import { mkdir as mkdir2, readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises";
|
|
8648
8706
|
import { join as join14 } from "node:path";
|
|
8649
8707
|
import { z as z7 } from "zod";
|
|
8650
|
-
var
|
|
8651
|
-
var COMPILED_RUNTIME_MODEL_CATALOG_CACHE_KIND = "ash-
|
|
8652
|
-
var COMPILED_RUNTIME_MODEL_CATALOG_CACHE_VERSION =
|
|
8708
|
+
var AI_GATEWAY_MODELS_CATALOG_URL = "https://ai-gateway.vercel.sh/v1/models/catalog";
|
|
8709
|
+
var COMPILED_RUNTIME_MODEL_CATALOG_CACHE_KIND = "ash-model-catalog-cache";
|
|
8710
|
+
var COMPILED_RUNTIME_MODEL_CATALOG_CACHE_VERSION = 2;
|
|
8653
8711
|
var COMPILED_RUNTIME_MODEL_CATALOG_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
8654
8712
|
var THINKING_SUFFIX = "-thinking";
|
|
8655
|
-
var
|
|
8656
|
-
|
|
8657
|
-
|
|
8658
|
-
|
|
8659
|
-
|
|
8660
|
-
|
|
8661
|
-
|
|
8662
|
-
),
|
|
8663
|
-
|
|
8713
|
+
var catalogModelProviderSchema = z7.object({
|
|
8714
|
+
provider: z7.string().min(1),
|
|
8715
|
+
providerModelId: z7.string().min(1),
|
|
8716
|
+
contextWindowTokens: z7.number().int().nonnegative().optional(),
|
|
8717
|
+
maxOutputTokens: z7.number().int().nonnegative().optional()
|
|
8718
|
+
}).passthrough();
|
|
8719
|
+
var catalogModelSchema = z7.object({
|
|
8720
|
+
slug: z7.string().min(1),
|
|
8721
|
+
providers: z7.array(catalogModelProviderSchema).min(1)
|
|
8722
|
+
}).passthrough();
|
|
8723
|
+
var modelCatalogResponseSchema = z7.object({
|
|
8724
|
+
models: z7.array(catalogModelSchema),
|
|
8725
|
+
providerAliases: z7.record(z7.string(), z7.string())
|
|
8664
8726
|
}).passthrough();
|
|
8665
8727
|
var compiledRuntimeModelLimitsSchema = z7.object({
|
|
8666
8728
|
contextWindowTokens: z7.number().int().positive(),
|
|
@@ -8669,8 +8731,8 @@ var compiledRuntimeModelLimitsSchema = z7.object({
|
|
|
8669
8731
|
var compiledRuntimeModelCatalogCacheSchema = z7.object({
|
|
8670
8732
|
fetchedAt: z7.string(),
|
|
8671
8733
|
kind: z7.literal(COMPILED_RUNTIME_MODEL_CATALOG_CACHE_KIND),
|
|
8672
|
-
models: z7.
|
|
8673
|
-
|
|
8734
|
+
models: z7.array(catalogModelSchema),
|
|
8735
|
+
providerAliases: z7.record(z7.string(), z7.string()),
|
|
8674
8736
|
version: z7.literal(COMPILED_RUNTIME_MODEL_CATALOG_CACHE_VERSION)
|
|
8675
8737
|
}).strict();
|
|
8676
8738
|
var builtInCompiledRuntimeModelLimitsById = /* @__PURE__ */ new Map([
|
|
@@ -8704,7 +8766,7 @@ function createCompiledRuntimeModelCatalogLoader(appRoot) {
|
|
|
8704
8766
|
let fetchedCatalogError = null;
|
|
8705
8767
|
let fetchedCatalogPromise = null;
|
|
8706
8768
|
const getCachedCatalog = async () => {
|
|
8707
|
-
cachedCatalogPromise ??=
|
|
8769
|
+
cachedCatalogPromise ??= readModelCatalogCache(appRoot);
|
|
8708
8770
|
return await cachedCatalogPromise;
|
|
8709
8771
|
};
|
|
8710
8772
|
const getFetchedCatalog = async () => {
|
|
@@ -8714,7 +8776,7 @@ function createCompiledRuntimeModelCatalogLoader(appRoot) {
|
|
|
8714
8776
|
if (fetchedCatalogPromise !== null) {
|
|
8715
8777
|
return await fetchedCatalogPromise;
|
|
8716
8778
|
}
|
|
8717
|
-
fetchedCatalogPromise =
|
|
8779
|
+
fetchedCatalogPromise = fetchAndPersistModelCatalog(appRoot).then((catalog) => {
|
|
8718
8780
|
cachedCatalogPromise = Promise.resolve(catalog);
|
|
8719
8781
|
return catalog;
|
|
8720
8782
|
});
|
|
@@ -8725,77 +8787,87 @@ function createCompiledRuntimeModelCatalogLoader(appRoot) {
|
|
|
8725
8787
|
throw error;
|
|
8726
8788
|
}
|
|
8727
8789
|
};
|
|
8790
|
+
const resolveModelsFromCacheOrFetch = async () => {
|
|
8791
|
+
const cachedCatalog = await getCachedCatalog();
|
|
8792
|
+
if (cachedCatalog !== null && isCacheFresh(cachedCatalog)) {
|
|
8793
|
+
return cachedCatalog;
|
|
8794
|
+
}
|
|
8795
|
+
try {
|
|
8796
|
+
return await getFetchedCatalog();
|
|
8797
|
+
} catch {
|
|
8798
|
+
if (cachedCatalog !== null) {
|
|
8799
|
+
return cachedCatalog;
|
|
8800
|
+
}
|
|
8801
|
+
return null;
|
|
8802
|
+
}
|
|
8803
|
+
};
|
|
8728
8804
|
return {
|
|
8729
8805
|
async getModelLimits(modelId) {
|
|
8730
|
-
const
|
|
8731
|
-
const
|
|
8732
|
-
|
|
8733
|
-
|
|
8734
|
-
|
|
8735
|
-
|
|
8736
|
-
|
|
8737
|
-
|
|
8738
|
-
|
|
8739
|
-
|
|
8740
|
-
|
|
8741
|
-
}
|
|
8742
|
-
} catch (error) {
|
|
8743
|
-
if (cachedLimits !== null) {
|
|
8744
|
-
return cachedLimits;
|
|
8745
|
-
}
|
|
8746
|
-
const builtInLimits = builtInCompiledRuntimeModelLimitsById.get(normalizedModelId);
|
|
8747
|
-
if (builtInLimits !== void 0) {
|
|
8748
|
-
return builtInLimits;
|
|
8806
|
+
const normalizedId = normalizeModelId(modelId);
|
|
8807
|
+
const resolved = await resolveModelsFromCacheOrFetch();
|
|
8808
|
+
if (resolved !== null) {
|
|
8809
|
+
const model = findBySlug(resolved.models, normalizedId);
|
|
8810
|
+
if (model) {
|
|
8811
|
+
for (const p of model.providers) {
|
|
8812
|
+
const limits = limitsFromProvider(p);
|
|
8813
|
+
if (limits !== null) {
|
|
8814
|
+
return limits;
|
|
8815
|
+
}
|
|
8816
|
+
}
|
|
8749
8817
|
}
|
|
8750
|
-
throw error;
|
|
8751
8818
|
}
|
|
8752
|
-
|
|
8753
|
-
|
|
8819
|
+
return builtInCompiledRuntimeModelLimitsById.get(normalizedId) ?? null;
|
|
8820
|
+
},
|
|
8821
|
+
async getByProviderModelId(provider, providerModelId) {
|
|
8822
|
+
const resolved = await resolveModelsFromCacheOrFetch();
|
|
8823
|
+
if (resolved === null) {
|
|
8824
|
+
return null;
|
|
8754
8825
|
}
|
|
8755
|
-
|
|
8826
|
+
const baseProvider = provider.split(".")[0];
|
|
8827
|
+
const resolvedProvider = resolved.providerAliases[baseProvider] ?? baseProvider;
|
|
8828
|
+
const normalizedModelId = normalizeModelId(providerModelId);
|
|
8829
|
+
for (const model of resolved.models) {
|
|
8830
|
+
for (const p of model.providers) {
|
|
8831
|
+
if (p.provider === resolvedProvider && normalizeModelId(p.providerModelId) === normalizedModelId) {
|
|
8832
|
+
const limits = limitsFromProvider(p);
|
|
8833
|
+
if (limits !== null) {
|
|
8834
|
+
return { slug: model.slug, limits };
|
|
8835
|
+
}
|
|
8836
|
+
}
|
|
8837
|
+
}
|
|
8838
|
+
}
|
|
8839
|
+
return null;
|
|
8756
8840
|
}
|
|
8757
8841
|
};
|
|
8758
8842
|
}
|
|
8759
|
-
async function
|
|
8760
|
-
const response = await fetch(
|
|
8843
|
+
async function fetchAndPersistModelCatalog(appRoot) {
|
|
8844
|
+
const response = await fetch(AI_GATEWAY_MODELS_CATALOG_URL);
|
|
8761
8845
|
if (!response.ok) {
|
|
8762
8846
|
throw new Error(
|
|
8763
8847
|
`AI Gateway model catalog request failed with HTTP ${response.status} ${response.statusText}.`
|
|
8764
8848
|
);
|
|
8765
8849
|
}
|
|
8766
|
-
const parsed =
|
|
8850
|
+
const parsed = modelCatalogResponseSchema.safeParse(await response.json());
|
|
8767
8851
|
if (!parsed.success) {
|
|
8768
8852
|
throw new Error("AI Gateway model catalog response did not match the expected schema.");
|
|
8769
8853
|
}
|
|
8770
|
-
const models = {};
|
|
8771
|
-
for (const model of parsed.data.data) {
|
|
8772
|
-
if (model.context_window === void 0 || model.context_window <= 0) {
|
|
8773
|
-
continue;
|
|
8774
|
-
}
|
|
8775
|
-
const limits = {
|
|
8776
|
-
contextWindowTokens: model.context_window
|
|
8777
|
-
};
|
|
8778
|
-
if (model.max_tokens !== void 0 && model.max_tokens > 0) {
|
|
8779
|
-
limits.maxOutputTokens = model.max_tokens;
|
|
8780
|
-
}
|
|
8781
|
-
models[model.id] = limits;
|
|
8782
|
-
}
|
|
8783
8854
|
const cacheArtifact = {
|
|
8784
8855
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8785
8856
|
kind: COMPILED_RUNTIME_MODEL_CATALOG_CACHE_KIND,
|
|
8786
|
-
models,
|
|
8787
|
-
|
|
8857
|
+
models: parsed.data.models,
|
|
8858
|
+
providerAliases: parsed.data.providerAliases,
|
|
8788
8859
|
version: COMPILED_RUNTIME_MODEL_CATALOG_CACHE_VERSION
|
|
8789
8860
|
};
|
|
8790
|
-
|
|
8791
|
-
|
|
8792
|
-
recursive: true
|
|
8793
|
-
|
|
8794
|
-
await writeFile2(cachePath, `${JSON.stringify(cacheArtifact, null, 2)}
|
|
8861
|
+
try {
|
|
8862
|
+
const cachePath = resolveCompiledRuntimeModelCatalogCachePath(appRoot);
|
|
8863
|
+
await mkdir2(join14(appRoot, ".ash", "cache"), { recursive: true });
|
|
8864
|
+
await writeFile2(cachePath, `${JSON.stringify(cacheArtifact, null, 2)}
|
|
8795
8865
|
`, "utf8");
|
|
8866
|
+
} catch {
|
|
8867
|
+
}
|
|
8796
8868
|
return cacheArtifact;
|
|
8797
8869
|
}
|
|
8798
|
-
async function
|
|
8870
|
+
async function readModelCatalogCache(appRoot) {
|
|
8799
8871
|
try {
|
|
8800
8872
|
const cacheText = await readFile3(resolveCompiledRuntimeModelCatalogCachePath(appRoot), "utf8");
|
|
8801
8873
|
const parsed = compiledRuntimeModelCatalogCacheSchema.safeParse(JSON.parse(cacheText));
|
|
@@ -8807,24 +8879,26 @@ async function readCompiledRuntimeModelCatalogCache(appRoot) {
|
|
|
8807
8879
|
return null;
|
|
8808
8880
|
}
|
|
8809
8881
|
}
|
|
8810
|
-
function
|
|
8811
|
-
|
|
8882
|
+
function findBySlug(models, slug) {
|
|
8883
|
+
return models.find((m) => m.slug === slug);
|
|
8884
|
+
}
|
|
8885
|
+
function limitsFromProvider(provider) {
|
|
8886
|
+
if (provider.contextWindowTokens === void 0 || provider.contextWindowTokens <= 0) {
|
|
8812
8887
|
return null;
|
|
8813
8888
|
}
|
|
8814
|
-
|
|
8815
|
-
|
|
8889
|
+
return {
|
|
8890
|
+
contextWindowTokens: provider.contextWindowTokens,
|
|
8891
|
+
...provider.maxOutputTokens !== void 0 && provider.maxOutputTokens > 0 && { maxOutputTokens: provider.maxOutputTokens }
|
|
8892
|
+
};
|
|
8816
8893
|
}
|
|
8817
|
-
function
|
|
8818
|
-
if (cache === null) {
|
|
8819
|
-
return false;
|
|
8820
|
-
}
|
|
8894
|
+
function isCacheFresh(cache) {
|
|
8821
8895
|
const fetchedAt = Date.parse(cache.fetchedAt);
|
|
8822
8896
|
if (!Number.isFinite(fetchedAt)) {
|
|
8823
8897
|
return false;
|
|
8824
8898
|
}
|
|
8825
8899
|
return Date.now() - fetchedAt <= COMPILED_RUNTIME_MODEL_CATALOG_CACHE_TTL_MS;
|
|
8826
8900
|
}
|
|
8827
|
-
function
|
|
8901
|
+
function normalizeModelId(modelId) {
|
|
8828
8902
|
return modelId.endsWith(THINKING_SUFFIX) ? modelId.slice(0, -THINKING_SUFFIX.length) : modelId;
|
|
8829
8903
|
}
|
|
8830
8904
|
|
|
@@ -9723,4 +9797,4 @@ export {
|
|
|
9723
9797
|
resolveWorkflowBuildDirectory,
|
|
9724
9798
|
getApplicationInfo
|
|
9725
9799
|
};
|
|
9726
|
-
//# sourceMappingURL=chunk-
|
|
9800
|
+
//# sourceMappingURL=chunk-IKHNAPQA.js.map
|