mbxai 0.5.16__py3-none-any.whl → 0.5.18__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 +60 -32
- {mbxai-0.5.16.dist-info → mbxai-0.5.18.dist-info}/METADATA +1 -1
- {mbxai-0.5.16.dist-info → mbxai-0.5.18.dist-info}/RECORD +7 -7
- {mbxai-0.5.16.dist-info → mbxai-0.5.18.dist-info}/WHEEL +0 -0
- {mbxai-0.5.16.dist-info → mbxai-0.5.18.dist-info}/licenses/LICENSE +0 -0
mbxai/__init__.py
CHANGED
mbxai/mcp/server.py
CHANGED
mbxai/tools/client.py
CHANGED
@@ -72,10 +72,54 @@ 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
|
76
|
-
"""
|
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
|
+
"""
|
82
|
+
tool_call_ids = set()
|
83
|
+
tool_response_ids = set()
|
84
|
+
|
85
|
+
for i, msg in enumerate(messages):
|
86
|
+
role = msg.get("role")
|
87
|
+
if role == "assistant" and "tool_calls" in msg:
|
88
|
+
# Track tool calls
|
89
|
+
for tc in msg["tool_calls"]:
|
90
|
+
tool_call_ids.add(tc["id"])
|
91
|
+
logger.info(f"Found tool call {tc['id']} for {tc['function']['name']} in message {i}")
|
92
|
+
elif role == "tool":
|
93
|
+
# Track tool responses
|
94
|
+
tool_response_ids.add(msg["tool_call_id"])
|
95
|
+
logger.info(f"Found tool response for call ID {msg['tool_call_id']} in message {i}")
|
96
|
+
|
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
|
+
"""
|
77
121
|
logger.info("Sending messages to OpenRouter:")
|
78
|
-
for msg in messages:
|
122
|
+
for i, msg in enumerate(messages):
|
79
123
|
role = msg.get("role", "unknown")
|
80
124
|
content = self._truncate_content(msg.get("content"))
|
81
125
|
tool_calls = msg.get("tool_calls", [])
|
@@ -86,33 +130,14 @@ class ToolClient:
|
|
86
130
|
f"{tc['function']['name']}(id={tc['id']})"
|
87
131
|
for tc in tool_calls
|
88
132
|
]
|
89
|
-
logger.info(f" {role}: content='{content}', tool_calls={tool_call_info}")
|
133
|
+
logger.info(f" Message {i} - {role}: content='{content}', tool_calls={tool_call_info}")
|
90
134
|
elif tool_call_id:
|
91
|
-
logger.info(f" {role}: content='{content}', tool_call_id={tool_call_id}")
|
135
|
+
logger.info(f" Message {i} - {role}: content='{content}', tool_call_id={tool_call_id}")
|
92
136
|
else:
|
93
|
-
logger.info(f" {role}: content='{content}'")
|
94
|
-
|
95
|
-
# Validate tool call responses
|
96
|
-
tool_call_ids = set()
|
97
|
-
tool_response_ids = set()
|
98
|
-
|
99
|
-
for msg in messages:
|
100
|
-
if msg.get("role") == "assistant" and "tool_calls" in msg:
|
101
|
-
for tc in msg["tool_calls"]:
|
102
|
-
tool_call_ids.add(tc["id"])
|
103
|
-
elif msg.get("role") == "tool":
|
104
|
-
tool_response_ids.add(msg["tool_call_id"])
|
137
|
+
logger.info(f" Message {i} - {role}: content='{content}'")
|
105
138
|
|
106
|
-
|
107
|
-
|
108
|
-
logger.error(f"Missing tool responses for call IDs: {missing_responses}")
|
109
|
-
logger.error("Message sequence:")
|
110
|
-
for msg in messages:
|
111
|
-
role = msg.get("role", "unknown")
|
112
|
-
if role == "assistant" and "tool_calls" in msg:
|
113
|
-
logger.error(f" Assistant message with tool calls: {[tc['id'] for tc in msg['tool_calls']]}")
|
114
|
-
elif role == "tool":
|
115
|
-
logger.error(f" Tool response for call ID: {msg['tool_call_id']}")
|
139
|
+
# Validate message sequence
|
140
|
+
self._validate_message_sequence(messages, validate_responses)
|
116
141
|
|
117
142
|
async def chat(
|
118
143
|
self,
|
@@ -141,8 +166,8 @@ class ToolClient:
|
|
141
166
|
kwargs["tool_choice"] = "auto"
|
142
167
|
|
143
168
|
while True:
|
144
|
-
# Log messages before sending to OpenRouter
|
145
|
-
self._log_messages(messages)
|
169
|
+
# Log messages before sending to OpenRouter, but don't validate responses yet
|
170
|
+
self._log_messages(messages, validate_responses=False)
|
146
171
|
|
147
172
|
# Get the model's response
|
148
173
|
response = self._client.chat_completion(
|
@@ -174,7 +199,7 @@ class ToolClient:
|
|
174
199
|
for tool_call in message.tool_calls
|
175
200
|
]
|
176
201
|
messages.append(assistant_message)
|
177
|
-
logger.info(f"
|
202
|
+
logger.info(f"Added assistant message with tool calls: {[tc.function.name for tc in message.tool_calls] if message.tool_calls else None}")
|
178
203
|
|
179
204
|
# If there are no tool calls, we're done
|
180
205
|
if not message.tool_calls:
|
@@ -213,7 +238,10 @@ class ToolClient:
|
|
213
238
|
"content": result,
|
214
239
|
}
|
215
240
|
messages.append(tool_response)
|
216
|
-
logger.info(f"
|
241
|
+
logger.info(f"Added tool response for call ID {tool_call.id}")
|
242
|
+
|
243
|
+
# Now validate the message sequence after all tool calls have been processed
|
244
|
+
self._validate_message_sequence(messages, validate_responses=True)
|
217
245
|
|
218
246
|
# Get a new response from the model with all tool results
|
219
247
|
response = self._client.chat_completion(
|
@@ -245,7 +273,7 @@ class ToolClient:
|
|
245
273
|
for tool_call in message.tool_calls
|
246
274
|
]
|
247
275
|
messages.append(assistant_message)
|
248
|
-
logger.info(f"
|
276
|
+
logger.info(f"Added assistant message with tool calls: {[tc.function.name for tc in message.tool_calls] if message.tool_calls else None}")
|
249
277
|
|
250
278
|
# If there are no more tool calls, we're done
|
251
279
|
if not message.tool_calls:
|
@@ -1,18 +1,18 @@
|
|
1
|
-
mbxai/__init__.py,sha256=
|
1
|
+
mbxai/__init__.py,sha256=tFcXsftXhe6lGhf_x4i-2A4VqY6oG4jt3o9rTgcfXuw,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=TL2Kr8SWMLRwtIsyiFcf9JPRLmja2PU_B-FE44fpDl8,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=Y7cY_Z5sxDbSyMr1xzqME9lxLzjtwrBfyYX4jESHYDw,16958
|
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.18.dist-info/METADATA,sha256=rV2rkKpOnSc5MzngBqQ281QowFO2XeQ6GUTDOP-QFwk,4108
|
16
|
+
mbxai-0.5.18.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
17
|
+
mbxai-0.5.18.dist-info/licenses/LICENSE,sha256=hEyhc4FxwYo3NQ40yNgZ7STqwVk-1_XcTXOnAPbGJAw,1069
|
18
|
+
mbxai-0.5.18.dist-info/RECORD,,
|
File without changes
|
File without changes
|