mbxai 0.5.19__tar.gz → 0.5.20__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 (25) hide show
  1. {mbxai-0.5.19 → mbxai-0.5.20}/PKG-INFO +1 -1
  2. {mbxai-0.5.19 → mbxai-0.5.20}/pyproject.toml +1 -1
  3. {mbxai-0.5.19 → mbxai-0.5.20}/setup.py +1 -1
  4. {mbxai-0.5.19 → mbxai-0.5.20}/src/mbxai/__init__.py +1 -1
  5. {mbxai-0.5.19 → mbxai-0.5.20}/src/mbxai/mcp/server.py +1 -1
  6. {mbxai-0.5.19 → mbxai-0.5.20}/src/mbxai/tools/client.py +61 -38
  7. {mbxai-0.5.19 → mbxai-0.5.20}/uv.lock +7 -7
  8. {mbxai-0.5.19 → mbxai-0.5.20}/.vscode/PythonImportHelper-v2-Completion.json +0 -0
  9. {mbxai-0.5.19 → mbxai-0.5.20}/LICENSE +0 -0
  10. {mbxai-0.5.19 → mbxai-0.5.20}/README.md +0 -0
  11. {mbxai-0.5.19 → mbxai-0.5.20}/src/mbxai/core.py +0 -0
  12. {mbxai-0.5.19 → mbxai-0.5.20}/src/mbxai/mcp/__init__.py +0 -0
  13. {mbxai-0.5.19 → mbxai-0.5.20}/src/mbxai/mcp/client.py +0 -0
  14. {mbxai-0.5.19 → mbxai-0.5.20}/src/mbxai/mcp/example.py +0 -0
  15. {mbxai-0.5.19 → mbxai-0.5.20}/src/mbxai/openrouter/__init__.py +0 -0
  16. {mbxai-0.5.19 → mbxai-0.5.20}/src/mbxai/openrouter/client.py +0 -0
  17. {mbxai-0.5.19 → mbxai-0.5.20}/src/mbxai/openrouter/config.py +0 -0
  18. {mbxai-0.5.19 → mbxai-0.5.20}/src/mbxai/openrouter/models.py +0 -0
  19. {mbxai-0.5.19 → mbxai-0.5.20}/src/mbxai/tools/__init__.py +0 -0
  20. {mbxai-0.5.19 → mbxai-0.5.20}/src/mbxai/tools/example.py +0 -0
  21. {mbxai-0.5.19 → mbxai-0.5.20}/src/mbxai/tools/types.py +0 -0
  22. {mbxai-0.5.19 → mbxai-0.5.20}/tests/test_core.py +0 -0
  23. {mbxai-0.5.19 → mbxai-0.5.20}/tests/test_mcp.py +0 -0
  24. {mbxai-0.5.19 → mbxai-0.5.20}/tests/test_openrouter.py +0 -0
  25. {mbxai-0.5.19 → mbxai-0.5.20}/tests/test_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mbxai
3
- Version: 0.5.19
3
+ Version: 0.5.20
4
4
  Summary: MBX AI SDK
5
5
  Project-URL: Homepage, https://www.mibexx.de
6
6
  Project-URL: Documentation, https://www.mibexx.de
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "mbxai"
7
- version = "0.5.19"
7
+ version = "0.5.20"
8
8
  authors = [
9
9
  { name = "MBX AI" }
10
10
  ]
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="mbxai",
5
- version="0.5.19",
5
+ version="0.5.20",
6
6
  author="MBX AI",
7
7
  description="MBX AI SDK",
8
8
  long_description=open("README.md").read(),
@@ -2,4 +2,4 @@
2
2
  MBX AI package.
3
3
  """
4
4
 
5
- __version__ = "0.5.19"
5
+ __version__ = "0.5.20"
@@ -31,7 +31,7 @@ class MCPServer:
31
31
  self.app = FastAPI(
32
32
  title=self.name,
33
33
  description=self.description,
34
- version="0.5.19",
34
+ version="0.5.20",
35
35
  )
36
36
 
37
37
  # Initialize MCP server
@@ -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 first
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
- # Get a new response from the model with all tool results
242
- response = self._client.chat_completion(
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,
@@ -292,11 +292,11 @@ wheels = [
292
292
 
293
293
  [[package]]
294
294
  name = "httpx-sse"
295
- version = "0.5.19"
295
+ version = "0.5.20"
296
296
  source = { registry = "https://pypi.org/simple" }
297
- sdist = { url = "https://files.pythonhosted.org/packages/4c/60/8f4281fa9bbf3c8034fd54c0e7412e66edbab6bc74c4996bd616f8d0406e/httpx-sse-0.5.19.tar.gz", hash = "sha256:1e81a3a3070ce322add1d3529ed42eb5f70817f45ed6ec915ab753f961139721", size = 12624 }
297
+ sdist = { url = "https://files.pythonhosted.org/packages/4c/60/8f4281fa9bbf3c8034fd54c0e7412e66edbab6bc74c4996bd616f8d0406e/httpx-sse-0.5.20.tar.gz", hash = "sha256:1e81a3a3070ce322add1d3529ed42eb5f70817f45ed6ec915ab753f961139721", size = 12624 }
298
298
  wheels = [
299
- { url = "https://files.pythonhosted.org/packages/e1/9b/a181f281f65d776426002f330c31849b86b31fc9d848db62e16f03ff739f/httpx_sse-0.5.19-py3-none-any.whl", hash = "sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f", size = 7819 },
299
+ { url = "https://files.pythonhosted.org/packages/e1/9b/a181f281f65d776426002f330c31849b86b31fc9d848db62e16f03ff739f/httpx_sse-0.5.20-py3-none-any.whl", hash = "sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f", size = 7819 },
300
300
  ]
301
301
 
302
302
  [[package]]
@@ -446,7 +446,7 @@ wheels = [
446
446
 
447
447
  [[package]]
448
448
  name = "mbxai"
449
- version = "0.5.19"
449
+ version = "0.5.20"
450
450
  source = { editable = "." }
451
451
  dependencies = [
452
452
  { name = "fastapi" },
@@ -980,14 +980,14 @@ wheels = [
980
980
 
981
981
  [[package]]
982
982
  name = "typing-inspection"
983
- version = "0.5.19"
983
+ version = "0.5.20"
984
984
  source = { registry = "https://pypi.org/simple" }
985
985
  dependencies = [
986
986
  { name = "typing-extensions" },
987
987
  ]
988
- sdist = { url = "https://files.pythonhosted.org/packages/82/5c/e6082df02e215b846b4b8c0b887a64d7d08ffaba30605502639d44c06b82/typing_inspection-0.5.19.tar.gz", hash = "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122", size = 76222 }
988
+ sdist = { url = "https://files.pythonhosted.org/packages/82/5c/e6082df02e215b846b4b8c0b887a64d7d08ffaba30605502639d44c06b82/typing_inspection-0.5.20.tar.gz", hash = "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122", size = 76222 }
989
989
  wheels = [
990
- { url = "https://files.pythonhosted.org/packages/31/08/aa4fdfb71f7de5176385bd9e90852eaf6b5d622735020ad600f2bab54385/typing_inspection-0.5.19-py3-none-any.whl", hash = "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f", size = 14125 },
990
+ { url = "https://files.pythonhosted.org/packages/31/08/aa4fdfb71f7de5176385bd9e90852eaf6b5d622735020ad600f2bab54385/typing_inspection-0.5.20-py3-none-any.whl", hash = "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f", size = 14125 },
991
991
  ]
992
992
 
993
993
  [[package]]
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