microsoft-agents-a365-tooling-extensions-semantickernel 0.2.1.dev7__py3-none-any.whl → 0.2.1.dev10__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.
- microsoft_agents_a365/tooling/extensions/semantickernel/services/mcp_tool_registration_service.py +368 -8
- {microsoft_agents_a365_tooling_extensions_semantickernel-0.2.1.dev7.dist-info → microsoft_agents_a365_tooling_extensions_semantickernel-0.2.1.dev10.dist-info}/METADATA +1 -1
- {microsoft_agents_a365_tooling_extensions_semantickernel-0.2.1.dev7.dist-info → microsoft_agents_a365_tooling_extensions_semantickernel-0.2.1.dev10.dist-info}/RECORD +5 -5
- {microsoft_agents_a365_tooling_extensions_semantickernel-0.2.1.dev7.dist-info → microsoft_agents_a365_tooling_extensions_semantickernel-0.2.1.dev10.dist-info}/WHEEL +0 -0
- {microsoft_agents_a365_tooling_extensions_semantickernel-0.2.1.dev7.dist-info → microsoft_agents_a365_tooling_extensions_semantickernel-0.2.1.dev10.dist-info}/top_level.txt +0 -0
microsoft_agents_a365/tooling/extensions/semantickernel/services/mcp_tool_registration_service.py
CHANGED
|
@@ -13,15 +13,23 @@ servers to agents.
|
|
|
13
13
|
import logging
|
|
14
14
|
import os
|
|
15
15
|
import re
|
|
16
|
-
|
|
16
|
+
import uuid
|
|
17
|
+
from datetime import datetime, timezone
|
|
18
|
+
from typing import Any, List, Optional, Sequence
|
|
19
|
+
|
|
20
|
+
# Third-party imports
|
|
17
21
|
from semantic_kernel import kernel as sk
|
|
18
22
|
from semantic_kernel.connectors.mcp import MCPStreamableHttpPlugin
|
|
23
|
+
from semantic_kernel.contents import AuthorRole, ChatHistory, ChatMessageContent
|
|
24
|
+
|
|
25
|
+
# Local imports
|
|
19
26
|
from microsoft_agents.hosting.core import Authorization, TurnContext
|
|
27
|
+
from microsoft_agents_a365.runtime import OperationError, OperationResult
|
|
20
28
|
from microsoft_agents_a365.runtime.utility import Utility
|
|
29
|
+
from microsoft_agents_a365.tooling.models import ChatHistoryMessage, ToolOptions
|
|
21
30
|
from microsoft_agents_a365.tooling.services.mcp_tool_server_configuration_service import (
|
|
22
31
|
McpToolServerConfigurationService,
|
|
23
32
|
)
|
|
24
|
-
from microsoft_agents_a365.tooling.models import ToolOptions
|
|
25
33
|
from microsoft_agents_a365.tooling.utils.constants import Constants
|
|
26
34
|
from microsoft_agents_a365.tooling.utils.utility import (
|
|
27
35
|
get_mcp_platform_authentication_scope,
|
|
@@ -119,7 +127,9 @@ class McpToolRegistrationService:
|
|
|
119
127
|
for server in servers:
|
|
120
128
|
try:
|
|
121
129
|
headers = {
|
|
122
|
-
Constants.Headers.AUTHORIZATION:
|
|
130
|
+
Constants.Headers.AUTHORIZATION: (
|
|
131
|
+
f"{Constants.Headers.BEARER_PREFIX} {auth_token}"
|
|
132
|
+
),
|
|
123
133
|
}
|
|
124
134
|
|
|
125
135
|
headers[Constants.Headers.USER_AGENT] = Utility.get_user_agent_header(
|
|
@@ -129,7 +139,8 @@ class McpToolRegistrationService:
|
|
|
129
139
|
# Use the URL from server (always populated by the configuration service)
|
|
130
140
|
server_url = server.url
|
|
131
141
|
|
|
132
|
-
# Use mcp_server_name if available (not None or empty),
|
|
142
|
+
# Use mcp_server_name if available (not None or empty),
|
|
143
|
+
# otherwise fall back to mcp_server_unique_name
|
|
133
144
|
server_name = server.mcp_server_name or server.mcp_server_unique_name
|
|
134
145
|
|
|
135
146
|
plugin = MCPStreamableHttpPlugin(
|
|
@@ -144,10 +155,11 @@ class McpToolRegistrationService:
|
|
|
144
155
|
# Add plugin to kernel
|
|
145
156
|
kernel.add_plugin(plugin, server_name)
|
|
146
157
|
|
|
147
|
-
# Store reference to keep plugin alive throughout application lifecycle
|
|
148
|
-
# By storing plugin references in _connected_plugins, we prevent
|
|
149
|
-
#
|
|
150
|
-
#
|
|
158
|
+
# Store reference to keep plugin alive throughout application lifecycle.
|
|
159
|
+
# By storing plugin references in _connected_plugins, we prevent
|
|
160
|
+
# Python's garbage collector from cleaning up the plugin objects.
|
|
161
|
+
# The connections remain active throughout the application lifecycle.
|
|
162
|
+
# Tools can be invoked because their underlying connections stay alive.
|
|
151
163
|
self._connected_plugins.append(plugin)
|
|
152
164
|
|
|
153
165
|
self._logger.info(
|
|
@@ -181,6 +193,354 @@ class McpToolRegistrationService:
|
|
|
181
193
|
clean_name = re.sub(r"[^a-zA-Z0-9_]", "_", server_name)
|
|
182
194
|
return f"{clean_name}Tools"
|
|
183
195
|
|
|
196
|
+
# ============================================================================
|
|
197
|
+
# SEND CHAT HISTORY - Semantic Kernel-specific implementations
|
|
198
|
+
# ============================================================================
|
|
199
|
+
|
|
200
|
+
async def send_chat_history(
|
|
201
|
+
self,
|
|
202
|
+
turn_context: TurnContext,
|
|
203
|
+
chat_history: ChatHistory,
|
|
204
|
+
limit: Optional[int] = None,
|
|
205
|
+
options: Optional[ToolOptions] = None,
|
|
206
|
+
) -> OperationResult:
|
|
207
|
+
"""
|
|
208
|
+
Send Semantic Kernel chat history to the MCP platform.
|
|
209
|
+
|
|
210
|
+
This method extracts messages from a Semantic Kernel ChatHistory object,
|
|
211
|
+
converts them to ChatHistoryMessage format, and sends them to the MCP
|
|
212
|
+
platform for real-time threat protection.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
turn_context: TurnContext from the Agents SDK containing conversation info.
|
|
216
|
+
chat_history: Semantic Kernel ChatHistory object containing messages.
|
|
217
|
+
limit: Optional maximum number of messages to send. If specified,
|
|
218
|
+
sends the most recent N messages. If None, sends all messages.
|
|
219
|
+
options: Optional configuration for the request.
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
OperationResult indicating success or failure.
|
|
223
|
+
|
|
224
|
+
Raises:
|
|
225
|
+
ValueError: If turn_context or chat_history is None.
|
|
226
|
+
|
|
227
|
+
Example:
|
|
228
|
+
>>> from semantic_kernel.contents import ChatHistory
|
|
229
|
+
>>> from microsoft_agents_a365.tooling.extensions.semantickernel import (
|
|
230
|
+
... McpToolRegistrationService
|
|
231
|
+
... )
|
|
232
|
+
>>>
|
|
233
|
+
>>> service = McpToolRegistrationService()
|
|
234
|
+
>>> chat_history = ChatHistory()
|
|
235
|
+
>>> chat_history.add_user_message("Hello!")
|
|
236
|
+
>>> chat_history.add_assistant_message("Hi there!")
|
|
237
|
+
>>>
|
|
238
|
+
>>> result = await service.send_chat_history(
|
|
239
|
+
... turn_context, chat_history, limit=50
|
|
240
|
+
... )
|
|
241
|
+
>>> if result.succeeded:
|
|
242
|
+
... print("Chat history sent successfully")
|
|
243
|
+
"""
|
|
244
|
+
# Validate inputs
|
|
245
|
+
if turn_context is None:
|
|
246
|
+
raise ValueError("turn_context cannot be None")
|
|
247
|
+
if chat_history is None:
|
|
248
|
+
raise ValueError("chat_history cannot be None")
|
|
249
|
+
|
|
250
|
+
try:
|
|
251
|
+
# Extract messages from ChatHistory
|
|
252
|
+
messages = list(chat_history.messages)
|
|
253
|
+
self._logger.debug(f"Extracted {len(messages)} messages from ChatHistory")
|
|
254
|
+
|
|
255
|
+
# Apply limit if specified
|
|
256
|
+
if limit is not None and limit > 0 and len(messages) > limit:
|
|
257
|
+
self._logger.info(f"Applying limit of {limit} to {len(messages)} messages")
|
|
258
|
+
messages = messages[-limit:] # Take the most recent N messages
|
|
259
|
+
|
|
260
|
+
# Delegate to the list-based method
|
|
261
|
+
return await self.send_chat_history_messages(
|
|
262
|
+
turn_context=turn_context,
|
|
263
|
+
messages=messages,
|
|
264
|
+
options=options,
|
|
265
|
+
)
|
|
266
|
+
except ValueError:
|
|
267
|
+
# Re-raise validation errors
|
|
268
|
+
raise
|
|
269
|
+
except Exception as ex:
|
|
270
|
+
self._logger.error(f"Failed to send chat history: {ex}")
|
|
271
|
+
return OperationResult.failed(OperationError(ex))
|
|
272
|
+
|
|
273
|
+
async def send_chat_history_messages(
|
|
274
|
+
self,
|
|
275
|
+
turn_context: TurnContext,
|
|
276
|
+
messages: Sequence[ChatMessageContent],
|
|
277
|
+
options: Optional[ToolOptions] = None,
|
|
278
|
+
) -> OperationResult:
|
|
279
|
+
"""
|
|
280
|
+
Send Semantic Kernel chat history messages to the MCP platform.
|
|
281
|
+
|
|
282
|
+
This method accepts a sequence of Semantic Kernel ChatMessageContent objects,
|
|
283
|
+
converts them to ChatHistoryMessage format, and sends them to the MCP
|
|
284
|
+
platform for real-time threat protection.
|
|
285
|
+
|
|
286
|
+
Args:
|
|
287
|
+
turn_context: TurnContext from the Agents SDK containing conversation info.
|
|
288
|
+
messages: Sequence of Semantic Kernel ChatMessageContent objects to send.
|
|
289
|
+
options: Optional configuration for the request.
|
|
290
|
+
|
|
291
|
+
Returns:
|
|
292
|
+
OperationResult indicating success or failure.
|
|
293
|
+
|
|
294
|
+
Raises:
|
|
295
|
+
ValueError: If turn_context or messages is None.
|
|
296
|
+
|
|
297
|
+
Example:
|
|
298
|
+
>>> from semantic_kernel.contents import ChatMessageContent, AuthorRole
|
|
299
|
+
>>> from microsoft_agents_a365.tooling.extensions.semantickernel import (
|
|
300
|
+
... McpToolRegistrationService
|
|
301
|
+
... )
|
|
302
|
+
>>>
|
|
303
|
+
>>> service = McpToolRegistrationService()
|
|
304
|
+
>>> messages = [
|
|
305
|
+
... ChatMessageContent(role=AuthorRole.USER, content="Hello!"),
|
|
306
|
+
... ChatMessageContent(role=AuthorRole.ASSISTANT, content="Hi there!"),
|
|
307
|
+
... ]
|
|
308
|
+
>>>
|
|
309
|
+
>>> result = await service.send_chat_history_messages(
|
|
310
|
+
... turn_context, messages
|
|
311
|
+
... )
|
|
312
|
+
>>> if result.succeeded:
|
|
313
|
+
... print("Chat history sent successfully")
|
|
314
|
+
"""
|
|
315
|
+
# Validate inputs
|
|
316
|
+
if turn_context is None:
|
|
317
|
+
raise ValueError("turn_context cannot be None")
|
|
318
|
+
if messages is None:
|
|
319
|
+
raise ValueError("messages cannot be None")
|
|
320
|
+
|
|
321
|
+
self._logger.info(f"Sending {len(messages)} Semantic Kernel messages as chat history")
|
|
322
|
+
|
|
323
|
+
# Set default options
|
|
324
|
+
if options is None:
|
|
325
|
+
options = ToolOptions(orchestrator_name=self._orchestrator_name)
|
|
326
|
+
elif options.orchestrator_name is None:
|
|
327
|
+
options.orchestrator_name = self._orchestrator_name
|
|
328
|
+
|
|
329
|
+
try:
|
|
330
|
+
# Convert Semantic Kernel messages to ChatHistoryMessage format
|
|
331
|
+
chat_history_messages = self._convert_sk_messages_to_chat_history(messages)
|
|
332
|
+
|
|
333
|
+
# Call core service even with empty chat_history_messages
|
|
334
|
+
if len(chat_history_messages) == 0:
|
|
335
|
+
self._logger.info(
|
|
336
|
+
"Empty chat history messages (either no input or all filtered), "
|
|
337
|
+
"still sending to register user message"
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
self._logger.debug(
|
|
341
|
+
f"Converted {len(chat_history_messages)} messages to ChatHistoryMessage format"
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
# Delegate to core service
|
|
345
|
+
return await self._mcp_server_configuration_service.send_chat_history(
|
|
346
|
+
turn_context=turn_context,
|
|
347
|
+
chat_history_messages=chat_history_messages,
|
|
348
|
+
options=options,
|
|
349
|
+
)
|
|
350
|
+
except ValueError:
|
|
351
|
+
# Re-raise validation errors from the core service
|
|
352
|
+
raise
|
|
353
|
+
except Exception as ex:
|
|
354
|
+
self._logger.error(f"Failed to send chat history messages: {ex}")
|
|
355
|
+
return OperationResult.failed(OperationError(ex))
|
|
356
|
+
|
|
357
|
+
# ============================================================================
|
|
358
|
+
# PRIVATE HELPER METHODS - Message Conversion
|
|
359
|
+
# ============================================================================
|
|
360
|
+
|
|
361
|
+
def _convert_sk_messages_to_chat_history(
|
|
362
|
+
self,
|
|
363
|
+
messages: Sequence[ChatMessageContent],
|
|
364
|
+
) -> List[ChatHistoryMessage]:
|
|
365
|
+
"""
|
|
366
|
+
Convert Semantic Kernel ChatMessageContent objects to ChatHistoryMessage format.
|
|
367
|
+
|
|
368
|
+
Args:
|
|
369
|
+
messages: Sequence of Semantic Kernel ChatMessageContent objects.
|
|
370
|
+
|
|
371
|
+
Returns:
|
|
372
|
+
List of ChatHistoryMessage objects. Messages that cannot be converted
|
|
373
|
+
are filtered out with a warning log.
|
|
374
|
+
"""
|
|
375
|
+
chat_history_messages: List[ChatHistoryMessage] = []
|
|
376
|
+
|
|
377
|
+
for idx, message in enumerate(messages):
|
|
378
|
+
converted = self._convert_single_sk_message(message, idx)
|
|
379
|
+
if converted is not None:
|
|
380
|
+
chat_history_messages.append(converted)
|
|
381
|
+
|
|
382
|
+
self._logger.info(
|
|
383
|
+
f"Converted {len(chat_history_messages)} of {len(messages)} messages "
|
|
384
|
+
"to ChatHistoryMessage format"
|
|
385
|
+
)
|
|
386
|
+
return chat_history_messages
|
|
387
|
+
|
|
388
|
+
def _convert_single_sk_message(
|
|
389
|
+
self,
|
|
390
|
+
message: ChatMessageContent,
|
|
391
|
+
index: int = 0,
|
|
392
|
+
) -> Optional[ChatHistoryMessage]:
|
|
393
|
+
"""
|
|
394
|
+
Convert a single Semantic Kernel message to ChatHistoryMessage format.
|
|
395
|
+
|
|
396
|
+
Args:
|
|
397
|
+
message: Single Semantic Kernel ChatMessageContent message.
|
|
398
|
+
index: Index of the message in the list (for logging).
|
|
399
|
+
|
|
400
|
+
Returns:
|
|
401
|
+
ChatHistoryMessage object or None if conversion fails.
|
|
402
|
+
"""
|
|
403
|
+
try:
|
|
404
|
+
# Skip None messages
|
|
405
|
+
if message is None:
|
|
406
|
+
self._logger.warning(f"Skipping null message at index {index}")
|
|
407
|
+
return None
|
|
408
|
+
|
|
409
|
+
# Map role to string
|
|
410
|
+
role = self._map_author_role(message.role)
|
|
411
|
+
|
|
412
|
+
# Extract content
|
|
413
|
+
content = self._extract_content(message)
|
|
414
|
+
if not content or not content.strip():
|
|
415
|
+
self._logger.warning(f"Skipping message at index {index} with empty content")
|
|
416
|
+
return None
|
|
417
|
+
|
|
418
|
+
# Extract or generate ID
|
|
419
|
+
msg_id = self._extract_or_generate_id(message, index)
|
|
420
|
+
|
|
421
|
+
# Extract or generate timestamp
|
|
422
|
+
timestamp = self._extract_or_generate_timestamp(message, index)
|
|
423
|
+
|
|
424
|
+
self._logger.debug(
|
|
425
|
+
f"Converting message {index}: role={role}, "
|
|
426
|
+
f"id={msg_id}, has_timestamp={timestamp is not None}"
|
|
427
|
+
)
|
|
428
|
+
|
|
429
|
+
return ChatHistoryMessage(
|
|
430
|
+
id=msg_id,
|
|
431
|
+
role=role,
|
|
432
|
+
content=content,
|
|
433
|
+
timestamp=timestamp,
|
|
434
|
+
)
|
|
435
|
+
except Exception as ex:
|
|
436
|
+
self._logger.error(f"Failed to convert message at index {index}: {ex}")
|
|
437
|
+
return None
|
|
438
|
+
|
|
439
|
+
def _map_author_role(self, role: AuthorRole) -> str:
|
|
440
|
+
"""
|
|
441
|
+
Map Semantic Kernel AuthorRole enum to lowercase string.
|
|
442
|
+
|
|
443
|
+
Args:
|
|
444
|
+
role: AuthorRole enum value.
|
|
445
|
+
|
|
446
|
+
Returns:
|
|
447
|
+
Lowercase string representation of the role.
|
|
448
|
+
"""
|
|
449
|
+
return role.name.lower()
|
|
450
|
+
|
|
451
|
+
def _extract_content(self, message: ChatMessageContent) -> str:
|
|
452
|
+
"""
|
|
453
|
+
Extract text content from a ChatMessageContent.
|
|
454
|
+
|
|
455
|
+
Args:
|
|
456
|
+
message: Semantic Kernel ChatMessageContent object.
|
|
457
|
+
|
|
458
|
+
Returns:
|
|
459
|
+
Content string (may be empty). Returns empty string for unexpected
|
|
460
|
+
types to avoid unintentionally exposing sensitive data.
|
|
461
|
+
"""
|
|
462
|
+
content = message.content
|
|
463
|
+
|
|
464
|
+
if content is None:
|
|
465
|
+
return ""
|
|
466
|
+
|
|
467
|
+
# If content is already a string, return it directly
|
|
468
|
+
if isinstance(content, str):
|
|
469
|
+
return content
|
|
470
|
+
|
|
471
|
+
# For unexpected types, log a warning and return empty string to avoid
|
|
472
|
+
# unintentionally stringifying objects that might contain sensitive data
|
|
473
|
+
content_type = type(content).__name__
|
|
474
|
+
self._logger.warning(
|
|
475
|
+
f"Unexpected content type '{content_type}' encountered. "
|
|
476
|
+
"Returning empty string to avoid potential data exposure."
|
|
477
|
+
)
|
|
478
|
+
return ""
|
|
479
|
+
|
|
480
|
+
def _extract_or_generate_id(
|
|
481
|
+
self,
|
|
482
|
+
message: ChatMessageContent,
|
|
483
|
+
index: int,
|
|
484
|
+
) -> str:
|
|
485
|
+
"""
|
|
486
|
+
Extract message ID from metadata or generate a new UUID.
|
|
487
|
+
|
|
488
|
+
Args:
|
|
489
|
+
message: Semantic Kernel ChatMessageContent object.
|
|
490
|
+
index: Message index for logging.
|
|
491
|
+
|
|
492
|
+
Returns:
|
|
493
|
+
Message ID string.
|
|
494
|
+
"""
|
|
495
|
+
# Try to get existing ID from metadata
|
|
496
|
+
if message.metadata and "id" in message.metadata:
|
|
497
|
+
existing_id = message.metadata["id"]
|
|
498
|
+
if existing_id:
|
|
499
|
+
return str(existing_id)
|
|
500
|
+
|
|
501
|
+
# Generate new UUID
|
|
502
|
+
generated_id = str(uuid.uuid4())
|
|
503
|
+
self._logger.debug(f"Generated UUID {generated_id} for message at index {index}")
|
|
504
|
+
return generated_id
|
|
505
|
+
|
|
506
|
+
def _extract_or_generate_timestamp(
|
|
507
|
+
self,
|
|
508
|
+
message: ChatMessageContent,
|
|
509
|
+
index: int,
|
|
510
|
+
) -> datetime:
|
|
511
|
+
"""
|
|
512
|
+
Extract timestamp from metadata or generate current UTC time.
|
|
513
|
+
|
|
514
|
+
Args:
|
|
515
|
+
message: Semantic Kernel ChatMessageContent object.
|
|
516
|
+
index: Message index for logging.
|
|
517
|
+
|
|
518
|
+
Returns:
|
|
519
|
+
Timestamp as datetime object.
|
|
520
|
+
"""
|
|
521
|
+
# Try to get existing timestamp from metadata
|
|
522
|
+
if message.metadata:
|
|
523
|
+
existing_timestamp = message.metadata.get("timestamp") or message.metadata.get(
|
|
524
|
+
"created_at"
|
|
525
|
+
)
|
|
526
|
+
if existing_timestamp:
|
|
527
|
+
if isinstance(existing_timestamp, datetime):
|
|
528
|
+
return existing_timestamp
|
|
529
|
+
elif isinstance(existing_timestamp, (int, float)):
|
|
530
|
+
# Unix timestamp
|
|
531
|
+
return datetime.fromtimestamp(existing_timestamp, tz=timezone.utc)
|
|
532
|
+
elif isinstance(existing_timestamp, str):
|
|
533
|
+
try:
|
|
534
|
+
return datetime.fromisoformat(existing_timestamp.replace("Z", "+00:00"))
|
|
535
|
+
except (ValueError, TypeError) as ex:
|
|
536
|
+
self._logger.debug(
|
|
537
|
+
f"Failed to parse timestamp '{existing_timestamp}' at index {index}: {ex}"
|
|
538
|
+
)
|
|
539
|
+
|
|
540
|
+
# Use current UTC time
|
|
541
|
+
self._logger.debug(f"Using current UTC time for message at index {index}")
|
|
542
|
+
return datetime.now(timezone.utc)
|
|
543
|
+
|
|
184
544
|
# ============================================================================
|
|
185
545
|
# Cleanup Methods
|
|
186
546
|
# ============================================================================
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
microsoft_agents_a365/tooling/extensions/semantickernel/__init__.py,sha256=IvWvvW3Yajk0vX0Il0zisWbN0F-2EIWBmSpAkTeEETw,398
|
|
2
2
|
microsoft_agents_a365/tooling/extensions/semantickernel/services/__init__.py,sha256=gS6eaKMSKI0PCvXzjUt5gx8xvwMcy2Ym0XLj8cJOqvQ,373
|
|
3
|
-
microsoft_agents_a365/tooling/extensions/semantickernel/services/mcp_tool_registration_service.py,sha256=
|
|
4
|
-
microsoft_agents_a365_tooling_extensions_semantickernel-0.2.1.
|
|
5
|
-
microsoft_agents_a365_tooling_extensions_semantickernel-0.2.1.
|
|
6
|
-
microsoft_agents_a365_tooling_extensions_semantickernel-0.2.1.
|
|
7
|
-
microsoft_agents_a365_tooling_extensions_semantickernel-0.2.1.
|
|
3
|
+
microsoft_agents_a365/tooling/extensions/semantickernel/services/mcp_tool_registration_service.py,sha256=BYQdXnwqYgpnC1lddH8ibJqNG0Rc69oidPqxprMwIsc,22052
|
|
4
|
+
microsoft_agents_a365_tooling_extensions_semantickernel-0.2.1.dev10.dist-info/METADATA,sha256=jDx-obviiNxGWsxNZw838bKGosOf0WN8Xmyn-B1wwHw,3365
|
|
5
|
+
microsoft_agents_a365_tooling_extensions_semantickernel-0.2.1.dev10.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
6
|
+
microsoft_agents_a365_tooling_extensions_semantickernel-0.2.1.dev10.dist-info/top_level.txt,sha256=G3c2_4sy5_EM_BWO67SbK2tKj4G8XFn-QXRbh8g9Lgk,22
|
|
7
|
+
microsoft_agents_a365_tooling_extensions_semantickernel-0.2.1.dev10.dist-info/RECORD,,
|
|
File without changes
|