tinyagent-py 0.0.3__tar.gz → 0.0.5__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.
- {tinyagent_py-0.0.3 → tinyagent_py-0.0.5}/PKG-INFO +65 -4
- tinyagent_py-0.0.3/tinyagent/tinyagent_py.egg-info/PKG-INFO → tinyagent_py-0.0.5/README.md +49 -21
- {tinyagent_py-0.0.3 → tinyagent_py-0.0.5}/pyproject.toml +23 -5
- tinyagent_py-0.0.5/tinyagent/__init__.py +4 -0
- tinyagent_py-0.0.5/tinyagent/mcp_client.py +167 -0
- tinyagent_py-0.0.5/tinyagent/tiny_agent.py +958 -0
- tinyagent_py-0.0.3/README.md → tinyagent_py-0.0.5/tinyagent_py.egg-info/PKG-INFO +82 -3
- {tinyagent_py-0.0.3/tinyagent → tinyagent_py-0.0.5}/tinyagent_py.egg-info/SOURCES.txt +8 -5
- tinyagent_py-0.0.5/tinyagent_py.egg-info/requires.txt +25 -0
- tinyagent_py-0.0.5/tinyagent_py.egg-info/top_level.txt +1 -0
- tinyagent_py-0.0.3/tinyagent/tinyagent_py.egg-info/requires.txt +0 -6
- tinyagent_py-0.0.3/tinyagent/tinyagent_py.egg-info/top_level.txt +0 -2
- {tinyagent_py-0.0.3 → tinyagent_py-0.0.5}/LICENSE +0 -0
- {tinyagent_py-0.0.3 → tinyagent_py-0.0.5}/setup.cfg +0 -0
- {tinyagent_py-0.0.3 → tinyagent_py-0.0.5}/tinyagent/hooks/__init__.py +0 -0
- {tinyagent_py-0.0.3 → tinyagent_py-0.0.5}/tinyagent/hooks/agno_storage_hook.py +0 -0
- {tinyagent_py-0.0.3 → tinyagent_py-0.0.5}/tinyagent/hooks/gradio_callback.py +0 -0
- {tinyagent_py-0.0.3 → tinyagent_py-0.0.5}/tinyagent/hooks/logging_manager.py +0 -0
- {tinyagent_py-0.0.3 → tinyagent_py-0.0.5}/tinyagent/hooks/rich_ui_callback.py +0 -0
- {tinyagent_py-0.0.3 → tinyagent_py-0.0.5}/tinyagent/storage/__init__.py +0 -0
- {tinyagent_py-0.0.3 → tinyagent_py-0.0.5}/tinyagent/storage/agno_storage.py +0 -0
- {tinyagent_py-0.0.3 → tinyagent_py-0.0.5}/tinyagent/storage/base.py +0 -0
- {tinyagent_py-0.0.3 → tinyagent_py-0.0.5}/tinyagent/storage/json_file_storage.py +0 -0
- {tinyagent_py-0.0.3 → tinyagent_py-0.0.5}/tinyagent/storage/postgres_storage.py +0 -0
- {tinyagent_py-0.0.3 → tinyagent_py-0.0.5}/tinyagent/storage/redis_storage.py +0 -0
- {tinyagent_py-0.0.3 → tinyagent_py-0.0.5}/tinyagent/storage/sqlite_storage.py +0 -0
- {tinyagent_py-0.0.3/tinyagent → tinyagent_py-0.0.5}/tinyagent_py.egg-info/dependency_links.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: tinyagent-py
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.5
|
4
4
|
Summary: Tiny Agent with MCP Client
|
5
5
|
Author-email: Mahdi Golchin <golchin@askdev.ai>
|
6
6
|
Project-URL: Homepage, https://github.com/askbudi/tinyagent
|
@@ -12,15 +12,36 @@ License-File: LICENSE
|
|
12
12
|
Requires-Dist: mcp
|
13
13
|
Requires-Dist: litellm
|
14
14
|
Requires-Dist: openai
|
15
|
+
Requires-Dist: tiktoken
|
16
|
+
Requires-Dist: uuid
|
15
17
|
Provides-Extra: dev
|
16
18
|
Requires-Dist: pytest; extra == "dev"
|
19
|
+
Requires-Dist: black; extra == "dev"
|
20
|
+
Requires-Dist: isort; extra == "dev"
|
21
|
+
Requires-Dist: mypy; extra == "dev"
|
22
|
+
Provides-Extra: postgres
|
23
|
+
Requires-Dist: asyncpg>=0.27.0; extra == "postgres"
|
24
|
+
Provides-Extra: sqlite
|
25
|
+
Requires-Dist: aiosqlite>=0.18.0; extra == "sqlite"
|
26
|
+
Provides-Extra: gradio
|
27
|
+
Requires-Dist: gradio>=3.50.0; extra == "gradio"
|
28
|
+
Provides-Extra: all
|
29
|
+
Requires-Dist: asyncpg>=0.27.0; extra == "all"
|
30
|
+
Requires-Dist: aiosqlite>=0.18.0; extra == "all"
|
31
|
+
Requires-Dist: gradio>=3.50.0; extra == "all"
|
17
32
|
Dynamic: license-file
|
18
33
|
|
19
|
-
#
|
20
|
-
Tiny Agent: 100 lines Agent with MCP
|
34
|
+
# TinyAgent
|
35
|
+
Tiny Agent: 100 lines Agent with MCP and extendable hook system
|
36
|
+
|
37
|
+
[](https://askdev.ai/github/askbudi/tinyagent)
|
38
|
+
|
39
|
+
|
21
40
|

|
22
41
|
|
23
42
|
|
43
|
+
[](https://askdev.ai/github/askbudi/tinyagent)
|
44
|
+
|
24
45
|
|
25
46
|
Inspired by:
|
26
47
|
- [Tiny Agents blog post](https://huggingface.co/blog/tiny-agents)
|
@@ -37,15 +58,47 @@ This is a tiny agent that uses MCP and LiteLLM to interact with a model. You hav
|
|
37
58
|
|
38
59
|
### Using pip
|
39
60
|
```bash
|
61
|
+
# Basic installation
|
40
62
|
pip install tinyagent-py
|
63
|
+
|
64
|
+
# Install with all optional dependencies
|
65
|
+
pip install tinyagent-py[all]
|
66
|
+
|
67
|
+
# Install with PostgreSQL support
|
68
|
+
pip install tinyagent-py[postgres]
|
69
|
+
|
70
|
+
# Install with SQLite support
|
71
|
+
pip install tinyagent-py[sqlite]
|
72
|
+
|
73
|
+
# Install with Gradio UI support
|
74
|
+
pip install tinyagent-py[gradio]
|
75
|
+
|
41
76
|
```
|
42
77
|
|
43
78
|
### Using uv
|
44
79
|
```bash
|
80
|
+
# Basic installation
|
45
81
|
uv pip install tinyagent-py
|
82
|
+
|
83
|
+
# Install with PostgreSQL support
|
84
|
+
uv pip install tinyagent-py[postgres]
|
85
|
+
|
86
|
+
# Install with SQLite support
|
87
|
+
uv pip install tinyagent-py[sqlite]
|
88
|
+
|
89
|
+
# Install with Gradio UI support
|
90
|
+
uv pip install tinyagent-py[gradio]
|
91
|
+
|
92
|
+
# Install with all optional dependencies
|
93
|
+
uv pip install tinyagent-py[all]
|
94
|
+
|
95
|
+
# Install with development tools
|
96
|
+
uv pip install tinyagent-py[dev]
|
46
97
|
```
|
47
98
|
|
48
99
|
## Usage
|
100
|
+
[](https://askdev.ai/github/askbudi/tinyagent)
|
101
|
+
|
49
102
|
|
50
103
|
```python
|
51
104
|
from tinyagent import TinyAgent
|
@@ -158,7 +211,7 @@ The `GradioCallback` hook lets you spin up a full-featured web chat interface fo
|
|
158
211
|
Features:
|
159
212
|
- **Browser-based chat** with streaming updates
|
160
213
|
- **File uploads** (\*.pdf, \*.docx, \*.txt) that the agent can reference
|
161
|
-
- **Live
|
214
|
+
- **Live "thinking" view** so you see intermediate thoughts
|
162
215
|
- **Collapsible tool-call sections** showing inputs & outputs
|
163
216
|
- **Real-time token usage** (prompt, completion, total)
|
164
217
|
- **Toggleable display options** for thinking & tool calls
|
@@ -194,6 +247,14 @@ if __name__ == "__main__":
|
|
194
247
|
```
|
195
248
|
---
|
196
249
|
|
250
|
+
## Build your own TinyAgent
|
251
|
+
|
252
|
+
You can chat with TinyAgent and build your own TinyAgent for your use case.
|
253
|
+
|
254
|
+
[](https://askdev.ai/github/askbudi/tinyagent)
|
255
|
+
|
256
|
+
---
|
257
|
+
|
197
258
|
## Contributing Hooks
|
198
259
|
|
199
260
|
- Place new hooks in the `tinyagent/hooks/` directory.
|
@@ -1,26 +1,14 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
Project-URL: Bug Tracker, https://github.com/askbudi/tinyagent/issues
|
8
|
-
Project-URL: Chat, https://askdev.ai/github/askbudi/tinyagent
|
9
|
-
Requires-Python: >=3.8
|
10
|
-
Description-Content-Type: text/markdown
|
11
|
-
License-File: LICENSE
|
12
|
-
Requires-Dist: mcp
|
13
|
-
Requires-Dist: litellm
|
14
|
-
Requires-Dist: openai
|
15
|
-
Provides-Extra: dev
|
16
|
-
Requires-Dist: pytest; extra == "dev"
|
17
|
-
Dynamic: license-file
|
18
|
-
|
19
|
-
# tinyagent
|
20
|
-
Tiny Agent: 100 lines Agent with MCP
|
1
|
+
# TinyAgent
|
2
|
+
Tiny Agent: 100 lines Agent with MCP and extendable hook system
|
3
|
+
|
4
|
+
[](https://askdev.ai/github/askbudi/tinyagent)
|
5
|
+
|
6
|
+
|
21
7
|

|
22
8
|
|
23
9
|
|
10
|
+
[](https://askdev.ai/github/askbudi/tinyagent)
|
11
|
+
|
24
12
|
|
25
13
|
Inspired by:
|
26
14
|
- [Tiny Agents blog post](https://huggingface.co/blog/tiny-agents)
|
@@ -37,15 +25,47 @@ This is a tiny agent that uses MCP and LiteLLM to interact with a model. You hav
|
|
37
25
|
|
38
26
|
### Using pip
|
39
27
|
```bash
|
28
|
+
# Basic installation
|
40
29
|
pip install tinyagent-py
|
30
|
+
|
31
|
+
# Install with all optional dependencies
|
32
|
+
pip install tinyagent-py[all]
|
33
|
+
|
34
|
+
# Install with PostgreSQL support
|
35
|
+
pip install tinyagent-py[postgres]
|
36
|
+
|
37
|
+
# Install with SQLite support
|
38
|
+
pip install tinyagent-py[sqlite]
|
39
|
+
|
40
|
+
# Install with Gradio UI support
|
41
|
+
pip install tinyagent-py[gradio]
|
42
|
+
|
41
43
|
```
|
42
44
|
|
43
45
|
### Using uv
|
44
46
|
```bash
|
47
|
+
# Basic installation
|
45
48
|
uv pip install tinyagent-py
|
49
|
+
|
50
|
+
# Install with PostgreSQL support
|
51
|
+
uv pip install tinyagent-py[postgres]
|
52
|
+
|
53
|
+
# Install with SQLite support
|
54
|
+
uv pip install tinyagent-py[sqlite]
|
55
|
+
|
56
|
+
# Install with Gradio UI support
|
57
|
+
uv pip install tinyagent-py[gradio]
|
58
|
+
|
59
|
+
# Install with all optional dependencies
|
60
|
+
uv pip install tinyagent-py[all]
|
61
|
+
|
62
|
+
# Install with development tools
|
63
|
+
uv pip install tinyagent-py[dev]
|
46
64
|
```
|
47
65
|
|
48
66
|
## Usage
|
67
|
+
[](https://askdev.ai/github/askbudi/tinyagent)
|
68
|
+
|
49
69
|
|
50
70
|
```python
|
51
71
|
from tinyagent import TinyAgent
|
@@ -158,7 +178,7 @@ The `GradioCallback` hook lets you spin up a full-featured web chat interface fo
|
|
158
178
|
Features:
|
159
179
|
- **Browser-based chat** with streaming updates
|
160
180
|
- **File uploads** (\*.pdf, \*.docx, \*.txt) that the agent can reference
|
161
|
-
- **Live
|
181
|
+
- **Live "thinking" view** so you see intermediate thoughts
|
162
182
|
- **Collapsible tool-call sections** showing inputs & outputs
|
163
183
|
- **Real-time token usage** (prompt, completion, total)
|
164
184
|
- **Toggleable display options** for thinking & tool calls
|
@@ -194,6 +214,14 @@ if __name__ == "__main__":
|
|
194
214
|
```
|
195
215
|
---
|
196
216
|
|
217
|
+
## Build your own TinyAgent
|
218
|
+
|
219
|
+
You can chat with TinyAgent and build your own TinyAgent for your use case.
|
220
|
+
|
221
|
+
[](https://askdev.ai/github/askbudi/tinyagent)
|
222
|
+
|
223
|
+
---
|
224
|
+
|
197
225
|
## Contributing Hooks
|
198
226
|
|
199
227
|
- Place new hooks in the `tinyagent/hooks/` directory.
|
@@ -3,12 +3,13 @@ requires = ["setuptools>=77.0", "wheel"]
|
|
3
3
|
build-backend = "setuptools.build_meta"
|
4
4
|
|
5
5
|
[tool.setuptools.packages.find]
|
6
|
-
where = ["
|
6
|
+
where = ["."]
|
7
|
+
include = ["tinyagent*"]
|
7
8
|
exclude = ["public", "public.*"]
|
8
9
|
|
9
10
|
[project]
|
10
11
|
name = "tinyagent-py"
|
11
|
-
version = "0.0.
|
12
|
+
version = "0.0.5"
|
12
13
|
description = "Tiny Agent with MCP Client"
|
13
14
|
readme = "README.md"
|
14
15
|
authors = [
|
@@ -18,15 +19,32 @@ requires-python = ">=3.8"
|
|
18
19
|
dependencies = [
|
19
20
|
"mcp",
|
20
21
|
"litellm",
|
21
|
-
"openai"
|
22
|
+
"openai",
|
23
|
+
"tiktoken",
|
24
|
+
"uuid",
|
22
25
|
# add whatever else you need…
|
23
26
|
]
|
24
27
|
|
25
28
|
[project.optional-dependencies]
|
26
29
|
dev = [
|
27
30
|
"pytest",
|
28
|
-
|
29
|
-
|
31
|
+
"black",
|
32
|
+
"isort",
|
33
|
+
"mypy"
|
34
|
+
]
|
35
|
+
postgres = [
|
36
|
+
"asyncpg>=0.27.0"
|
37
|
+
]
|
38
|
+
sqlite = [
|
39
|
+
"aiosqlite>=0.18.0"
|
40
|
+
]
|
41
|
+
gradio = [
|
42
|
+
"gradio>=3.50.0"
|
43
|
+
]
|
44
|
+
all = [
|
45
|
+
"asyncpg>=0.27.0",
|
46
|
+
"aiosqlite>=0.18.0",
|
47
|
+
"gradio>=3.50.0"
|
30
48
|
]
|
31
49
|
[project.urls]
|
32
50
|
"Homepage" = "https://github.com/askbudi/tinyagent"
|
@@ -0,0 +1,167 @@
|
|
1
|
+
import asyncio
|
2
|
+
import json
|
3
|
+
import logging
|
4
|
+
from typing import Dict, List, Optional, Any, Tuple, Callable
|
5
|
+
|
6
|
+
# Keep your MCPClient implementation unchanged
|
7
|
+
import asyncio
|
8
|
+
from contextlib import AsyncExitStack
|
9
|
+
|
10
|
+
# MCP core imports
|
11
|
+
from mcp import ClientSession, StdioServerParameters
|
12
|
+
from mcp.client.stdio import stdio_client
|
13
|
+
|
14
|
+
# Set up logging
|
15
|
+
logger = logging.getLogger(__name__)
|
16
|
+
|
17
|
+
class MCPClient:
|
18
|
+
def __init__(self, logger: Optional[logging.Logger] = None):
|
19
|
+
self.session = None
|
20
|
+
self.exit_stack = AsyncExitStack()
|
21
|
+
self.logger = logger or logging.getLogger(__name__)
|
22
|
+
|
23
|
+
# Simplified callback system
|
24
|
+
self.callbacks: List[callable] = []
|
25
|
+
|
26
|
+
self.logger.debug("MCPClient initialized")
|
27
|
+
|
28
|
+
def add_callback(self, callback: callable) -> None:
|
29
|
+
"""
|
30
|
+
Add a callback function to the client.
|
31
|
+
|
32
|
+
Args:
|
33
|
+
callback: A function that accepts (event_name, client, **kwargs)
|
34
|
+
"""
|
35
|
+
self.callbacks.append(callback)
|
36
|
+
|
37
|
+
async def _run_callbacks(self, event_name: str, **kwargs) -> None:
|
38
|
+
"""
|
39
|
+
Run all registered callbacks for an event.
|
40
|
+
|
41
|
+
Args:
|
42
|
+
event_name: The name of the event
|
43
|
+
**kwargs: Additional data for the event
|
44
|
+
"""
|
45
|
+
for callback in self.callbacks:
|
46
|
+
try:
|
47
|
+
logger.debug(f"Running callback: {callback}")
|
48
|
+
if asyncio.iscoroutinefunction(callback):
|
49
|
+
logger.debug(f"Callback is a coroutine function")
|
50
|
+
await callback(event_name, self, **kwargs)
|
51
|
+
else:
|
52
|
+
# Check if the callback is a class with an async __call__ method
|
53
|
+
if hasattr(callback, '__call__') and asyncio.iscoroutinefunction(callback.__call__):
|
54
|
+
logger.debug(f"Callback is a class with an async __call__ method")
|
55
|
+
await callback(event_name, self, **kwargs)
|
56
|
+
else:
|
57
|
+
logger.debug(f"Callback is a regular function")
|
58
|
+
callback(event_name, self, **kwargs)
|
59
|
+
except Exception as e:
|
60
|
+
logger.error(f"Error in callback for {event_name}: {str(e)}")
|
61
|
+
|
62
|
+
async def connect(self, command: str, args: list[str]):
|
63
|
+
"""
|
64
|
+
Launches the MCP server subprocess and initializes the client session.
|
65
|
+
:param command: e.g. "python" or "node"
|
66
|
+
:param args: list of args to pass, e.g. ["my_server.py"] or ["build/index.js"]
|
67
|
+
"""
|
68
|
+
# Prepare stdio transport parameters
|
69
|
+
params = StdioServerParameters(command=command, args=args)
|
70
|
+
# Open the stdio client transport
|
71
|
+
self.stdio, self.sock_write = await self.exit_stack.enter_async_context(
|
72
|
+
stdio_client(params)
|
73
|
+
)
|
74
|
+
# Create and initialize the MCP client session
|
75
|
+
self.session = await self.exit_stack.enter_async_context(
|
76
|
+
ClientSession(self.stdio, self.sock_write)
|
77
|
+
)
|
78
|
+
await self.session.initialize()
|
79
|
+
|
80
|
+
async def list_tools(self):
|
81
|
+
resp = await self.session.list_tools()
|
82
|
+
print("Available tools:")
|
83
|
+
for tool in resp.tools:
|
84
|
+
print(f" • {tool.name}: {tool.description}")
|
85
|
+
|
86
|
+
async def call_tool(self, name: str, arguments: dict):
|
87
|
+
"""
|
88
|
+
Invokes a named tool and returns its raw content list.
|
89
|
+
"""
|
90
|
+
# Notify tool start
|
91
|
+
await self._run_callbacks("tool_start", tool_name=name, arguments=arguments)
|
92
|
+
|
93
|
+
try:
|
94
|
+
resp = await self.session.call_tool(name, arguments)
|
95
|
+
|
96
|
+
# Notify tool end
|
97
|
+
await self._run_callbacks("tool_end", tool_name=name, arguments=arguments,
|
98
|
+
result=resp.content, success=True)
|
99
|
+
|
100
|
+
return resp.content
|
101
|
+
except Exception as e:
|
102
|
+
# Notify tool end with error
|
103
|
+
await self._run_callbacks("tool_end", tool_name=name, arguments=arguments,
|
104
|
+
error=str(e), success=False)
|
105
|
+
raise
|
106
|
+
|
107
|
+
async def close(self):
|
108
|
+
"""Clean up subprocess and streams."""
|
109
|
+
if self.session:
|
110
|
+
try:
|
111
|
+
await self.session.close()
|
112
|
+
except Exception as e:
|
113
|
+
self.logger.error(f"Error closing session: {e}")
|
114
|
+
if self.exit_stack:
|
115
|
+
try:
|
116
|
+
await self.exit_stack.aclose()
|
117
|
+
except (RuntimeError, asyncio.CancelledError) as e:
|
118
|
+
# Log the error but don't re-raise it
|
119
|
+
self.logger.error(f"Error during client cleanup: {e}")
|
120
|
+
finally:
|
121
|
+
# Always reset these regardless of success or failure
|
122
|
+
self.session = None
|
123
|
+
self.exit_stack = AsyncExitStack()
|
124
|
+
|
125
|
+
async def run_example():
|
126
|
+
"""Example usage of MCPClient with proper logging."""
|
127
|
+
import sys
|
128
|
+
from tinyagent.hooks.logging_manager import LoggingManager
|
129
|
+
|
130
|
+
# Create and configure logging manager
|
131
|
+
log_manager = LoggingManager(default_level=logging.INFO)
|
132
|
+
log_manager.set_levels({
|
133
|
+
'tinyagent.mcp_client': logging.DEBUG, # Debug for this module
|
134
|
+
'tinyagent.tiny_agent': logging.INFO,
|
135
|
+
})
|
136
|
+
|
137
|
+
# Configure a console handler
|
138
|
+
console_handler = logging.StreamHandler(sys.stdout)
|
139
|
+
log_manager.configure_handler(
|
140
|
+
console_handler,
|
141
|
+
format_string='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
142
|
+
level=logging.DEBUG
|
143
|
+
)
|
144
|
+
|
145
|
+
# Get module-specific logger
|
146
|
+
mcp_logger = log_manager.get_logger('tinyagent.mcp_client')
|
147
|
+
|
148
|
+
mcp_logger.debug("Starting MCPClient example")
|
149
|
+
|
150
|
+
# Create client with our logger
|
151
|
+
client = MCPClient(logger=mcp_logger)
|
152
|
+
|
153
|
+
try:
|
154
|
+
# Connect to a simple echo server
|
155
|
+
await client.connect("python", ["-m", "mcp.examples.echo_server"])
|
156
|
+
|
157
|
+
# List available tools
|
158
|
+
await client.list_tools()
|
159
|
+
|
160
|
+
# Call the echo tool
|
161
|
+
result = await client.call_tool("echo", {"message": "Hello, MCP!"})
|
162
|
+
mcp_logger.info(f"Echo result: {result}")
|
163
|
+
|
164
|
+
finally:
|
165
|
+
# Clean up
|
166
|
+
await client.close()
|
167
|
+
mcp_logger.debug("Example completed")
|