mbxai 0.5.17__py3-none-any.whl → 0.5.19__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 +47 -40
- {mbxai-0.5.17.dist-info → mbxai-0.5.19.dist-info}/METADATA +1 -1
- {mbxai-0.5.17.dist-info → mbxai-0.5.19.dist-info}/RECORD +7 -7
- {mbxai-0.5.17.dist-info → mbxai-0.5.19.dist-info}/WHEEL +0 -0
- {mbxai-0.5.17.dist-info → mbxai-0.5.19.dist-info}/licenses/LICENSE +0 -0
mbxai/__init__.py
CHANGED
mbxai/mcp/server.py
CHANGED
mbxai/tools/client.py
CHANGED
@@ -72,8 +72,13 @@ class ToolClient:
|
|
72
72
|
truncated[k] = str(v)[:max_length] + "..." if len(str(v)) > max_length else v
|
73
73
|
return str(truncated)
|
74
74
|
|
75
|
-
def _validate_message_sequence(self, messages: list[dict[str, Any]]) -> None:
|
76
|
-
"""Validate the message sequence for tool calls and responses.
|
75
|
+
def _validate_message_sequence(self, messages: list[dict[str, Any]], validate_responses: bool = True) -> None:
|
76
|
+
"""Validate the message sequence for tool calls and responses.
|
77
|
+
|
78
|
+
Args:
|
79
|
+
messages: The message sequence to validate
|
80
|
+
validate_responses: Whether to validate that all tool calls have responses
|
81
|
+
"""
|
77
82
|
tool_call_ids = set()
|
78
83
|
tool_response_ids = set()
|
79
84
|
|
@@ -89,23 +94,30 @@ class ToolClient:
|
|
89
94
|
tool_response_ids.add(msg["tool_call_id"])
|
90
95
|
logger.info(f"Found tool response for call ID {msg['tool_call_id']} in message {i}")
|
91
96
|
|
92
|
-
#
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
97
|
+
# Only validate responses if requested
|
98
|
+
if validate_responses:
|
99
|
+
# Check for missing responses
|
100
|
+
missing_responses = tool_call_ids - tool_response_ids
|
101
|
+
if missing_responses:
|
102
|
+
logger.error(f"Missing tool responses for call IDs: {missing_responses}")
|
103
|
+
logger.error("Message sequence:")
|
104
|
+
for i, msg in enumerate(messages):
|
105
|
+
role = msg.get("role", "unknown")
|
106
|
+
if role == "assistant" and "tool_calls" in msg:
|
107
|
+
logger.error(f" Message {i} - Assistant with tool calls: {[tc['id'] for tc in msg['tool_calls']]}")
|
108
|
+
elif role == "tool":
|
109
|
+
logger.error(f" Message {i} - Tool response for call ID: {msg['tool_call_id']}")
|
110
|
+
else:
|
111
|
+
logger.error(f" Message {i} - {role}: {self._truncate_content(msg.get('content'))}")
|
112
|
+
raise ValueError(f"Invalid message sequence: missing responses for tool calls {missing_responses}")
|
113
|
+
|
114
|
+
def _log_messages(self, messages: list[dict[str, Any]], validate_responses: bool = True) -> None:
|
115
|
+
"""Log the messages being sent to OpenRouter.
|
116
|
+
|
117
|
+
Args:
|
118
|
+
messages: The messages to log
|
119
|
+
validate_responses: Whether to validate that all tool calls have responses
|
120
|
+
"""
|
109
121
|
logger.info("Sending messages to OpenRouter:")
|
110
122
|
for i, msg in enumerate(messages):
|
111
123
|
role = msg.get("role", "unknown")
|
@@ -125,7 +137,7 @@ class ToolClient:
|
|
125
137
|
logger.info(f" Message {i} - {role}: content='{content}'")
|
126
138
|
|
127
139
|
# Validate message sequence
|
128
|
-
self._validate_message_sequence(messages)
|
140
|
+
self._validate_message_sequence(messages, validate_responses)
|
129
141
|
|
130
142
|
async def chat(
|
131
143
|
self,
|
@@ -135,17 +147,7 @@ class ToolClient:
|
|
135
147
|
stream: bool = False,
|
136
148
|
**kwargs: Any,
|
137
149
|
) -> Any:
|
138
|
-
"""Chat with the model, handling tool calls.
|
139
|
-
|
140
|
-
Args:
|
141
|
-
messages: The conversation messages
|
142
|
-
model: Optional model override
|
143
|
-
stream: Whether to stream the response
|
144
|
-
**kwargs: Additional parameters for the chat completion
|
145
|
-
|
146
|
-
Returns:
|
147
|
-
The final response from the model
|
148
|
-
"""
|
150
|
+
"""Chat with the model, handling tool calls."""
|
149
151
|
tools = [tool.to_openai_function() for tool in self._tools.values()]
|
150
152
|
|
151
153
|
if tools:
|
@@ -154,9 +156,6 @@ class ToolClient:
|
|
154
156
|
kwargs["tool_choice"] = "auto"
|
155
157
|
|
156
158
|
while True:
|
157
|
-
# Log messages before sending to OpenRouter
|
158
|
-
self._log_messages(messages)
|
159
|
-
|
160
159
|
# Get the model's response
|
161
160
|
response = self._client.chat_completion(
|
162
161
|
messages=messages,
|
@@ -193,7 +192,8 @@ class ToolClient:
|
|
193
192
|
if not message.tool_calls:
|
194
193
|
return response
|
195
194
|
|
196
|
-
#
|
195
|
+
# Process all tool calls first
|
196
|
+
tool_responses = []
|
197
197
|
for tool_call in message.tool_calls:
|
198
198
|
tool = self._tools.get(tool_call.function.name)
|
199
199
|
if not tool:
|
@@ -219,17 +219,24 @@ class ToolClient:
|
|
219
219
|
if not isinstance(result, str):
|
220
220
|
result = json.dumps(result)
|
221
221
|
|
222
|
-
# Create
|
222
|
+
# Create the tool response
|
223
223
|
tool_response = {
|
224
224
|
"role": "tool",
|
225
225
|
"tool_call_id": tool_call.id,
|
226
226
|
"content": result,
|
227
227
|
}
|
228
|
-
|
229
|
-
logger.info(f"
|
228
|
+
tool_responses.append(tool_response)
|
229
|
+
logger.info(f"Created tool response for call ID {tool_call.id}")
|
230
|
+
|
231
|
+
# Add all tool responses to the messages
|
232
|
+
messages.extend(tool_responses)
|
233
|
+
logger.info(f"Added {len(tool_responses)} tool responses to messages")
|
234
|
+
|
235
|
+
# Validate the message sequence
|
236
|
+
self._validate_message_sequence(messages, validate_responses=True)
|
230
237
|
|
231
|
-
#
|
232
|
-
self.
|
238
|
+
# Log the messages we're about to send
|
239
|
+
self._log_messages(messages, validate_responses=False)
|
233
240
|
|
234
241
|
# Get a new response from the model with all tool results
|
235
242
|
response = self._client.chat_completion(
|
@@ -1,18 +1,18 @@
|
|
1
|
-
mbxai/__init__.py,sha256=
|
1
|
+
mbxai/__init__.py,sha256=fBHYV_6ZmWukpBBQkb6diHAP4h69-vDoHNwmywdi4G4,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=rjDCSR3IZOm5Xb-A2eMm-aMuJANSuRmq8uHmy85hjT8,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=6FWaM80OFeHR2tI6vhsUcqln8dObfglRiM36vPAyUB8,16733
|
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.19.dist-info/METADATA,sha256=CZyWoVf5vd8iu0_kgCDNYWypoD_MyxggF3xYe9Xy6BE,4108
|
16
|
+
mbxai-0.5.19.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
17
|
+
mbxai-0.5.19.dist-info/licenses/LICENSE,sha256=hEyhc4FxwYo3NQ40yNgZ7STqwVk-1_XcTXOnAPbGJAw,1069
|
18
|
+
mbxai-0.5.19.dist-info/RECORD,,
|
File without changes
|
File without changes
|