mbxai 0.5.19__py3-none-any.whl → 0.5.20__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/server.py +1 -1
- mbxai/tools/client.py +61 -38
- {mbxai-0.5.19.dist-info → mbxai-0.5.20.dist-info}/METADATA +1 -1
- {mbxai-0.5.19.dist-info → mbxai-0.5.20.dist-info}/RECORD +7 -7
- {mbxai-0.5.19.dist-info → mbxai-0.5.20.dist-info}/WHEEL +0 -0
- {mbxai-0.5.19.dist-info → mbxai-0.5.20.dist-info}/licenses/LICENSE +0 -0
mbxai/__init__.py
CHANGED
mbxai/mcp/server.py
CHANGED
mbxai/tools/client.py
CHANGED
@@ -139,6 +139,62 @@ class ToolClient:
|
|
139
139
|
# Validate message sequence
|
140
140
|
self._validate_message_sequence(messages, validate_responses)
|
141
141
|
|
142
|
+
async def _process_tool_calls(self, message: Any, messages: list[dict[str, Any]]) -> None:
|
143
|
+
"""Process all tool calls in a message.
|
144
|
+
|
145
|
+
Args:
|
146
|
+
message: The message containing tool calls
|
147
|
+
messages: The list of messages to add responses to
|
148
|
+
"""
|
149
|
+
if not message.tool_calls:
|
150
|
+
return
|
151
|
+
|
152
|
+
# Process all tool calls first
|
153
|
+
tool_responses = []
|
154
|
+
for tool_call in message.tool_calls:
|
155
|
+
tool = self._tools.get(tool_call.function.name)
|
156
|
+
if not tool:
|
157
|
+
raise ValueError(f"Unknown tool: {tool_call.function.name}")
|
158
|
+
|
159
|
+
# Parse arguments if they're a string
|
160
|
+
arguments = tool_call.function.arguments
|
161
|
+
if isinstance(arguments, str):
|
162
|
+
try:
|
163
|
+
arguments = json.loads(arguments)
|
164
|
+
except json.JSONDecodeError as e:
|
165
|
+
logger.error(f"Failed to parse tool arguments: {e}")
|
166
|
+
raise ValueError(f"Invalid tool arguments format: {arguments}")
|
167
|
+
|
168
|
+
# Call the tool
|
169
|
+
logger.info(f"Calling tool: {tool.name} with args: {self._truncate_dict(arguments)}")
|
170
|
+
if inspect.iscoroutinefunction(tool.function):
|
171
|
+
result = await tool.function(**arguments)
|
172
|
+
else:
|
173
|
+
result = tool.function(**arguments)
|
174
|
+
|
175
|
+
# Convert result to JSON string if it's not already
|
176
|
+
if not isinstance(result, str):
|
177
|
+
result = json.dumps(result)
|
178
|
+
|
179
|
+
# Create the tool response
|
180
|
+
tool_response = {
|
181
|
+
"role": "tool",
|
182
|
+
"tool_call_id": tool_call.id,
|
183
|
+
"content": result,
|
184
|
+
}
|
185
|
+
tool_responses.append(tool_response)
|
186
|
+
logger.info(f"Created tool response for call ID {tool_call.id}")
|
187
|
+
|
188
|
+
# Add all tool responses to the messages
|
189
|
+
messages.extend(tool_responses)
|
190
|
+
logger.info(f"Message count: {len(messages)}, Added {len(tool_responses)} tool responses to messages")
|
191
|
+
|
192
|
+
# Validate the message sequence
|
193
|
+
self._validate_message_sequence(messages, validate_responses=True)
|
194
|
+
|
195
|
+
# Log the messages we're about to send
|
196
|
+
self._log_messages(messages, validate_responses=False)
|
197
|
+
|
142
198
|
async def chat(
|
143
199
|
self,
|
144
200
|
messages: list[dict[str, Any]],
|
@@ -186,13 +242,13 @@ class ToolClient:
|
|
186
242
|
for tool_call in message.tool_calls
|
187
243
|
]
|
188
244
|
messages.append(assistant_message)
|
189
|
-
logger.info(f"Added assistant message with tool calls: {[tc.function.name for tc in message.tool_calls] if message.tool_calls else None}")
|
245
|
+
logger.info(f"Message count: {len(messages)}, Added assistant message with tool calls: {[tc.function.name for tc in message.tool_calls] if message.tool_calls else None}")
|
190
246
|
|
191
247
|
# If there are no tool calls, we're done
|
192
248
|
if not message.tool_calls:
|
193
249
|
return response
|
194
250
|
|
195
|
-
# Process all tool calls
|
251
|
+
# Process all tool calls
|
196
252
|
tool_responses = []
|
197
253
|
for tool_call in message.tool_calls:
|
198
254
|
tool = self._tools.get(tool_call.function.name)
|
@@ -230,7 +286,7 @@ class ToolClient:
|
|
230
286
|
|
231
287
|
# Add all tool responses to the messages
|
232
288
|
messages.extend(tool_responses)
|
233
|
-
logger.info(f"Added {len(tool_responses)} tool responses to messages")
|
289
|
+
logger.info(f"Message count: {len(messages)}, Added {len(tool_responses)} tool responses to messages")
|
234
290
|
|
235
291
|
# Validate the message sequence
|
236
292
|
self._validate_message_sequence(messages, validate_responses=True)
|
@@ -238,41 +294,8 @@ class ToolClient:
|
|
238
294
|
# Log the messages we're about to send
|
239
295
|
self._log_messages(messages, validate_responses=False)
|
240
296
|
|
241
|
-
#
|
242
|
-
|
243
|
-
messages=messages,
|
244
|
-
model=model,
|
245
|
-
stream=stream,
|
246
|
-
**kwargs,
|
247
|
-
)
|
248
|
-
|
249
|
-
if stream:
|
250
|
-
return response
|
251
|
-
|
252
|
-
message = response.choices[0].message
|
253
|
-
# Add the assistant's message with tool calls
|
254
|
-
assistant_message = {
|
255
|
-
"role": "assistant",
|
256
|
-
"content": message.content or None, # Ensure content is None if empty
|
257
|
-
}
|
258
|
-
if message.tool_calls:
|
259
|
-
assistant_message["tool_calls"] = [
|
260
|
-
{
|
261
|
-
"id": tool_call.id,
|
262
|
-
"type": "function",
|
263
|
-
"function": {
|
264
|
-
"name": tool_call.function.name,
|
265
|
-
"arguments": tool_call.function.arguments,
|
266
|
-
},
|
267
|
-
}
|
268
|
-
for tool_call in message.tool_calls
|
269
|
-
]
|
270
|
-
messages.append(assistant_message)
|
271
|
-
logger.info(f"Added assistant message with tool calls: {[tc.function.name for tc in message.tool_calls] if message.tool_calls else None}")
|
272
|
-
|
273
|
-
# If there are no more tool calls, we're done
|
274
|
-
if not message.tool_calls:
|
275
|
-
return response
|
297
|
+
# Continue the loop to get the next response
|
298
|
+
continue
|
276
299
|
|
277
300
|
async def parse(
|
278
301
|
self,
|
@@ -1,18 +1,18 @@
|
|
1
|
-
mbxai/__init__.py,sha256=
|
1
|
+
mbxai/__init__.py,sha256=PUJe90d--hNgAyBIE5Y18DZDiuCdN7znT-cSzdXGpWM,48
|
2
2
|
mbxai/core.py,sha256=WMvmU9TTa7M_m-qWsUew4xH8Ul6xseCZ2iBCXJTW-Bs,196
|
3
3
|
mbxai/mcp/__init__.py,sha256=_ek9iYdYqW5saKetj4qDci11jxesQDiHPJRpHMKkxgU,175
|
4
4
|
mbxai/mcp/client.py,sha256=hEAVWIrIq758C1zm9aWGf-FiITB3LxtuxZEZ0CcjJ4s,5343
|
5
5
|
mbxai/mcp/example.py,sha256=oaol7AvvZnX86JWNz64KvPjab5gg1VjVN3G8eFSzuaE,2350
|
6
|
-
mbxai/mcp/server.py,sha256=
|
6
|
+
mbxai/mcp/server.py,sha256=8dfQSFdA0LN0kwSws-9our6vqq5L0F6U-s3gkB9-zME,3463
|
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=chTzGN6Tyi8Z428e5sR3BklieH8vBSKlx95SZ56GKg8,17729
|
13
13
|
mbxai/tools/example.py,sha256=1HgKK39zzUuwFbnp3f0ThyWVfA_8P28PZcTwaUw5K78,2232
|
14
14
|
mbxai/tools/types.py,sha256=fo5t9UbsHGynhA88vD_ecgDqL8iLvt2E1h1ym43Rrgk,745
|
15
|
-
mbxai-0.5.
|
16
|
-
mbxai-0.5.
|
17
|
-
mbxai-0.5.
|
18
|
-
mbxai-0.5.
|
15
|
+
mbxai-0.5.20.dist-info/METADATA,sha256=cm360CdwmXEwZnwFNj8pS2ssbonWyl_zFCiKyCTMrrM,4108
|
16
|
+
mbxai-0.5.20.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
17
|
+
mbxai-0.5.20.dist-info/licenses/LICENSE,sha256=hEyhc4FxwYo3NQ40yNgZ7STqwVk-1_XcTXOnAPbGJAw,1069
|
18
|
+
mbxai-0.5.20.dist-info/RECORD,,
|
File without changes
|
File without changes
|