mbxai 0.5.4__py3-none-any.whl → 0.5.6__py3-none-any.whl
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.
- mbxai/__init__.py +1 -1
- mbxai/mcp/client.py +6 -4
- mbxai/mcp/server.py +1 -1
- mbxai/tools/client.py +58 -12
- mbxai/tools/types.py +8 -11
- {mbxai-0.5.4.dist-info → mbxai-0.5.6.dist-info}/METADATA +1 -1
- {mbxai-0.5.4.dist-info → mbxai-0.5.6.dist-info}/RECORD +9 -9
- {mbxai-0.5.4.dist-info → mbxai-0.5.6.dist-info}/WHEEL +0 -0
- {mbxai-0.5.4.dist-info → mbxai-0.5.6.dist-info}/licenses/LICENSE +0 -0
mbxai/__init__.py
CHANGED
mbxai/mcp/client.py
CHANGED
@@ -24,10 +24,12 @@ class MCPTool(Tool):
|
|
24
24
|
def to_openai_function(self) -> dict[str, Any]:
|
25
25
|
"""Convert the tool to an OpenAI function definition."""
|
26
26
|
return {
|
27
|
-
"
|
28
|
-
"
|
29
|
-
|
30
|
-
|
27
|
+
"type": "function",
|
28
|
+
"function": {
|
29
|
+
"name": self.name,
|
30
|
+
"description": self.description,
|
31
|
+
"parameters": self._convert_to_openai_schema(self.input_schema)
|
32
|
+
}
|
31
33
|
}
|
32
34
|
|
33
35
|
def _convert_to_openai_schema(self, mcp_schema: dict[str, Any]) -> dict[str, Any]:
|
mbxai/mcp/server.py
CHANGED
mbxai/tools/client.py
CHANGED
@@ -3,10 +3,13 @@ ToolClient implementation for MBX AI.
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
from typing import Any, Callable, TypeVar, cast
|
6
|
+
import logging
|
6
7
|
from pydantic import BaseModel
|
7
8
|
from ..openrouter import OpenRouterClient
|
8
9
|
from .types import Tool, ToolCall
|
9
10
|
|
11
|
+
logger = logging.getLogger(__name__)
|
12
|
+
|
10
13
|
T = TypeVar("T", bound=BaseModel)
|
11
14
|
|
12
15
|
class ToolClient:
|
@@ -43,6 +46,7 @@ class ToolClient:
|
|
43
46
|
schema=schema,
|
44
47
|
)
|
45
48
|
self._tools[name] = tool
|
49
|
+
logger.debug(f"Registered tool: {name}")
|
46
50
|
|
47
51
|
def chat(
|
48
52
|
self,
|
@@ -65,12 +69,12 @@ class ToolClient:
|
|
65
69
|
"""
|
66
70
|
tools = [tool.to_openai_function() for tool in self._tools.values()]
|
67
71
|
|
72
|
+
if tools:
|
73
|
+
logger.debug(f"Using tools: {tools}")
|
74
|
+
kwargs["tools"] = tools
|
75
|
+
kwargs["tool_choice"] = "auto"
|
76
|
+
|
68
77
|
while True:
|
69
|
-
# Add tools to the request if we have any
|
70
|
-
if tools:
|
71
|
-
kwargs["tools"] = tools
|
72
|
-
kwargs["tool_choice"] = "auto"
|
73
|
-
|
74
78
|
# Get the model's response
|
75
79
|
response = self._client.chat_completion(
|
76
80
|
messages=messages,
|
@@ -91,12 +95,33 @@ class ToolClient:
|
|
91
95
|
|
92
96
|
# Handle each tool call
|
93
97
|
for tool_call in message.tool_calls:
|
98
|
+
logger.debug(f"Processing tool call: {tool_call}")
|
99
|
+
logger.debug(f"Tool call ID: {tool_call.id}")
|
100
|
+
logger.debug(f"Tool call function: {tool_call.function}")
|
101
|
+
logger.debug(f"Tool call arguments: {tool_call.function.arguments}")
|
102
|
+
|
94
103
|
tool = self._tools.get(tool_call.function.name)
|
95
104
|
if not tool:
|
96
105
|
raise ValueError(f"Unknown tool: {tool_call.function.name}")
|
97
106
|
|
107
|
+
# Parse arguments if they're a string
|
108
|
+
arguments = tool_call.function.arguments
|
109
|
+
logger.debug(f"Raw arguments type: {type(arguments)}")
|
110
|
+
logger.debug(f"Raw arguments: {arguments}")
|
111
|
+
|
112
|
+
if isinstance(arguments, str):
|
113
|
+
import json
|
114
|
+
try:
|
115
|
+
arguments = json.loads(arguments)
|
116
|
+
logger.debug(f"Parsed arguments: {arguments}")
|
117
|
+
except json.JSONDecodeError as e:
|
118
|
+
logger.error(f"Failed to parse tool arguments: {e}")
|
119
|
+
raise ValueError(f"Invalid tool arguments format: {arguments}")
|
120
|
+
|
98
121
|
# Call the tool
|
99
|
-
|
122
|
+
logger.debug(f"Calling tool {tool.name} with arguments: {arguments}")
|
123
|
+
result = tool.function(**arguments)
|
124
|
+
logger.debug(f"Tool result: {result}")
|
100
125
|
|
101
126
|
# Add the tool response to the messages
|
102
127
|
messages.append({
|
@@ -129,12 +154,12 @@ class ToolClient:
|
|
129
154
|
"""
|
130
155
|
tools = [tool.to_openai_function() for tool in self._tools.values()]
|
131
156
|
|
157
|
+
if tools:
|
158
|
+
logger.debug(f"Using tools: {tools}")
|
159
|
+
kwargs["tools"] = tools
|
160
|
+
kwargs["tool_choice"] = "auto"
|
161
|
+
|
132
162
|
while True:
|
133
|
-
# Add tools to the request if we have any
|
134
|
-
if tools:
|
135
|
-
kwargs["tools"] = tools
|
136
|
-
kwargs["tool_choice"] = "auto"
|
137
|
-
|
138
163
|
# Get the model's response
|
139
164
|
response = self._client.chat_completion_parse(
|
140
165
|
messages=messages,
|
@@ -156,12 +181,33 @@ class ToolClient:
|
|
156
181
|
|
157
182
|
# Handle each tool call
|
158
183
|
for tool_call in message.tool_calls:
|
184
|
+
logger.debug(f"Processing tool call: {tool_call}")
|
185
|
+
logger.debug(f"Tool call ID: {tool_call.id}")
|
186
|
+
logger.debug(f"Tool call function: {tool_call.function}")
|
187
|
+
logger.debug(f"Tool call arguments: {tool_call.function.arguments}")
|
188
|
+
|
159
189
|
tool = self._tools.get(tool_call.function.name)
|
160
190
|
if not tool:
|
161
191
|
raise ValueError(f"Unknown tool: {tool_call.function.name}")
|
162
192
|
|
193
|
+
# Parse arguments if they're a string
|
194
|
+
arguments = tool_call.function.arguments
|
195
|
+
logger.debug(f"Raw arguments type: {type(arguments)}")
|
196
|
+
logger.debug(f"Raw arguments: {arguments}")
|
197
|
+
|
198
|
+
if isinstance(arguments, str):
|
199
|
+
import json
|
200
|
+
try:
|
201
|
+
arguments = json.loads(arguments)
|
202
|
+
logger.debug(f"Parsed arguments: {arguments}")
|
203
|
+
except json.JSONDecodeError as e:
|
204
|
+
logger.error(f"Failed to parse tool arguments: {e}")
|
205
|
+
raise ValueError(f"Invalid tool arguments format: {arguments}")
|
206
|
+
|
163
207
|
# Call the tool
|
164
|
-
|
208
|
+
logger.debug(f"Calling tool {tool.name} with arguments: {arguments}")
|
209
|
+
result = tool.function(**arguments)
|
210
|
+
logger.debug(f"Tool result: {result}")
|
165
211
|
|
166
212
|
# Add the tool response to the messages
|
167
213
|
messages.append({
|
mbxai/tools/types.py
CHANGED
@@ -2,15 +2,9 @@
|
|
2
2
|
Type definitions for the tools package.
|
3
3
|
"""
|
4
4
|
|
5
|
-
from typing import Any, Callable
|
5
|
+
from typing import Any, Callable
|
6
6
|
from pydantic import BaseModel
|
7
7
|
|
8
|
-
class ToolFunction(TypedDict):
|
9
|
-
"""OpenAI function definition for a tool."""
|
10
|
-
name: str
|
11
|
-
description: str
|
12
|
-
parameters: dict[str, Any]
|
13
|
-
|
14
8
|
class ToolCall(BaseModel):
|
15
9
|
"""A tool call from the model."""
|
16
10
|
id: str
|
@@ -24,10 +18,13 @@ class Tool(BaseModel):
|
|
24
18
|
function: Callable[..., Any]
|
25
19
|
schema: dict[str, Any]
|
26
20
|
|
27
|
-
def to_openai_function(self) ->
|
21
|
+
def to_openai_function(self) -> dict[str, Any]:
|
28
22
|
"""Convert the tool to an OpenAI function definition."""
|
29
23
|
return {
|
30
|
-
"
|
31
|
-
"
|
32
|
-
|
24
|
+
"type": "function",
|
25
|
+
"function": {
|
26
|
+
"name": self.name,
|
27
|
+
"description": self.description,
|
28
|
+
"parameters": self.schema
|
29
|
+
}
|
33
30
|
}
|
@@ -1,18 +1,18 @@
|
|
1
|
-
mbxai/__init__.py,sha256=
|
1
|
+
mbxai/__init__.py,sha256=3cCdE3UF7hWaEKRs2Ftl0x1qU4zqaFY1bNSZR5-JcZ0,47
|
2
2
|
mbxai/core.py,sha256=WMvmU9TTa7M_m-qWsUew4xH8Ul6xseCZ2iBCXJTW-Bs,196
|
3
3
|
mbxai/mcp/__init__.py,sha256=_ek9iYdYqW5saKetj4qDci11jxesQDiHPJRpHMKkxgU,175
|
4
|
-
mbxai/mcp/client.py,sha256=
|
4
|
+
mbxai/mcp/client.py,sha256=QxVeQRBQryeEGXDU8X_9qQBfT-ubDd9L9KSc5-P354U,5590
|
5
5
|
mbxai/mcp/example.py,sha256=oaol7AvvZnX86JWNz64KvPjab5gg1VjVN3G8eFSzuaE,2350
|
6
|
-
mbxai/mcp/server.py,sha256=
|
6
|
+
mbxai/mcp/server.py,sha256=LGhjJvUg2CiQ5i0C0aAqeXRghboz5sn7YBOEIaoSPXc,3462
|
7
7
|
mbxai/openrouter/__init__.py,sha256=Ito9Qp_B6q-RLGAQcYyTJVWwR2YAZvNqE-HIYXxhtD8,298
|
8
8
|
mbxai/openrouter/client.py,sha256=XLRMRNRJH96Jl6_af0KkzRDdLJnixh8I3RvEEcFuXyg,10840
|
9
9
|
mbxai/openrouter/config.py,sha256=MTX_YHsFrM7JYqovJSkEF6JzVyIdajeI5Dja2CALH58,2874
|
10
10
|
mbxai/openrouter/models.py,sha256=b3IjjtZAjeGOf2rLsdnCD1HacjTnS8jmv_ZXorc-KJQ,2604
|
11
11
|
mbxai/tools/__init__.py,sha256=QUFaXhDm-UKcuAtT1rbKzhBkvyRBVokcQIOf9cxIuwc,160
|
12
|
-
mbxai/tools/client.py,sha256=
|
12
|
+
mbxai/tools/client.py,sha256=f4i4lyLWeI81NPwnV8Rz1cO5bGh6kLHcxahNijUrTxw,7718
|
13
13
|
mbxai/tools/example.py,sha256=1HgKK39zzUuwFbnp3f0ThyWVfA_8P28PZcTwaUw5K78,2232
|
14
|
-
mbxai/tools/types.py,sha256=
|
15
|
-
mbxai-0.5.
|
16
|
-
mbxai-0.5.
|
17
|
-
mbxai-0.5.
|
18
|
-
mbxai-0.5.
|
14
|
+
mbxai/tools/types.py,sha256=fo5t9UbsHGynhA88vD_ecgDqL8iLvt2E1h1ym43Rrgk,745
|
15
|
+
mbxai-0.5.6.dist-info/METADATA,sha256=Y4o8ab_4BJvwsAvlrWD72eLkyg8S5v4LfWmeH6hsGBo,4107
|
16
|
+
mbxai-0.5.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
17
|
+
mbxai-0.5.6.dist-info/licenses/LICENSE,sha256=hEyhc4FxwYo3NQ40yNgZ7STqwVk-1_XcTXOnAPbGJAw,1069
|
18
|
+
mbxai-0.5.6.dist-info/RECORD,,
|
File without changes
|
File without changes
|