Skip to content

SNHuan/EasyAgent

Repository files navigation

EasyAgent

PyPI version License: MIT Python 3.12+

English | 简体中文

EasyAgent is a lightweight agent SDK organised as a small set of composable layers. The goal is to let you learn agent design step by step: start with a single model call, then add memory and context, build up to a ReAct loop with tools and skills, drop into a sandbox, and finally orchestrate multiple agents through the Entity-World-Schedule architecture.

Install

pip install easy-agent-sdk

From source:

git clone https://github.com/SNHuan/EasyAgent.git
cd EasyAgent
pip install -e ".[dev]"

Optional extras:

pip install easy-agent-sdk[sandbox]
pip install easy-agent-sdk[web]
pip install easy-agent-sdk[all]

Quick Start

import asyncio
from easyagent import LiteLLMModel, ReactAgent


async def main():
    agent = ReactAgent(
        model=LiteLLMModel("gpt-4o-mini"),
        system_prompt="You are a concise assistant.",
        max_iterations=5,
    )
    result = await agent.run("What is 2 + 2?")
    print(result.final_output)


asyncio.run(main())

Create easyagent/config/config.yaml or configure LiteLLM through environment variables:

debug: false

models:
  gpt-4o-mini:
    api_type: openai
    base_url: https://api.openai.com/v1
    api_key: sk-xxx

Layered Design

EasyAgent is organised around three layers:

Single-agent:    Model + Memory + Context + Tool → Agent / ReactAgent / SkillAgent / SandboxAgent
Multi-agent:     Entity + World + Schedule → Runtime
Presets:         sequential / fanout / debate / chatroom / groupchat
  • Model — provider adapter and message schema.
  • Memory + Context — store conversation history and decide what reaches the model each turn.
  • Agent — composes a model, memory, context, and any tools/skills/sandbox. Four built-in classes: Agent (single-turn) → ReactAgent (ReAct loop) → SkillAgent / SandboxAgent.
  • Entity — wraps an Agent (or any async actor) for multi-agent participation. Protocol: id property + async act(Perception) -> Action | None.
  • World — the environment entities perceive and act upon. Built-ins: ConversationWorld, PipelineWorld, SpatialWorld, StatefulWorld.
  • Schedule — determines who acts next. Built-ins: TakeTurns, RoundRobin, AllParallel, Reactive, MaxTicks, UntilIdle.
  • Runtime — the perceive-act-apply loop wiring Entity + World + Schedule.

See docs/architecture.md for the full design guide.

Public API

The root package exposes the common SDK surface:

from easyagent import (
    # single-agent
    Agent, ReactAgent, SkillAgent, SandboxAgent,
    AgentSession, AgentRunResult,
    LiteLLMModel, Message,
    EventBus, MessageEvent,
    ToolManager, SkillManager, register_tool,
    # multi-agent protocols
    Entity, World, Schedule, Runtime, RuntimeResult,
    # perception & action types
    Perception, Speak, Silent, ChatMessage,
    # entities
    LLMEntity, TeamEntity, HumanEntity,
    # worlds
    ConversationWorld, PipelineWorld, SpatialWorld, StatefulWorld, SharedState,
    # schedules
    TakeTurns, RoundRobin, AllParallel, MaxTicks, UntilIdle, Reactive,
    # presets
    sequential, fanout, debate, chatroom, groupchat,
)

Learning Path

The examples are ordered by layer. Each one introduces one new idea:

# Single agent (00–06)
python examples/00_model_call.py             # Just call the model
python examples/01_single_turn_agent.py      # Compose a minimal Agent
python examples/02_memory_and_context.py     # Memory + Context
python examples/03_react_with_tools.py       # ReactAgent + tool calls
python examples/04_skills_lazy_loading.py    # SkillAgent (SKILL.md packages)
python examples/05_sandbox_agent.py          # SandboxAgent (bash, write/read file)
python examples/06_custom_tool.py            # Define your own tool

# Multi-agent: Entity-World-Schedule (07–14)
python examples/07_two_agents_talk.py        # LLMEntity + ConversationWorld + RoundRobin
python examples/08_sequential.py             # sequential() preset
python examples/09_chatroom.py               # Manual turn-taking + if/else
python examples/10_groupchat.py              # Reactive schedule, LLM picks next
python examples/11_debate_and_judge.py       # Third-party judge after debate
python examples/12_nested.py                 # TeamEntity: Runtime-as-Entity nesting
python examples/13_shared_state.py           # SharedState + StatefulWorld blackboard
python examples/14_advanced_runtime.py       # SpatialWorld: 2D grid + range-limited perception

Tools

from easyagent import LiteLLMModel, ReactAgent, register_tool


@register_tool
class GetWeather:
    name = "get_weather"
    type = "function"
    description = "Get weather for a city."
    parameters = {
        "type": "object",
        "properties": {"city": {"type": "string"}},
        "required": ["city"],
    }

    def init(self) -> None: ...

    def execute(self, city: str) -> str:
        return f"Sunny in {city}."


agent = ReactAgent(
    model=LiteLLMModel("gpt-4o-mini"),
    tools=[GetWeather],
)

Pass tool classes or instances directly via tools=[...]. The agent automatically registers an end tool — call it to terminate the loop early.

Skills

Skills are directory packages loaded on demand. SKILL.md is the required entry file; supporting files can live alongside it:

skills/my-skill/
├── SKILL.md
├── references/
├── templates/
├── assets/
└── scripts/
from easyagent import LiteLLMModel, SkillAgent

agent = SkillAgent(
    model=LiteLLMModel("gpt-4o-mini"),
    skills=["my-skill"],
    skill_root="./skills",
)

Multi-agent

Wrap any Agent as an LLMEntity, then compose with presets:

from easyagent import LiteLLMModel, ReactAgent, LLMEntity, sequential

model = LiteLLMModel("gpt-4o-mini")
researcher = LLMEntity("researcher", ReactAgent(model=model, name="researcher", system_prompt="..."))
writer     = LLMEntity("writer",     ReactAgent(model=model, name="writer",     system_prompt="..."))
reviewer   = LLMEntity("reviewer",   ReactAgent(model=model, name="reviewer",   system_prompt="..."))

result = await sequential([researcher, writer, reviewer], "Write a product blurb.")
print(result.last_speech)

Available presets: sequential / fanout / chatroom / groupchat / debate. For recursive nesting, wrap an inner Runtime as a TeamEntity and drop it into any outer pipeline. See examples/07_* through examples/14_* for walkthroughs.

Custom World

The architecture is extensible beyond conversation. Swap the World to get entirely different behaviour with the same Entity and Schedule:

from easyagent import SpatialWorld, Grid2D, Runtime, RoundRobin, MaxTicks

grid = Grid2D()
grid.place("alice", (0, 0))
grid.place("bob", (5, 5))

world = SpatialWorld(grid=grid, listen_radius=3.0)
schedule = MaxTicks(inner=RoundRobin(ids=["alice", "bob"]), n=10)

rt = Runtime(world=world, entities={"alice": alice, "bob": bob}, schedule=schedule)
result = await rt.run("Start exploring")

Module Layout

easyagent/
├── agent/      # Agent, ReactAgent, SkillAgent, SandboxAgent, AgentSession
├── core/       # Entity, World, Schedule protocols + Runtime loop
├── entities/   # LLMEntity, TeamEntity, HumanEntity
├── worlds/     # ConversationWorld, PipelineWorld, SpatialWorld, StatefulWorld
├── presets.py  # sequential, fanout, debate, chatroom, groupchat
├── context/    # SlidingWindowContext, SummaryContext, MultiAgentFormatter
├── events/     # MessageEvent, EventBus, telemetry events
├── memory/     # InMemoryMemory
├── model/      # LiteLLMModel + Message schema
├── prompt/     # System-prompt builders
├── sandbox/    # Local / Docker sandboxes
├── skill/      # SKILL.md loading
├── tool/       # Tool registry + built-ins (bash, file, web, end)
├── config/     # Config loading
└── debug/      # Logging

License

MIT License © 2025 Yiran Peng

About

A lightweight and highly extensible Agent framework

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages