forked from themanojdesai/python-a2a
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvalidation.py
More file actions
148 lines (114 loc) · 4.83 KB
/
Copy pathvalidation.py
File metadata and controls
148 lines (114 loc) · 4.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
"""
Validation utilities for A2A messages and conversations.
"""
from typing import Dict, List, Any, Optional, Union
import uuid
from ..models.message import Message, MessageRole
from ..models.conversation import Conversation
from ..exceptions import A2AValidationError
def validate_message(message: Message) -> None:
"""
Validate that a message conforms to the A2A protocol
Args:
message: The message to validate
Raises:
A2AValidationError: If the message is invalid
"""
# Check required fields
if not hasattr(message, 'content') or message.content is None:
raise A2AValidationError("Message must have content")
if not hasattr(message, 'role') or message.role is None:
raise A2AValidationError("Message must have a role")
# Check valid role
if message.role not in list(MessageRole):
raise A2AValidationError(f"Invalid role: {message.role}. Must be one of {list(MessageRole)}")
# Validate content based on type
content_type = message.content.type
if content_type == "text":
if not hasattr(message.content, "text") or not message.content.text:
raise A2AValidationError("Text content must have a text field")
elif content_type == "function_call":
if not hasattr(message.content, "name") or not message.content.name:
raise A2AValidationError("Function call must have a name")
if not hasattr(message.content, "parameters"):
raise A2AValidationError("Function call must have a parameters field")
elif content_type == "function_response":
if not hasattr(message.content, "name") or not message.content.name:
raise A2AValidationError("Function response must have a name")
if not hasattr(message.content, "response"):
raise A2AValidationError("Function response must have a response field")
elif content_type == "error":
if not hasattr(message.content, "message") or not message.content.message:
raise A2AValidationError("Error content must have a message field")
else:
raise A2AValidationError(f"Unknown content type: {content_type}")
# Validate IDs
if message.message_id:
try:
uuid.UUID(message.message_id)
except ValueError:
# Not raising an error here, as custom ID formats are allowed
pass
if message.parent_message_id:
try:
uuid.UUID(message.parent_message_id)
except ValueError:
# Not raising an error here, as custom ID formats are allowed
pass
if message.conversation_id:
try:
uuid.UUID(message.conversation_id)
except ValueError:
# Not raising an error here, as custom ID formats are allowed
pass
def is_valid_message(message: Message) -> bool:
"""
Check if a message is valid according to the A2A protocol
Args:
message: The message to check
Returns:
True if the message is valid, False otherwise
"""
try:
validate_message(message)
return True
except A2AValidationError:
return False
def validate_conversation(conversation: Conversation) -> None:
"""
Validate that a conversation conforms to the A2A protocol
Args:
conversation: The conversation to validate
Raises:
A2AValidationError: If the conversation is invalid
"""
# Check required fields
if not hasattr(conversation, 'conversation_id') or not conversation.conversation_id:
raise A2AValidationError("Conversation must have an ID")
if not hasattr(conversation, 'messages'):
raise A2AValidationError("Conversation must have a messages field")
# Validate all messages in the conversation
for i, message in enumerate(conversation.messages):
try:
validate_message(message)
except A2AValidationError as e:
raise A2AValidationError(f"Invalid message at index {i}: {str(e)}")
# Check that the conversation_id matches
if message.conversation_id and message.conversation_id != conversation.conversation_id:
raise A2AValidationError(
f"Message at index {i} has conversation_id {message.conversation_id}, "
f"which does not match the conversation's ID {conversation.conversation_id}"
)
def is_valid_conversation(conversation: Conversation) -> bool:
"""
Check if a conversation is valid according to the A2A protocol
Args:
conversation: The conversation to check
Returns:
True if the conversation is valid, False otherwise
"""
try:
validate_conversation(conversation)
return True
except A2AValidationError:
return False