lite-agent 0.1.0__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of lite-agent might be problematic. Click here for more details.
- lite_agent-0.2.0/.github/workflows/ci.yml +33 -0
- {lite_agent-0.1.0 → lite_agent-0.2.0}/.gitignore +1 -0
- lite_agent-0.2.0/CHANGELOG.md +85 -0
- lite_agent-0.2.0/PKG-INFO +111 -0
- lite_agent-0.2.0/README.md +86 -0
- lite_agent-0.2.0/examples/basic.py +46 -0
- lite_agent-0.2.0/examples/channels/rich_channel.py +50 -0
- lite_agent-0.2.0/examples/confirm_and_continue.py +60 -0
- lite_agent-0.2.0/examples/context.py +60 -0
- lite_agent-0.2.0/examples/handoffs.py +74 -0
- lite_agent-0.2.0/examples/message_transfer_example.py +173 -0
- lite_agent-0.2.0/examples/message_transfer_example_new.py +173 -0
- lite_agent-0.2.0/examples/responses.py +42 -0
- lite_agent-0.2.0/examples/terminal.py +61 -0
- lite_agent-0.2.0/examples/test_consolidate_history.py +47 -0
- {lite_agent-0.1.0 → lite_agent-0.2.0}/pyproject.toml +20 -3
- lite_agent-0.2.0/pyrightconfig.json +5 -0
- lite_agent-0.2.0/scripts/record_chat_messages.py +51 -0
- lite_agent-0.2.0/src/lite_agent/__init__.py +7 -0
- lite_agent-0.2.0/src/lite_agent/agent.py +330 -0
- lite_agent-0.2.0/src/lite_agent/loggers.py +3 -0
- lite_agent-0.2.0/src/lite_agent/message_transfers.py +111 -0
- lite_agent-0.2.0/src/lite_agent/processors/__init__.py +3 -0
- lite_agent-0.2.0/src/lite_agent/processors/stream_chunk_processor.py +106 -0
- lite_agent-0.2.0/src/lite_agent/runner.py +487 -0
- lite_agent-0.2.0/src/lite_agent/stream_handlers/__init__.py +5 -0
- lite_agent-0.2.0/src/lite_agent/stream_handlers/litellm.py +106 -0
- lite_agent-0.2.0/src/lite_agent/types/__init__.py +55 -0
- lite_agent-0.2.0/src/lite_agent/types/chunks.py +89 -0
- lite_agent-0.2.0/src/lite_agent/types/messages.py +68 -0
- lite_agent-0.2.0/src/lite_agent/types/tool_calls.py +15 -0
- lite_agent-0.2.0/tests/integration/test_agent_with_mocks.py +80 -0
- lite_agent-0.2.0/tests/integration/test_basic.py +32 -0
- lite_agent-0.2.0/tests/integration/test_mock_litellm.py +93 -0
- lite_agent-0.2.0/tests/mocks/basic/1.jsonl +28 -0
- lite_agent-0.2.0/tests/mocks/confirm_and_continue/1.jsonl +32 -0
- lite_agent-0.2.0/tests/mocks/confirm_and_continue/2.jsonl +36 -0
- lite_agent-0.2.0/tests/mocks/context/1.jsonl +14 -0
- lite_agent-0.2.0/tests/unit/test_agent.py +214 -0
- lite_agent-0.2.0/tests/unit/test_agent_handoffs.py +457 -0
- lite_agent-0.2.0/tests/unit/test_append_message.py +209 -0
- lite_agent-0.2.0/tests/unit/test_file_recording.py +316 -0
- lite_agent-0.2.0/tests/unit/test_litellm_stream_handler.py +162 -0
- lite_agent-0.2.0/tests/unit/test_message_transfer.py +194 -0
- lite_agent-0.2.0/tests/unit/test_message_transfers.py +74 -0
- lite_agent-0.2.0/tests/unit/test_runner.py +199 -0
- lite_agent-0.2.0/tests/unit/test_stream_chunk_processor.py +276 -0
- lite_agent-0.2.0/tests/utils/mock_litellm.py +73 -0
- {lite_agent-0.1.0 → lite_agent-0.2.0}/uv.lock +201 -190
- lite_agent-0.1.0/PKG-INFO +0 -22
- lite_agent-0.1.0/src/lite_agent/__init__.py +0 -0
- lite_agent-0.1.0/src/lite_agent/__main__.py +0 -110
- lite_agent-0.1.0/src/lite_agent/agent.py +0 -36
- lite_agent-0.1.0/src/lite_agent/chunk_handler.py +0 -166
- lite_agent-0.1.0/src/lite_agent/loggers.py +0 -3
- lite_agent-0.1.0/src/lite_agent/processors/__init__.py +0 -3
- lite_agent-0.1.0/src/lite_agent/processors/stream_chunk_processor.py +0 -85
- lite_agent-0.1.0/src/lite_agent/runner.py +0 -51
- lite_agent-0.1.0/src/lite_agent/types.py +0 -152
- {lite_agent-0.1.0 → lite_agent-0.2.0}/.python-version +0 -0
- {lite_agent-0.1.0 → lite_agent-0.2.0}/.vscode/launch.json +0 -0
- /lite_agent-0.1.0/README.md → /lite_agent-0.2.0/examples/handoff_workflow_demo.py +0 -0
- {lite_agent-0.1.0 → lite_agent-0.2.0}/src/lite_agent/py.typed +0 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
|
|
12
|
+
steps:
|
|
13
|
+
- name: Checkout code
|
|
14
|
+
uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- name: Set up uv
|
|
17
|
+
uses: astral-sh/setup-uv@v6
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.12"
|
|
20
|
+
activate-environment: true
|
|
21
|
+
|
|
22
|
+
- name: Install dependencies
|
|
23
|
+
run: uv sync
|
|
24
|
+
|
|
25
|
+
- name: Run tests with coverage
|
|
26
|
+
run: |
|
|
27
|
+
pytest --cov=src --cov-report=xml
|
|
28
|
+
- name: Upload coverage to Codecov
|
|
29
|
+
uses: codecov/codecov-action@v4
|
|
30
|
+
with:
|
|
31
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
32
|
+
files: ./coverage.xml
|
|
33
|
+
fail_ci_if_error: true
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
## v0.2.0
|
|
2
|
+
|
|
3
|
+
[v0.1.0...v0.2.0](https://github.com/Jannchie/lite-agent/compare/v0.1.0...v0.2.0)
|
|
4
|
+
|
|
5
|
+
### :rocket: Breaking Changes
|
|
6
|
+
|
|
7
|
+
- **agent**: rename stream_async to completion - By [Jannchie](mailto:jannchie@gmail.com) in [dae25cc](https://github.com/Jannchie/lite-agent/commit/dae25cc)
|
|
8
|
+
- **messages**: add support for function call message types and responses format conversion - By [Jannchie](mailto:jannchie@gmail.com) in [9e71ccc](https://github.com/Jannchie/lite-agent/commit/9e71ccc)
|
|
9
|
+
- **project-structure**: rename package to lite-agent && update processor imports - By [Jannchie](mailto:jannchie@gmail.com) in [6e0747a](https://github.com/Jannchie/lite-agent/commit/6e0747a)
|
|
10
|
+
- **runner**: rename run_stream to run throughout codebase - By [Jannchie](mailto:jannchie@gmail.com) in [525865f](https://github.com/Jannchie/lite-agent/commit/525865f)
|
|
11
|
+
- **stream-handler**: rename litellm_raw to completion_raw - By [Jannchie](mailto:jannchie@gmail.com) in [9001f19](https://github.com/Jannchie/lite-agent/commit/9001f19)
|
|
12
|
+
- **types**: remove AgentToolCallMessage usage and definition - By [Jannchie](mailto:jannchie@gmail.com) in [fb3592e](https://github.com/Jannchie/lite-agent/commit/fb3592e)
|
|
13
|
+
- migrate chunk and message types to pydantic models && update runner and processors for model usage - By [Jannchie](mailto:jannchie@gmail.com) in [da0d6fc](https://github.com/Jannchie/lite-agent/commit/da0d6fc)
|
|
14
|
+
|
|
15
|
+
### :sparkles: Features
|
|
16
|
+
|
|
17
|
+
- **agent**: support dynamic handoff and parent transfer - By [Jannchie](mailto:jannchie@gmail.com) in [5019018](https://github.com/Jannchie/lite-agent/commit/5019018)
|
|
18
|
+
- **agent**: add async tool call handling - By [Jannchie](mailto:jannchie@gmail.com) in [7de9103](https://github.com/Jannchie/lite-agent/commit/7de9103)
|
|
19
|
+
- **context**: add context support for agent and runner - By [Jannchie](mailto:jannchie@gmail.com) in [e4885ee](https://github.com/Jannchie/lite-agent/commit/e4885ee)
|
|
20
|
+
- **handoffs**: support multiple agents and add weather tools - By [Jannchie](mailto:jannchie@gmail.com) in [b9440ea](https://github.com/Jannchie/lite-agent/commit/b9440ea)
|
|
21
|
+
- **handoffs**: add agent handoff and transfer functionality - By [Jannchie](mailto:jannchie@gmail.com) in [7655029](https://github.com/Jannchie/lite-agent/commit/7655029)
|
|
22
|
+
- **message-transfer**: add message_transfer callback support to agent and runner && provide consolidate_history_transfer utility && add tests and usage examples - By [Jannchie](mailto:jannchie@gmail.com) in [16d4788](https://github.com/Jannchie/lite-agent/commit/16d4788)
|
|
23
|
+
- **runner**: add record_to param to run_until_complete - By [Jannchie](mailto:jannchie@gmail.com) in [597bff6](https://github.com/Jannchie/lite-agent/commit/597bff6)
|
|
24
|
+
- **runner**: support chat stream recording and improve sequence typing - By [Jannchie](mailto:jannchie@gmail.com) in [5c1d609](https://github.com/Jannchie/lite-agent/commit/5c1d609)
|
|
25
|
+
- **runner**: add run_continue method and require confirm tool handling - By [Jannchie](mailto:jannchie@gmail.com) in [d130ebc](https://github.com/Jannchie/lite-agent/commit/d130ebc)
|
|
26
|
+
- **testing**: add integration and unit tests for agent and file recording - By [Jannchie](mailto:jannchie@gmail.com) in [e5a58ce](https://github.com/Jannchie/lite-agent/commit/e5a58ce)
|
|
27
|
+
- **tool**: add require_confirmation support for tool calls - By [Jannchie](mailto:panjianqi@preferred.jp) in [69625c8](https://github.com/Jannchie/lite-agent/commit/69625c8)
|
|
28
|
+
- **tool-calls**: add require_confirm chunk type and flow - By [Jannchie](mailto:panjianqi@preferred.jp) in [b2d1654](https://github.com/Jannchie/lite-agent/commit/b2d1654)
|
|
29
|
+
- **types**: add agent message and tool call types - By [Jannchie](mailto:jannchie@gmail.com) in [489e370](https://github.com/Jannchie/lite-agent/commit/489e370)
|
|
30
|
+
|
|
31
|
+
### :adhesive_bandage: Fixes
|
|
32
|
+
|
|
33
|
+
- **agent**: update tool target to completion - By [Jannchie](mailto:jannchie@gmail.com) in [6c8978c](https://github.com/Jannchie/lite-agent/commit/6c8978c)
|
|
34
|
+
- **examples**: simplify temper agent instructions - By [Jannchie](mailto:jannchie@gmail.com) in [6632092](https://github.com/Jannchie/lite-agent/commit/6632092)
|
|
35
|
+
- **loggers**: update logger name to lite_agent - By [Jannchie](mailto:jannchie@gmail.com) in [b4c59aa](https://github.com/Jannchie/lite-agent/commit/b4c59aa)
|
|
36
|
+
- **types**: change tool_calls from sequence to list - By [Jannchie](mailto:jannchie@gmail.com) in [334c9c0](https://github.com/Jannchie/lite-agent/commit/334c9c0)
|
|
37
|
+
|
|
38
|
+
### :art: Refactors
|
|
39
|
+
|
|
40
|
+
- **agent**: rename prepare_messages to prepare_completion_messages - By [Jannchie](mailto:jannchie@gmail.com) in [02eeed6](https://github.com/Jannchie/lite-agent/commit/02eeed6)
|
|
41
|
+
- **agent**: remove unused completions to responses converter - By [Jannchie](mailto:jannchie@gmail.com) in [f6432c6](https://github.com/Jannchie/lite-agent/commit/f6432c6)
|
|
42
|
+
- **chunk-handler**: update type annotations and chunk types - By [Jannchie](mailto:panjianqi@preferred.jp) in [f2b95c5](https://github.com/Jannchie/lite-agent/commit/f2b95c5)
|
|
43
|
+
- **chunk-handler**: extract helper functions for chunk processing - By [Jannchie](mailto:jannchie@gmail.com) in [083a164](https://github.com/Jannchie/lite-agent/commit/083a164)
|
|
44
|
+
- **litellm**: extract chunk processing logic to function - By [Jannchie](mailto:jannchie@gmail.com) in [f31e459](https://github.com/Jannchie/lite-agent/commit/f31e459)
|
|
45
|
+
- **litellm-stream**: decouple funcall from stream handler && adjust runner tool call logic - By [Jannchie](mailto:jannchie@gmail.com) in [2747e7e](https://github.com/Jannchie/lite-agent/commit/2747e7e)
|
|
46
|
+
- **rich-channel**: extract rich channel to separate module && clean main - By [Jannchie](mailto:jannchie@gmail.com) in [a8be74d](https://github.com/Jannchie/lite-agent/commit/a8be74d)
|
|
47
|
+
- **runner**: modularize runner methods and simplify message handling - By [Jannchie](mailto:jannchie@gmail.com) in [628a6b5](https://github.com/Jannchie/lite-agent/commit/628a6b5)
|
|
48
|
+
- **tests**: parametrize tool call type tests and clean up redundant cases - By [Jannchie](mailto:jannchie@gmail.com) in [0791582](https://github.com/Jannchie/lite-agent/commit/0791582)
|
|
49
|
+
- **types**: move chunk types to types.py && update type imports - By [Jannchie](mailto:panjianqi@preferred.jp) in [d2ebeec](https://github.com/Jannchie/lite-agent/commit/d2ebeec)
|
|
50
|
+
|
|
51
|
+
### :lipstick: Styles
|
|
52
|
+
|
|
53
|
+
- **tests**: improve formatting and consistency - By [Jannchie](mailto:jannchie@gmail.com) in [4342aa4](https://github.com/Jannchie/lite-agent/commit/4342aa4)
|
|
54
|
+
|
|
55
|
+
### :memo: Documentation
|
|
56
|
+
|
|
57
|
+
- add initial project readme - By [Jannchie](mailto:panjianqi@preferred.jp) in [f04ec7a](https://github.com/Jannchie/lite-agent/commit/f04ec7a)
|
|
58
|
+
|
|
59
|
+
### :wrench: Chores
|
|
60
|
+
|
|
61
|
+
- **ci**: switch to uv for dependency management and update to python 3.12 - By [Jannchie](mailto:panjianqi@preferred.jp) in [64d3085](https://github.com/Jannchie/lite-agent/commit/64d3085)
|
|
62
|
+
- **ci**: add github actions workflow - By [Jannchie](mailto:panjianqi@preferred.jp) in [051be1b](https://github.com/Jannchie/lite-agent/commit/051be1b)
|
|
63
|
+
- **deps**: update lock file - By [Jannchie](mailto:jannchie@gmail.com) in [9aa1e77](https://github.com/Jannchie/lite-agent/commit/9aa1e77)
|
|
64
|
+
- **metadata**: rename project and reformat keywords array - By [Jannchie](mailto:jannchie@gmail.com) in [2659c4d](https://github.com/Jannchie/lite-agent/commit/2659c4d)
|
|
65
|
+
- **metadata**: update ai topic classifier - By [Jannchie](mailto:jannchie@gmail.com) in [15d46ea](https://github.com/Jannchie/lite-agent/commit/15d46ea)
|
|
66
|
+
- **rename**: rename project name - By [Jannchie](mailto:jannchie@gmail.com) in [84077a8](https://github.com/Jannchie/lite-agent/commit/84077a8)
|
|
67
|
+
|
|
68
|
+
## v0.1.0
|
|
69
|
+
|
|
70
|
+
[5859f296f4aa3bf9156e560e5bbd98b3d8795b0d...v0.1.0](https://github.com/Jannchie/lite-agent/compare/5859f296f4aa3bf9156e560e5bbd98b3d8795b0d...v0.1.0)
|
|
71
|
+
|
|
72
|
+
### :sparkles: Features
|
|
73
|
+
|
|
74
|
+
- **chunk-handler**: add content-delta and tool-call-delta chunk types && update includes list in runner - By [Jannchie](mailto:jannchie@gmail.com) in [a3ba7d1](https://github.com/Jannchie/lite-agent/commit/a3ba7d1)
|
|
75
|
+
- **easy_agent**: add prompt toolkit dependency && update agent to use prompt session && improve chunk handling - By [Jannchie](mailto:jannchie@gmail.com) in [b408c14](https://github.com/Jannchie/lite-agent/commit/b408c14)
|
|
76
|
+
|
|
77
|
+
### :art: Refactors
|
|
78
|
+
|
|
79
|
+
- **main**: remove datetime imports and usage && add input validator - By [Jannchie](mailto:jannchie@gmail.com) in [eab45b3](https://github.com/Jannchie/lite-agent/commit/eab45b3)
|
|
80
|
+
|
|
81
|
+
### :wrench: Chores
|
|
82
|
+
|
|
83
|
+
- **import**: remove unused json tool import - By [Jannchie](mailto:jannchie@gmail.com) in [8de5975](https://github.com/Jannchie/lite-agent/commit/8de5975)
|
|
84
|
+
- **lock**: update lock file - By [Jannchie](mailto:jannchie@gmail.com) in [64880d3](https://github.com/Jannchie/lite-agent/commit/64880d3)
|
|
85
|
+
- **pyproject**: update version && improve description && expand keywords && add classifiers - By [Jannchie](mailto:jannchie@gmail.com) in [c3e8ee6](https://github.com/Jannchie/lite-agent/commit/c3e8ee6)
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lite-agent
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: A lightweight, extensible framework for building AI agent.
|
|
5
|
+
Author-email: Jianqi Pan <jannchie@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: AI,agent framework,assistant,chatbot,function call,openai,pydantic,rich,tooling
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: Intended Audience :: Science/Research
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Topic :: Communications :: Chat
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Requires-Dist: aiofiles>=24.1.0
|
|
21
|
+
Requires-Dist: funcall>=0.7.0
|
|
22
|
+
Requires-Dist: prompt-toolkit>=3.0.51
|
|
23
|
+
Requires-Dist: rich>=14.0.0
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# LiteAgent
|
|
27
|
+
|
|
28
|
+
[](https://codecov.io/gh/Jannchie/lite-agent)
|
|
29
|
+
|
|
30
|
+
## Introduction
|
|
31
|
+
|
|
32
|
+
LiteAgent is an easy-to-learn, lightweight, and extensible AI agent framework built on top of [LiteLLM](https://github.com/BerriAI/litellm). It is designed as a minimal yet practical implementation for quickly building intelligent assistants and chatbots with robust tool-calling capabilities. The codebase is intentionally simple, making it ideal for learning, extension, and rapid prototyping.
|
|
33
|
+
|
|
34
|
+
**Key Advantages:**
|
|
35
|
+
|
|
36
|
+
- **Minimal and approachable:** The simplest agent implementation for fast learning and hacking.
|
|
37
|
+
- **Accurate and complete type hints:** All function signatures are fully type-hinted and never faked, ensuring reliable developer experience and static analysis.
|
|
38
|
+
- **Flexible parameter definition:** Supports defining tool function parameters using basic types, Pydantic models, or Python dataclasses—even in combination.
|
|
39
|
+
- **Streaming responses:** Seamless support for LiteLLM streaming output.
|
|
40
|
+
- **Custom tool functions:** Easily integrate your own Python functions (e.g., weather, temperature queries).
|
|
41
|
+
- **Rich type annotations, Pydantic-based.**
|
|
42
|
+
- **Easy to extend and test.**
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
45
|
+
|
|
46
|
+
You can install LiteAgent directly from PyPI:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pip install lite-agent
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Or use [uv](https://github.com/astral-sh/uv):
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
uv pip install lite-agent
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
If you want to install from source for development:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
uv pip install -e .
|
|
62
|
+
# or
|
|
63
|
+
pip install -e .
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Quick Start
|
|
67
|
+
|
|
68
|
+
### Code Example
|
|
69
|
+
|
|
70
|
+
See `examples/basic.py`:
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
import asyncio
|
|
74
|
+
from lite_agent.agent import Agent
|
|
75
|
+
from lite_agent.runner import Runner
|
|
76
|
+
|
|
77
|
+
async def get_whether(city: str) -> str:
|
|
78
|
+
await asyncio.sleep(1)
|
|
79
|
+
return f"The weather in {city} is sunny with a few clouds."
|
|
80
|
+
|
|
81
|
+
async def main():
|
|
82
|
+
agent = Agent(
|
|
83
|
+
model="gpt-4.1",
|
|
84
|
+
name="Weather Assistant",
|
|
85
|
+
instructions="You are a helpful weather assistant.",
|
|
86
|
+
tools=[get_whether],
|
|
87
|
+
)
|
|
88
|
+
runner = Runner(agent)
|
|
89
|
+
resp = await runner.run_until_complete("What's the weather in New York?")
|
|
90
|
+
for chunk in resp:
|
|
91
|
+
print(chunk)
|
|
92
|
+
|
|
93
|
+
if __name__ == "__main__":
|
|
94
|
+
asyncio.run(main())
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
See `pyproject.toml` for details.
|
|
98
|
+
|
|
99
|
+
## Testing
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
pytest
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## License
|
|
106
|
+
|
|
107
|
+
MIT License
|
|
108
|
+
|
|
109
|
+
## Author
|
|
110
|
+
|
|
111
|
+
Jianqi Pan ([jannchie@gmail.com](mailto:jannchie@gmail.com))
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# LiteAgent
|
|
2
|
+
|
|
3
|
+
[](https://codecov.io/gh/Jannchie/lite-agent)
|
|
4
|
+
|
|
5
|
+
## Introduction
|
|
6
|
+
|
|
7
|
+
LiteAgent is an easy-to-learn, lightweight, and extensible AI agent framework built on top of [LiteLLM](https://github.com/BerriAI/litellm). It is designed as a minimal yet practical implementation for quickly building intelligent assistants and chatbots with robust tool-calling capabilities. The codebase is intentionally simple, making it ideal for learning, extension, and rapid prototyping.
|
|
8
|
+
|
|
9
|
+
**Key Advantages:**
|
|
10
|
+
|
|
11
|
+
- **Minimal and approachable:** The simplest agent implementation for fast learning and hacking.
|
|
12
|
+
- **Accurate and complete type hints:** All function signatures are fully type-hinted and never faked, ensuring reliable developer experience and static analysis.
|
|
13
|
+
- **Flexible parameter definition:** Supports defining tool function parameters using basic types, Pydantic models, or Python dataclasses—even in combination.
|
|
14
|
+
- **Streaming responses:** Seamless support for LiteLLM streaming output.
|
|
15
|
+
- **Custom tool functions:** Easily integrate your own Python functions (e.g., weather, temperature queries).
|
|
16
|
+
- **Rich type annotations, Pydantic-based.**
|
|
17
|
+
- **Easy to extend and test.**
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
You can install LiteAgent directly from PyPI:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install lite-agent
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Or use [uv](https://github.com/astral-sh/uv):
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
uv pip install lite-agent
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
If you want to install from source for development:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
uv pip install -e .
|
|
37
|
+
# or
|
|
38
|
+
pip install -e .
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Quick Start
|
|
42
|
+
|
|
43
|
+
### Code Example
|
|
44
|
+
|
|
45
|
+
See `examples/basic.py`:
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
import asyncio
|
|
49
|
+
from lite_agent.agent import Agent
|
|
50
|
+
from lite_agent.runner import Runner
|
|
51
|
+
|
|
52
|
+
async def get_whether(city: str) -> str:
|
|
53
|
+
await asyncio.sleep(1)
|
|
54
|
+
return f"The weather in {city} is sunny with a few clouds."
|
|
55
|
+
|
|
56
|
+
async def main():
|
|
57
|
+
agent = Agent(
|
|
58
|
+
model="gpt-4.1",
|
|
59
|
+
name="Weather Assistant",
|
|
60
|
+
instructions="You are a helpful weather assistant.",
|
|
61
|
+
tools=[get_whether],
|
|
62
|
+
)
|
|
63
|
+
runner = Runner(agent)
|
|
64
|
+
resp = await runner.run_until_complete("What's the weather in New York?")
|
|
65
|
+
for chunk in resp:
|
|
66
|
+
print(chunk)
|
|
67
|
+
|
|
68
|
+
if __name__ == "__main__":
|
|
69
|
+
asyncio.run(main())
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
See `pyproject.toml` for details.
|
|
73
|
+
|
|
74
|
+
## Testing
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
pytest
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## License
|
|
81
|
+
|
|
82
|
+
MIT License
|
|
83
|
+
|
|
84
|
+
## Author
|
|
85
|
+
|
|
86
|
+
Jianqi Pan ([jannchie@gmail.com](mailto:jannchie@gmail.com))
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
from rich.logging import RichHandler
|
|
5
|
+
|
|
6
|
+
from lite_agent.agent import Agent
|
|
7
|
+
from lite_agent.runner import Runner
|
|
8
|
+
|
|
9
|
+
logging.basicConfig(
|
|
10
|
+
level=logging.WARNING,
|
|
11
|
+
format="%(message)s",
|
|
12
|
+
datefmt="[%X]",
|
|
13
|
+
handlers=[RichHandler(rich_tracebacks=True)],
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger("lite_agent")
|
|
17
|
+
logger.setLevel(logging.DEBUG)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
async def get_temperature(city: str) -> str:
|
|
21
|
+
"""Get the temperature for a city."""
|
|
22
|
+
await asyncio.sleep(1)
|
|
23
|
+
return f"The temperature in {city} is 25°C."
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
agent = Agent(
|
|
27
|
+
model="gpt-4.1-nano",
|
|
28
|
+
name="Weather Assistant",
|
|
29
|
+
instructions="You are a helpful weather assistant. Before using tools, briefly explain what you are going to do. Provide friendly and informative responses.",
|
|
30
|
+
tools=[get_temperature],
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
async def main():
|
|
35
|
+
runner = Runner(agent)
|
|
36
|
+
resp = runner.run(
|
|
37
|
+
"What is the temperature in New York?",
|
|
38
|
+
includes=["final_message", "usage", "tool_call", "tool_call_result"],
|
|
39
|
+
record_to="tests/mocks/basic/1.jsonl",
|
|
40
|
+
)
|
|
41
|
+
async for chunk in resp:
|
|
42
|
+
logger.info(chunk)
|
|
43
|
+
print(runner.messages)
|
|
44
|
+
|
|
45
|
+
if __name__ == "__main__":
|
|
46
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from rich.console import Console
|
|
2
|
+
|
|
3
|
+
from lite_agent.types import AgentChunk, ContentDeltaChunk
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class RichChannel:
|
|
7
|
+
def __init__(self) -> None:
|
|
8
|
+
self.console = Console()
|
|
9
|
+
self.map = {
|
|
10
|
+
"final_message": self.handle_final_message,
|
|
11
|
+
"tool_call": self.handle_tool_call,
|
|
12
|
+
"tool_call_result": self.handle_tool_call_result,
|
|
13
|
+
"tool_call_delta": self.handle_tool_call_delta,
|
|
14
|
+
"content_delta": self.handle_content_delta,
|
|
15
|
+
"usage": self.handle_usage,
|
|
16
|
+
"require_confirm": self.handle_require_confirm,
|
|
17
|
+
}
|
|
18
|
+
self.new_turn = True
|
|
19
|
+
|
|
20
|
+
async def handle(self, chunk: AgentChunk):
|
|
21
|
+
handler = self.map[chunk.type]
|
|
22
|
+
return await handler(chunk)
|
|
23
|
+
|
|
24
|
+
async def handle_final_message(self, _chunk: AgentChunk):
|
|
25
|
+
print()
|
|
26
|
+
self.new_turn = True
|
|
27
|
+
|
|
28
|
+
async def handle_tool_call(self, chunk: AgentChunk):
|
|
29
|
+
name = getattr(chunk, "name", "<unknown>")
|
|
30
|
+
arguments = getattr(chunk, "arguments", "")
|
|
31
|
+
self.console.print(f"🛠️ [green]{name}[/green]([yellow]{arguments}[/yellow])")
|
|
32
|
+
|
|
33
|
+
async def handle_tool_call_result(self, chunk: AgentChunk):
|
|
34
|
+
name = getattr(chunk, "name", "<unknown>")
|
|
35
|
+
content = getattr(chunk, "content", "")
|
|
36
|
+
self.console.print(f"🛠️ [green]{name}[/green] → [yellow]{content}[/yellow]")
|
|
37
|
+
|
|
38
|
+
async def handle_tool_call_delta(self, chunk: AgentChunk): ...
|
|
39
|
+
async def handle_content_delta(self, chunk: ContentDeltaChunk):
|
|
40
|
+
if self.new_turn:
|
|
41
|
+
self.console.print("🤖 ", end="")
|
|
42
|
+
self.new_turn = False
|
|
43
|
+
print(chunk.delta, end="", flush=True)
|
|
44
|
+
|
|
45
|
+
async def handle_usage(self, chunk: AgentChunk):
|
|
46
|
+
if False:
|
|
47
|
+
usage = chunk.usage
|
|
48
|
+
self.console.print(f"In: {usage.prompt_tokens}, Out: {usage.completion_tokens}, Total: {usage.total_tokens}")
|
|
49
|
+
|
|
50
|
+
async def handle_require_confirm(self, chunk: AgentChunk): ...
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
from funcall.decorators import tool
|
|
5
|
+
from rich.logging import RichHandler
|
|
6
|
+
|
|
7
|
+
from lite_agent.agent import Agent
|
|
8
|
+
from lite_agent.runner import Runner
|
|
9
|
+
|
|
10
|
+
logging.basicConfig(
|
|
11
|
+
level=logging.WARNING,
|
|
12
|
+
format="%(message)s",
|
|
13
|
+
datefmt="[%X]",
|
|
14
|
+
handlers=[RichHandler(rich_tracebacks=True)],
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger("lite_agent")
|
|
18
|
+
logger.setLevel(logging.DEBUG)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@tool(require_confirmation=True)
|
|
22
|
+
async def get_whether(city: str) -> str:
|
|
23
|
+
"""Get the weather for a city."""
|
|
24
|
+
await asyncio.sleep(1)
|
|
25
|
+
return f"The weather in {city} is sunny with a few clouds."
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
async def get_temperature(city: str) -> str:
|
|
29
|
+
"""Get the temperature for a city."""
|
|
30
|
+
await asyncio.sleep(1)
|
|
31
|
+
return f"The temperature in {city} is 25°C."
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
agent = Agent(
|
|
35
|
+
model="gpt-4.1-nano",
|
|
36
|
+
name="Weather Assistant",
|
|
37
|
+
instructions="You are a helpful weather assistant. Before using tools, briefly explain what you are going to do. Provide friendly and informative responses.",
|
|
38
|
+
tools=[get_whether, get_temperature],
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
async def main():
|
|
43
|
+
runner = Runner(agent)
|
|
44
|
+
resp = runner.run(
|
|
45
|
+
"What is the weather in New York? And what is the temperature there?",
|
|
46
|
+
includes=["final_message", "usage", "tool_call", "tool_call_result"],
|
|
47
|
+
record_to="tests/mocks/confirm_and_continue/1.jsonl",
|
|
48
|
+
)
|
|
49
|
+
async for chunk in resp:
|
|
50
|
+
logger.info(chunk)
|
|
51
|
+
resp = runner.run_continue_stream(
|
|
52
|
+
includes=["final_message", "usage", "tool_call", "tool_call_result"],
|
|
53
|
+
record_to="tests/mocks/confirm_and_continue/2.jsonl",
|
|
54
|
+
)
|
|
55
|
+
async for chunk in resp:
|
|
56
|
+
logger.info(chunk)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
if __name__ == "__main__":
|
|
60
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
from funcall import Context
|
|
5
|
+
from rich.logging import RichHandler
|
|
6
|
+
|
|
7
|
+
from lite_agent.agent import Agent, BaseModel
|
|
8
|
+
from lite_agent.runner import Runner
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class WeatherContext(BaseModel):
|
|
12
|
+
city: str
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
weather_context = Context(WeatherContext(city="New York"))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
logging.basicConfig(
|
|
19
|
+
level=logging.WARNING,
|
|
20
|
+
format="%(message)s",
|
|
21
|
+
datefmt="[%X]",
|
|
22
|
+
handlers=[RichHandler(rich_tracebacks=True)],
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger("lite_agent")
|
|
26
|
+
logger.setLevel(logging.DEBUG)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
async def get_current_city_temperature(context: Context[WeatherContext]) -> str:
|
|
30
|
+
"""Get the temperature for the current city specified in the context."""
|
|
31
|
+
await asyncio.sleep(1)
|
|
32
|
+
if not context.value:
|
|
33
|
+
msg = "City must be specified in the context."
|
|
34
|
+
raise ValueError(msg)
|
|
35
|
+
return f"The temperature in {context.value.city} is 25°C."
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
agent = Agent(
|
|
39
|
+
model="gpt-4.1-nano",
|
|
40
|
+
name="Weather Assistant",
|
|
41
|
+
instructions="You are a weather assistant. Use the tools provided to answer questions about the weather.",
|
|
42
|
+
tools=[get_current_city_temperature],
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
async def main():
|
|
47
|
+
runner = Runner(agent)
|
|
48
|
+
resp = runner.run(
|
|
49
|
+
"What is the temperature in current city?",
|
|
50
|
+
includes=["final_message", "usage", "tool_call", "tool_call_result"],
|
|
51
|
+
record_to="tests/mocks/context/1.jsonl",
|
|
52
|
+
context=weather_context,
|
|
53
|
+
)
|
|
54
|
+
async for chunk in resp:
|
|
55
|
+
logger.info(chunk)
|
|
56
|
+
print(runner.messages)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
if __name__ == "__main__":
|
|
60
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Example showing how to use handoffs between agents.
|
|
3
|
+
|
|
4
|
+
This example demonstrates how agents can transfer conversations to each other
|
|
5
|
+
using automatically generated transfer functions.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import logging
|
|
10
|
+
|
|
11
|
+
from rich.logging import RichHandler
|
|
12
|
+
|
|
13
|
+
from lite_agent import consolidate_history_transfer
|
|
14
|
+
from lite_agent.agent import Agent
|
|
15
|
+
from lite_agent.loggers import logger
|
|
16
|
+
from lite_agent.runner import Runner
|
|
17
|
+
|
|
18
|
+
logging.basicConfig(
|
|
19
|
+
format="%(message)s",
|
|
20
|
+
datefmt="[%X]",
|
|
21
|
+
handlers=[RichHandler(rich_tracebacks=True)],
|
|
22
|
+
)
|
|
23
|
+
logger.setLevel(logging.DEBUG)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def get_temperature(city: str) -> str:
|
|
27
|
+
"""Get the temperature of a city."""
|
|
28
|
+
# In a real application, this would call an API or database.
|
|
29
|
+
return f"The temperature in {city} is 25°C."
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def get_weather(city: str) -> str:
|
|
33
|
+
"""Get the weather of a city."""
|
|
34
|
+
# In a real application, this would call an API or database.
|
|
35
|
+
return f"The weather in {city} is sunny."
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
async def main():
|
|
39
|
+
"""Demonstrate agent handoffs functionality."""
|
|
40
|
+
parent = Agent(
|
|
41
|
+
model="gpt-4.1",
|
|
42
|
+
name="ParentAgent",
|
|
43
|
+
instructions="You are a helpful agent.",
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
whether_agent = Agent(
|
|
47
|
+
model="gpt-4.1",
|
|
48
|
+
name="WhetherAgent",
|
|
49
|
+
instructions="You are a helpful agent to check weather.",
|
|
50
|
+
tools=[get_weather],
|
|
51
|
+
message_transfer=consolidate_history_transfer,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
temper_agent = Agent(
|
|
55
|
+
model="gpt-4.1",
|
|
56
|
+
name="TemperatureAgent",
|
|
57
|
+
instructions="You are a helpful agent to check temperature.",
|
|
58
|
+
tools=[get_temperature],
|
|
59
|
+
message_transfer=consolidate_history_transfer,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
parent.add_handoff(whether_agent)
|
|
63
|
+
parent.add_handoff(temper_agent)
|
|
64
|
+
|
|
65
|
+
print(temper_agent.fc.function_registry)
|
|
66
|
+
runner = Runner(parent)
|
|
67
|
+
resp = runner.run("Hello, I need to check the whether and temperature of Tokyo.", includes=["final_message", "tool_call", "tool_call_result"])
|
|
68
|
+
async for message in resp:
|
|
69
|
+
logger.info(message)
|
|
70
|
+
logger.info(runner.agent.name)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
if __name__ == "__main__":
|
|
74
|
+
asyncio.run(main())
|