eve 0.35.0 → 0.37.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.
Files changed (95) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +1 -0
  3. package/dist/src/cli/commands/agent-instructions.d.ts +4 -4
  4. package/dist/src/cli/commands/init-confirm.d.ts +12 -0
  5. package/dist/src/cli/commands/init-confirm.js +1 -0
  6. package/dist/src/cli/commands/init.d.ts +6 -5
  7. package/dist/src/cli/commands/init.js +1 -1
  8. package/dist/src/cli/run.d.ts +1 -0
  9. package/dist/src/cli/run.js +3 -3
  10. package/dist/src/compiled/.vendor-stamp.json +2 -1
  11. package/dist/src/compiled/@vercel/sandbox/api-client/api-client.d.ts +339 -0
  12. package/dist/src/compiled/@vercel/sandbox/api-client/index.d.ts +1 -1
  13. package/dist/src/compiled/@vercel/sandbox/api-client/validators.d.ts +25 -1
  14. package/dist/src/compiled/@vercel/sandbox/drive.d.ts +140 -0
  15. package/dist/src/compiled/@vercel/sandbox/index.d.ts +3 -2
  16. package/dist/src/compiled/@vercel/sandbox/index.js +13 -13
  17. package/dist/src/compiled/@vercel/sandbox/sandbox.d.ts +55 -18
  18. package/dist/src/compiled/@vercel/sandbox-stable/LICENSE +201 -0
  19. package/dist/src/compiled/@vercel/sandbox-stable/_async-retry.d.ts +8 -0
  20. package/dist/src/compiled/@vercel/sandbox-stable/_workflow-serde.d.ts +5 -0
  21. package/dist/src/compiled/@vercel/sandbox-stable/api-client/api-client.d.ts +1456 -0
  22. package/dist/src/compiled/@vercel/sandbox-stable/api-client/api-error.d.ts +29 -0
  23. package/dist/src/compiled/@vercel/sandbox-stable/api-client/base-client.d.ts +39 -0
  24. package/dist/src/compiled/@vercel/sandbox-stable/api-client/file-writer.d.ts +66 -0
  25. package/dist/src/compiled/@vercel/sandbox-stable/api-client/index.d.ts +2 -0
  26. package/dist/src/compiled/@vercel/sandbox-stable/api-client/validators.d.ts +899 -0
  27. package/dist/src/compiled/@vercel/sandbox-stable/api-client/with-retry.d.ts +10 -0
  28. package/dist/src/compiled/@vercel/sandbox-stable/auth/error.d.ts +15 -0
  29. package/dist/src/compiled/@vercel/sandbox-stable/auth/file.d.ts +18 -0
  30. package/dist/src/compiled/@vercel/sandbox-stable/auth/index.d.ts +6 -0
  31. package/dist/src/compiled/@vercel/sandbox-stable/auth/oauth.d.ts +111 -0
  32. package/dist/src/compiled/@vercel/sandbox-stable/auth/poll-for-token.d.ts +28 -0
  33. package/dist/src/compiled/@vercel/sandbox-stable/auth/project.d.ts +40 -0
  34. package/dist/src/compiled/@vercel/sandbox-stable/command.d.ts +292 -0
  35. package/dist/src/compiled/@vercel/sandbox-stable/constants.d.ts +5 -0
  36. package/dist/src/compiled/@vercel/sandbox-stable/execution-context.d.ts +116 -0
  37. package/dist/src/compiled/@vercel/sandbox-stable/filesystem.d.ts +258 -0
  38. package/dist/src/compiled/@vercel/sandbox-stable/index.d.ts +12 -0
  39. package/dist/src/compiled/@vercel/sandbox-stable/index.js +1 -0
  40. package/dist/src/compiled/@vercel/sandbox-stable/network-policy.d.ts +169 -0
  41. package/dist/src/compiled/@vercel/sandbox-stable/proxy.d.ts +55 -0
  42. package/dist/src/compiled/@vercel/sandbox-stable/sandbox-user.d.ts +212 -0
  43. package/dist/src/compiled/@vercel/sandbox-stable/sandbox.d.ts +1216 -0
  44. package/dist/src/compiled/@vercel/sandbox-stable/session.d.ts +433 -0
  45. package/dist/src/compiled/@vercel/sandbox-stable/snapshot.d.ts +229 -0
  46. package/dist/src/compiled/@vercel/sandbox-stable/utils/get-credentials.d.ts +21 -0
  47. package/dist/src/compiled/@vercel/sandbox-stable/utils/paginator.d.ts +16 -0
  48. package/dist/src/compiled/@vercel/sandbox-stable/utils/resolveSignal.d.ts +15 -0
  49. package/dist/src/compiled/@vercel/sandbox-stable/utils/sandbox-snapshot.d.ts +11 -0
  50. package/dist/src/compiled/@vercel/sandbox-stable/utils/types.d.ts +11 -0
  51. package/dist/src/compiled/_chunks/node/{auth-BS3UoyvT.js → auth-BaNbsImr.js} +1 -1
  52. package/dist/src/compiled/_chunks/node/version-BYHw-SDY.js +1 -0
  53. package/dist/src/evals/context.js +1 -1
  54. package/dist/src/evals/session.d.ts +1 -0
  55. package/dist/src/evals/session.js +1 -1
  56. package/dist/src/evals/types.d.ts +2 -0
  57. package/dist/src/execution/sandbox/bindings/vercel.d.ts +2 -1
  58. package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
  59. package/dist/src/harness/approval-delivery-coordinator.js +1 -1
  60. package/dist/src/internal/application/package.js +1 -1
  61. package/dist/src/packages/eve-catalog/src/index.js +1 -1
  62. package/dist/src/public/nuxt/module.js +1 -1
  63. package/dist/src/public/sandbox/backends/vercel.d.ts +5 -4
  64. package/dist/src/public/sandbox/backends/vercel.js +1 -1
  65. package/dist/src/public/sandbox/vercel-sandbox.d.ts +25 -1
  66. package/dist/src/public/sandbox/vercel.d.ts +2 -1
  67. package/dist/src/public/sandbox/vercel.js +1 -1
  68. package/dist/src/public/sveltekit/index.d.ts +6 -20
  69. package/dist/src/public/sveltekit/index.js +1 -1
  70. package/dist/src/public/sveltekit/routing.d.ts +0 -24
  71. package/dist/src/public/sveltekit/routing.js +1 -1
  72. package/dist/src/setup/boxes/select-model.d.ts +6 -6
  73. package/dist/src/setup/boxes/select-model.js +1 -1
  74. package/dist/src/setup/scaffold/create/project.js +1 -1
  75. package/dist/src/setup/scaffold/create/web-template.d.ts +1 -1
  76. package/dist/src/setup/scaffold/create/web-template.js +0 -1
  77. package/dist/src/shared/default-agent-model.d.ts +1 -1
  78. package/dist/src/shared/default-agent-model.js +1 -1
  79. package/dist/src/shared/sandbox-network-policy.d.ts +1 -1
  80. package/dist/src/{public/nuxt → shared}/vercel-services.d.ts +18 -19
  81. package/dist/src/shared/vercel-services.js +1 -0
  82. package/docs/agent-config.md +4 -1
  83. package/docs/channels/custom.mdx +1 -1
  84. package/docs/concepts/sessions-runs-and-streaming.md +1 -1
  85. package/docs/getting-started.mdx +1 -1
  86. package/docs/guides/client/messages.mdx +3 -1
  87. package/docs/guides/dynamic-capabilities.md +38 -0
  88. package/docs/guides/frontend/sveltekit.mdx +22 -1
  89. package/docs/reference/cli.md +15 -11
  90. package/docs/sandbox.mdx +8 -0
  91. package/package.json +2 -1
  92. package/dist/src/compiled/_chunks/node/version-Cztrk7z6.js +0 -1
  93. package/dist/src/public/nuxt/vercel-services.js +0 -1
  94. package/dist/src/public/sveltekit/vercel-json.d.ts +0 -17
  95. package/dist/src/public/sveltekit/vercel-json.js +0 -1
@@ -1,14 +1,3 @@
1
- /**
2
- * Private route namespace for hosting eve as a separate experimental Vercel
3
- * service behind the SvelteKit app.
4
- */
5
- export declare const EVE_SVELTEKIT_SERVICE_PREFIX = "/_eve_internal/eve";
6
- /**
7
- * Normalize a user-supplied service prefix into a leading-slash, no-trailing-
8
- * slash route. Throws when the prefix resolves to the root route, which would
9
- * collide with the SvelteKit web service.
10
- */
11
- export declare function normalizeRoutePrefix(prefix: string): string;
12
1
  /**
13
2
  * Join a route prefix and a path with exactly one separating slash.
14
3
  */
@@ -17,16 +6,3 @@ export declare function joinRoutePrefix(prefix: string, path: string): string;
17
6
  * Reduce an origin string to its canonical `protocol://host[:port]` form.
18
7
  */
19
8
  export declare function normalizeOrigin(origin: string): string;
20
- /**
21
- * A Vercel rewrite that forwards eve transport requests (`/eve/v1/**`) to the
22
- * private eve service prefix (`/_eve_internal/eve/eve/v1/**`).
23
- */
24
- export interface EveVercelRewrite {
25
- readonly destination: string;
26
- readonly source: string;
27
- }
28
- /**
29
- * Build the Vercel rewrite that forwards browser eve transport requests to the
30
- * sibling eve service.
31
- */
32
- export declare function createEveVercelRewrite(servicePrefix: string): EveVercelRewrite;
@@ -1 +1 @@
1
- import{EVE_ROUTE_PREFIX}from"#protocol/routes.js";const EVE_SVELTEKIT_SERVICE_PREFIX=`/_eve_internal/eve`;function normalizeRoutePrefix(e){let t=(e.startsWith(`/`)?e:`/${e}`).replace(/\/+$/,``);if(t.length===0)throw Error(`eve SvelteKit service prefix cannot resolve to the root route.`);return t}function joinRoutePrefix(e,t){return`${e.replace(/\/+$/,``)}/${t.replace(/^\/+/,``)}`}function normalizeOrigin(e){return new URL(e.trim()).origin}function createEveVercelRewrite(t){return{destination:`${joinRoutePrefix(t,EVE_ROUTE_PREFIX)}/:path*`,source:`${EVE_ROUTE_PREFIX}/:path*`}}export{EVE_SVELTEKIT_SERVICE_PREFIX,createEveVercelRewrite,joinRoutePrefix,normalizeOrigin,normalizeRoutePrefix};
1
+ function joinRoutePrefix(e,t){return`${e.replace(/\/+$/,``)}/${t.replace(/^\/+/,``)}`}function normalizeOrigin(e){return new URL(e.trim()).origin}export{joinRoutePrefix,normalizeOrigin};
@@ -24,12 +24,12 @@ export declare function fetchGatewayCatalog(signal?: AbortSignal): Promise<Gatew
24
24
  */
25
25
  export declare function parseGatewayCatalog(input: unknown): GatewayCatalogModel[];
26
26
  /**
27
- * Builds picker options from a fetched catalog (filtered to language models
28
- * with the `web-search` tag), with the curated shortlist first in its own
29
- * order and the rest sorted newest release first. Catalog entries on the
30
- * shortlist are marked `featured`, so a searchable picker opens on just them
31
- * and scrolling or filtering reaches the rest. Falls back to a static
32
- * shortlist when the catalog is missing or yields nothing.
27
+ * Builds picker options from a fetched catalog, keeping the default model and
28
+ * filtering the rest to language models with the `web-search` tag. The curated
29
+ * shortlist comes first in its own order, followed by the rest newest-first.
30
+ * Catalog entries on the shortlist are marked `featured`, so a searchable
31
+ * picker opens on just them and scrolling or filtering reaches the rest. Falls
32
+ * back to a static shortlist when the catalog is missing or yields nothing.
33
33
  */
34
34
  export declare function modelOptionsFromCatalog(catalog: readonly GatewayCatalogModel[] | undefined): SelectOption<string>[];
35
35
  /** Injected for tests; defaults to the real AI Gateway catalog fetch. */
@@ -1 +1 @@
1
- import{select}from"../ask.js";import{z}from"#compiled/zod/index.js";import{DEFAULT_AGENT_MODEL_ID}from"#shared/default-agent-model.js";import{AI_GATEWAY_MODELS_URL,vercelGatewayFetch}from"#internal/gateway.js";const gatewayCatalogModelSchema=z.object({id:z.string(),name:z.string(),type:z.string(),owned_by:z.string(),released:z.number().finite().optional().catch(void 0),tags:z.array(z.string()).optional().catch(void 0),pricing:z.object({service_tiers:z.record(z.string(),z.unknown()).optional().catch(void 0)}).optional().catch(void 0)}),gatewayCatalogSchema=z.object({data:z.array(z.unknown())}).transform(({data:e})=>e.flatMap(e=>{let t=gatewayCatalogModelSchema.safeParse(e);return t.success?[t.data]:[]}));function modelOption(e,t,n,r=!0){return{id:e,label:t,value:e,hint:n,featured:r||void 0}}const FEATURED_MODEL_IDS=[DEFAULT_AGENT_MODEL_ID,`anthropic/claude-opus-4.8`,`openai/gpt-5.5`],FALLBACK_MODELS=[modelOption(DEFAULT_AGENT_MODEL_ID,`Claude Sonnet 5`,`Anthropic`),modelOption(`anthropic/claude-opus-4.8`,`Claude Opus 4.8`,`Anthropic`),modelOption(`openai/gpt-5.5`,`GPT-5.5`,`OpenAI`),modelOption(`google/gemini-3.5`,`Gemini 3.5`,`Google`,!1)],PROVIDER_BRANDS={openai:`OpenAI`,xai:`xAI`,deepseek:`DeepSeek`,moonshotai:`Moonshot AI`};function providerLabel(e){return e.length===0?``:PROVIDER_BRANDS[e]??e.charAt(0).toUpperCase()+e.slice(1)}async function fetchGatewayCatalog(e){let t=new AbortController,n=setTimeout(()=>t.abort(),5e3);try{let n=await vercelGatewayFetch(AI_GATEWAY_MODELS_URL,{signal:e===void 0?t.signal:AbortSignal.any([e,t.signal])});if(!n.ok)throw Error(`AI Gateway model catalog request failed (${n.status}).`);return parseGatewayCatalog(await n.json())}finally{clearTimeout(n)}}function parseGatewayCatalog(e){let t=gatewayCatalogSchema.safeParse(e);if(!t.success)throw Error(`AI Gateway returned an invalid model catalog.`);return t.data}function featuredPriority(e){let t=FEATURED_MODEL_IDS.indexOf(e);return t===-1?FEATURED_MODEL_IDS.length:t}function modelOptionsFromCatalog(e){if(e===void 0)return FALLBACK_MODELS;let t=e.filter(e=>e.type===`language`&&(e.tags??[]).includes(`web-search`)).map(e=>{let t=e.id.split(`/`)[0]??``;return{value:e.id,label:e.name,hint:providerLabel(t),provider:t,released:e.released}}).sort((e,t)=>{let n=featuredPriority(e.value)-featuredPriority(t.value);if(n!==0)return n;let r=(t.released??-1/0)-(e.released??-1/0);if(r!==0)return r;let i=e.label.localeCompare(t.label);return i===0?e.value.localeCompare(t.value):i});return t.length===0?FALLBACK_MODELS:t.map(({value:e,label:t,hint:n})=>({id:e,label:t,value:e,hint:n,featured:FEATURED_MODEL_IDS.includes(e)||void 0}))}async function buildModelOptions(e,t){try{return modelOptionsFromCatalog(await e(t))}catch{return t?.throwIfAborted(),FALLBACK_MODELS}}function selectModel(t){let r=t.deps??{fetchModels:fetchGatewayCatalog};return{id:`select-model`,async gather({signal:i}){let a=t.presetModel;if(a!==void 0&&a.length>0)return a;let o=await buildModelOptions(r.fetchModels,i),s=t.defaultModel!==void 0&&o.some(e=>e.value===t.defaultModel)?t.defaultModel:o.some(e=>e.value===DEFAULT_AGENT_MODEL_ID)?DEFAULT_AGENT_MODEL_ID:o[0]?.value;return t.asker.ask(select({key:`model`,message:`Which model should your agent use?`,options:o,recommended:s,required:!0,search:!0,placeholder:`type to search`}))},async perform({input:e}){return e},apply(e,t){return{...e,modelId:t}}}}export{fetchGatewayCatalog,modelOptionsFromCatalog,parseGatewayCatalog,selectModel};
1
+ import{select}from"../ask.js";import{z}from"#compiled/zod/index.js";import{DEFAULT_AGENT_MODEL_ID}from"#shared/default-agent-model.js";import{AI_GATEWAY_MODELS_URL,vercelGatewayFetch}from"#internal/gateway.js";const gatewayCatalogModelSchema=z.object({id:z.string(),name:z.string(),type:z.string(),owned_by:z.string(),released:z.number().finite().optional().catch(void 0),tags:z.array(z.string()).optional().catch(void 0),pricing:z.object({service_tiers:z.record(z.string(),z.unknown()).optional().catch(void 0)}).optional().catch(void 0)}),gatewayCatalogSchema=z.object({data:z.array(z.unknown())}).transform(({data:e})=>e.flatMap(e=>{let t=gatewayCatalogModelSchema.safeParse(e);return t.success?[t.data]:[]}));function modelOption(e,t,n,r=!0){return{id:e,label:t,value:e,hint:n,featured:r||void 0}}const FEATURED_MODEL_IDS=[DEFAULT_AGENT_MODEL_ID,`anthropic/claude-opus-4.8`,`openai/gpt-5.5`],FALLBACK_MODELS=[modelOption(DEFAULT_AGENT_MODEL_ID,`GLM 5.2`,`Z.AI`),modelOption(`anthropic/claude-opus-4.8`,`Claude Opus 4.8`,`Anthropic`),modelOption(`openai/gpt-5.5`,`GPT-5.5`,`OpenAI`),modelOption(`google/gemini-3.5`,`Gemini 3.5`,`Google`,!1)],PROVIDER_BRANDS={openai:`OpenAI`,zai:`Z.AI`,xai:`xAI`,deepseek:`DeepSeek`,moonshotai:`Moonshot AI`};function providerLabel(e){return e.length===0?``:PROVIDER_BRANDS[e]??e.charAt(0).toUpperCase()+e.slice(1)}async function fetchGatewayCatalog(e){let t=new AbortController,n=setTimeout(()=>t.abort(),5e3);try{let n=await vercelGatewayFetch(AI_GATEWAY_MODELS_URL,{signal:e===void 0?t.signal:AbortSignal.any([e,t.signal])});if(!n.ok)throw Error(`AI Gateway model catalog request failed (${n.status}).`);return parseGatewayCatalog(await n.json())}finally{clearTimeout(n)}}function parseGatewayCatalog(e){let t=gatewayCatalogSchema.safeParse(e);if(!t.success)throw Error(`AI Gateway returned an invalid model catalog.`);return t.data}function featuredPriority(e){let t=FEATURED_MODEL_IDS.indexOf(e);return t===-1?FEATURED_MODEL_IDS.length:t}function modelOptionsFromCatalog(e){if(e===void 0)return FALLBACK_MODELS;let t=e.filter(e=>e.type===`language`&&(e.id===DEFAULT_AGENT_MODEL_ID||(e.tags??[]).includes(`web-search`))).map(e=>{let t=e.id.split(`/`)[0]??``;return{value:e.id,label:e.name,hint:providerLabel(t),provider:t,released:e.released}}).sort((e,t)=>{let n=featuredPriority(e.value)-featuredPriority(t.value);if(n!==0)return n;let r=(t.released??-1/0)-(e.released??-1/0);if(r!==0)return r;let i=e.label.localeCompare(t.label);return i===0?e.value.localeCompare(t.value):i});return t.length===0?FALLBACK_MODELS:t.map(({value:e,label:t,hint:n})=>({id:e,label:t,value:e,hint:n,featured:FEATURED_MODEL_IDS.includes(e)||void 0}))}async function buildModelOptions(e,t){try{return modelOptionsFromCatalog(await e(t))}catch{return t?.throwIfAborted(),FALLBACK_MODELS}}function selectModel(t){let r=t.deps??{fetchModels:fetchGatewayCatalog};return{id:`select-model`,async gather({signal:i}){let a=t.presetModel;if(a!==void 0&&a.length>0)return a;let o=await buildModelOptions(r.fetchModels,i),s=t.defaultModel!==void 0&&o.some(e=>e.value===t.defaultModel)?t.defaultModel:o.some(e=>e.value===DEFAULT_AGENT_MODEL_ID)?DEFAULT_AGENT_MODEL_ID:o[0]?.value;return t.asker.ask(select({key:`model`,message:`Which model should your agent use?`,options:o,recommended:s,required:!0,search:!0,placeholder:`type to search`}))},async perform({input:e}){return e},apply(e,t){return{...e,modelId:t}}}}export{fetchGatewayCatalog,modelOptionsFromCatalog,parseGatewayCatalog,selectModel};
@@ -1,4 +1,4 @@
1
- import{pinnedNodeEngineMajor}from"../../node-engine.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{pathExists,writeTextFile}from"../files.js";import{blockingCreateInPlaceEntries}from"../create-in-place.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{mkdir,readdir,stat}from"node:fs/promises";import{basename,join,resolve}from"node:path";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,DEFAULT_AI_PACKAGE_VERSION=`^7.0.58`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.4.3`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.35.0`,nodeEngine:`>=24`};function resolveEvePackageContract(e=DEFAULT_EVE_PACKAGE_CONTRACT){return{version:resolveVersionToken(`evePackage.version`,e.version),nodeEngine:resolveVersionToken(`evePackage.nodeEngine`,e.nodeEngine)}}function modelProviderSlug(e){let t=(e.split(`/`)[0]??``).replaceAll(/[^A-Za-z0-9._-]/gu,``);return t.length>0?t:`anthropic`}function byokProviderEnvVar(e){let t=modelProviderSlug(e).toUpperCase().replaceAll(/[^A-Z0-9]/gu,`_`);return`${/^[0-9]/.test(t)?`_`:``}${t}_API_KEY`}function agentTemplateFiles(e,t){return{"agent/agent.ts":BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(t)),"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE}}function reasoningTemplateLine(e){return e===void 0||e===`provider-default`?``:` reasoning: "${e}",\n`}function renderTemplate(e,t){return e.replaceAll(`__EVE_INIT_APP_NAME__`,t.appName).replaceAll(`__EVE_INIT_MODEL__`,t.model).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(t.reasoning)).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(t.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(t.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(t.eveVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,t.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,t.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,t.zodPackageVersion).replaceAll(`__EVE_INIT_TYPESCRIPT_VERSION__`,t.typescriptPackageVersion).replaceAll(`__EVE_INIT_TYPES_NODE_VERSION__`,t.nodeTypesVersion).replaceAll(`__EVE_INIT_NODE_ENGINE__`,t.nodeEngine)}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}const BASE_AGENT_TEMPLATE=`import { defineAgent } from "eve";
1
+ import{pinnedNodeEngineMajor}from"../../node-engine.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{pathExists,writeTextFile}from"../files.js";import{blockingCreateInPlaceEntries}from"../create-in-place.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{mkdir,readdir,stat}from"node:fs/promises";import{basename,join,resolve}from"node:path";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,DEFAULT_AI_PACKAGE_VERSION=`^7.0.58`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.4.3`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.37.0`,nodeEngine:`>=24`};function resolveEvePackageContract(e=DEFAULT_EVE_PACKAGE_CONTRACT){return{version:resolveVersionToken(`evePackage.version`,e.version),nodeEngine:resolveVersionToken(`evePackage.nodeEngine`,e.nodeEngine)}}function modelProviderSlug(e){let t=(e.split(`/`)[0]??``).replaceAll(/[^A-Za-z0-9._-]/gu,``);return t.length>0?t:`anthropic`}function byokProviderEnvVar(e){let t=modelProviderSlug(e).toUpperCase().replaceAll(/[^A-Z0-9]/gu,`_`);return`${/^[0-9]/.test(t)?`_`:``}${t}_API_KEY`}function agentTemplateFiles(e,t){return{"agent/agent.ts":BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(t)),"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE}}function reasoningTemplateLine(e){return e===void 0||e===`provider-default`?``:` reasoning: "${e}",\n`}function renderTemplate(e,t){return e.replaceAll(`__EVE_INIT_APP_NAME__`,t.appName).replaceAll(`__EVE_INIT_MODEL__`,t.model).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(t.reasoning)).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(t.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(t.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(t.eveVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,t.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,t.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,t.zodPackageVersion).replaceAll(`__EVE_INIT_TYPESCRIPT_VERSION__`,t.typescriptPackageVersion).replaceAll(`__EVE_INIT_TYPES_NODE_VERSION__`,t.nodeTypesVersion).replaceAll(`__EVE_INIT_NODE_ENGINE__`,t.nodeEngine)}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}const BASE_AGENT_TEMPLATE=`import { defineAgent } from "eve";
2
2
 
3
3
  export default defineAgent({
4
4
  model: "__EVE_INIT_MODEL__",
@@ -37,7 +37,7 @@ export declare const WEB_APP_TEMPLATE_FILES: {
37
37
  readonly "tsconfig.json": '{\n "$schema": "https://json.schemastore.org/tsconfig",\n "compilerOptions": {\n "target": "ES2017",\n "lib": ["dom", "dom.iterable", "esnext"],\n "allowJs": true,\n "skipLibCheck": true,\n "strict": true,\n "noEmit": true,\n "esModuleInterop": true,\n "module": "esnext",\n "moduleResolution": "Bundler",\n "resolveJsonModule": true,\n "isolatedModules": true,\n "jsx": "react-jsx",\n "incremental": true,\n "plugins": [\n {\n "name": "next"\n }\n ],\n "paths": {\n "@/*": ["./*"]\n }\n },\n "include": [\n "next-env.d.ts",\n "**/*.ts",\n "**/*.tsx",\n ".next/types/**/*.ts",\n ".next/dev/types/**/*.ts"\n ],\n "exclude": ["node_modules"]\n}\n';
38
38
  };
39
39
  export declare const WEB_APP_SIGN_IN_WITH_VERCEL_TEMPLATE_FILES: {
40
- readonly "agent/channels/eve.ts": 'import { eveChannel } from "eve/channels/eve";\nimport { localDev, type AuthFn, vercelOidc } from "eve/channels/auth";\nimport { auth } from "@/lib/auth";\n\nconst betterAuthSession: AuthFn<Request> = async (request) => {\n const session = await auth.api.getSession({ headers: request.headers });\n if (!session) return null;\n\n const attributes: Record<string, string> = {\n email: session.user.email,\n name: session.user.name,\n };\n if (session.user.image) {\n attributes.picture = session.user.image;\n }\n\n return {\n attributes,\n authenticator: "better-auth:vercel",\n issuer: "https://vercel.com",\n principalId: session.user.id,\n principalType: "user",\n };\n};\n\nexport default eveChannel({\n auth: [betterAuthSession, vercelOidc(), localDev()],\n});\n';
40
+ readonly "agent/channels/eve.ts": 'import { eveChannel } from "eve/channels/eve";\nimport { localDev, type AuthFn, vercelOidc } from "eve/channels/auth";\nimport { auth } from "@/lib/auth";\n\nconst betterAuthSession: AuthFn<Request> = async (request) => {\n const session = await auth.api.getSession({ headers: request.headers });\n if (!session) return null;\n\n const attributes: Record<string, string> = {\n email: session.user.email,\n name: session.user.name,\n };\n if (session.user.image) {\n attributes.picture = session.user.image;\n }\n\n return {\n attributes,\n authenticator: "better-auth:vercel",\n principalId: session.user.id,\n principalType: "user",\n };\n};\n\nexport default eveChannel({\n auth: [betterAuthSession, vercelOidc(), localDev()],\n});\n';
41
41
  readonly "app/_components/web-chat-auth.tsx": '"use client";\n\nimport { LogOutIcon } from "lucide-react";\nimport { useState } from "react";\nimport { Button } from "@/components/ui/button";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from "@/components/ui/dropdown-menu";\nimport { authClient } from "@/lib/auth-client";\n\nconst AGENT_NAME = "__EVE_INIT_APP_NAME__";\n\nexport function SignIn() {\n const [pending, setPending] = useState(false);\n const [error, setError] = useState<string>();\n\n async function signIn() {\n setPending(true);\n setError(undefined);\n try {\n const result = await authClient.signIn.social({\n callbackURL: "/",\n provider: "vercel",\n });\n if (!result.error) return;\n setPending(false);\n setError("Sign-in failed. Try again.");\n } catch {\n setPending(false);\n setError("Sign-in failed. Try again.");\n }\n }\n\n return (\n <main className="flex h-dvh items-center justify-center bg-background px-6 text-foreground">\n <div className="flex w-full max-w-sm flex-col items-center gap-6 text-center">\n <div className="space-y-2">\n <h1 className="break-words font-medium text-4xl tracking-tighter">{AGENT_NAME}</h1>\n <p className="text-muted-foreground text-sm">\n Team members can sign in with Vercel to chat.\n </p>\n </div>\n <Button disabled={pending} onClick={signIn}>\n Sign in with Vercel\n </Button>\n {error ? (\n <p className="text-destructive text-sm" role="alert">\n {error}\n </p>\n ) : null}\n </div>\n </main>\n );\n}\n\nexport function AccountControl({\n email,\n image,\n name,\n}: {\n readonly email: string;\n readonly image?: string | null;\n readonly name: string;\n}) {\n const [imageFailed, setImageFailed] = useState(false);\n const [pending, setPending] = useState(false);\n const initials = getInitials(name, email);\n\n async function signOut() {\n setPending(true);\n try {\n await authClient.signOut({\n fetchOptions: {\n onError: () => setPending(false),\n onSuccess: () => window.location.assign("/"),\n },\n });\n } catch {\n setPending(false);\n }\n }\n\n return (\n <div className="fixed top-3 right-3 z-10">\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n aria-label={`Open account menu for ${name}`}\n className="size-9 cursor-pointer overflow-hidden rounded-full p-0"\n size="icon"\n variant="outline"\n >\n {image && !imageFailed ? (\n <img\n alt=""\n className="size-full object-cover"\n onError={() => setImageFailed(true)}\n src={image}\n />\n ) : (\n <span aria-hidden="true" className="font-medium text-xs">\n {initials}\n </span>\n )}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align="end" className="w-64">\n <div className="min-w-0 px-2 py-1.5 text-sm">\n <span className="block truncate font-medium leading-5" title={name}>\n {name}\n </span>\n <span className="block truncate text-muted-foreground leading-5" title={email}>\n {email}\n </span>\n </div>\n <DropdownMenuSeparator />\n <DropdownMenuItem\n className="cursor-pointer justify-between"\n disabled={pending}\n onSelect={signOut}\n >\n {pending ? "Logging out…" : "Log out"}\n <LogOutIcon aria-hidden="true" />\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n );\n}\n\nfunction getInitials(name: string, email: string): string {\n const parts = name.trim().split(/\\s+/).filter(Boolean);\n if (parts.length >= 2) {\n return `${parts[0]?.[0] ?? ""}${parts.at(-1)?.[0] ?? ""}`.toUpperCase();\n }\n return (parts[0]?.[0] ?? email[0] ?? "?").toUpperCase();\n}\n';
42
42
  readonly "app/api/auth/[...all]/route.ts": 'import { toNextJsHandler } from "better-auth/next-js";\nimport { auth } from "@/lib/auth";\n\nexport const { GET, POST } = toNextJsHandler(auth);\n';
43
43
  readonly "app/layout.tsx": 'import type { Metadata } from "next";\nimport { Geist, Geist_Mono } from "next/font/google";\nimport type { ReactNode } from "react";\nimport { TooltipProvider } from "@/components/ui/tooltip";\nimport { cn } from "@/lib/utils";\nimport "./globals.css";\n\nconst sans = Geist({\n variable: "--font-sans",\n subsets: ["latin"],\n weight: "variable",\n display: "swap",\n});\n\nconst mono = Geist_Mono({\n variable: "--font-mono",\n subsets: ["latin"],\n weight: "variable",\n display: "swap",\n});\n\nexport const metadata: Metadata = {\n title: "__EVE_INIT_APP_NAME__",\n description: "A Next.js starter for eve agents with AI Elements.",\n};\n\n// The page and Eve routes validate the generated app\'s Better Auth session.\nexport default function RootLayout({ children }: { readonly children: ReactNode }) {\n return (\n <html className={cn(sans.variable, mono.variable)} lang="en">\n <body>\n <TooltipProvider>{children}</TooltipProvider>\n </body>\n </html>\n );\n}\n';
@@ -4988,7 +4988,6 @@ const betterAuthSession: AuthFn<Request> = async (request) => {
4988
4988
  return {
4989
4989
  attributes,
4990
4990
  authenticator: "better-auth:vercel",
4991
- issuer: "https://vercel.com",
4992
4991
  principalId: session.user.id,
4993
4992
  principalType: "user",
4994
4993
  };
@@ -2,4 +2,4 @@
2
2
  * Model used when an agent does not declare one, baked in by `eve init`, and
3
3
  * pre-selected in the setup model picker.
4
4
  */
5
- export declare const DEFAULT_AGENT_MODEL_ID = "anthropic/claude-sonnet-5";
5
+ export declare const DEFAULT_AGENT_MODEL_ID = "zai/glm-5.2";
@@ -1 +1 @@
1
- const DEFAULT_AGENT_MODEL_ID=`anthropic/claude-sonnet-5`;export{DEFAULT_AGENT_MODEL_ID};
1
+ const DEFAULT_AGENT_MODEL_ID=`zai/glm-5.2`;export{DEFAULT_AGENT_MODEL_ID};
@@ -1,4 +1,4 @@
1
- import type * as Vercel from "#compiled/@vercel/sandbox/index.js";
1
+ import type * as Vercel from "#compiled/@vercel/sandbox-stable/index.js";
2
2
  /**
3
3
  * Firewall network policy applied to a live sandbox session.
4
4
  *
@@ -49,10 +49,10 @@ export type EveVercelGeneratedService = {
49
49
  readonly root: string;
50
50
  };
51
51
  /**
52
- * Minimal shape of the Nitro Vercel build-output config the module merges the
53
- * generated eve service into.
52
+ * Minimal shape of a Vercel Build Output config that can carry generated eve
53
+ * services.
54
54
  */
55
- export interface NitroVercelBuildConfig {
55
+ export interface VercelBuildConfig {
56
56
  version?: number;
57
57
  routes?: unknown[];
58
58
  services?: Record<string, VercelServiceConfig>;
@@ -61,8 +61,8 @@ export interface NitroVercelBuildConfig {
61
61
  /**
62
62
  * Result of {@link ensureEveVercelServicesConfig}: `root` when `vercel.json`
63
63
  * already declares stable services (the user owns routing; nothing is
64
- * generated), `generated` with the service record to merge into the Nitro
65
- * Vercel build config otherwise.
64
+ * generated), `generated` with the service record to merge into a Vercel Build
65
+ * Output config otherwise.
66
66
  */
67
67
  export type EnsureEveVercelServicesConfigResult = {
68
68
  readonly mode: "root";
@@ -82,36 +82,35 @@ export declare function createEveServiceRoute(serviceName?: string): EveVercelSe
82
82
  */
83
83
  export declare function createEveServiceRequestPathRoute(): EveVercelServiceRequestPathRoute;
84
84
  /**
85
- * Resolve the stable Vercel services configuration for a Nuxt + eve
85
+ * Resolve the stable Vercel services configuration for a framework + eve
86
86
  * deployment.
87
87
  *
88
88
  * When `vercel.json` (looked up from the linked Vercel project root, falling
89
- * back to the Nuxt root) already declares stable `services`, it must include
89
+ * back to the host root) already declares stable `services`, it must include
90
90
  * an eve service and the module generates nothing. Otherwise this prepares a
91
91
  * generated eve service — creating its isolated build root under
92
92
  * `.eve/vercel-services/eve` so the eve build output cannot collide with the
93
- * Nuxt Build Output — and returns the service record plus the public service
94
- * route for the caller to merge into the Nitro Vercel build config. A legacy
93
+ * host Build Output — and returns the service record plus the public service
94
+ * route for the caller to merge into its Vercel build config. A legacy
95
95
  * `experimentalServices` field is ignored with a migration warning: Vercel no
96
96
  * longer routes it.
97
97
  */
98
98
  export declare function ensureEveVercelServicesConfig(input: {
99
99
  readonly appRoot: string;
100
100
  readonly eveBuildCommand?: string;
101
- readonly nuxtRoot: string;
101
+ readonly frameworkName: string;
102
+ readonly hostRoot: string;
102
103
  }): Promise<EnsureEveVercelServicesConfigResult>;
103
104
  /**
104
- * Merge the generated eve service and its public route into a Nitro Vercel
105
- * build config (`nitro.vercel.config`).
105
+ * Merge the generated eve service and its public route into a Vercel Build
106
+ * Output config.
106
107
  *
107
108
  * The service route is inserted before an existing `handle: "filesystem"`
108
- * route, or prepended when none exists — Nitro appends its own generated
109
- * routes (including the filesystem handle) after this config's routes, so the
110
- * eve route always resolves before the Nuxt app's filesystem routing. An eve
111
- * service already configured by the user is preserved and only gains the
112
- * `request.path` route; everything else passes through untouched.
109
+ * route, or prepended when none exists. An eve service already configured by
110
+ * the user is preserved and only gains the `request.path` route; everything
111
+ * else passes through untouched.
113
112
  */
114
- export declare function mergeEveVercelConfig(existing: NitroVercelBuildConfig | undefined, generated: Extract<EnsureEveVercelServicesConfigResult, {
113
+ export declare function mergeEveVercelConfig(existing: VercelBuildConfig | undefined, generated: Extract<EnsureEveVercelServicesConfigResult, {
115
114
  mode: "generated";
116
- }>): NitroVercelBuildConfig;
115
+ }>): VercelBuildConfig;
117
116
  export {};
@@ -0,0 +1 @@
1
+ import{mkdir,readFile}from"node:fs/promises";import{EVE_ROUTE_PREFIX}from"#protocol/routes.js";import{dirname,join,relative}from"node:path";import{EVE_INTERNAL_BUILD_OUTPUT_DIRECTORY_ENV,EVE_INTERNAL_HOST_BUILD_OUTPUT_DIRECTORY_ENV}from"#internal/application/paths.js";import{findClosestLinkedVercelDirectory}from"#shared/vercel-output-directory.js";import{resolveEveBinaryPath}from"#shared/resolve-eve-binary.js";const VERCEL_JSON_FILE_NAME=`vercel.json`,EVE_SERVICE_ROUTE_SRC=`^${EVE_ROUTE_PREFIX}/(.*)$`,EVE_SERVICE_ROUTE_PATH=`${EVE_ROUTE_PREFIX}/$1`;function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function toPosixRelative(e,t){let n=relative(e,t);return n.length===0?`.`:n.replaceAll(`\\`,`/`)}function quoteShellArgument(e){return`'${e.replaceAll(`'`,`'\\''`)}'`}function isNamedServiceConfigArray(e){return Array.isArray(e)}function createServiceConfigRecord(e){if(e===void 0)return{};if(isNamedServiceConfigArray(e)){let t={};for(let n of e)if(typeof n.name==`string`&&n.name.trim().length>0){let{name:e,...r}=n;t[e]=r}return t}return e}function normalizeVercelJsonConfig(e){if(!isRecord(e))throw Error(`${VERCEL_JSON_FILE_NAME} must contain a JSON object.`);let t=e.services;if(t!==void 0&&!isRecord(t)&&!(Array.isArray(t)&&t.every(e=>isRecord(e)&&typeof e.name==`string`&&e.name.trim().length>0)))throw Error(`${VERCEL_JSON_FILE_NAME} services must be a JSON object or named service array.`);return e}async function readVercelJsonConfig(e){try{return normalizeVercelJsonConfig(JSON.parse(await readFile(e,`utf8`)))}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return{};throw e}}function findEveService(e){return Object.values(e).find(e=>e.framework===`eve`)}function assertRootServicesIncludeEve(e,t){if(findEveService(e)===void 0)throw Error(`${VERCEL_JSON_FILE_NAME} already defines services, so the eve ${t} integration cannot add a generated eve service. Add an eve service (framework "eve") and a rewrite from ${EVE_ROUTE_PREFIX}/(.*) to it in ${VERCEL_JSON_FILE_NAME}, or remove services from ${VERCEL_JSON_FILE_NAME}.`)}function createEveServiceRoute(e=`eve`){return{destination:{service:e,type:`service`},src:EVE_SERVICE_ROUTE_SRC}}function createEveServiceRequestPathRoute(){return{src:EVE_SERVICE_ROUTE_SRC,transforms:[{args:EVE_SERVICE_ROUTE_PATH,op:`set`,type:`request.path`}]}}function isEveServiceRoute(e,t){let n=e.destination;return e.src===EVE_SERVICE_ROUTE_SRC&&isRecord(n)&&n.type===`service`&&n.service===t}function insertEveServiceRoute(e,t){let n=e.filter(e=>!(isRecord(e)&&isEveServiceRoute(e,t))),r=n.findIndex(e=>isRecord(e)&&e.handle===`filesystem`);return r===-1?[createEveServiceRoute(t),...n]:[...n.slice(0,r),createEveServiceRoute(t),...n.slice(r)]}function insertEveServiceRequestPathRoute(e){let t=(e??[]).filter(e=>e.src!==EVE_SERVICE_ROUTE_SRC);return[createEveServiceRequestPathRoute(),...t]}function createGeneratedServiceBuild(e){let t=join(e.hostRoot,`.eve/vercel-services`,`eve`),n=join(t,`.vercel`,`output`),r=join(e.hostRoot,`.vercel`,`output`),a=toPosixRelative(t,e.appRoot),c=toPosixRelative(e.appRoot,n),l=toPosixRelative(e.appRoot,r),u=e.eveBuildCommand??`node ${quoteShellArgument(toPosixRelative(e.appRoot,resolveEveBinaryPath(e.hostRoot)))} build`;return{buildCommand:`cd ${quoteShellArgument(a)} && export ${EVE_INTERNAL_BUILD_OUTPUT_DIRECTORY_ENV}=${quoteShellArgument(c)} && export ${EVE_INTERNAL_HOST_BUILD_OUTPUT_DIRECTORY_ENV}=${quoteShellArgument(l)} && ${u}`,root:toPosixRelative(e.hostRoot,t),rootDirectory:t}}async function ensureEveVercelServicesConfig(t){let n=await findClosestLinkedVercelDirectory(t.hostRoot),a=await readVercelJsonConfig(join(n===void 0?t.hostRoot:dirname(n),VERCEL_JSON_FILE_NAME)),o=createServiceConfigRecord(a.services);if(Object.keys(o).length>0)return assertRootServicesIncludeEve(o,t.frameworkName),{mode:`root`};a.experimentalServices!==void 0&&console.warn(`[eve] ${VERCEL_JSON_FILE_NAME} defines experimentalServices, which Vercel no longer routes. The eve ${t.frameworkName} integration now generates the stable services config automatically — remove experimentalServices from ${VERCEL_JSON_FILE_NAME}.`);let s=createGeneratedServiceBuild(t);return await mkdir(s.rootDirectory,{recursive:!0}),{mode:`generated`,services:{eve:{buildCommand:s.buildCommand,framework:`eve`,routes:[createEveServiceRequestPathRoute()],root:s.root}}}}function mergeEveVercelConfig(e,t){let n=e?.services??{},r=Object.entries(n).find(([e,t])=>e===`eve`||t.framework===`eve`),i=r?.[0]??`eve`,a=r?{...n,[i]:{...r[1],routes:insertEveServiceRequestPathRoute(r[1].routes)}}:{...n,...t.services};return{version:3,...e,routes:insertEveServiceRoute(e?.routes??[],i),services:a}}export{createEveServiceRequestPathRoute,createEveServiceRoute,ensureEveVercelServicesConfig,mergeEveVercelConfig};
@@ -22,7 +22,10 @@ project root with `eve set --model anthropic/claude-opus-4.8` or from the local
22
22
  dev TUI with `/model anthropic/claude-opus-4.8`.
23
23
 
24
24
  The root `agent.ts` can be omitted when no runtime config is needed. In that case, eve defaults
25
- to `anthropic/claude-sonnet-5`. When `agent.ts` is present, `model` is required.
25
+ to `zai/glm-5.2`. GLM 5.2 does not support image input; choose a
26
+ vision-capable model or [route image inputs to Gemini
27
+ Flash](./guides/dynamic-capabilities#route-image-inputs-to-a-vision-model).
28
+ When `agent.ts` is present, `model` is required.
26
29
 
27
30
  `model` accepts a gateway model id string, which routes through the [Vercel AI Gateway](https://vercel.com/docs/ai-gateway). To call a provider directly and configure the model in code, pass a provider-authored `LanguageModel`.
28
31
 
@@ -388,7 +388,7 @@ defineChannel({
388
388
 
389
389
  The `URL` object survives the queue boundary as a string and is reconstituted inside the workflow step. The staging pipeline calls `fetchFile` with the URL serialized as a string (the URL's `href`), which is why the example matches on `url.startsWith(...)`. Return bytes to stage the file to the sandbox, or `null` to let the URL pass through to the model provider.
390
390
 
391
- The framework handles staging bytes to the sandbox, enforcing upload policy, hydrating files for the model call, and reconstituting `URL` objects after queue serialization.
391
+ The framework handles staging bytes to the sandbox, enforcing upload policy, hydrating files for the model call, and reconstituting `URL` objects after queue serialization. See [Inbound attachments](../sandbox#inbound-attachments) for the shared storage, size, and provider-input behavior.
392
392
 
393
393
  ## What to read next
394
394
 
@@ -160,7 +160,7 @@ curl -X POST http://127.0.0.1:2000/eve/v1/session/<sessionId> \
160
160
 
161
161
  Message sends default to cancellation-backed `"steer"`; if a turn is active, eve buffers the follow-up, cancels that turn, and starts the message under a new turn ID. Channels and TypeScript `Session.send(...)` calls can select `turnPolicy: "queue"` when active work should finish first. Structured `inputResponses` never steer.
162
162
 
163
- If one pending batch is waiting on a human-in-the-loop approval, a matching text reply such as `approve` or `cancel` answers it. Unrelated text starts an ordinary turn immediately without denying the tool call; the approval stays pending and answerable. A later structured `inputResponses` answer keyed by its `requestId` still resumes the original tool call, even after intervening turns.
163
+ If the session is waiting on a human-in-the-loop approval, respond with the channel’s Approve or Cancel controls. Text messages do not decide an approval; unrelated text starts an ordinary turn while the approval stays pending and answerable. A later structured `inputResponses` answer keyed by its `requestId` still resumes the original tool call, even after intervening turns.
164
164
 
165
165
  With one question-only batch, an exact option match or permitted freeform response answers `ask_question`. Any other follow-up marks the question unanswered and starts the new turn. With several approval or question batches pending, eve does not guess which batch plain text addresses: the message starts an ordinary turn and the batches stay open. Use structured responses to target requests unambiguously.
166
166
 
@@ -29,7 +29,7 @@ The command creates the project, installs dependencies, and initializes Git. If
29
29
  Pass an AI Gateway model ID or reasoning effort when you do not want the defaults:
30
30
 
31
31
  ```bash
32
- npx eve@latest init my-agent --model openai/gpt-5.5 --reasoning high
32
+ npx eve@latest init my-agent --model openai/gpt-5.6-terra --reasoning high
33
33
  ```
34
34
 
35
35
  To add eve to a project that already has a `package.json`, run this command from its root before you create any `agent/` files:
@@ -96,7 +96,9 @@ await response.result();
96
96
 
97
97
  The stream confirms the turn with `message.received`. Its `data.message` remains the flattened
98
98
  summary for compatibility, and `data.parts` contains structured text and file metadata for clients
99
- that render attachments. File parts never include raw bytes or internal sandbox paths.
99
+ that render attachments. File parts never include raw bytes or internal sandbox paths. See [Inbound
100
+ attachments](../../sandbox#inbound-attachments) for how eve stages byte-backed files in the session
101
+ sandbox and prepares them for each model call.
100
102
 
101
103
  ## Answer human input requests
102
104
 
@@ -21,6 +21,44 @@ resolver first selects a model, eve normalizes the selection and resolves any
21
21
  omitted context-window metadata from the AI Gateway catalog. Dynamic tools,
22
22
  skills, instructions, and subagents may return `null` to omit a capability.
23
23
 
24
+ ### Route image inputs to a vision model
25
+
26
+ Use `step.started` when model choice depends on the current messages. This
27
+ keeps GLM for text and switches to Gemini Flash when user history contains an
28
+ image:
29
+
30
+ ```ts title="agent/agent.ts"
31
+ import { defineAgent, defineDynamic } from "eve";
32
+
33
+ export default defineAgent({
34
+ model: defineDynamic({
35
+ events: {
36
+ "step.started": (_event, ctx) => {
37
+ const hasImage = ctx.messages.some(
38
+ (message) =>
39
+ message.role === "user" &&
40
+ Array.isArray(message.content) &&
41
+ message.content.some(
42
+ (part) =>
43
+ part.type === "image" ||
44
+ (part.type === "file" &&
45
+ (part.mediaType === "image" || part.mediaType.startsWith("image/"))),
46
+ ),
47
+ );
48
+
49
+ return hasImage ? "google/gemini-3.5-flash" : "zai/glm-5.2";
50
+ },
51
+ },
52
+ }),
53
+ });
54
+ ```
55
+
56
+ eve stages byte-backed `file` parts under `/workspace/attachments` before
57
+ `step.started`, but keeps their media type in `ctx.messages`. When an image
58
+ reaches the provider, vision models can process it and non-vision models reject
59
+ it. eve does not reroute automatically. See [Inbound
60
+ attachments](../sandbox#inbound-attachments).
61
+
24
62
  ## Dynamic subagents
25
63
 
26
64
  Wrap a declared subagent's own `agent.ts` in `defineDynamic` when its
@@ -74,7 +74,7 @@ The browser still needs a production authentication policy. See [Authenticate br
74
74
  ## Dev vs deploy topology
75
75
 
76
76
  - **Local dev.** `npm run dev` boots the eve dev server next to SvelteKit and proxies the eve routes to it, so the browser only ever hits the SvelteKit origin. `npm run build && npm run preview` behaves the same way: the preview server gets its own eve route proxy and either reuses the shared eve server or starts one.
77
- - **Vercel.** The SvelteKit app and the eve runtime deploy as a single project. The web app is public; the eve runtime sits behind it on the same origin. Use `eveBuildCommand` for a project-specific agent build:
77
+ - **Vercel.** The SvelteKit app and the eve runtime deploy as a single project. On Vercel builds the plugin adds Build Output [`services`](https://vercel.com/docs/services) for eve and a `routes` entry that sends `/eve/v1/**` to that service before filesystem routing; the SvelteKit app remains the default app. No `vercel.json` is required. By default the generated service runs the installed eve binary from the SvelteKit app's dependencies, so the agent directory does not need its own `package.json`. When the agent needs its own build step, set `eveBuildCommand`:
78
78
 
79
79
  ```ts
80
80
  export default defineConfig({
@@ -95,6 +95,27 @@ The browser still needs a production authentication policy. See [Authenticate br
95
95
  });
96
96
  ```
97
97
 
98
+ ## Managing vercel.json yourself
99
+
100
+ When `vercel.json` declares [`services`](https://vercel.com/docs/services), the plugin generates nothing and your configuration owns routing. It must include the eve service (`framework: "eve"`) and a rewrite that exposes the eve transport, or the build fails:
101
+
102
+ ```json title="vercel.json"
103
+ {
104
+ "services": {
105
+ "web": { "root": ".", "framework": "sveltekit" },
106
+ "eve": { "root": "agent", "framework": "eve", "buildCommand": "eve build" }
107
+ },
108
+ "rewrites": [{ "source": "/eve/v1/(.*)", "destination": { "service": "eve" } }]
109
+ }
110
+ ```
111
+
112
+ ### Migrating from experimentalServices
113
+
114
+ Earlier versions of the plugin wrote the legacy `experimentalServices` field into `vercel.json`. Vercel no longer routes that model, so the plugin now ignores the field and warns when it sees one. Migrate either way:
115
+
116
+ - **Generated (default).** Delete `vercel.json` (or just its `experimentalServices` block) and set the project's Framework Preset back to SvelteKit. The plugin generates the eve service and its routing on every Vercel build.
117
+ - **Hand-maintained.** Replace `experimentalServices` with the stable `services` and `rewrites` shown above, and keep the Services Framework Preset.
118
+
98
119
  ## What to read next
99
120
 
100
121
  - [`useEveAgent` (Svelte)](./use-eve-agent-svelte): the binding API
@@ -3,12 +3,13 @@ title: "CLI"
3
3
  description: "Reference for every eve CLI command: init, set, info, build, start, dev, logs, trace, link, deploy, eval, channels, and extension."
4
4
  ---
5
5
 
6
- The `eve` binary (`bin: eve`) runs from your app root, and every command first loads `.env`/`.env.local` from that root. Running `eve` with no command runs `eve dev`.
6
+ The `eve` binary (`bin: eve`) runs from your app root. Every command first loads `.env`/`.env.local` from that root. Running `eve` with no command runs `eve init` when the current directory is not an eve project, or `eve dev` when it is.
7
7
 
8
8
  ## Commands
9
9
 
10
10
  | Command | Description |
11
11
  | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
12
+ | `eve` | Initialize the current directory, or start development when it is already an eve project |
12
13
  | `eve init [target]` | Create a new agent, or add an agent to an existing project |
13
14
  | `eve info` | Print the resolved application, including static instructions and discovered capabilities, routes, artifact paths, and diagnostics |
14
15
  | `eve build` | Compile `.eve/` artifacts and build the host output; prints the output directory |
@@ -40,19 +41,22 @@ eve init [target] [--model <provider/model-id>] [--reasoning <effort>] [--channe
40
41
 
41
42
  Creates a new agent app or adds an agent to an existing app. Always installs dependencies. New directories also initialize Git.
42
43
 
43
- | Target | What happens |
44
- | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
45
- | `eve init my-agent` | New agent project in `my-agent/` |
46
- | `eve init .` (or an existing project dir) | Adds `agent/` plus missing `eve`, `ai`, and `zod` deps. Needs a `package.json` and no `agent/` files yet |
47
- | `eve init` with no target | Same as `eve init .`, except coding agents (Claude Code, Cursor, and similar) get a setup guide instead of scaffolding — they have not chosen a name yet |
44
+ | Target | What happens |
45
+ | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
46
+ | `eve init my-agent` | Creates an agent project in `my-agent/` |
47
+ | `eve init` or `eve init .` in an empty directory | Creates an agent project in the current directory |
48
+ | `eve init` or `eve init .` in a non-empty directory without `package.json` | Asks whether to scaffold in the current directory or a named subdirectory. Using the current directory preserves unrelated files but overwrites files at generated paths |
49
+ | `eve init .` in an existing project | Adds `agent/` plus missing `eve`, `ai`, and `zod` dependencies. Requires `package.json` and no existing `agent/` files |
50
+
51
+ Coding-agent launches and non-interactive terminals cannot answer the location prompt and fail before writing. Pass a new directory name, such as `eve init my-agent`, in those environments.
48
52
 
49
53
  After scaffolding, a human terminal usually continues into `eve dev`. If a coding-agent REPL is on `PATH`, the handoff menu can open it instead or exit without starting either process. Coding-agent launches print the next steps instead of opening the TUI, so the session does not get stuck. Fresh projects use the parent workspace's package manager when there is one; otherwise they use the manager that launched `eve init`.
50
54
 
51
- | Flag | Type | Default | Description |
52
- | ---------------------- | ------ | --------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
53
- | `--model <model>` | string | `anthropic/claude-sonnet-5` | Set the root agent's AI Gateway model ID. |
54
- | `--reasoning <effort>` | enum | provider default | Set reasoning to `none`, `minimal`, `low`, `medium`, `high`, or `xhigh`. `provider-default` leaves the field unauthored. |
55
- | `--channel-web-nextjs` | flag | off | Add the Web Chat app (Next.js). Not for existing projects — run `eve add channel/web` there instead. |
55
+ | Flag | Type | Default | Description |
56
+ | ---------------------- | ------ | ---------------- | ------------------------------------------------------------------------------------------------------------------------ |
57
+ | `--model <model>` | string | `zai/glm-5.2` | Set the root agent's AI Gateway model ID. |
58
+ | `--reasoning <effort>` | enum | provider default | Set reasoning to `none`, `minimal`, `low`, `medium`, `high`, or `xhigh`. `provider-default` leaves the field unauthored. |
59
+ | `--channel-web-nextjs` | flag | off | Add the Web Chat app (Next.js). Not for existing projects — run `eve add channel/web` there instead. |
56
60
 
57
61
  ## `eve extension`
58
62
 
package/docs/sandbox.mdx CHANGED
@@ -70,6 +70,14 @@ A `SandboxProcess` exposes `stdout`/`stderr` byte streams, `wait()` (resolves wi
70
70
 
71
71
  The option types (`SandboxSpawnOptions`, `SandboxReadBinaryFileOptions`, `SandboxWriteBinaryFileOptions`, and so on) are named exports from `eve/sandbox`, alongside `SandboxProcess`.
72
72
 
73
+ ## Inbound attachments
74
+
75
+ Before the first model step, eve writes byte-backed AI SDK `file` parts under
76
+ `/workspace/attachments` and stores a sandbox reference in session history.
77
+ For provider calls, images up to 3 MiB and PDFs up to 20 MiB are restored as
78
+ bytes; other files become text references to their sandbox paths. Unresolved
79
+ remote URLs and legacy AI SDK `image` parts are not staged.
80
+
73
81
  ## Seeding `/workspace`
74
82
 
75
83
  Mount authored files into the sandbox at session start by placing them under `agent/sandbox/workspace/`. This requires the folder layout (`agent/sandbox/sandbox.ts`), not the top-level shorthand:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eve",
3
- "version": "0.35.0",
3
+ "version": "0.37.0",
4
4
  "private": false,
5
5
  "description": "Filesystem-first framework for durable backend AI agents that run anywhere.",
6
6
  "keywords": [
@@ -325,6 +325,7 @@
325
325
  "@vercel/oidc": "3.8.0",
326
326
  "@vercel/otel": "2.1.3",
327
327
  "@vercel/sandbox": "2.8.0",
328
+ "@vercel/sandbox-drives": "npm:@vercel/sandbox@2.10.0-beta.0",
328
329
  "@vercel/sdk": "1.28.8",
329
330
  "@workflow/core": "5.0.0-beta.41",
330
331
  "@workflow/errors": "5.0.0-beta.16",
@@ -1 +0,0 @@
1
- const e=`2.8.0`;export{e as t};
@@ -1 +0,0 @@
1
- import{mkdir,readFile}from"node:fs/promises";import{EVE_ROUTE_PREFIX}from"#protocol/routes.js";import{dirname,join,relative}from"node:path";import{EVE_INTERNAL_BUILD_OUTPUT_DIRECTORY_ENV,EVE_INTERNAL_HOST_BUILD_OUTPUT_DIRECTORY_ENV}from"#internal/application/paths.js";import{findClosestLinkedVercelDirectory}from"#shared/vercel-output-directory.js";import{resolveEveBinaryPath}from"#shared/resolve-eve-binary.js";const VERCEL_JSON_FILE_NAME=`vercel.json`,EVE_SERVICE_ROUTE_SRC=`^${EVE_ROUTE_PREFIX}/(.*)$`,EVE_SERVICE_ROUTE_PATH=`${EVE_ROUTE_PREFIX}/$1`;function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function toPosixRelative(e,t){let n=relative(e,t);return n.length===0?`.`:n.replaceAll(`\\`,`/`)}function quoteShellArgument(e){return`'${e.replaceAll(`'`,`'\\''`)}'`}function isNamedServiceConfigArray(e){return Array.isArray(e)}function createServiceConfigRecord(e){if(e===void 0)return{};if(isNamedServiceConfigArray(e)){let t={};for(let n of e)if(typeof n.name==`string`&&n.name.trim().length>0){let{name:e,...r}=n;t[e]=r}return t}return e}function normalizeVercelJsonConfig(e){if(!isRecord(e))throw Error(`${VERCEL_JSON_FILE_NAME} must contain a JSON object.`);let t=e.services;if(t!==void 0&&!isRecord(t)&&!(Array.isArray(t)&&t.every(e=>isRecord(e)&&typeof e.name==`string`&&e.name.trim().length>0)))throw Error(`${VERCEL_JSON_FILE_NAME} services must be a JSON object or named service array.`);return e}async function readVercelJsonConfig(e){try{return normalizeVercelJsonConfig(JSON.parse(await readFile(e,`utf8`)))}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return{};throw e}}function findEveService(e){return Object.values(e).find(e=>e.framework===`eve`)}function assertRootServicesIncludeEve(e){if(findEveService(e)===void 0)throw Error(`${VERCEL_JSON_FILE_NAME} already defines services, so the eve Nuxt module cannot add a generated eve service. Add an eve service (framework "eve") and a rewrite from ${EVE_ROUTE_PREFIX}/(.*) to it in ${VERCEL_JSON_FILE_NAME}, or remove services from ${VERCEL_JSON_FILE_NAME}.`)}function createEveServiceRoute(e=`eve`){return{destination:{service:e,type:`service`},src:EVE_SERVICE_ROUTE_SRC}}function createEveServiceRequestPathRoute(){return{src:EVE_SERVICE_ROUTE_SRC,transforms:[{args:EVE_SERVICE_ROUTE_PATH,op:`set`,type:`request.path`}]}}function isEveServiceRoute(e,t){let n=e.destination;return e.src===EVE_SERVICE_ROUTE_SRC&&isRecord(n)&&n.type===`service`&&n.service===t}function insertEveServiceRoute(e,t){let n=e.filter(e=>!(isRecord(e)&&isEveServiceRoute(e,t))),r=n.findIndex(e=>isRecord(e)&&e.handle===`filesystem`);return r===-1?[createEveServiceRoute(t),...n]:[...n.slice(0,r),createEveServiceRoute(t),...n.slice(r)]}function insertEveServiceRequestPathRoute(e){let t=(e??[]).filter(e=>e.src!==EVE_SERVICE_ROUTE_SRC);return[createEveServiceRequestPathRoute(),...t]}function createGeneratedServiceBuild(e){let t=join(e.nuxtRoot,`.eve/vercel-services`,`eve`),n=join(t,`.vercel`,`output`),r=join(e.nuxtRoot,`.vercel`,`output`),a=toPosixRelative(t,e.appRoot),c=toPosixRelative(e.appRoot,n),l=toPosixRelative(e.appRoot,r),u=e.eveBuildCommand??`node ${quoteShellArgument(toPosixRelative(e.appRoot,resolveEveBinaryPath(e.nuxtRoot)))} build`;return{buildCommand:`cd ${quoteShellArgument(a)} && export ${EVE_INTERNAL_BUILD_OUTPUT_DIRECTORY_ENV}=${quoteShellArgument(c)} && export ${EVE_INTERNAL_HOST_BUILD_OUTPUT_DIRECTORY_ENV}=${quoteShellArgument(l)} && ${u}`,root:toPosixRelative(e.nuxtRoot,t),rootDirectory:t}}async function ensureEveVercelServicesConfig(t){let n=await findClosestLinkedVercelDirectory(t.nuxtRoot),a=await readVercelJsonConfig(join(n===void 0?t.nuxtRoot:dirname(n),VERCEL_JSON_FILE_NAME)),o=createServiceConfigRecord(a.services);if(Object.keys(o).length>0)return assertRootServicesIncludeEve(o),{mode:`root`};a.experimentalServices!==void 0&&console.warn(`[eve] ${VERCEL_JSON_FILE_NAME} defines experimentalServices, which Vercel no longer routes. The eve Nuxt module now generates the stable services config automatically — remove experimentalServices from ${VERCEL_JSON_FILE_NAME}.`);let s=createGeneratedServiceBuild(t);return await mkdir(s.rootDirectory,{recursive:!0}),{mode:`generated`,services:{eve:{buildCommand:s.buildCommand,framework:`eve`,routes:[createEveServiceRequestPathRoute()],root:s.root}}}}function mergeEveVercelConfig(e,t){let n=e?.services??{},r=Object.entries(n).find(([e,t])=>e===`eve`||t.framework===`eve`),i=r?.[0]??`eve`,a=r?{...n,[i]:{...r[1],routes:insertEveServiceRequestPathRoute(r[1].routes)}}:{...n,...t.services};return{version:3,...e,routes:insertEveServiceRoute(e?.routes??[],i),services:a}}export{createEveServiceRequestPathRoute,createEveServiceRoute,ensureEveVercelServicesConfig,mergeEveVercelConfig};
@@ -1,17 +0,0 @@
1
- export interface EnsureVercelJsonResult {
2
- readonly servicePrefix: string;
3
- }
4
- /**
5
- * Ensure `vercel.json` declares the SvelteKit web service and the eve agent
6
- * service so a Vercel deployment ships both from one project.
7
- *
8
- * Existing services are preserved untouched; an already-configured eve
9
- * service's `routePrefix` wins over {@link input.servicePrefix}. The file is
10
- * only rewritten when the resulting config differs from what is on disk.
11
- */
12
- export declare function ensureEveVercelJson(input: {
13
- readonly appRoot: string;
14
- readonly eveBuildCommand: string;
15
- readonly servicePrefix: string;
16
- readonly svelteKitRoot: string;
17
- }): Promise<EnsureVercelJsonResult>;
@@ -1 +0,0 @@
1
- import{createEveVercelRewrite}from"./routing.js";import{readFile,writeFile}from"node:fs/promises";import{join,relative}from"node:path";const VERCEL_JSON_FILE_NAME=`vercel.json`;function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function resolveRelativeEntrypoint(e,t){let n=relative(e,t);return n.length===0?`.`:n.replaceAll(`\\`,`/`)}function normalizeVercelJsonConfig(e){if(!isRecord(e))throw Error(`${VERCEL_JSON_FILE_NAME} must contain a JSON object.`);let t=e.experimentalServices;if(t!==void 0&&!isRecord(t))throw Error(`${VERCEL_JSON_FILE_NAME} experimentalServices must be a JSON object.`);let n=e.rewrites;if(n!==void 0&&!Array.isArray(n))throw Error(`${VERCEL_JSON_FILE_NAME} rewrites must be an array.`);return e}async function readVercelJsonConfig(e){try{return normalizeVercelJsonConfig(JSON.parse(await readFile(e,`utf8`)))}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return{};throw e}}function findServiceByFramework(e,t){return Object.values(e).find(e=>e.framework===t)}function hasRewrite(e,t){return e.some(e=>e.source===t.source&&e.destination===t.destination)}async function ensureEveVercelJson(t){let r=join(t.svelteKitRoot,VERCEL_JSON_FILE_NAME),i=await readVercelJsonConfig(r),a=resolveRelativeEntrypoint(t.svelteKitRoot,t.appRoot),o=i.experimentalServices??{},s=findServiceByFramework(o,`eve`),c=findServiceByFramework(o,`sveltekit`),l=s?.routePrefix??t.servicePrefix,u={...o};c===void 0&&(u.web={entrypoint:`.`,framework:`sveltekit`,routePrefix:`/`}),s===void 0&&(u.eve={buildCommand:t.eveBuildCommand,entrypoint:a,framework:`eve`,routePrefix:l});let d=createEveVercelRewrite(l),f=i.rewrites??[],p={...i,$schema:i.$schema??`https://openapi.vercel.sh/vercel.json`,experimentalServices:u,rewrites:hasRewrite(f,d)?f:[d,...f]};return JSON.stringify(i)!==JSON.stringify(p)&&await writeFile(r,`${JSON.stringify(p,null,2)}\n`),{servicePrefix:l}}export{ensureEveVercelJson};