shuvi
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
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)
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
shuvi-0.1.2-py3-none-any.whl
(9.2 kB
view details)
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
23b310ab15acadc5923e647096fced0ea84a5fc3384ea8bc4363caa9f421c439
|
|
| MD5 |
b681e29a9d215df69cdb121efdd44638
|
|
| BLAKE2b-256 |
0ebeff45bb5ded7beaa8d3ae3abc977674773be3b72f397862919b9565629611
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
702ce6fae6ff7cd7a74594602be8473dd94d8be1f6742179e7356253b8182ee3
|
|
| MD5 |
724f975f8e9970e40b5c7ce8b9e5c134
|
|
| BLAKE2b-256 |
5b55c62063949f03806f676566b1736e1dfaa813c437de58dc4f8105b4c8f2ea
|