Skip to main content

A lightweight async agent loop for building AI companions with Python.

Project description

shuvi

English | Chinese

A lightweight, extensible async agent loop for building AI companions with Python. shuvi covers tool-using conversational agents, context management, completion verification, callbacks, and multi-agent handoffs.


Features

  • Async agent runtime for iterative LLM calls and tool execution.
  • Tool calling support through hydrogen-ai, including text and image results.
  • Configurable loop controls for max iterations, retries, and completion verification.
  • Callback hooks for streaming chunks, assistant messages, tool calls, tool results, errors, and state updates.

Development

Setup

# Clone the repo
git clone https://github.com/waifu-lab/Shuvi
cd Shuvi

# Install all workspace dependencies
uv sync

Example

Basic usage:

import asyncio
import os

from hai.providers.openai import OpenAI
from shuvi.agent import Agent
from shuvi.types import AgentConfig, UserMessage


async def main() -> None:
    provider = OpenAI(
        api_key=os.environ["OPENAI_API_KEY"],
        model="gpt-4o-mini",
        stream=False,
    )
    agent = Agent(
        AgentConfig(
            provider=provider,
            system_prompt="You are a helpful AI companion.",
        )
    )

    result = await agent.run(
        [
            UserMessage(
                content=[
                    {
                        "type": "text",
                        "text": "Hello!",
                    }
                ]
            )
        ]
    )
    print(result.messages[-1].content)


asyncio.run(main())

With tools:

import asyncio
import os

from hai.providers.openai import OpenAI
from hai.tool import tool
from shuvi.agent import Agent
from shuvi.types import AgentConfig, LoopConfig, UserMessage


@tool(
    description="Add two numbers together",
    parameters={
        "type": "object",
        "properties": {
            "a": {"type": "number"},
            "b": {"type": "number"},
        },
        "required": ["a", "b"],
    },
)
def add(a: float, b: float) -> float:
    return a + b


async def main() -> None:
    provider = OpenAI(
        api_key=os.environ["OPENAI_API_KEY"],
        model="gpt-4o-mini",
        stream=False,
    )
    agent = Agent(
        AgentConfig(
            provider=provider,
            system_prompt="You are a calculator assistant. Use tools when needed.",
            tools=[add],
            loop=LoopConfig(max_inner_iterations=10),
        )
    )

    result = await agent.run(
        [
            UserMessage(
                content=[
                    {
                        "type": "text",
                        "text": "Please calculate 123 + 456.",
                    }
                ]
            )
        ]
    )
    print(result.messages[-1].content)


asyncio.run(main())

Streaming mode:

import asyncio
import os

from hai.providers.openai import OpenAI
from shuvi.agent import Agent
from shuvi.types import AgentCallbacks, AgentConfig, UserMessage


def print_chunk(chunk: str) -> None:
    print(chunk, end="", flush=True)


async def main() -> None:
    provider = OpenAI(
        api_key=os.environ["OPENAI_API_KEY"],
        model="gpt-4o-mini",
        stream=True,
    )
    agent = Agent(
        AgentConfig(
            provider=provider,
            system_prompt="You are a helpful AI companion.",
            callbacks=AgentCallbacks(on_chunk=print_chunk),
        )
    )

    await agent.run(
        [
            UserMessage(
                content=[
                    {
                        "type": "text",
                        "text": "Introduce shuvi in three sentences.",
                    }
                ]
            )
        ]
    )
    print()


asyncio.run(main())

Testing

uv run pytest

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

shuvi-0.1.2.tar.gz (7.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

shuvi-0.1.2-py3-none-any.whl (9.2 kB view details)

Uploaded Python 3

File details

Details for the file shuvi-0.1.2.tar.gz.

File metadata

  • Download URL: shuvi-0.1.2.tar.gz
  • Upload date:
  • Size: 7.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.4 CPython/3.12.5 Windows/11

File hashes

Hashes for shuvi-0.1.2.tar.gz
Algorithm Hash digest
SHA256 23b310ab15acadc5923e647096fced0ea84a5fc3384ea8bc4363caa9f421c439
MD5 b681e29a9d215df69cdb121efdd44638
BLAKE2b-256 0ebeff45bb5ded7beaa8d3ae3abc977674773be3b72f397862919b9565629611

See more details on using hashes here.

File details

Details for the file shuvi-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: shuvi-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 9.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.4 CPython/3.12.5 Windows/11

File hashes

Hashes for shuvi-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 702ce6fae6ff7cd7a74594602be8473dd94d8be1f6742179e7356253b8182ee3
MD5 724f975f8e9970e40b5c7ce8b9e5c134
BLAKE2b-256 5b55c62063949f03806f676566b1736e1dfaa813c437de58dc4f8105b4c8f2ea

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page