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, + )} +
+ )) + )} +
+ +
+