Nuxt

Use Better Agent in Nuxt with a server route and the Vue useAgent hook.

Server

// lib/better-agent/server.ts
import { betterAgent, defineAgent } from "@better-agent/core";
import { openai } from "@better-agent/openai";

const supportAgent = defineAgent({
  name: "support",
  model: openai("gpt-5.5"),
  instruction: "You help customers.",
});

const app = betterAgent({
  agents: [supportAgent],
  basePath: "/api/agents",
});

export default app;

Route

// server/api/agents/[...path].ts
import { defineEventHandler, toWebRequest } from "h3";
import app from "~~/lib/better-agent/server";

export default defineEventHandler((event) => app.handler(toWebRequest(event)));

Client

// lib/better-agent/client.ts
import { createClient } from "@better-agent/client";
import type app from "./server";

export const client = createClient<typeof app>({
  baseURL: "/api/agents",
});

Basic chat

<script setup lang="ts">
import { useAgent } from "@better-agent/client/vue";
import { ref } from "vue";
import { client } from "~~/lib/better-agent/client";

const input = ref("");
const agent = useAgent(client.agent("support"), {
  threadId: "main",
});

async function send() {
  const message = input.value.trim();
  if (!message) return;
  input.value = "";
  await agent.sendMessage(message);
}
</script>

<template>
  <form @submit.prevent="send">
    <p v-for="message in agent.messages.value" :key="message.id">
      {{ message.role }}
    </p>
    <p v-if="agent.error.value">{{ agent.error.value.message }}</p>
    <input v-model="input" />
    <button :disabled="agent.isRunning.value">Send</button>
    <button type="button" :disabled="!agent.isRunning.value" @click="agent.stop()">
      Stop
    </button>
  </form>
</template>

Threads

<script setup lang="ts">
const agent = useAgent(client.agent("support"), {
  threadId: "customer-123",
});

async function switchThread() {
  await agent.loadMessages();
  await agent.selectThread("customer-456");
}
</script>

Context

<script setup lang="ts">
const agent = useAgent(client.agent("support"), {
  context: {
    workspaceId: "workspace_123",
  },
});
</script>

Client tools

<script setup lang="ts">
const agent = useAgent(client.agent("support"), {
  toolHandlers: {
    confirm_address: async (input) => {
      const confirmed = window.confirm(input.address);
      return { confirmed };
    },
  },
});
</script>

Approvals

<template>
  <div v-for="approval in agent.pendingToolApprovals.value" :key="approval.interruptId">
    <p>{{ approval.toolName }}</p>
    <button @click="agent.approveToolCall(approval.interruptId)">
      Approve
    </button>
    <button @click="agent.rejectToolCall(approval.interruptId)">
      Reject
    </button>
  </div>
</template>

Events

<script setup lang="ts">
import { EventType } from "@better-agent/core";

const agent = useAgent(client.agent("support"), {
  onEvent(event) {
    if (event.type === EventType.TEXT_MESSAGE_CONTENT) {
      console.log(event.delta);
    }
  },
});
</script>

Finish and errors

<script setup lang="ts">
const agent = useAgent(client.agent("support"), {
  onFinish(finish) {
    console.log(finish.runId, finish.isInterrupted);
  },
  onError(error) {
    console.error(error.code, error.message);
  },
});
</script>

Next

See Client, Tools, Human in the Loop, Memory, Events, and Storage.