Skip to content

lleverage-ai/agent-sdk

@lleverage-ai/agent-sdk

A TypeScript framework for building AI agents using the Vercel AI SDK v6.

Packages

This monorepo contains two packages:

Package Description Version
@lleverage-ai/agent-sdk Core agent framework — tools, plugins, hooks, teams npm
@lleverage-ai/agent-threads Event transport, replay, and durable transcripts npm

Which Package Do I Need?

Use @lleverage-ai/agent-sdk if you want to build agents with models, tools, plugins, hooks, sessions, and subagents. This is the default starting point for most users.

Use @lleverage-ai/agent-threads if you need infrastructure for conversation transport and persistence: event streams, replay, WebSocket transport, run lifecycle management, and durable transcripts. You can use it by itself or alongside the SDK.

The simplest way to think about the split is:

  • @lleverage-ai/agent-sdk is the agent framework
  • @lleverage-ai/agent-threads is the conversation infrastructure layer

If you are unsure, start with @lleverage-ai/agent-sdk and only add @lleverage-ai/agent-threads when you need durable thread history, replay, or transport primitives.

Installation

bun add @lleverage-ai/agent-sdk ai zod

You'll also need at least one AI provider:

bun add @ai-sdk/anthropic  # or @ai-sdk/openai

If you also need durable transcript or transport primitives:

bun add @lleverage-ai/agent-threads

Quick Start

import { createAgent } from "@lleverage-ai/agent-sdk";
import { anthropic } from "@ai-sdk/anthropic";
import { tool } from "ai";
import { z } from "zod";

const agent = createAgent({
  model: anthropic("claude-sonnet-4-20250514"),
  systemPrompt: "You are a friendly assistant.",
  tools: {
    greet: tool({
      description: "Greet a person by name",
      inputSchema: z.object({
        name: z.string().describe("The name of the person to greet"),
      }),
      execute: async ({ name }) => `Hello, ${name}!`,
    }),
  },
});

const result = await agent.generate({
  prompt: "Say hello to Alice",
});

console.log(result.text);

Core Concepts

Agents

Agents combine a language model with tools, plugins, and hooks. Core tools for filesystem operations and task tracking are automatically included.

const agent = createAgent({
  model: anthropic("claude-sonnet-4-20250514"),
  systemPrompt: "You are a helpful assistant.",
  maxSteps: 10,
  tools: { /* custom tools */ },
  plugins: [ /* plugins */ ],
});

// Disable specific core tools if needed
const safeAgent = createAgent({
  model,
  disabledCoreTools: ["bash", "write"],
});

Core tools included: read, write, edit, glob, grep, todo_write, bash (requires backend with enableBash: true), skill (when skills are configured), search_tools (when enabled), call_tool (when deferred or proxied tools are present)

Tools

Tools use the AI SDK's tool() function with inputSchema:

import { tool } from "ai";
import { z } from "zod";

const calculator = tool({
  description: "Perform basic math operations",
  inputSchema: z.object({
    operation: z.enum(["add", "subtract", "multiply", "divide"]),
    a: z.number(),
    b: z.number(),
  }),
  execute: async ({ operation, a, b }) => {
    switch (operation) {
      case "add": return a + b;
      case "subtract": return a - b;
      case "multiply": return a * b;
      case "divide": return a / b;
    }
  },
});

const agent = createAgent({
  model,
  tools: { calculator },
});

Plugins

Plugins bundle tools, skills, and hooks. Inline plugin tools are exposed as <plugin>__<tool>, while tools from external MCP servers use mcp__<server>__<tool>.

import { definePlugin } from "@lleverage-ai/agent-sdk";

const myPlugin = definePlugin({
  name: "my-plugin",
  description: "A collection of useful tools",
  tools: {
    myTool: tool({
      description: "Does something useful",
      inputSchema: z.object({ input: z.string() }),
      execute: async ({ input }) => `Result: ${input}`,
    }),
  },
});

const agent = createAgent({
  model,
  plugins: [myPlugin],
});
// Inline plugin tool available as: my-plugin__myTool

Skills

Skills provide contextual instructions that guide agent behavior following the Agent Skills specification. They support both programmatic (TypeScript) and file-based (SKILL.md) formats.

Programmatic skills:

import { defineSkill } from "@lleverage-ai/agent-sdk";

const dataPlugin = definePlugin({
  name: "data-explorer",
  tools: { getSchema, queryData, createChart },
  skills: [
    defineSkill({
      name: "data-exploration",
      description: "Query and visualize data",
      instructions: `You have access to data exploration tools.
Available tables: products, users, sales.
Always use getSchema first to see column types.`,
    }),
  ],
});

File-based skills:

import { loadSkillsFromDirectories } from "@lleverage-ai/agent-sdk";

// Load skills from SKILL.md files
const { skills } = await loadSkillsFromDirectories(["/path/to/skills"]);

// Agent auto-creates registry and skill tool
const agent = createAgent({ model, skills });

See Skills Documentation for complete details on the skills system and Agent Skills spec compliance.

Prompt Builder

Create dynamic, context-aware system prompts from composable components. Instead of static strings, prompts can combine behavior rules, capability summaries, explicit instruction layers, and structured memory inputs.

The default prompt builder is cache-friendly: it avoids per-turn dynamic context sections by default so repeated generations in the same thread can reuse provider prompt caches more effectively.

Using the default builder:

const agent = createAgent({
  model,
  // No systemPrompt = uses default prompt builder
  tools: { read, write, bash },
});
// Automatically generates:
// "You are an interactive agent. Your job is to help the user achieve their goal...
//
// # Action Policy
// ...
//
// # Capability Summary
// - You can work with files in the configured workspace.
// - You can run shell commands when that helps achieve the user's goal."

Customizing the prompt:

import { createDefaultPromptBuilder } from "@lleverage-ai/agent-sdk";

const builder = createDefaultPromptBuilder()
  .register({
    name: "project-context",
    priority: 95,
    render: () => "You are working on a TypeScript project.",
  });

const agent = createAgent({
  model,
  promptBuilder: builder,
  tools,
});

Passing explicit instruction layers and memory:

const agent = createAgent({
  model,
  memoryAvailable: true,
  instructionLayers: [
    {
      label: "App Policy",
      instructions: "Prefer terse answers unless the user asks for detail.",
      precedence: 70,
    },
  ],
});

await agent.generate({
  prompt: "Continue",
  memory: {
    standingInstructions: [
      { label: "Project Memory", content: "Use Bun workspace commands." },
    ],
    recall: [
      { label: "Recent Recall", content: "The user is working on prompt composition." },
    ],
  },
});

Set memoryAvailable: true when you want the default builder to advertise the general # Memory policy. Passing memory to agent.generate() still populates PromptContext.memory either way, so instruction layers and recalled memory can render without opting into persistent-memory guidance.

Static prompts still work:

const agent = createAgent({
  model,
  systemPrompt: "You are a helpful assistant.",
  tools,
});

See Prompt Builder Documentation for complete details on dynamic prompts, components, and customization.

Hooks

Hooks allow you to observe and react to agent lifecycle events:

import { createAgent, createToolHook } from "@lleverage-ai/agent-sdk";

const agent = createAgent({
  model,
  hooks: {
    // Simple observation hook (void return is fine)
    PreGenerate: [async ({ options }) => {
      console.log("Starting generation...");
    }],

    // Use createToolHook helper for tool-specific hooks
    PostToolUse: [
      createToolHook(async ({ tool_name, tool_response }) => {
        console.log("Tool completed:", tool_name);
      }, { matcher: "search_*" }), // Only match tools starting with "search_"
    ],
  },
});

Available hooks:

  • PreGenerate, PostGenerate, PostGenerateFailure — Generation lifecycle
  • GenerationRetryDecision — Retry-policy observability for classified generation failures
  • PreToolUse, PostToolUse, PostToolUseFailure — Tool execution lifecycle
  • MCPConnectionFailed, MCPConnectionRestored — MCP server connection lifecycle
  • Custom — Plugin-defined custom events (see below)

Hook utilities: createRetryHooks, createRateLimitHooks, createLoggingHooks, createGuardrailsHooks, createSecretsFilterHooks, createToolHook

Request-class-aware generation retry: You can configure generationRetryPolicy on createAgent() and set requestClass per request to vary overload behavior for interactive vs background work, recover from authentication or stale-socket failures, and optionally shrink maxTokens after context-overflow errors.

const agent = createAgent({
  model,
  fallbackModel,
  generationRetryPolicy: {
    requestClasses: {
      foreground: { maxConsecutiveOverloadRetries: 2 },
      background: {
        maxConsecutiveOverloadRetries: 0,
        fallbackOnOverloadExhaustion: false,
      },
    },
    onAuthenticationFailure: async ({ options }) => ({
      retry: true,
      updatedOptions: {
        ...options,
        headers: { ...options.headers, Authorization: `Bearer ${await refreshToken()}` },
      },
    }),
    contextOverflow: {
      reductionFactor: 0.5,
      minMaxTokens: 256,
    },
  },
});

await agent.generate({
  prompt: "Generate a summary",
  requestClass: "background",
});

Plugin hooks: Plugins can define hooks in their configuration, which are automatically merged into the agent's hook registration:

const myPlugin = definePlugin({
  name: "my-plugin",
  tools: { /* ... */ },
  hooks: {
    PostToolUse: [async ({ tool_name }) => {
      console.log("Tool used:", tool_name);
    }],
  },
});

Custom hooks: Plugins can define their own lifecycle events via Custom hooks and invokeCustomHook():

import { invokeCustomHook, TEAM_HOOKS } from "@lleverage-ai/agent-sdk";

// Subscribe to custom events
const agent = createAgent({
  model,
  hooks: {
    Custom: {
      [TEAM_HOOKS.TeammateSpawned]: [async (input) => {
        console.log("Teammate spawned:", input.payload);
      }],
    },
  },
});

Background Tasks

Background tasks (bash commands and subagents) are automatically handled. When generate(), stream(), streamResponse(), or streamDataResponse() spawns a background task, the agent waits for completion and triggers follow-up generations to process results.

const agent = createAgent({
  model,
  subagents: [researcherSubagent],

  // These are the defaults:
  waitForBackgroundTasks: true,

  // Customize follow-up prompt formatting
  formatTaskCompletion: (task) => `Task ${task.id} done: ${task.result}`,
  formatTaskFailure: (task) => `Task ${task.id} failed: ${task.error}`,
});

// generate() returns only after all background tasks are processed
const result = await agent.generate({ prompt: "Research this in the background" });

Agent Teams

Multi-agent coordination where the primary agent becomes a team lead:

import {
  createAgent,
  createAgentTeamsPlugin,
  InMemoryTeamCoordinator,
} from "@lleverage-ai/agent-sdk";

const teamsPlugin = createAgentTeamsPlugin({
  teammates: [
    {
      id: "researcher",
      name: "Researcher",
      description: "Researches topics",
      create: ({ model }) => createAgent({ model, systemPrompt: "You research topics." }),
    },
  ],
  coordinator: new InMemoryTeamCoordinator(),
});

const agent = createAgent({
  model,
  plugins: [teamsPlugin],
});

The agent gets a start_team tool. When called, it gains team management tools (team_spawn, team_message, team_task_create, etc.) at runtime. Teammates run in background sessions and communicate via mailboxes.

See Subagents & Teams for full details.

Streaming

Agents support streaming responses for real-time output:

for await (const part of agent.stream({ prompt: "Tell me a story" })) {
  if (part.type === "text-delta") {
    process.stdout.write(part.text);
  }
}

// Next.js API route
export async function POST(req: Request) {
  const { messages } = await req.json();
  return agent.streamResponse({ messages });
}

Documentation

Contributing

See CONTRIBUTING.md for setup, quality checks, changelog expectations, and pull request guidelines.

License

MIT

About

Agent SDK for building AI agents

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors