ai-microcore 4.0.0.dev19__tar.gz → 4.0.0.dev21__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.
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/PKG-INFO +7 -5
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/README.md +3 -2
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/__init__.py +1 -1
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/mcp.py +38 -99
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/pyproject.toml +3 -2
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/LICENSE +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/_env.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/_llm_functions.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/_prepare_llm_args.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/ai_func/__init__.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/ai_func/ai-func.json.j2 +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/ai_func/ai-func.pythonic.j2 +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/ai_modules.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/configuration.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/embedding_db/__init__.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/embedding_db/chromadb.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/file_storage.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/interactive_setup.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/json_parsing.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/llm/__init__.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/llm/_openai_llm_v0.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/llm/_openai_llm_v1.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/llm/anthropic.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/llm/google_genai.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/llm/google_vertex_ai.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/llm/local_llm.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/llm/local_transformers.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/llm/openai_llm.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/llm/shared.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/logging.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/message_types.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/metrics.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/python.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/templating/__init__.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/templating/jinja2.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/text2speech/elevenlabs.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/tokenizing.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/types.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/ui.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/utils.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/wrappers/__init__.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/wrappers/llm_response_wrapper.py +0 -0
- {ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/wrappers/prompt_wrapper.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ai-microcore
|
|
3
|
-
Version: 4.0.0.
|
|
3
|
+
Version: 4.0.0.dev21
|
|
4
4
|
Summary: # Minimalistic Foundation for AI Applications
|
|
5
5
|
Keywords: llm,large language models,ai,similarity search,ai search,gpt,openai,framework,adapter
|
|
6
6
|
Author-email: Vitalii Stepanenko <mail@vitalii.in>
|
|
@@ -17,20 +17,22 @@ Classifier: Intended Audience :: Developers
|
|
|
17
17
|
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
18
18
|
License-File: LICENSE
|
|
19
19
|
Requires-Dist: openai>=0.28.1,<2
|
|
20
|
-
Requires-Dist: python-dotenv~=1.
|
|
20
|
+
Requires-Dist: python-dotenv~=1.1.0
|
|
21
21
|
Requires-Dist: Jinja2~=3.1.2
|
|
22
22
|
Requires-Dist: colorama~=0.4.6
|
|
23
23
|
Requires-Dist: PyYAML~=6.0
|
|
24
24
|
Requires-Dist: chardet~=5.2.0
|
|
25
25
|
Requires-Dist: tiktoken>=0.7.0,<1.0
|
|
26
|
-
Requires-Dist: mcp~=1.9.
|
|
26
|
+
Requires-Dist: mcp~=1.9.2
|
|
27
|
+
Requires-Dist: fastmcp~=2.8.0
|
|
27
28
|
Requires-Dist: docstring_parser~=0.16.0
|
|
28
29
|
Project-URL: Source Code, https://github.com/Nayjest/ai-microcore
|
|
29
30
|
|
|
30
|
-
<p align="right">
|
|
31
|
-
<a href="https://github.com/Nayjest/ai-microcore/releases" target="_blank"><img src="https://img.shields.io/github/release/ai-microcore
|
|
31
|
+
<p align="right">
|
|
32
|
+
<a href="https://github.com/Nayjest/ai-microcore/releases" target="_blank"><img src="https://img.shields.io/github/v/release/Nayjest/ai-microcore.svg" alt="Release Notes"></a>
|
|
32
33
|
<a href="https://app.codacy.com/gh/Nayjest/ai-microcore/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade" target="_blank"><img src="https://app.codacy.com/project/badge/Grade/441d03416bc048828c649129530dcbc3" alt="Code Quality"></a>
|
|
33
34
|
<a href="https://github.com/Nayjest/ai-microcore/actions/workflows/pylint.yml" target="_blank"><img src="https://github.com/Nayjest/ai-microcore/actions/workflows/pylint.yml/badge.svg" alt="Pylint"></a>
|
|
35
|
+
<img src="coverage.svg" alt="Code Coverage">
|
|
34
36
|
<a href="https://github.com/Nayjest/ai-microcore/actions/workflows/tests.yml" target="_blank"><img src="https://github.com/Nayjest/ai-microcore/actions/workflows/tests.yml/badge.svg" alt="Tests"></a>
|
|
35
37
|
<a href="https://github.com/Nayjest/ai-microcore/blob/main/LICENSE" target="_blank"><img src="https://img.shields.io/static/v1?label=license&message=MIT&color=d08aff" alt="License"></a>
|
|
36
38
|
</p>
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
<p align="right">
|
|
2
|
-
<a href="https://github.com/Nayjest/ai-microcore/releases" target="_blank"><img src="https://img.shields.io/github/release/ai-microcore
|
|
1
|
+
<p align="right">
|
|
2
|
+
<a href="https://github.com/Nayjest/ai-microcore/releases" target="_blank"><img src="https://img.shields.io/github/v/release/Nayjest/ai-microcore.svg" alt="Release Notes"></a>
|
|
3
3
|
<a href="https://app.codacy.com/gh/Nayjest/ai-microcore/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade" target="_blank"><img src="https://app.codacy.com/project/badge/Grade/441d03416bc048828c649129530dcbc3" alt="Code Quality"></a>
|
|
4
4
|
<a href="https://github.com/Nayjest/ai-microcore/actions/workflows/pylint.yml" target="_blank"><img src="https://github.com/Nayjest/ai-microcore/actions/workflows/pylint.yml/badge.svg" alt="Pylint"></a>
|
|
5
|
+
<img src="coverage.svg" alt="Code Coverage">
|
|
5
6
|
<a href="https://github.com/Nayjest/ai-microcore/actions/workflows/tests.yml" target="_blank"><img src="https://github.com/Nayjest/ai-microcore/actions/workflows/tests.yml/badge.svg" alt="Tests"></a>
|
|
6
7
|
<a href="https://github.com/Nayjest/ai-microcore/blob/main/LICENSE" target="_blank"><img src="https://img.shields.io/static/v1?label=license&message=MIT&color=d08aff" alt="License"></a>
|
|
7
8
|
</p>
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import logging
|
|
3
|
+
import datetime
|
|
3
4
|
from typing import Optional
|
|
4
5
|
from dataclasses import dataclass, field
|
|
5
6
|
from enum import Enum
|
|
6
7
|
|
|
7
8
|
import requests
|
|
8
|
-
from
|
|
9
|
-
from
|
|
10
|
-
|
|
9
|
+
from fastmcp import Client
|
|
10
|
+
from fastmcp.client.progress import ProgressHandler
|
|
11
|
+
import mcp.types
|
|
11
12
|
|
|
12
13
|
from .utils import ExtendedString, ConvertableToMessage
|
|
13
14
|
from .ai_func import AiFuncSyntax
|
|
@@ -64,13 +65,8 @@ class McpTransport(str, Enum):
|
|
|
64
65
|
class MCPConnection:
|
|
65
66
|
url: str = None
|
|
66
67
|
transport: McpTransport = field(default=McpTransport.STREAMABLE_HTTP)
|
|
67
|
-
read_stream: any = None
|
|
68
|
-
write_stream: any = None
|
|
69
|
-
context_manager: any = None
|
|
70
|
-
session: ClientSession = field(default=None, init=False)
|
|
71
68
|
tools: Optional["Tools"] = field(default=None, init=False)
|
|
72
|
-
|
|
73
|
-
_del_event: asyncio.Event = field(default=None, init=False)
|
|
69
|
+
_client: Client | None = field(default=None, init=False)
|
|
74
70
|
|
|
75
71
|
@staticmethod
|
|
76
72
|
async def init(
|
|
@@ -80,88 +76,20 @@ class MCPConnection:
|
|
|
80
76
|
use_cache: bool = True,
|
|
81
77
|
connect_timeout: float = 10,
|
|
82
78
|
) -> "MCPConnection":
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
# That's a bit of a hack for closing the async context managers
|
|
90
|
-
async def lifecycle():
|
|
91
|
-
try:
|
|
92
|
-
logging.info(f"Connecting to {transport} MCP {url}...")
|
|
93
|
-
if transport == McpTransport.STREAMABLE_HTTP:
|
|
94
|
-
context_manager = streamablehttp_client(url)
|
|
95
|
-
(
|
|
96
|
-
read_stream,
|
|
97
|
-
write_stream,
|
|
98
|
-
_
|
|
99
|
-
) = await context_manager.__aenter__() # pylint: disable=E1101
|
|
100
|
-
elif transport == McpTransport.SSE:
|
|
101
|
-
context_manager = sse_client(url)
|
|
102
|
-
(
|
|
103
|
-
read_stream,
|
|
104
|
-
write_stream
|
|
105
|
-
) = await context_manager.__aenter__() # pylint: disable=E1101
|
|
106
|
-
else:
|
|
107
|
-
raise ValueError(f"Unsupported transport type: {transport}")
|
|
108
|
-
con.url = url
|
|
109
|
-
con.transport = transport
|
|
110
|
-
con.read_stream = read_stream
|
|
111
|
-
con.write_stream = write_stream
|
|
112
|
-
con.context_manager = context_manager
|
|
113
|
-
await con.init_session()
|
|
114
|
-
if fetch_tools:
|
|
115
|
-
await con.fetch_tools(use_cache=use_cache)
|
|
116
|
-
opened_event.set()
|
|
117
|
-
|
|
118
|
-
finally:
|
|
119
|
-
await del_event.wait()
|
|
120
|
-
await con._close() # pylint: disable=W0212
|
|
121
|
-
|
|
122
|
-
con._lifecycle_task = asyncio.create_task(lifecycle()) # pylint: disable=W0212
|
|
123
|
-
try:
|
|
124
|
-
await asyncio.wait_for(opened_event.wait(), timeout=connect_timeout)
|
|
125
|
-
except Exception as e:
|
|
126
|
-
logging.warning(f"Failed to connect to MCP {url}: {e}")
|
|
127
|
-
try:
|
|
128
|
-
await con._close() # pylint: disable=W0212
|
|
129
|
-
except: # noqa: E722 # pylint: disable=W0702
|
|
130
|
-
pass
|
|
131
|
-
raise
|
|
79
|
+
con: MCPConnection = MCPConnection(url=url, transport=transport)
|
|
80
|
+
con._client = Client(url, timeout=connect_timeout) # pylint: disable=W0212
|
|
81
|
+
await con._client.__aenter__() # pylint: disable=E1101,W0212,C2801
|
|
82
|
+
if fetch_tools:
|
|
83
|
+
await con.fetch_tools(use_cache=use_cache)
|
|
132
84
|
return con
|
|
133
85
|
|
|
134
86
|
async def close(self):
|
|
135
|
-
self.
|
|
136
|
-
|
|
137
|
-
|
|
87
|
+
if self._client:
|
|
88
|
+
await self._client.__aexit__(None, None, None)
|
|
89
|
+
self._client = None
|
|
138
90
|
else:
|
|
139
91
|
logging.error(f"Trying to close MCP connection that is not opened ({self.url})")
|
|
140
92
|
|
|
141
|
-
async def _close(self):
|
|
142
|
-
logging.info(f"Closing MCP session ({self.url})...")
|
|
143
|
-
try:
|
|
144
|
-
if self.session:
|
|
145
|
-
await self.session.__aexit__(None, None, None)
|
|
146
|
-
del self.session
|
|
147
|
-
self.session = None
|
|
148
|
-
finally:
|
|
149
|
-
logging.info(f"Closing MCP connection ({self.url})...")
|
|
150
|
-
try:
|
|
151
|
-
if self.context_manager:
|
|
152
|
-
await self.context_manager.__aexit__(None, None, None)
|
|
153
|
-
del self.context_manager
|
|
154
|
-
self.context_manager = None
|
|
155
|
-
finally:
|
|
156
|
-
logging.info(f"Closed CTX ({self.url})")
|
|
157
|
-
|
|
158
|
-
async def init_session(self):
|
|
159
|
-
logging.info(f"Initializing MCP session ({self.url})")
|
|
160
|
-
self.session = ClientSession(self.read_stream, self.write_stream)
|
|
161
|
-
await self.session.__aenter__() # pylint: disable=unnecessary-dunder-call
|
|
162
|
-
await self.session.initialize()
|
|
163
|
-
return self.session
|
|
164
|
-
|
|
165
93
|
async def fetch_tools(self, use_cache: bool = True) -> "Tools":
|
|
166
94
|
if self.tools is not None:
|
|
167
95
|
return self.tools
|
|
@@ -172,8 +100,8 @@ class MCPConnection:
|
|
|
172
100
|
return self.tools
|
|
173
101
|
|
|
174
102
|
logging.info("Fetching tools from MCP %s", ui.green(self.url))
|
|
175
|
-
mcp_tools = await self.
|
|
176
|
-
self.tools = Tools.from_list([Tool.from_mcp(tool) for tool in mcp_tools
|
|
103
|
+
mcp_tools = await self._client.list_tools()
|
|
104
|
+
self.tools = Tools.from_list([Tool.from_mcp(tool) for tool in mcp_tools])
|
|
177
105
|
if use_cache:
|
|
178
106
|
self.update_tools_cache()
|
|
179
107
|
return self.tools
|
|
@@ -183,17 +111,24 @@ class MCPConnection:
|
|
|
183
111
|
raise RuntimeError("Tools are not fetched yet. Call fetch_tools() first.")
|
|
184
112
|
ToolsCache.write(self.url, self.tools)
|
|
185
113
|
|
|
186
|
-
def
|
|
187
|
-
self
|
|
188
|
-
|
|
189
|
-
|
|
114
|
+
async def call(
|
|
115
|
+
self,
|
|
116
|
+
name: str,
|
|
117
|
+
timeout: datetime.timedelta | float | int | None = None,
|
|
118
|
+
progress_handler: ProgressHandler | None = None,
|
|
119
|
+
**kwargs
|
|
120
|
+
):
|
|
190
121
|
assert env().config.AI_SYNTAX_FUNCTION_NAME_FIELD not in kwargs
|
|
191
122
|
params = dict(kwargs)
|
|
192
123
|
params[env().config.AI_SYNTAX_FUNCTION_NAME_FIELD] = name
|
|
193
|
-
return await self.exec(params)
|
|
194
|
-
|
|
124
|
+
return await self.exec(params, timeout=timeout, progress_handler=progress_handler)
|
|
195
125
|
|
|
196
|
-
async def exec(
|
|
126
|
+
async def exec(
|
|
127
|
+
self,
|
|
128
|
+
params: dict | LLMResponse,
|
|
129
|
+
timeout: datetime.timedelta | float | int | None = None,
|
|
130
|
+
progress_handler: ProgressHandler | None = None,
|
|
131
|
+
):
|
|
197
132
|
if isinstance(params, LLMResponse):
|
|
198
133
|
try:
|
|
199
134
|
params = params.parse_json(
|
|
@@ -209,11 +144,15 @@ class MCPConnection:
|
|
|
209
144
|
f"Tool name should be passed in {env().config.AI_SYNTAX_FUNCTION_NAME_FIELD} field"
|
|
210
145
|
)
|
|
211
146
|
logging.info(f"Calling MCP tool {ui.green(name)} with {params}...")
|
|
212
|
-
|
|
213
|
-
|
|
147
|
+
content = await self._client.call_tool(
|
|
148
|
+
name=name,
|
|
149
|
+
arguments=params,
|
|
150
|
+
timeout=timeout,
|
|
151
|
+
progress_handler=progress_handler
|
|
152
|
+
)
|
|
214
153
|
if content and len(content) == 1 and content[0].type == "text":
|
|
215
|
-
return MCPAnswer(content[0].text,
|
|
216
|
-
return
|
|
154
|
+
return MCPAnswer(content[0].text, dict(response=content))
|
|
155
|
+
return content
|
|
217
156
|
|
|
218
157
|
|
|
219
158
|
@dataclass
|
|
@@ -242,7 +181,7 @@ class Tool:
|
|
|
242
181
|
self.args[key] = Tool.Arg(**self.args[key])
|
|
243
182
|
|
|
244
183
|
@staticmethod
|
|
245
|
-
def from_mcp(tool: types.Tool) -> "Tool":
|
|
184
|
+
def from_mcp(tool: mcp.types.Tool) -> "Tool":
|
|
246
185
|
t = Tool(
|
|
247
186
|
name=tool.name,
|
|
248
187
|
description=tool.description,
|
|
@@ -20,13 +20,14 @@ classifiers = [
|
|
|
20
20
|
|
|
21
21
|
dependencies = [
|
|
22
22
|
"openai>=0.28.1,<2",
|
|
23
|
-
"python-dotenv~=1.
|
|
23
|
+
"python-dotenv~=1.1.0",
|
|
24
24
|
"Jinja2~=3.1.2",
|
|
25
25
|
"colorama~=0.4.6",
|
|
26
26
|
"PyYAML~=6.0",
|
|
27
27
|
"chardet~=5.2.0",
|
|
28
28
|
"tiktoken>=0.7.0,<1.0",
|
|
29
|
-
"mcp~=1.9.
|
|
29
|
+
"mcp~=1.9.2",
|
|
30
|
+
"fastmcp~=2.8.0",
|
|
30
31
|
"docstring_parser~=0.16.0",
|
|
31
32
|
]
|
|
32
33
|
requires-python = ">=3.10"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ai_microcore-4.0.0.dev19 → ai_microcore-4.0.0.dev21}/microcore/wrappers/llm_response_wrapper.py
RENAMED
|
File without changes
|
|
File without changes
|