tinyagent-py 0.0.4__tar.gz → 0.0.6__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.
Files changed (26) hide show
  1. {tinyagent_py-0.0.4/tinyagent/tinyagent_py.egg-info → tinyagent_py-0.0.6}/PKG-INFO +19 -3
  2. {tinyagent_py-0.0.4 → tinyagent_py-0.0.6}/README.md +18 -2
  3. {tinyagent_py-0.0.4 → tinyagent_py-0.0.6}/pyproject.toml +3 -2
  4. tinyagent_py-0.0.6/tinyagent/__init__.py +4 -0
  5. tinyagent_py-0.0.6/tinyagent/mcp_client.py +162 -0
  6. tinyagent_py-0.0.6/tinyagent/tiny_agent.py +1003 -0
  7. {tinyagent_py-0.0.4 → tinyagent_py-0.0.6/tinyagent_py.egg-info}/PKG-INFO +19 -3
  8. {tinyagent_py-0.0.4/tinyagent → tinyagent_py-0.0.6}/tinyagent_py.egg-info/SOURCES.txt +8 -5
  9. tinyagent_py-0.0.6/tinyagent_py.egg-info/top_level.txt +1 -0
  10. tinyagent_py-0.0.4/tinyagent/tinyagent_py.egg-info/top_level.txt +0 -2
  11. {tinyagent_py-0.0.4 → tinyagent_py-0.0.6}/LICENSE +0 -0
  12. {tinyagent_py-0.0.4 → tinyagent_py-0.0.6}/setup.cfg +0 -0
  13. {tinyagent_py-0.0.4 → tinyagent_py-0.0.6}/tinyagent/hooks/__init__.py +0 -0
  14. {tinyagent_py-0.0.4 → tinyagent_py-0.0.6}/tinyagent/hooks/agno_storage_hook.py +0 -0
  15. {tinyagent_py-0.0.4 → tinyagent_py-0.0.6}/tinyagent/hooks/gradio_callback.py +0 -0
  16. {tinyagent_py-0.0.4 → tinyagent_py-0.0.6}/tinyagent/hooks/logging_manager.py +0 -0
  17. {tinyagent_py-0.0.4 → tinyagent_py-0.0.6}/tinyagent/hooks/rich_ui_callback.py +0 -0
  18. {tinyagent_py-0.0.4 → tinyagent_py-0.0.6}/tinyagent/storage/__init__.py +0 -0
  19. {tinyagent_py-0.0.4 → tinyagent_py-0.0.6}/tinyagent/storage/agno_storage.py +0 -0
  20. {tinyagent_py-0.0.4 → tinyagent_py-0.0.6}/tinyagent/storage/base.py +0 -0
  21. {tinyagent_py-0.0.4 → tinyagent_py-0.0.6}/tinyagent/storage/json_file_storage.py +0 -0
  22. {tinyagent_py-0.0.4 → tinyagent_py-0.0.6}/tinyagent/storage/postgres_storage.py +0 -0
  23. {tinyagent_py-0.0.4 → tinyagent_py-0.0.6}/tinyagent/storage/redis_storage.py +0 -0
  24. {tinyagent_py-0.0.4 → tinyagent_py-0.0.6}/tinyagent/storage/sqlite_storage.py +0 -0
  25. {tinyagent_py-0.0.4/tinyagent → tinyagent_py-0.0.6}/tinyagent_py.egg-info/dependency_links.txt +0 -0
  26. {tinyagent_py-0.0.4/tinyagent → tinyagent_py-0.0.6}/tinyagent_py.egg-info/requires.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tinyagent-py
3
- Version: 0.0.4
3
+ Version: 0.0.6
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
@@ -31,11 +31,17 @@ Requires-Dist: aiosqlite>=0.18.0; extra == "all"
31
31
  Requires-Dist: gradio>=3.50.0; extra == "all"
32
32
  Dynamic: license-file
33
33
 
34
- # tinyagent
35
- Tiny Agent: 100 lines Agent with MCP
34
+ # TinyAgent
35
+ Tiny Agent: 100 lines Agent with MCP and extendable hook system
36
+
37
+ [![AskDev.AI | Chat with TinyAgent](https://img.shields.io/badge/AskDev.AI-Chat_with_TinyAgent-blue?style=flat-square)](https://askdev.ai/github/askbudi/tinyagent)
38
+
39
+
36
40
  ![TinyAgent Logo](https://raw.githubusercontent.com/askbudi/tinyagent/main/public/logo.png)
37
41
 
38
42
 
43
+ [![AskDev.AI | Chat with TinyAgent](https://img.shields.io/badge/AskDev.AI-Chat_with_TinyAgent-blue?style=flat-square)](https://askdev.ai/github/askbudi/tinyagent)
44
+
39
45
 
40
46
  Inspired by:
41
47
  - [Tiny Agents blog post](https://huggingface.co/blog/tiny-agents)
@@ -91,6 +97,8 @@ uv pip install tinyagent-py[dev]
91
97
  ```
92
98
 
93
99
  ## Usage
100
+ [![AskDev.AI | Chat with TinyAgent](https://img.shields.io/badge/AskDev.AI-Chat_with_TinyAgent-blue?style=flat-square)](https://askdev.ai/github/askbudi/tinyagent)
101
+
94
102
 
95
103
  ```python
96
104
  from tinyagent import TinyAgent
@@ -239,6 +247,14 @@ if __name__ == "__main__":
239
247
  ```
240
248
  ---
241
249
 
250
+ ## Build your own TinyAgent
251
+
252
+ You can chat with TinyAgent and build your own TinyAgent for your use case.
253
+
254
+ [![AskDev.AI | Chat with TinyAgent](https://img.shields.io/badge/AskDev.AI-Chat_with_TinyAgent-blue?style=flat-square)](https://askdev.ai/github/askbudi/tinyagent)
255
+
256
+ ---
257
+
242
258
  ## Contributing Hooks
243
259
 
244
260
  - Place new hooks in the `tinyagent/hooks/` directory.
@@ -1,8 +1,14 @@
1
- # tinyagent
2
- Tiny Agent: 100 lines Agent with MCP
1
+ # TinyAgent
2
+ Tiny Agent: 100 lines Agent with MCP and extendable hook system
3
+
4
+ [![AskDev.AI | Chat with TinyAgent](https://img.shields.io/badge/AskDev.AI-Chat_with_TinyAgent-blue?style=flat-square)](https://askdev.ai/github/askbudi/tinyagent)
5
+
6
+
3
7
  ![TinyAgent Logo](https://raw.githubusercontent.com/askbudi/tinyagent/main/public/logo.png)
4
8
 
5
9
 
10
+ [![AskDev.AI | Chat with TinyAgent](https://img.shields.io/badge/AskDev.AI-Chat_with_TinyAgent-blue?style=flat-square)](https://askdev.ai/github/askbudi/tinyagent)
11
+
6
12
 
7
13
  Inspired by:
8
14
  - [Tiny Agents blog post](https://huggingface.co/blog/tiny-agents)
@@ -58,6 +64,8 @@ uv pip install tinyagent-py[dev]
58
64
  ```
59
65
 
60
66
  ## Usage
67
+ [![AskDev.AI | Chat with TinyAgent](https://img.shields.io/badge/AskDev.AI-Chat_with_TinyAgent-blue?style=flat-square)](https://askdev.ai/github/askbudi/tinyagent)
68
+
61
69
 
62
70
  ```python
63
71
  from tinyagent import TinyAgent
@@ -206,6 +214,14 @@ if __name__ == "__main__":
206
214
  ```
207
215
  ---
208
216
 
217
+ ## Build your own TinyAgent
218
+
219
+ You can chat with TinyAgent and build your own TinyAgent for your use case.
220
+
221
+ [![AskDev.AI | Chat with TinyAgent](https://img.shields.io/badge/AskDev.AI-Chat_with_TinyAgent-blue?style=flat-square)](https://askdev.ai/github/askbudi/tinyagent)
222
+
223
+ ---
224
+
209
225
  ## Contributing Hooks
210
226
 
211
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 = ["tinyagent"]
6
+ where = ["."]
7
+ include = ["tinyagent*"]
7
8
  exclude = ["public", "public.*"]
8
9
 
9
10
  [project]
10
11
  name = "tinyagent-py"
11
- version = "0.0.4"
12
+ version = "0.0.6"
12
13
  description = "Tiny Agent with MCP Client"
13
14
  readme = "README.md"
14
15
  authors = [
@@ -0,0 +1,4 @@
1
+ from .tiny_agent import TinyAgent,tool
2
+ from .mcp_client import MCPClient
3
+
4
+ __all__ = ["TinyAgent", "MCPClient","tool"]
@@ -0,0 +1,162 @@
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.exit_stack:
110
+ try:
111
+ await self.exit_stack.aclose()
112
+ except (RuntimeError, asyncio.CancelledError) as e:
113
+ # Log the error but don't re-raise it
114
+ self.logger.error(f"Error during client cleanup: {e}")
115
+ finally:
116
+ # Always reset these regardless of success or failure
117
+ self.session = None
118
+ self.exit_stack = AsyncExitStack()
119
+
120
+ async def run_example():
121
+ """Example usage of MCPClient with proper logging."""
122
+ import sys
123
+ from tinyagent.hooks.logging_manager import LoggingManager
124
+
125
+ # Create and configure logging manager
126
+ log_manager = LoggingManager(default_level=logging.INFO)
127
+ log_manager.set_levels({
128
+ 'tinyagent.mcp_client': logging.DEBUG, # Debug for this module
129
+ 'tinyagent.tiny_agent': logging.INFO,
130
+ })
131
+
132
+ # Configure a console handler
133
+ console_handler = logging.StreamHandler(sys.stdout)
134
+ log_manager.configure_handler(
135
+ console_handler,
136
+ format_string='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
137
+ level=logging.DEBUG
138
+ )
139
+
140
+ # Get module-specific logger
141
+ mcp_logger = log_manager.get_logger('tinyagent.mcp_client')
142
+
143
+ mcp_logger.debug("Starting MCPClient example")
144
+
145
+ # Create client with our logger
146
+ client = MCPClient(logger=mcp_logger)
147
+
148
+ try:
149
+ # Connect to a simple echo server
150
+ await client.connect("python", ["-m", "mcp.examples.echo_server"])
151
+
152
+ # List available tools
153
+ await client.list_tools()
154
+
155
+ # Call the echo tool
156
+ result = await client.call_tool("echo", {"message": "Hello, MCP!"})
157
+ mcp_logger.info(f"Echo result: {result}")
158
+
159
+ finally:
160
+ # Clean up
161
+ await client.close()
162
+ mcp_logger.debug("Example completed")