Skip to content

Turi-Labs/YAAF2

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 

Repository files navigation

yaaf2

Yet Another Agent Framework — a Python library for building scheduled, memory-aware, tool-using AI agents.

Define agents as markdown files. Write tools as plain Python functions. yaaf2 handles the rest: the LLM loop, tool execution, memory, sessions, scheduling, and inbound messages.


Install

pip install yaaf2[openai,supabase,discord]

Or just OpenAI with no persistence:

pip install yaaf2[openai]

Quick start

from yaaf2 import Agent
from yaaf2.llm import OpenAIProvider

agent = Agent(
    agents_dir="agents/",
    tools_dir="tools/",
    llm=OpenAIProvider(),
)

# Run one task
result = agent.run_solo("alice", "Summarize today's AI news in 3 bullets.")
print(result.final_response)

# Or run on a schedule forever
agent.run_schedule("schedule.md")

Agent definition

Each agent is a folder:

agents/
└── alice/
    ├── soul.md          # Who the agent is
    └── skills/
        ├── standup.md   # Context appended for standup sessions
        └── research.md  # Context appended for research sessions

soul.md

---
id: alice
name: Alice
role: Research assistant
description: Scans for trends and summarizes them clearly.
capabilities:
  - research
  - summarization
---

You are Alice, a research assistant. Be concise. Use bullet points.
When you complete a task, store a memory of what you did.

Skills are appended to the system prompt automatically based on the session type.


Tools

A tool is a Python file with two things:

# tools/search_web.py

SCHEMA = {
    "type": "function",
    "function": {
        "name": "search_web",
        "description": "Search the web for a query.",
        "parameters": {
            "type": "object",
            "properties": {
                "query": {"type": "string"}
            },
            "required": ["query"],
        },
    },
}

def execute(agent_id: str, query: str) -> str:
    # ... do the search
    return results

Tools can also be async def execute(...). yaaf2 detects and handles both.

Discovery order (later overrides earlier on name collision):

  1. Built-in tools (memory, learnings)
  2. Shared tools/ directory
  3. Agent-local agents/<id>/tools/

Built-in tools

yaaf2 ships four tools out of the box. Agents can call these without any setup:

Tool Description
store_memory Persist an experience or observation
recall_memories Query past memories
write_learning Record a durable insight with a confidence score
query_learnings Retrieve relevant learnings

These require a memory= and learnings= backend to be configured.


Schedule

Define your schedule in a markdown file:

# schedule.md

```python
[
    {
        "time": "09:00",
        "type": "solo",
        "agent": "alice",
        "session_type": "research",
        "task": "Scan for AI trends and summarize the top 3."
    },
    {
        "time": "11:00",
        "type": "meeting",
        "agents": ["alice", "bob"],
        "session_type": "brainstorm",
        "task": "Brainstorm content ideas based on today's trends."
    },
    {
        "interval_minutes": 60,
        "type": "solo",
        "agent": "alice",
        "session_type": "solo",
        "task": "Check for anything urgent and note it."
    },
]

run_schedule() also handles catch-up: on startup it replays any tasks missed in the last 3 hours.


Memory and learnings

Pass a backend to enable persistence:

from yaaf2.memory.backends.supabase import SupabaseMemory
from yaaf2.learnings.backends.supabase import SupabaseLearnings
from yaaf2.sessions.backends.supabase import SupabaseSessionStore

agent = Agent(
    agents_dir="agents/",
    llm=OpenAIProvider(),
    memory=SupabaseMemory(),
    learnings=SupabaseLearnings(),
    sessions=SupabaseSessionStore(),
)

All three are backed by abstract base classes. Swap the backend by subclassing:

from yaaf2.memory.base import MemoryStore

class PostgresMemory(MemoryStore):
    def store(self, agent_id, type, summary, full_content, ...): ...
    def query(self, agent_id, type=None, tags=None, limit=10): ...

Inbound messages (Discord)

from yaaf2.comms.discord import DiscordAdapter

agent = Agent(
    ...
    comms=DiscordAdapter(
        channels={"general": "CHANNEL_ID", "standup": "CHANNEL_ID"},
        channel_agents={"CHANNEL_ID": "alice"},
    ),
)

yaaf2 polls Discord in a background thread. Messages are routed to agents by @mention or channel default, then dispatched as inbox_request solo runs.


Multi-agent meetings

conversation = agent.run_meeting(
    agent_ids=["alice", "bob"],
    task="Debate the best content format for this week.",
    max_turns=10,
)

Agents take turns in a round-robin. The meeting ends when any agent signals conclusion or max_turns is reached.


LLM providers

yaaf2 uses the OpenAI SDK, which is compatible with any OpenAI-compatible API:

from yaaf2.llm import OpenAIProvider

# OpenAI
llm = OpenAIProvider()

# DeepSeek
llm = OpenAIProvider(api_key="sk-...", base_url="https://api.deepseek.com")

# Local (Ollama, LM Studio, etc.)
llm = OpenAIProvider(api_key="ollama", base_url="http://localhost:11434/v1")

Supabase schema

If you're using the Supabase backends, create these tables:

create table memories (
    id uuid primary key default gen_random_uuid(),
    agent_id text not null,
    type text not null,
    summary text,
    full_content text,
    emotional_valence text default 'neutral',
    tags text[] default '{}',
    created_at timestamptz default now()
);

create table learnings (
    id uuid primary key default gen_random_uuid(),
    agent_id text not null,
    type text not null,
    statement text not null,
    confidence float default 0.7,
    tags text[] default '{}',
    evidence_refs text[] default '{}',
    source_session_id uuid,
    created_at timestamptz default now()
);

create table sessions (
    id uuid primary key default gen_random_uuid(),
    type text not null,
    participants text[] default '{}',
    initiator text,
    intent text,
    status text default 'in_progress',
    conversation jsonb default '[]',
    artifacts jsonb default '{}',
    created_at timestamptz default now(),
    completed_at timestamptz
);

Environment variables

Variable Description
OPENAI_API_KEY OpenAI API key
SUPABASE_URL Supabase project URL
SUPABASE_KEY Supabase anon/service key
DISCORD_BOT_TOKEN Default Discord bot token
DISCORD_<AGENT_ID>_BOT_TOKEN Per-agent Discord token

License

MIT

About

A Python framework for building scheduled, memory-aware, tool-using AI agents. Define agents as markdown files, write tools as plain functions, and let yaaf2 handle the loop.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages