Fastify

05 Tools and Context

Pass Fastify auth, request data, and retrieval context into Anvia tools.

Use Fastify decorators or hooks for auth. Pass request-local data into Anvia at the route boundary.

1. Add A User Decoration

import fp from "fastify-plugin";

declare module "fastify" {
  interface FastifyRequest {
    user?: { id: string };
  }
}

export const authPlugin = fp(async (app) => {
  app.addHook("preHandler", async (request, reply) => {
    const user = await auth.userFromRequest(request);

    if (!user) {
      return reply.status(401).send({ error: { code: "unauthorized" } });
    }

    request.user = { id: user.id };
  });
});

2. Build Request-Local Tools

import { createTool } from "@anvia/core";
import { z } from "zod";

export function createAccountTool(input: { userId: string }) {
  return createTool({
    name: "get_account_status",
    description: "Read the authenticated user's account status.",
    input: z.object({}),
    output: z.object({ plan: z.string(), openTickets: z.number() }),
    async execute() {
      return db.account.findStatus({ userId: input.userId });
    },
  });
}

3. Attach Context In The Route

app.post("/support", async (request, reply) => {
  const { message } = SupportRequest.parse(request.body);
  const userId = request.user?.id;

  if (!userId) {
    return reply.status(401).send({ error: { code: "unauthorized" } });
  }

  const response = await supportAgent
    .prompt(message)
    .tool(createAccountTool({ userId }))
    .context({ userId })
    .send();

  return reply.send({ output: response.output });
});

4. Add Retrieval Context

const documents = await knowledge.search({
  query: message,
  filter: { userId: request.user.id },
  limit: 5,
});

const response = await supportAgent.prompt(message).documents(documents).send();

Next

Persist history in Persistence. Related guides: Runtime Context, Tool Handlers, and RAG Context.