agentic-blocks 0.1.6__py3-none-any.whl → 0.1.7__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.
@@ -68,9 +68,11 @@ class Messages:
68
68
  tool_call: The tool call dictionary with id, type, function, etc.
69
69
  """
70
70
  # Check if the latest message is an assistant message with tool_calls
71
- if (self.messages
72
- and self.messages[-1].get("role") == "assistant"
73
- and "tool_calls" in self.messages[-1]):
71
+ if (
72
+ self.messages
73
+ and self.messages[-1].get("role") == "assistant"
74
+ and "tool_calls" in self.messages[-1]
75
+ ):
74
76
  # Append to existing assistant message
75
77
  self.messages[-1]["tool_calls"].append(tool_call)
76
78
  else:
@@ -82,6 +84,33 @@ class Messages:
82
84
  }
83
85
  self.messages.append(assistant_message)
84
86
 
87
+ def add_tool_calls(self, tool_calls):
88
+ """
89
+ Add multiple tool calls from ChatCompletionMessageFunctionToolCall objects.
90
+
91
+ Args:
92
+ tool_calls: A list of ChatCompletionMessageFunctionToolCall objects or a single object
93
+ """
94
+ # Handle single tool call or list of tool calls
95
+ if not isinstance(tool_calls, list):
96
+ tool_calls = [tool_calls]
97
+
98
+ # Create assistant message with empty content and tool calls
99
+ assistant_message = {"role": "assistant", "content": "", "tool_calls": []}
100
+
101
+ for tool_call in tool_calls:
102
+ tool_call_dict = {
103
+ "id": tool_call.id,
104
+ "type": tool_call.type,
105
+ "function": {
106
+ "name": tool_call.function.name,
107
+ "arguments": tool_call.function.arguments,
108
+ },
109
+ }
110
+ assistant_message["tool_calls"].append(tool_call_dict)
111
+
112
+ self.messages.append(assistant_message)
113
+
85
114
  def add_tool_response(self, tool_call_id: str, content: str):
86
115
  """
87
116
  Add a tool response message.
@@ -108,7 +137,7 @@ class Messages:
108
137
  for response in tool_responses:
109
138
  tool_call_id = response.get("tool_call_id", "unknown")
110
139
  is_error = response.get("is_error", False)
111
-
140
+
112
141
  if is_error:
113
142
  content = f"Error: {response.get('error', 'Unknown error')}"
114
143
  else:
@@ -125,34 +154,22 @@ class Messages:
125
154
 
126
155
  self.add_tool_response(tool_call_id, content)
127
156
 
128
- def add_response_message(self, message):
157
+ def add_response_message(self, model_response):
129
158
  """
130
159
  Add a response message (ChatCompletionMessage) to the conversation.
131
160
 
132
161
  Args:
133
- message: A ChatCompletionMessage object with role, content, and potentially tool_calls
162
+ model_response: A ChatCompletionMessage object with role, content, and potentially tool_calls
134
163
  """
135
- # Convert the ChatCompletionMessage to a dictionary format
136
- msg_dict = {"role": message.role}
137
-
138
- # Add content (handle None case)
139
- msg_dict["content"] = message.content or ""
140
-
141
- # Add tool_calls if present
142
- if message.tool_calls:
143
- msg_dict["tool_calls"] = []
144
- for tool_call in message.tool_calls:
145
- tool_call_dict = {
146
- "id": tool_call.id,
147
- "type": tool_call.type,
148
- "function": {
149
- "name": tool_call.function.name,
150
- "arguments": tool_call.function.arguments
151
- }
152
- }
153
- msg_dict["tool_calls"].append(tool_call_dict)
154
-
155
- self.messages.append(msg_dict)
164
+ # If there are tool calls, use add_tool_calls
165
+ if model_response.tool_calls:
166
+ self.add_tool_calls(model_response.tool_calls)
167
+ # If there's also content, update the message content
168
+ if model_response.content:
169
+ self.messages[-1]["content"] = model_response.content
170
+ else:
171
+ # No tool calls, just add content as assistant message
172
+ self.add_assistant_message(model_response.content or "")
156
173
 
157
174
  def get_messages(self) -> List[Dict[str, Any]]:
158
175
  """Get the current messages list."""
@@ -169,17 +186,20 @@ class Messages:
169
186
  return False
170
187
 
171
188
  last_message = self.messages[-1]
172
-
189
+
173
190
  # Check if the last message is an assistant message with tool calls
174
191
  if last_message.get("role") == "assistant" and "tool_calls" in last_message:
175
192
  # Check if there are subsequent tool responses
176
193
  tool_call_ids = {tc.get("id") for tc in last_message["tool_calls"]}
177
-
194
+
178
195
  # Look for tool responses after this message
179
196
  for msg in reversed(self.messages):
180
- if msg.get("role") == "tool" and msg.get("tool_call_id") in tool_call_ids:
197
+ if (
198
+ msg.get("role") == "tool"
199
+ and msg.get("tool_call_id") in tool_call_ids
200
+ ):
181
201
  tool_call_ids.remove(msg.get("tool_call_id"))
182
-
202
+
183
203
  # If there are still unresponded tool call IDs, we have pending calls
184
204
  return len(tool_call_ids) > 0
185
205
 
@@ -201,7 +221,7 @@ class Messages:
201
221
  for j, tool_call in enumerate(message["tool_calls"], 1):
202
222
  function_name = tool_call.get("function", {}).get("name", "unknown")
203
223
  lines.append(f" └─ Tool Call {j}: {function_name}")
204
-
224
+
205
225
  # Handle tool messages
206
226
  elif role == "tool":
207
227
  tool_call_id = message.get("tool_call_id", "unknown")
@@ -209,7 +229,7 @@ class Messages:
209
229
  if len(content) > 200:
210
230
  content = content[:197] + "..."
211
231
  lines.append(f"{i}. {role} [{tool_call_id[:8]}...]: {content}")
212
-
232
+
213
233
  # Handle other message types
214
234
  else:
215
235
  # Truncate long content for readability
@@ -227,28 +247,28 @@ def example_usage():
227
247
  messages = Messages(
228
248
  system_prompt="You are a helpful assistant.",
229
249
  user_prompt="Hello, how are you?",
230
- add_date_and_time=True
250
+ add_date_and_time=True,
231
251
  )
232
-
252
+
233
253
  # Add assistant response
234
254
  messages.add_assistant_message("I'm doing well, thank you!")
235
-
255
+
236
256
  # Add a tool call
237
257
  tool_call = {
238
258
  "id": "call_123",
239
259
  "type": "function",
240
- "function": {"name": "get_weather", "arguments": '{"location": "Paris"}'}
260
+ "function": {"name": "get_weather", "arguments": '{"location": "Paris"}'},
241
261
  }
242
262
  messages.add_tool_call(tool_call)
243
-
263
+
244
264
  # Add tool response
245
265
  messages.add_tool_response("call_123", "The weather in Paris is sunny, 22°C")
246
-
266
+
247
267
  print("Conversation:")
248
268
  print(messages)
249
-
269
+
250
270
  print(f"\nHas pending tool calls: {messages.has_pending_tool_calls()}")
251
271
 
252
272
 
253
273
  if __name__ == "__main__":
254
- example_usage()
274
+ example_usage()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentic-blocks
3
- Version: 0.1.6
3
+ Version: 0.1.7
4
4
  Summary: Simple building blocks for agentic AI systems with MCP client and conversation management
5
5
  Author-email: Magnus Bjelkenhed <bjelkenhed@gmail.com>
6
6
  License: MIT
@@ -0,0 +1,9 @@
1
+ agentic_blocks/__init__.py,sha256=LJy2tzTwX9ZjPw8dqkXOWiude7ZDDIaBIvaLC8U4d_Y,435
2
+ agentic_blocks/llm.py,sha256=CznQ5iNFz_nQsGqjSmtZbCz1YyL6ha1qvnaoFOwsJtk,4868
3
+ agentic_blocks/mcp_client.py,sha256=15mIN_Qw0OVNJAvfgO3jVZS4-AU4TtvEQSFDlL9ruqA,9773
4
+ agentic_blocks/messages.py,sha256=WhZDFYb9afvJH9YcieTvEbPdSOkRcclFkCSiMM-9YjY,9904
5
+ agentic_blocks-0.1.7.dist-info/licenses/LICENSE,sha256=r4IcBaAjTv3-yfjXgDPuRD953Qci0Y0nQn5JfHwLyBY,1073
6
+ agentic_blocks-0.1.7.dist-info/METADATA,sha256=wQIebdtAorFhdsiVKrLi-M_3C60S7qI1oZ9l2ivlLQs,9445
7
+ agentic_blocks-0.1.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
+ agentic_blocks-0.1.7.dist-info/top_level.txt,sha256=-1a4RAemqicXLU1rRzw4QHV3KlNeQDNxVs3m2gAT238,15
9
+ agentic_blocks-0.1.7.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- agentic_blocks/__init__.py,sha256=LJy2tzTwX9ZjPw8dqkXOWiude7ZDDIaBIvaLC8U4d_Y,435
2
- agentic_blocks/llm.py,sha256=CznQ5iNFz_nQsGqjSmtZbCz1YyL6ha1qvnaoFOwsJtk,4868
3
- agentic_blocks/mcp_client.py,sha256=15mIN_Qw0OVNJAvfgO3jVZS4-AU4TtvEQSFDlL9ruqA,9773
4
- agentic_blocks/messages.py,sha256=VKfqetR0mKrOnqKxzVzqm42qEKTlK0YNytoy_Oel2Wc,9224
5
- agentic_blocks-0.1.6.dist-info/licenses/LICENSE,sha256=r4IcBaAjTv3-yfjXgDPuRD953Qci0Y0nQn5JfHwLyBY,1073
6
- agentic_blocks-0.1.6.dist-info/METADATA,sha256=62GDddF1n1iSVGjlsbJRBHdYDJ1kPjFElsHU8wWb-aw,9445
7
- agentic_blocks-0.1.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
- agentic_blocks-0.1.6.dist-info/top_level.txt,sha256=-1a4RAemqicXLU1rRzw4QHV3KlNeQDNxVs3m2gAT238,15
9
- agentic_blocks-0.1.6.dist-info/RECORD,,