From d6aee48af643d7a1da4ab47d1d846b8b9046171d Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Thu, 9 Jul 2026 10:15:17 -0700 Subject: [PATCH] feat(eve): support named Next agents Signed-off-by: JJ Kasper --- .changeset/named-next-agents.md | 5 + apps/frameworks/README.md | 1 + apps/frameworks/next-multi-agent/README.md | 16 + .../next-multi-agent/agents/billing/agent.ts | 5 + .../agents/billing/instructions.md | 4 + .../agents/billing/tools/identify_agent.ts | 11 + .../next-multi-agent/agents/research/agent.ts | 5 + .../agents/research/instructions.md | 4 + .../agents/research/tools/identify_agent.ts | 11 + .../next-multi-agent/agents/support/agent.ts | 5 + .../agents/support/instructions.md | 4 + .../agents/support/tools/identify_agent.ts | 11 + .../next-multi-agent/app/layout.tsx | 19 ++ apps/frameworks/next-multi-agent/app/page.tsx | 100 ++++++ .../next-multi-agent/app/styles.css | 173 ++++++++++ .../frameworks/next-multi-agent/next-env.d.ts | 6 + .../next-multi-agent/next.config.ts | 16 + apps/frameworks/next-multi-agent/package.json | 26 ++ .../frameworks/next-multi-agent/tsconfig.json | 21 ++ docs/guides/frontend/nextjs.mdx | 39 ++- docs/guides/frontend/overview.mdx | 8 +- packages/eve/src/client/agent-host.test.ts | 27 ++ packages/eve/src/client/agent-host.ts | 28 ++ .../src/discover/agent.integration.test.ts | 27 ++ packages/eve/src/discover/filesystem.ts | 18 + packages/eve/src/discover/project.ts | 4 +- .../host/build-application.scenario.test.ts | 192 ++++++++--- .../internal/nitro/host/build-application.ts | 88 ++++- .../create-application-nitro.scenario.test.ts | 25 +- .../nitro/host/create-application-nitro.ts | 27 ++ .../eve-service-route-output.ts | 132 +------- .../workflow-bundle/vercel-workflow-output.ts | 4 - .../src/public/next/index.integration.test.ts | 245 +++++++++++++- packages/eve/src/public/next/index.test.ts | 141 +++++++- packages/eve/src/public/next/index.ts | 257 +++++++++++--- .../public/next/server.integration.test.ts | 52 +++ packages/eve/src/public/next/server.ts | 93 +++++- .../src/public/next/vercel-output-config.ts | 316 ++++++++++++++---- packages/eve/src/react/use-eve-agent.test.ts | 37 ++ packages/eve/src/react/use-eve-agent.ts | 12 +- packages/eve/src/svelte/use-eve-agent.ts | 12 +- packages/eve/src/vue/use-eve-agent.ts | 12 +- pnpm-lock.yaml | 34 ++ 43 files changed, 1938 insertions(+), 335 deletions(-) create mode 100644 .changeset/named-next-agents.md create mode 100644 apps/frameworks/next-multi-agent/README.md create mode 100644 apps/frameworks/next-multi-agent/agents/billing/agent.ts create mode 100644 apps/frameworks/next-multi-agent/agents/billing/instructions.md create mode 100644 apps/frameworks/next-multi-agent/agents/billing/tools/identify_agent.ts create mode 100644 apps/frameworks/next-multi-agent/agents/research/agent.ts create mode 100644 apps/frameworks/next-multi-agent/agents/research/instructions.md create mode 100644 apps/frameworks/next-multi-agent/agents/research/tools/identify_agent.ts create mode 100644 apps/frameworks/next-multi-agent/agents/support/agent.ts create mode 100644 apps/frameworks/next-multi-agent/agents/support/instructions.md create mode 100644 apps/frameworks/next-multi-agent/agents/support/tools/identify_agent.ts create mode 100644 apps/frameworks/next-multi-agent/app/layout.tsx create mode 100644 apps/frameworks/next-multi-agent/app/page.tsx create mode 100644 apps/frameworks/next-multi-agent/app/styles.css create mode 100644 apps/frameworks/next-multi-agent/next-env.d.ts create mode 100644 apps/frameworks/next-multi-agent/next.config.ts create mode 100644 apps/frameworks/next-multi-agent/package.json create mode 100644 apps/frameworks/next-multi-agent/tsconfig.json create mode 100644 packages/eve/src/client/agent-host.test.ts create mode 100644 packages/eve/src/client/agent-host.ts diff --git a/.changeset/named-next-agents.md b/.changeset/named-next-agents.md new file mode 100644 index 000000000..6a22efa99 --- /dev/null +++ b/.changeset/named-next-agents.md @@ -0,0 +1,5 @@ +--- +"eve": patch +--- + +Add named multi-agent routing to `withEve` and `useEveAgent`. Next.js apps can now configure multiple eve roots with `agents`, then target one from the frontend with `useEveAgent({ agent: "name" })`. diff --git a/apps/frameworks/README.md b/apps/frameworks/README.md index f36feef15..50ad9c7fc 100644 --- a/apps/frameworks/README.md +++ b/apps/frameworks/README.md @@ -3,6 +3,7 @@ These apps verify eve's frontend framework integrations and act as runnable examples for maintainers. - `framework-next` covers `eve/next` and `withEve()`. +- `framework-next-multi-agent` covers `withEve({ agents })` and named `useEveAgent({ agent })` calls. - `framework-nuxt` covers the `eve/nuxt` module. - `framework-sveltekit` covers the `eve/sveltekit` Vite plugin. diff --git a/apps/frameworks/next-multi-agent/README.md b/apps/frameworks/next-multi-agent/README.md new file mode 100644 index 000000000..2c6f8e88b --- /dev/null +++ b/apps/frameworks/next-multi-agent/README.md @@ -0,0 +1,16 @@ +# Next.js multi-agent eve demo + +This app demonstrates `withEve({ agents })` with three independent eve agents +mounted into one Next.js app: + +- `support` at `/eve/agents/support/eve/v1/*` +- `billing` at `/eve/agents/billing/eve/v1/*` +- `research` at `/eve/agents/research/eve/v1/*` + +Run it locally with: + +```sh +pnpm --filter framework-next-multi-agent dev +``` + +The page calls each agent with `useEveAgent({ agent: "" })`. diff --git a/apps/frameworks/next-multi-agent/agents/billing/agent.ts b/apps/frameworks/next-multi-agent/agents/billing/agent.ts new file mode 100644 index 000000000..af4b36659 --- /dev/null +++ b/apps/frameworks/next-multi-agent/agents/billing/agent.ts @@ -0,0 +1,5 @@ +import { defineAgent } from "eve"; + +export default defineAgent({ + model: "anthropic/claude-opus-4.6", +}); diff --git a/apps/frameworks/next-multi-agent/agents/billing/instructions.md b/apps/frameworks/next-multi-agent/agents/billing/instructions.md new file mode 100644 index 000000000..f83fefeba --- /dev/null +++ b/apps/frameworks/next-multi-agent/agents/billing/instructions.md @@ -0,0 +1,4 @@ +You are the billing agent in the Next.js multi-agent fixture. + +Keep replies to one or two short sentences. Help with invoices, plans, refunds, +and payment status. diff --git a/apps/frameworks/next-multi-agent/agents/billing/tools/identify_agent.ts b/apps/frameworks/next-multi-agent/agents/billing/tools/identify_agent.ts new file mode 100644 index 000000000..10288c5b3 --- /dev/null +++ b/apps/frameworks/next-multi-agent/agents/billing/tools/identify_agent.ts @@ -0,0 +1,11 @@ +import { defineTool } from "eve/tools"; +import { z } from "zod"; + +export default defineTool({ + description: "Return the identity and focus area of this fixture agent.", + inputSchema: z.object({}), + execute: async () => ({ + agent: "billing", + focus: "Invoices, plans, and payment questions", + }), +}); diff --git a/apps/frameworks/next-multi-agent/agents/research/agent.ts b/apps/frameworks/next-multi-agent/agents/research/agent.ts new file mode 100644 index 000000000..af4b36659 --- /dev/null +++ b/apps/frameworks/next-multi-agent/agents/research/agent.ts @@ -0,0 +1,5 @@ +import { defineAgent } from "eve"; + +export default defineAgent({ + model: "anthropic/claude-opus-4.6", +}); diff --git a/apps/frameworks/next-multi-agent/agents/research/instructions.md b/apps/frameworks/next-multi-agent/agents/research/instructions.md new file mode 100644 index 000000000..bb480b174 --- /dev/null +++ b/apps/frameworks/next-multi-agent/agents/research/instructions.md @@ -0,0 +1,4 @@ +You are the research agent in the Next.js multi-agent fixture. + +Keep replies to one or two short sentences. Help turn research questions into a +clear next step or brief summary. diff --git a/apps/frameworks/next-multi-agent/agents/research/tools/identify_agent.ts b/apps/frameworks/next-multi-agent/agents/research/tools/identify_agent.ts new file mode 100644 index 000000000..7f7b3bcad --- /dev/null +++ b/apps/frameworks/next-multi-agent/agents/research/tools/identify_agent.ts @@ -0,0 +1,11 @@ +import { defineTool } from "eve/tools"; +import { z } from "zod"; + +export default defineTool({ + description: "Return the identity and focus area of this fixture agent.", + inputSchema: z.object({}), + execute: async () => ({ + agent: "research", + focus: "Research summaries and source planning", + }), +}); diff --git a/apps/frameworks/next-multi-agent/agents/support/agent.ts b/apps/frameworks/next-multi-agent/agents/support/agent.ts new file mode 100644 index 000000000..af4b36659 --- /dev/null +++ b/apps/frameworks/next-multi-agent/agents/support/agent.ts @@ -0,0 +1,5 @@ +import { defineAgent } from "eve"; + +export default defineAgent({ + model: "anthropic/claude-opus-4.6", +}); diff --git a/apps/frameworks/next-multi-agent/agents/support/instructions.md b/apps/frameworks/next-multi-agent/agents/support/instructions.md new file mode 100644 index 000000000..393dabeed --- /dev/null +++ b/apps/frameworks/next-multi-agent/agents/support/instructions.md @@ -0,0 +1,4 @@ +You are the support agent in the Next.js multi-agent fixture. + +Keep replies to one or two short sentences. Help triage product issues and ask +for only the next missing detail. diff --git a/apps/frameworks/next-multi-agent/agents/support/tools/identify_agent.ts b/apps/frameworks/next-multi-agent/agents/support/tools/identify_agent.ts new file mode 100644 index 000000000..29c05aacc --- /dev/null +++ b/apps/frameworks/next-multi-agent/agents/support/tools/identify_agent.ts @@ -0,0 +1,11 @@ +import { defineTool } from "eve/tools"; +import { z } from "zod"; + +export default defineTool({ + description: "Return the identity and focus area of this fixture agent.", + inputSchema: z.object({}), + execute: async () => ({ + agent: "support", + focus: "Customer-facing triage and troubleshooting", + }), +}); diff --git a/apps/frameworks/next-multi-agent/app/layout.tsx b/apps/frameworks/next-multi-agent/app/layout.tsx new file mode 100644 index 000000000..844e0080d --- /dev/null +++ b/apps/frameworks/next-multi-agent/app/layout.tsx @@ -0,0 +1,19 @@ +import type { Metadata } from "next"; +import "./styles.css"; + +export const metadata: Metadata = { + title: "eve multi-agent Next.js fixture", + description: "Next.js fixture for withEve named agents.", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + {children} + + ); +} diff --git a/apps/frameworks/next-multi-agent/app/page.tsx b/apps/frameworks/next-multi-agent/app/page.tsx new file mode 100644 index 000000000..009fba6df --- /dev/null +++ b/apps/frameworks/next-multi-agent/app/page.tsx @@ -0,0 +1,100 @@ +"use client"; + +import { useState, type ComponentProps } from "react"; +import { useEveAgent } from "eve/react"; + +const AGENTS = [ + { + description: "Customer-facing triage and troubleshooting", + initialPrompt: "My checkout page is failing.", + name: "support", + }, + { + description: "Invoices, plans, and payment questions", + initialPrompt: "Why did my invoice increase?", + name: "billing", + }, + { + description: "Research summaries and source planning", + initialPrompt: "Compare two options briefly.", + name: "research", + }, +] as const; + +type AgentName = (typeof AGENTS)[number]["name"]; + +export default function Home() { + return ( +
+
+

Next.js named agents fixture

+

Three eve agents mounted through one Next.js app

+
+
+ {AGENTS.map((agent) => ( + + ))} +
+
+ ); +} + +function AgentPanel({ + agent, +}: { + readonly agent: { + readonly description: string; + readonly initialPrompt: string; + readonly name: AgentName; + }; +}) { + const eve = useEveAgent({ agent: agent.name }); + const [message, setMessage] = useState(agent.initialPrompt); + const isBusy = eve.status === "submitted" || eve.status === "streaming"; + + const submit: ComponentProps<"form">["onSubmit"] = async (event) => { + event.preventDefault(); + const trimmed = message.trim(); + if (trimmed.length === 0 || isBusy) return; + setMessage(""); + await eve.send({ message: trimmed }); + }; + + return ( +
+
+
+

{agent.name}

+

{agent.description}

+
+ {eve.status} +
+ +
+ {eve.data.messages.length === 0 ? ( +

Send a short prompt to the {agent.name} agent.

+ ) : ( + eve.data.messages.map((item) => ( +
+ {item.role} + {item.parts.map((part, index) => + part.type === "text" ?

{part.text}

: null, + )} +
+ )) + )} +
+ +
+