☰
eve × SvelteKit:用 eveSvelteKit Vite 插件把 Agent 与前端合二为一
2026/10/14 15:06:27 网站建设 项目流程
  • 人工智能
  • AI Agent
  • Agent 框架
  • 后端
  • 工具调用

【免费下载链接】eve

The Open Framework for Building Agents

项目地址:https://gitcode.com/gh_mirrors/eve28/eve
点击查看免费下载

本文以apps/frameworks/sveltekit/下的 SvelteKit 示例应用为主体,讲解如何通过eveSvelteKit()Vite 插件将 eve agent 与 SvelteKit 应用整合为单一项目:从agent/目录的指令、工具与频道配置,到useEveAgentSvelte 绑定驱动的控制台 UI,再到本地开发与 Vercel 部署的完整拓扑。读完本文,你将掌握在 SvelteKit 中挂载 eve 运行时的全部接线方式、插件的两个配置项(eveRoot/eveBuildCommand)的语义,以及从源码层面理解 dev 代理与 Vercel Build Output 生成机制的原理。

1. 一体化项目的整体结构

这个示例的定位很直接:一个嵌入了 eve agent 的 SvelteKit 应用,通过eve/sveltekit提供的 Vite 插件完成集成(见 README):

import { eveSvelteKit } from "eve/sveltekit"; export default defineConfig({ plugins: [eveSvelteKit(), sveltekit()], });

仓库中的实际配置(vite.config.ts)在插件链中还加入了 Tailwind 与 Vercel 适配器:

import adapter from "@sveltejs/adapter-vercel"; import { sveltekit } from "@sveltejs/kit/vite"; import tailwindcss from "@tailwindcss/vite"; import { eveSvelteKit } from "eve/sveltekit"; import { defineConfig } from "vite"; export default defineConfig({ plugins: [eveSvelteKit(), tailwindcss(), sveltekit({ adapter: adapter() })], });

注意插件注册顺序:eveSvelteKit()写在sveltekit()之前,且插件内部以enforce: "post"挂入,确保在 SvelteKit 自身配置解析后再注入代理与构建产物逻辑(见 插件入口)。

整个 demo 的目录分工:

  • agent/:eve agent 本体——指令、工具、频道配置;
  • src/lib/:基于 eve 的 Svelte 绑定构建的小型 agent 控制台,具备流式输出、推理块与工具调用渲染;
  • src/routes/:SvelteKit 路由,首页即控制台。

依赖方面(package.json):@sveltejs/kit、svelte5、vite8、@sveltejs/adapter-vercel与eve(workspace 依赖)。

2. agent/ 目录:指令、模型、工具与频道

2.1 模型与推理配置

agent/agent.ts 用defineAgent声明 agent,开启了 Anthropic 的自适应思考模式:

import { defineAgent } from "eve"; export default defineAgent({ model: "anthropic/claude-opus-4.7", modelOptions: { providerOptions: { anthropic: { thinking: { type: "adaptive", display: "summarized" }, effort: "high", }, }, }, });

thinking.display: "summarized"意味着思考内容会以摘要形式回传给前端,这正好对应控制台中ReasoningBlock组件对reasoning类型消息片的渲染(流式时标记state === "streaming")。

2.2 内置天气工具

agent/tools/get_weather.ts 演示了用 zod 定义入参 schema 的工具:

import { defineTool } from "eve/tools"; import { never } from "eve/tools/approval"; import { z } from "zod"; export default defineTool({ approval: never(), description: "Get the current weather for a city.", inputSchema: z.object({ city: z.string(), }), async execute(input) { const city = input.city; await sleep(300); return { city, temperatureF: 72, condition: "Sunny", summary: `Sunny in ${city} with a light breeze.`, }; }, });

两个要点:approval: never()表示该工具永不触发人工审批;300ms 的sleep是为了让前端能观察到工具调用从input-available(Running)到output-available(Completed)的状态流转。

2.3 频道与鉴权

agent/channels/eve.ts 配置了eve频道:

import { localDev, none } from "eve/channels/auth"; import { eveChannel } from "eve/channels/eve"; // 示例接受匿名流量以便部署后的 demo 可直接点击体验; // 公开暴露 agent 前请换成真实 provider(Auth.js、Clerk、vercelOidc() 等)。 export default eveChannel({ auth: [localDev(), none()], });

源码注释明确说明:none()只适合受部署保护门禁约束的演示环境;浏览器端生产环境仍需一套生产鉴权策略,可参考 前端总览 中默认的 fail-closed 行为与频道配置说明。指令文件 agent/instructions.md 则将 agent 限定为"内嵌在 SvelteKit 应用中的天气助手"。

3. 注册 Vite 插件:eveRoot 与 eveBuildCommand

完整指南见 SvelteKit 前端文档。前置条件:项目已安装eve包、存在一个 eve agent 目录、有一个要挂载 agent 的 SvelteKit 应用。

插件默认在 SvelteKit 项目根目录查找agent/文件夹;当 agent 位于别处时,用eveRoot指定(相对路径基于 SvelteKit 项目根,也支持绝对路径——见 resolveApplicationRoot):

export default defineConfig({ plugins: [ eveSvelteKit({ eveRoot: "../my-agent", }), sveltekit(), ], });

插件只接受两个选项(EveSvelteKitPluginOptions):

选项类型作用
eveRootstring?eve 应用根目录,相对 SvelteKit 项目根(除非是绝对路径),默认即 SvelteKit 项目根
eveBuildCommandstring?在生成的 Vercel eve service 内部构建 eve 应用的命令;默认直接运行 SvelteKit 依赖中的 eve 二进制(node <path>/eve/bin/eve.js build)

因此 agent 目录本身不需要独立的package.json,eve 运行时复用 SvelteKit 应用依赖里安装的eve。只有当 agent 需要自己的构建步骤时才设置eveBuildCommand:

export default defineConfig({ plugins: [ eveSvelteKit({ eveBuildCommand: "npm run build:eve", }), sveltekit(), ], });

4. 在组件中调用 useEveAgent

插件注册后,组件直接从eve/svelte调用useEveAgent(),不需要传 host——它会自动发现挂载在本应用源站上的路由(浏览器只访问 SvelteKit origin,没有 CORS、也没有需要同步的 URL 环境变量):

<script lang="ts"> import { useEveAgent } from "eve/svelte"; const agent = useEveAgent(); let message = $state(""); let isBusy = $derived(agent.status === "submitted" || agent.status === "streaming"); let isInputDisabled = $derived(isBusy || agent.status === "resuming"); async function handleSubmit() { const text = message.trim(); if (!text || isInputDisabled) return; message = ""; await agent.send(text); } </script> <form onsubmit={(event) => { event.preventDefault(); void handleSubmit(); }}> <input bind:value={message} disabled={isInputDisabled} /> <button type="submit" disabled={isInputDisabled}>Send</button> </form>

绑定返回的对象不是 Svelte store:状态字段(data、status、error、events、session)是 Svelte 5 风格的响应式 getter,可直接在模板、$derived、$effect中读取;命令(send、respond、prewarm、resume、cancel、reset)是普通方法。完整接口见 useEveAgent (Svelte) 与 Svelte 绑定实现。

示例控制台的关键实现

EveAgentConsole.svelte 展示了这套绑定的典型用法:

  • 用agent.status推导isBusy(submitted/streaming)与isResuming(resuming),据此禁用输入;
  • 消息按message.parts分类型渲染:text直出、reasoning交给 ReasoningBlock、file渲染附件卡片、dynamic-tool交给 ToolBlock;
  • 流式生成期间发送按钮变为"停止"按钮,调用agent.cancel()请求取消服务端持久化的这一轮;
  • HITL 审批/提问通过agent.respond(responses)回传,ToolBlock 会渲染approval-requested等状态并提供选项按钮;
  • StatusDot 把ready/submitted/streaming/error状态映射为不同颜色圆点。

5. dev 与部署拓扑(源码级解析)

5.1 本地开发:代理到共享 eve dev server

插件在serve阶段把/eve/v1前缀(EVE_ROUTE_PREFIX,定义于 protocol/routes.ts)代理到 eve 服务器。代理目标按以下顺序解析(resolveEveDevProxyTarget):

  1. 环境变量EVE_BASE_URL已设置时,直接使用其指向的 origin;
  2. 否则查找该应用已经存在且健康的共享 eve dev server(基于.eve/sveltekit-dev-server.json注册表,带 30s 超时与锁文件,见 dev-server.ts);
  3. 仍无则新启动eve dev --no-ui --port 0。

所以npm run dev启动的是"SvelteKit + 旁边的 eve dev server",浏览器始终只命中 SvelteKit origin;npm run build && npm run preview同理——preview 服务器同样拿到一份 eve 路由代理(对应插件中env.isPreview分支写入preview.proxy的逻辑,见 index.ts)。

在仓库内运行这个 demo:

pnpm --filter framework-sveltekit dev

其他常用脚本(package.json):build/build:sveltekit(vite build)、preview(vite preview)、typecheck(svelte-kit sync && tsc --noEmit)。

5.2 Vercel:单项目部署,无需 vercel.json

在 Vercel 构建时,插件把 SvelteKit 应用与 eve 运行时作为同一项目部署。构建期间插件向 Vercel Build Output 追加 eve 的services条目,并插入一条把/eve/v1/**先于文件系统路由转给该 service 的routes规则;SvelteKit 应用仍是默认 app。合并动作发生在 SSR 构建的closeBundle阶段,写入.vercel/output/config.json(mergeGeneratedVercelServicesConfig、closeBundle handler)。服务路由的匹配与 path transform 逻辑实现在 shared/vercel-services.ts。

因此不需要vercel.json。当 agent 需要自己的构建步骤时,用eveBuildCommand覆盖默认的node <path>/eve/bin/eve.js build。

5.3 非 Vercel 托管

当 eve service 跑在独立 origin 上时,直接把host传给绑定:

const agent = useEveAgent({ host: "https://agent.example.com", });

5.4 自行维护 vercel.json

如果vercel.json已声明services,插件不再生成任何配置,路由完全由你的文件拥有(插件源码中对应mode: "root"的跳过分支,见 EnsureEveVercelServicesConfigResult)。此时文件必须包含 eve service(framework: "eve")以及暴露 eve transport 的 rewrite,否则构建失败:

{ "services": { "web": { "root": ".", "framework": "sveltekit" }, "eve": { "root": "agent", "framework": "eve", "buildCommand": "eve build" } }, "rewrites": [{ "source": "/eve/v1/(.*)", "destination": { "service": "eve" } }] }

从旧版experimentalServices迁移有两个方向:

  • 生成式(默认):删除vercel.json(或仅删掉其experimentalServices块),并把项目 Framework Preset 设回 SvelteKit,插件会在每次 Vercel 构建时生成 eve service 与路由;
  • 手工维护式:把experimentalServices替换为上文稳定的services+rewrites,并保留 Services Framework Preset。

6. 小结

关注点本示例的做法依据
插件注册plugins: [eveSvelteKit(), tailwindcss(), sveltekit({ adapter })]vite.config.ts
agent 位置项目根agent/(默认,无需eveRoot)agent 目录
前端绑定useEveAgent(),不传 hostEveAgentConsole.svelte
本地运行pnpm --filter framework-sveltekit devpackage.json
Vercel 部署插件生成 service 与/eve/v1/**路由,无需 vercel.jsonvercel-services.ts
独立 originuseEveAgent({ host })SvelteKit 指南

这套接线让 SvelteKit 前端与 eve agent 在开发时共享一个源站(靠 Vite 代理)、在部署时共享一个项目(靠 Build Output services),前端拿到的是一套与 React/Vue 等绑定共享语义的响应式 API——流式消息、推理摘要、工具状态与 HITL 审批都能以 Svelte 5 runes 的方式直接投影到 UI。

  • 人工智能
  • AI Agent
  • Agent 框架
  • 后端
  • 工具调用

【免费下载链接】eve

The Open Framework for Building Agents

项目地址:https://gitcode.com/gh_mirrors/eve28/eve
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询