A very simple Typescript framework to build tool-wielding AI Agents.
easy-agent
is a powerful, lightweight TypeScript framework designed for building AI agents with tool-use capabilities and prompt-caching. It supports Anthropic's Claude family of models.
- Simple: There's too much plumbing and setup in vanilla AI SDKs. You spend more time parsing JSON than iterating on your agent.
- Typescript First: TS > Python if you're already working in web apps.
- Minimal: You only need two concepts to make an awesome AI Agent: Agents and Tools. This package hides everything else and focuses on a good experience with those two concepts.
- Hides configuration and plumbing behind two simple typesafe
Agent
andTool
classes. - Start making a custom Agent with one function call in one file:
start-here.ts
. - Sensible defaults which you can easily override
- Automatically handles the tool request/response cycle
- Supports message & stream modes
- Vigorous type-safety
- A few fun pre-baked Agents
- Use Agents in either CLI and Server Modes
- Prompt caching support
Make sure you have an ANTHROPIC_API_KEY key in your environment.
Install:
bun install
Run:
bun start
You can use easy-agent
as project boilerplate or as a library.
See example.cli.ts
for a typical project setup in CLI Mode.
CLI Mode allows you to interact with your agents in a simple command-line interface.
Start it with bun run start
or bun run cli
.
Server Mode runs an Express server, allowing interaction with agents via HTTP requests.
See example.server.ts
for a typical project setup in Server Mode.
-
Start the server:
bun run server
-
The server will start on
http://localhost:3000
. -
Interact with agents via HTTP:
List available agents:
curl http://localhost:3000
Send a message to an agent:
curl -X POST http://localhost:3000 -H "Content-Type: application/json" \
-d '{"agentName": "summarizer", "message": "Summarize this: https://example.com"}'
Note: Server Mode currently supports stateless interactions only. You'll need to handle state on the client side.
You can use easy-agent
as a library in your project.
First, import an EasyAgentCLI
or EasyAgentServer
mode from easy-agent
. Then, create an instance of that mode and pass your agents to it.
import { EasyAgentCLI, Agent } from "easy-agent";
EasyAgentCLI.start([
Agent.create({
name: "MyAgent",
prompt: "I am a helpful assistant that...",
tools: [MyCustomTool],
}),
]);
This will start a CLI session with any agents you register in the array.
The simplest possible way to make an agent is to call bun run add-agent
and follow the prompts.
You can also check out example.cli.ts
and add code like the following:
Agent.create({
name: "Dad Joke Agent",
prompt: "I tell Dad Jokes and only Dad Jokes"
})
Now type bun start
and dad-joke-agent
will be available to use.
For more advanced use cases, you can follow patterns in the agents
and tools
directories:
-
Create a new file in the
agents
directory, e.g.,agents/my-agent.ts
:import Agent from "src/lib/agent"; import MyCustomTool from "src/tools/my-custom-tool"; const MY_PROMPT = `You are a helpful assistant that...`; export default Agent.create({ name: "MyAgent", prompt: MY_PROMPT, tools: [MyCustomTool], // Optionally customize other settings... // mode: "stream", // model: "claude-3-opus-20240229", // maxTokens: 4000, // cacheOptions: ["system", "tools"], });
-
Register your agent wherever you've called an EasyAgent mode (see
example.cli.ts
):import { EasyAgentCLI } from "easy-agent/modes"; import MyAgent from "easy-agent/agents/my-agent"; EasyAgentCLI.start([ // ... other agents MyAgent, ]);
-
Your agent is now available in both CLI and Server modes!
To create more complex agents:
- Add custom tools in the
tools
directory - Experiment with different prompts and configurations
- Use the
cacheOptions
to optimize performance for frequently used contexts
The simplest possible way to make an agent is to call bun run add-tool
and follow the prompts.
-
Create a new file in the
tools
directory, e.g.,tools/my-custom-tool.ts
:import Tool from "src/lib/tool"; async function fetchWeather(city: string): Promise<string> { // Implement weather fetching logic here return `The weather in ${city} is sunny.`; } export default Tool.create({ name: "fetch_weather", description: "Fetch current weather for a given city", inputs: [ { name: "city", type: "string", description: "The name of the city", required: true, }, ], fn: async ({ city }: { city: string }) => { const weather = await fetchWeather(city); return { weather }; }, });
-
Import and use your tool in an agent:
// in agents/weather-agent.ts import Agent from "src/lib/agent"; import FetchWeather from "src/tools/my-custom-tool"; export default Agent.create({ name: "WeatherAgent", prompt: "You are a helpful weather assistant. Use the fetch_weather tool to provide accurate weather information.", tools: [FetchWeather], });
-
Register your new agent in
start-here.ts
to make it available. Your agent will not intelligently use the tool.
Tips for creating effective tools:
- Provide clear, concise descriptions for your tool and its inputs.
- Handle errors gracefully and return informative error messages.
- Consider adding type definitions for complex input/output structures.
easy-agent comes bundled with an agent named Toolmaker, which can make tools for your agents.
To use:
- Start easy-agent in CLI mode:
bun run start
. - Select
toolmaker
- Tell it the kind of tool you want e.g.
Create a tool that fetches the current price of Bitcoin
- The tool will appear in the
tools
directory. - Fix up the tool as needed.
- Import the tool into your agent.
Toolmaker writes all tools in Typescript. It can also fetch data from websites if needed, so feel free to send in a url for API docs or other data sources.
Toolmaker creates tools but does not use them immediately. You'll need to manually import and add new tools to your agents. Always review and test automatically generated tools before using them in production environments.
Here are some more advanced examples of agent configurations:
export default Agent.create({
name: "StreamingExpert",
prompt: "You are an AI that provides real-time analysis of streaming data.",
mode: "stream",
model: "claude-3-opus-20240229",
maxTokens: 4000,
tools: [StreamDataAnalyzer, DataVisualizer],
});
export default Agent.create({
name: "ResearchAssistant",
prompt: "You are a research assistant capable of gathering and analyzing information from multiple sources.",
tools: [WebSearchTool, PDFExtractor, DataAnalyzer, CitationGenerator],
cacheOptions: ["system", "tools"],
maxTokens: 8000,
});
export default Agent.create({
name: "CodeReviewer",
prompt: "You are an expert code reviewer. Analyze code snippets for best practices, potential bugs, and suggest improvements.",
tools: [CodeParser, StaticAnalyzer, BenchmarkTool],
model: "claude-3-opus-20240229",
maxTokens: 16000,
cacheOptions: ["system"],
});
Easy-agent supports Anthropic's prompt caching feature, which can significantly improve response times and reduce token usage for repeated interactions.
Prompt caching allows certain parts of the context to be stored on Anthropic's servers, reducing the need to resend this information with each request. In easy-agent, caching is implemented with a focus on efficiency and adherence to Anthropic's limits.
-
System Prompt: The system prompt is cached first, as it's typically the most static and frequently used part of the context.
-
Tools: After the system prompt, tools are cached in the order they are configured in the agent. This ensures that the most important or frequently used tools are prioritized for caching.
Anthropic imposes a limit on the number of items that can be cached (currently set to globals.ANTHROPIC_MAX_PROMPT_CACHE_SIZE
). Easy-agent respects this limit by:
- Caching the system prompt first (if enabled)
- Caching tools in order until the limit is reached
- Stopping cache attempts for additional tools once the limit is hit
To enable caching for your agent, use the cacheOptions
parameter in your agent configuration:
Agent.create({
name: "CachedAgent",
prompt: "Your prompt here",
tools: [Tool1, Tool2, Tool3],
cacheOptions: ["system", "tools"],
// ... other configurations
});
This setup will cache both the system prompt and tools, in that order, up to the Anthropic-imposed limit.