mbxai 0.6.22__tar.gz → 0.6.24__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. {mbxai-0.6.22 → mbxai-0.6.24}/PKG-INFO +1 -1
  2. {mbxai-0.6.22 → mbxai-0.6.24}/pyproject.toml +1 -1
  3. {mbxai-0.6.22 → mbxai-0.6.24}/setup.py +1 -1
  4. {mbxai-0.6.22 → mbxai-0.6.24}/src/mbxai/__init__.py +1 -1
  5. {mbxai-0.6.22 → mbxai-0.6.24}/src/mbxai/mcp/client.py +8 -2
  6. {mbxai-0.6.22 → mbxai-0.6.24}/src/mbxai/mcp/server.py +1 -1
  7. mbxai-0.6.24/src/mbxai/tools/types.py +151 -0
  8. {mbxai-0.6.22 → mbxai-0.6.24}/uv.lock +1 -1
  9. mbxai-0.6.22/src/mbxai/tools/types.py +0 -115
  10. {mbxai-0.6.22 → mbxai-0.6.24}/.gitignore +0 -0
  11. {mbxai-0.6.22 → mbxai-0.6.24}/LICENSE +0 -0
  12. {mbxai-0.6.22 → mbxai-0.6.24}/README.md +0 -0
  13. {mbxai-0.6.22 → mbxai-0.6.24}/src/mbxai/core.py +0 -0
  14. {mbxai-0.6.22 → mbxai-0.6.24}/src/mbxai/mcp/__init__.py +0 -0
  15. {mbxai-0.6.22 → mbxai-0.6.24}/src/mbxai/mcp/example.py +0 -0
  16. {mbxai-0.6.22 → mbxai-0.6.24}/src/mbxai/openrouter/__init__.py +0 -0
  17. {mbxai-0.6.22 → mbxai-0.6.24}/src/mbxai/openrouter/client.py +0 -0
  18. {mbxai-0.6.22 → mbxai-0.6.24}/src/mbxai/openrouter/config.py +0 -0
  19. {mbxai-0.6.22 → mbxai-0.6.24}/src/mbxai/openrouter/models.py +0 -0
  20. {mbxai-0.6.22 → mbxai-0.6.24}/src/mbxai/tools/__init__.py +0 -0
  21. {mbxai-0.6.22 → mbxai-0.6.24}/src/mbxai/tools/client.py +0 -0
  22. {mbxai-0.6.22 → mbxai-0.6.24}/src/mbxai/tools/example.py +0 -0
  23. {mbxai-0.6.22 → mbxai-0.6.24}/tests/test_core.py +0 -0
  24. {mbxai-0.6.22 → mbxai-0.6.24}/tests/test_mcp.py +0 -0
  25. {mbxai-0.6.22 → mbxai-0.6.24}/tests/test_openrouter.py +0 -0
  26. {mbxai-0.6.22 → mbxai-0.6.24}/tests/test_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mbxai
3
- Version: 0.6.22
3
+ Version: 0.6.24
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.6.22"
7
+ version = "0.6.24"
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.6.22",
5
+ version="0.6.24",
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.6.22"
5
+ __version__ = "0.6.24"
@@ -24,8 +24,8 @@ class MCPTool(Tool):
24
24
 
25
25
  def to_openai_function(self) -> dict[str, Any]:
26
26
  """Convert the tool to an OpenAI function definition."""
27
- # Use the base Tool's schema conversion
28
- strict_schema = convert_to_strict_schema(self.input_schema, strict=self.strict)
27
+ # Use the unified schema conversion with keep_input_wrapper=True for MCP tools
28
+ strict_schema = convert_to_strict_schema(self.input_schema, strict=self.strict, keep_input_wrapper=True)
29
29
  logger.info(f"Converted schema for {self.name}: {json.dumps(strict_schema, indent=2)}")
30
30
 
31
31
  return {
@@ -56,11 +56,13 @@ class MCPTool(Tool):
56
56
  # Handle input wrapper
57
57
  if "properties" in mcp_schema and "input" in mcp_schema["properties"]:
58
58
  input_schema = mcp_schema["properties"]["input"]
59
+ logger.info(f"Found input wrapper. Input schema: {json.dumps(input_schema, indent=2)}")
59
60
 
60
61
  # If input has a $ref, resolve it
61
62
  if "$ref" in input_schema:
62
63
  ref = input_schema["$ref"].split("/")[-1]
63
64
  input_schema = mcp_schema.get("$defs", {}).get(ref, {})
65
+ logger.info(f"Resolved $ref to: {json.dumps(input_schema, indent=2)}")
64
66
 
65
67
  # Create the input property schema
66
68
  input_prop_schema = {
@@ -88,10 +90,12 @@ class MCPTool(Tool):
88
90
  new_prop[key] = value
89
91
 
90
92
  input_prop_schema["properties"][prop_name] = new_prop
93
+ logger.info(f"Added property {prop_name}: {json.dumps(new_prop, indent=2)}")
91
94
 
92
95
  # Copy over required fields for input schema
93
96
  if "required" in input_schema:
94
97
  input_prop_schema["required"] = input_schema["required"]
98
+ logger.info(f"Added required fields for input schema: {input_prop_schema['required']}")
95
99
 
96
100
  # Add the input property to the main schema
97
101
  strict_schema["properties"]["input"] = input_prop_schema
@@ -99,7 +103,9 @@ class MCPTool(Tool):
99
103
  # Copy over required fields for main schema
100
104
  if "required" in mcp_schema:
101
105
  strict_schema["required"] = mcp_schema["required"]
106
+ logger.info(f"Added required fields for main schema: {strict_schema['required']}")
102
107
 
108
+ logger.info(f"Final strict schema: {json.dumps(strict_schema, indent=2)}")
103
109
  return strict_schema
104
110
 
105
111
 
@@ -31,7 +31,7 @@ class MCPServer:
31
31
  self.app = FastAPI(
32
32
  title=self.name,
33
33
  description=self.description,
34
- version="0.6.22",
34
+ version="0.6.24",
35
35
  )
36
36
 
37
37
  # Initialize MCP server
@@ -0,0 +1,151 @@
1
+ """
2
+ Type definitions for the tools package.
3
+ """
4
+
5
+ from typing import Any, Callable
6
+ from pydantic import BaseModel, Field
7
+ import logging
8
+ import json
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+ def convert_to_strict_schema(schema: dict[str, Any], strict: bool = True, keep_input_wrapper: bool = False) -> dict[str, Any]:
13
+ """Convert a schema to strict format required by OpenAI.
14
+
15
+ Args:
16
+ schema: The input schema to validate and convert
17
+ strict: Whether to enforce strict validation with additionalProperties: false
18
+ keep_input_wrapper: Whether to keep the input wrapper (for MCP tools)
19
+
20
+ Returns:
21
+ A schema in strict format
22
+ """
23
+ logger.info(f"Converting schema to strict format. Input schema: {json.dumps(schema, indent=2)}")
24
+ logger.info(f"Strict mode: {strict}, Keep input wrapper: {keep_input_wrapper}")
25
+
26
+ if not schema:
27
+ return {"type": "object", "properties": {}, "required": []}
28
+
29
+ # Create a new schema object to ensure we have all required fields
30
+ strict_schema = {
31
+ "type": "object",
32
+ "properties": {},
33
+ "required": []
34
+ }
35
+
36
+ # Add additionalProperties: false for strict validation
37
+ if strict:
38
+ strict_schema["additionalProperties"] = False
39
+
40
+ # Handle input wrapper
41
+ if "properties" in schema and "input" in schema["properties"]:
42
+ input_schema = schema["properties"]["input"]
43
+ logger.info(f"Found input wrapper. Input schema: {json.dumps(input_schema, indent=2)}")
44
+
45
+ # If input has a $ref, resolve it
46
+ if "$ref" in input_schema:
47
+ ref = input_schema["$ref"].split("/")[-1]
48
+ input_schema = schema.get("$defs", {}).get(ref, {})
49
+ logger.info(f"Resolved $ref to: {json.dumps(input_schema, indent=2)}")
50
+
51
+ if keep_input_wrapper:
52
+ # Create the input property schema
53
+ input_prop_schema = {
54
+ "type": "object",
55
+ "properties": {},
56
+ "required": []
57
+ }
58
+
59
+ # Add additionalProperties: false for input schema
60
+ if strict:
61
+ input_prop_schema["additionalProperties"] = False
62
+
63
+ # Copy over input properties
64
+ if "properties" in input_schema:
65
+ for prop_name, prop in input_schema["properties"].items():
66
+ # Create a new property object with only allowed fields
67
+ new_prop = {
68
+ "type": prop.get("type", "string"),
69
+ "description": prop.get("description", f"The {prop_name} parameter")
70
+ }
71
+
72
+ input_prop_schema["properties"][prop_name] = new_prop
73
+ logger.info(f"Added property {prop_name}: {json.dumps(new_prop, indent=2)}")
74
+
75
+ # Copy over required fields for input schema
76
+ if "required" in input_schema:
77
+ input_prop_schema["required"] = input_schema["required"]
78
+ logger.info(f"Added required fields for input schema: {input_prop_schema['required']}")
79
+
80
+ # Add the input property to the main schema
81
+ strict_schema["properties"]["input"] = input_prop_schema
82
+
83
+ # Copy over required fields for main schema
84
+ if "required" in schema:
85
+ strict_schema["required"] = schema["required"]
86
+ logger.info(f"Added required fields for main schema: {strict_schema['required']}")
87
+ else:
88
+ # If not keeping input wrapper, use input schema directly
89
+ if "properties" in input_schema:
90
+ for prop_name, prop in input_schema["properties"].items():
91
+ # Create a new property object with only allowed fields
92
+ new_prop = {
93
+ "type": prop.get("type", "string"),
94
+ "description": prop.get("description", f"The {prop_name} parameter")
95
+ }
96
+
97
+ strict_schema["properties"][prop_name] = new_prop
98
+ logger.info(f"Added property {prop_name}: {json.dumps(new_prop, indent=2)}")
99
+
100
+ # Copy over required fields
101
+ if "required" in input_schema:
102
+ strict_schema["required"] = input_schema["required"]
103
+ logger.info(f"Added required fields: {strict_schema['required']}")
104
+ else:
105
+ # If no input wrapper, use the schema as is
106
+ if "properties" in schema:
107
+ for prop_name, prop in schema["properties"].items():
108
+ # Create a new property object with only allowed fields
109
+ new_prop = {
110
+ "type": prop.get("type", "string"),
111
+ "description": prop.get("description", f"The {prop_name} parameter")
112
+ }
113
+
114
+ strict_schema["properties"][prop_name] = new_prop
115
+ logger.info(f"Added property {prop_name}: {json.dumps(new_prop, indent=2)}")
116
+
117
+ # Copy over required fields
118
+ if "required" in schema:
119
+ strict_schema["required"] = schema["required"]
120
+ logger.info(f"Added required fields: {strict_schema['required']}")
121
+
122
+ logger.info(f"Final strict schema: {json.dumps(strict_schema, indent=2)}")
123
+ return strict_schema
124
+
125
+ class ToolCall(BaseModel):
126
+ """A tool call from the model."""
127
+ id: str
128
+ name: str
129
+ arguments: dict[str, Any]
130
+
131
+ class Tool(BaseModel):
132
+ """A tool that can be used by the model."""
133
+ name: str
134
+ description: str
135
+ function: Callable[..., Any] | None = None # Make function optional
136
+ schema: dict[str, Any]
137
+
138
+ def to_openai_function(self) -> dict[str, Any]:
139
+ """Convert the tool to an OpenAI function definition."""
140
+ # Ensure schema is in strict format
141
+ strict_schema = convert_to_strict_schema(self.schema)
142
+ logger.info(f"Converted schema for {self.name}: {json.dumps(strict_schema, indent=2)}")
143
+
144
+ return {
145
+ "type": "function",
146
+ "function": {
147
+ "name": self.name,
148
+ "description": self.description,
149
+ "parameters": strict_schema
150
+ }
151
+ }
@@ -446,7 +446,7 @@ wheels = [
446
446
 
447
447
  [[package]]
448
448
  name = "mbxai"
449
- version = "0.6.22"
449
+ version = "0.6.24"
450
450
  source = { editable = "." }
451
451
  dependencies = [
452
452
  { name = "fastapi" },
@@ -1,115 +0,0 @@
1
- """
2
- Type definitions for the tools package.
3
- """
4
-
5
- from typing import Any, Callable
6
- from pydantic import BaseModel, Field
7
- import logging
8
- import json
9
-
10
- logger = logging.getLogger(__name__)
11
-
12
- def convert_to_strict_schema(schema: dict[str, Any], strict: bool = True) -> dict[str, Any]:
13
- """Convert a schema to strict format required by OpenAI.
14
-
15
- Args:
16
- schema: The input schema to validate and convert
17
- strict: Whether to enforce strict validation with additionalProperties: false
18
-
19
- Returns:
20
- A schema in strict format
21
- """
22
- logger.info(f"Converting schema to strict format. Input schema: {json.dumps(schema, indent=2)}")
23
- logger.info(f"Strict mode: {strict}")
24
-
25
- if not schema:
26
- return {"type": "object", "properties": {}, "required": []}
27
-
28
- # Create a new schema object to ensure we have all required fields
29
- strict_schema = {
30
- "type": "object",
31
- "properties": {},
32
- "required": []
33
- }
34
-
35
- # Add additionalProperties: false for strict validation
36
- if strict:
37
- strict_schema["additionalProperties"] = False
38
-
39
- # Handle input wrapper
40
- if "properties" in schema and "input" in schema["properties"]:
41
- input_schema = schema["properties"]["input"]
42
- logger.info(f"Found input wrapper. Input schema: {json.dumps(input_schema, indent=2)}")
43
-
44
- # If input has a $ref, resolve it
45
- if "$ref" in input_schema:
46
- ref = input_schema["$ref"].split("/")[-1]
47
- input_schema = schema.get("$defs", {}).get(ref, {})
48
- logger.info(f"Resolved $ref to: {json.dumps(input_schema, indent=2)}")
49
-
50
- # Create the input property schema
51
- input_prop_schema = {
52
- "type": "object",
53
- "properties": {},
54
- "required": []
55
- }
56
-
57
- # Add additionalProperties: false for input schema
58
- if strict:
59
- input_prop_schema["additionalProperties"] = False
60
-
61
- # Copy over input properties
62
- if "properties" in input_schema:
63
- for prop_name, prop in input_schema["properties"].items():
64
- # Create a new property object with only allowed fields
65
- new_prop = {
66
- "type": prop.get("type", "string"),
67
- "description": prop.get("description", f"The {prop_name} parameter")
68
- }
69
-
70
- input_prop_schema["properties"][prop_name] = new_prop
71
- logger.info(f"Added property {prop_name}: {json.dumps(new_prop, indent=2)}")
72
-
73
- # Copy over required fields for input schema
74
- if "required" in input_schema:
75
- input_prop_schema["required"] = input_schema["required"]
76
- logger.info(f"Added required fields for input schema: {input_prop_schema['required']}")
77
-
78
- # Add the input property to the main schema
79
- strict_schema["properties"]["input"] = input_prop_schema
80
-
81
- # Copy over required fields for main schema
82
- if "required" in schema:
83
- strict_schema["required"] = schema["required"]
84
- logger.info(f"Added required fields for main schema: {strict_schema['required']}")
85
-
86
- logger.info(f"Final strict schema: {json.dumps(strict_schema, indent=2)}")
87
- return strict_schema
88
-
89
- class ToolCall(BaseModel):
90
- """A tool call from the model."""
91
- id: str
92
- name: str
93
- arguments: dict[str, Any]
94
-
95
- class Tool(BaseModel):
96
- """A tool that can be used by the model."""
97
- name: str
98
- description: str
99
- function: Callable[..., Any] | None = None # Make function optional
100
- schema: dict[str, Any]
101
-
102
- def to_openai_function(self) -> dict[str, Any]:
103
- """Convert the tool to an OpenAI function definition."""
104
- # Ensure schema is in strict format
105
- strict_schema = convert_to_strict_schema(self.schema)
106
- logger.info(f"Converted schema for {self.name}: {json.dumps(strict_schema, indent=2)}")
107
-
108
- return {
109
- "type": "function",
110
- "function": {
111
- "name": self.name,
112
- "description": self.description,
113
- "parameters": strict_schema
114
- }
115
- }
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