A modular Python CLI for multi-turn conversations with LLM agents.
- Runs an interactive chat loop from the terminal
- LLM Support - Anthropic, Google, OpenAI, Mistral, and a dummy provider for local testing without API keys.
- Tool calling — built-in
get_weather,get_current_time,read_skilltools for all providers but dummy. - ReAct loop — optional multi-step reason-act-observe loop (
--react) for Anthropic, Google, OpenAI, and Mistral. The agent iteratively calls tools and feeds observations back until it produces a final answer or hits the step budget
sunraise/
├── src/
│ ├── agent.py # Agent wrapper around an LLM provider
│ ├── banner.py # Colored CLI startup banner
│ ├── config.py # Provider config map, version, Google tool/system-instruction config
│ ├── conversation.py # Helpers functions to pre-process and store conversation on disk
│ ├── llm.py # LLM Provider abstract class
│ ├── provider_anthropic.py # Provider implementations for Anthropic LLM
│ ├── provider_dummy.py # Provider implementations for Dummy LLM
│ ├── provider_google.py # Provider implementations for Google LLM
│ ├── provider_mistral.py # Provider implementations for Mistral LLM
│ ├── provider_openai.py # Provider implementations for OpenAI LLM
│ ├── provider_openllm.py # Provider implementations for Google LLM
│ ├── main.py # CLI entry point (multi-turn chat)
│ ├── user.py # User identity model
│ ├── skill_loader.py # Skill management helper functions
│ └── skills/
│ │ ├── basic-skill/ # basic-skill to help create a skill
│ │ └── SKILL.md
│ └── tools/
│ ├── weather.py # get_weather tool + per-provider schemas
│ └── current_time.py # get_current_time tool + per-provider schemas
│ └── read_skill.py # read_skill tool + per-provider schemas
└── requirements.txt
- Python 3.10+
- API keys for the providers you plan to use (not required for
--provider dummy)
- Clone the repository and enter the project directory:
cd /sunraise- Create and activate a virtual or conda environment:
python -m venv .venv
source .venv/bin/activateor
conda create -n sunraise python=3.10
conda activate sunraise- Install dependencies:
pip install -r requirements.txtrequirements.txt includes:
- all provider SDKs:
google-genai,anthropic,openai,mistralai - the dev tooling:
pre-commit,black,ruff tzdataon Windows (needed byget_current_time'szoneinfo)python-dotenv
- IMPORTANT: Create a
.envfile insrc/with your API keys and model names (see table below).
API keys are free for Google Gemini and Mistral AI:
Add these to src/.env (only the variables for your chosen provider are required):
| Variable | Description |
|---|---|
API_KEY_GEMINI |
Google Gemini API key |
LLM_MODEL_GEMINI |
Gemini model name (e.g. gemini-flash-latest) |
API_KEY_CLAUDE |
Anthropic API key |
LLM_MODEL_CLAUDE |
Claude model name (e.g. claude-opus-4-8) |
API_KEY_GPT |
OpenAI API key |
LLM_MODEL_GPT |
OpenAI model name (e.g gpt-5.5) |
API_KEY_MISTRAL |
Mistral API key |
LLM_MODEL_MISTRAL |
Mistral model name (e.g. mistral-small-latest) |
API_KEY_OPENLLM |
OpenLLM API key |
LLM_MODEL_OPENLLM |
OpenLLM name (e.g. google/gemma-4-26b-a4b-qat) for LM Studio |
BASE_URL_OPENLLM |
OpenLLM url (e.g. http://127.0.0.1:1234/v1) for LM Studio |
Notice:
- Without a
.envfile, only the dummy provider works. - OpenLLM requires the extra BASE_URL_OPENLLM variable
| Flag | Provider |
|---|---|
--provider dummy |
Echoes your input (no API key needed) |
--provider anthropic |
Claude via Anthropic SDK |
--provider google |
Gemini via Google GenAI SDK |
--provider openai |
GPT via OpenAI SDK |
--provider openllm |
OpenLLM via LM Studio, Ollama, vLLM |
--provider mistral |
Mistral via Mistral SDK |
Example with a live provider:
cd /src
python main.py --provider googleDuring the session:
- Type your message at the
[user]:prompt - Read the agent reply at
[agent]: - End the session with
exit,quit, or/q
Sunraise ships with two built-in tools, implemented in src/tools/:
get_weather(city)— returns the weather for a cityget_current_time(timezone)— returns the current date and time for a timezoneread_skill(skill_name)— returns skill as a dictionnary
Each provider expects its tools in a different shape, so every tool defines a per-provider schema:
- Anthropic uses a
blockdefinition - Google uses a
partdefinition andconfighelper - OpenAI uses
itemdefinition - Mistral uses
itemdefinition
The dummy provider has no tools.
The skills_loader.py utility allows to load skills stored within /skills folder. Skills are automatically discovered and loaded as a catalog passed to agent system instruction. Skills have to follow a YAML frontmatter + body definition like /basic-skill/SKILL.md example.
By default, each provider does a single reason→tool→answer round-trip.
Passing --react N enables a multi-step ReAct loop where the agent repeatedly:
- Calls the model with the running conversation
- Executes any requested tools (
get_weather,get_current_time) - Appends the observations back into the conversation
- Repeats until the model returns a final answer with no tool calls, or
Nsteps are reached (a budget message is returned)
N must be one of 3, 5, 7, 9, 100. Supported for anthropic, google, openai, openllm, mistral.
cd src/
python main.py --provider openai --react 3flowchart LR
User["User (CLI)"] --> Main["main.py"]
Main --> Agent["Agent"]
Agent --> LLM["LLMProvider"]
Agent --> Tools
Agent --> Skills
Agent --> ReAct
ReAct --> Agent
LLM --> Anthropic
LLM --> Google
LLM --> OpenAI
LLM --> OpenLLM
LLM --> Mistral
LLM --> Dummy
**LLMProvider**— abstract base class; each provider implements__call__with provider-specific message formatting**Agent**— holds a provider instance and delegates inference**User**— lightweight identity model (UUID per session)**main.py**— builds the conversation history, formats messages per provider, and persists on exit**config.py**- support modules for provider config**banner.py**— version and the CLI startup banner**tools**— each provider routes tool calls throughtool_switchtoget_weather/get_current_timetemplates
- Pre-commit hooks are configured via
.pre-commit-config.yaml
See LICENSE.