aixtools 0.1.4__py3-none-any.whl → 0.1.5__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.

Potentially problematic release.


This version of aixtools might be problematic. Click here for more details.

Files changed (45) hide show
  1. aixtools/_version.py +2 -2
  2. aixtools/a2a/app.py +1 -1
  3. aixtools/a2a/google_sdk/__init__.py +0 -0
  4. aixtools/a2a/google_sdk/card.py +27 -0
  5. aixtools/a2a/google_sdk/pydantic_ai_adapter/agent_executor.py +199 -0
  6. aixtools/a2a/google_sdk/pydantic_ai_adapter/storage.py +26 -0
  7. aixtools/a2a/google_sdk/remote_agent_connection.py +88 -0
  8. aixtools/a2a/google_sdk/utils.py +59 -0
  9. aixtools/agents/prompt.py +97 -0
  10. aixtools/context.py +5 -0
  11. aixtools/google/client.py +25 -0
  12. aixtools/logging/logging_config.py +45 -0
  13. aixtools/mcp/client.py +274 -0
  14. aixtools/server/utils.py +3 -3
  15. aixtools/utils/config.py +6 -0
  16. aixtools/utils/files.py +17 -0
  17. aixtools/utils/utils.py +7 -0
  18. {aixtools-0.1.4.dist-info → aixtools-0.1.5.dist-info}/METADATA +3 -1
  19. {aixtools-0.1.4.dist-info → aixtools-0.1.5.dist-info}/RECORD +44 -13
  20. {aixtools-0.1.4.dist-info → aixtools-0.1.5.dist-info}/top_level.txt +1 -0
  21. scripts/test.sh +23 -0
  22. tests/__init__.py +0 -0
  23. tests/unit/__init__.py +0 -0
  24. tests/unit/a2a/__init__.py +0 -0
  25. tests/unit/a2a/google_sdk/__init__.py +0 -0
  26. tests/unit/a2a/google_sdk/pydantic_ai_adapter/__init__.py +0 -0
  27. tests/unit/a2a/google_sdk/pydantic_ai_adapter/test_agent_executor.py +188 -0
  28. tests/unit/a2a/google_sdk/pydantic_ai_adapter/test_storage.py +156 -0
  29. tests/unit/a2a/google_sdk/test_card.py +114 -0
  30. tests/unit/a2a/google_sdk/test_remote_agent_connection.py +413 -0
  31. tests/unit/a2a/google_sdk/test_utils.py +208 -0
  32. tests/unit/agents/__init__.py +0 -0
  33. tests/unit/agents/test_prompt.py +363 -0
  34. tests/unit/google/__init__.py +1 -0
  35. tests/unit/google/test_client.py +233 -0
  36. tests/unit/mcp/__init__.py +0 -0
  37. tests/unit/mcp/test_client.py +242 -0
  38. tests/unit/server/__init__.py +0 -0
  39. tests/unit/server/test_path.py +225 -0
  40. tests/unit/server/test_utils.py +362 -0
  41. tests/unit/utils/__init__.py +0 -0
  42. tests/unit/utils/test_files.py +146 -0
  43. aixtools/a2a/__init__.py +0 -5
  44. {aixtools-0.1.4.dist-info → aixtools-0.1.5.dist-info}/WHEEL +0 -0
  45. {aixtools-0.1.4.dist-info → aixtools-0.1.5.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,362 @@
1
+ """Unit tests for aixtools.server.utils module."""
2
+
3
+ import asyncio
4
+ import unittest
5
+ from unittest.mock import AsyncMock, Mock, patch
6
+
7
+ from aixtools.server.utils import (
8
+ get_session_id_from_request,
9
+ get_session_id_str,
10
+ get_session_id_tuple,
11
+ get_user_id_from_request,
12
+ run_in_thread,
13
+ )
14
+
15
+
16
+ class TestGetSessionIdFromRequest(unittest.TestCase):
17
+ """Test cases for get_session_id_from_request function."""
18
+
19
+ @patch('aixtools.server.utils.dependencies')
20
+ def test_get_session_id_with_context_none(self, mock_dependencies):
21
+ """Test getting session ID when context is None."""
22
+ mock_request = Mock()
23
+ mock_request.headers.get.return_value = "test-session-123"
24
+ mock_dependencies.get_http_request.return_value = mock_request
25
+
26
+ result = get_session_id_from_request(None)
27
+
28
+ self.assertEqual(result, "test-session-123")
29
+ mock_dependencies.get_http_request.assert_called_once()
30
+ mock_request.headers.get.assert_called_once_with("session-id")
31
+
32
+ def test_get_session_id_with_context_provided(self):
33
+ """Test getting session ID when context is provided."""
34
+ mock_ctx = Mock()
35
+ mock_request = Mock()
36
+ mock_request.headers.get.return_value = "ctx-session-456"
37
+ mock_ctx.get_http_request.return_value = mock_request
38
+
39
+ result = get_session_id_from_request(mock_ctx)
40
+
41
+ self.assertEqual(result, "ctx-session-456")
42
+ mock_ctx.get_http_request.assert_called_once()
43
+ mock_request.headers.get.assert_called_once_with("session-id")
44
+
45
+ @patch('aixtools.server.utils.dependencies')
46
+ def test_get_session_id_header_not_found(self, mock_dependencies):
47
+ """Test getting session ID when header is not found."""
48
+ mock_request = Mock()
49
+ mock_request.headers.get.return_value = None
50
+ mock_dependencies.get_http_request.return_value = mock_request
51
+
52
+ result = get_session_id_from_request(None)
53
+
54
+ self.assertIsNone(result)
55
+
56
+ @patch('aixtools.server.utils.dependencies')
57
+ def test_get_session_id_value_error(self, mock_dependencies):
58
+ """Test getting session ID when ValueError is raised."""
59
+ mock_dependencies.get_http_request.side_effect = ValueError("Request error")
60
+
61
+ result = get_session_id_from_request(None)
62
+
63
+ self.assertIsNone(result)
64
+
65
+ @patch('aixtools.server.utils.dependencies')
66
+ def test_get_session_id_runtime_error(self, mock_dependencies):
67
+ """Test getting session ID when RuntimeError is raised."""
68
+ mock_dependencies.get_http_request.side_effect = RuntimeError("Runtime error")
69
+
70
+ result = get_session_id_from_request(None)
71
+
72
+ self.assertIsNone(result)
73
+
74
+
75
+ class TestGetUserIdFromRequest(unittest.TestCase):
76
+ """Test cases for get_user_id_from_request function."""
77
+
78
+ @patch('aixtools.server.utils.dependencies')
79
+ def test_get_user_id_with_context_none(self, mock_dependencies):
80
+ """Test getting user ID when context is None."""
81
+ mock_request = Mock()
82
+ mock_request.headers.get.return_value = "TEST-USER-123"
83
+ mock_dependencies.get_http_request.return_value = mock_request
84
+
85
+ result = get_user_id_from_request(None)
86
+
87
+ self.assertEqual(result, "test-user-123") # Should be lowercase
88
+ mock_dependencies.get_http_request.assert_called_once()
89
+ mock_request.headers.get.assert_called_once_with("user-id")
90
+
91
+ def test_get_user_id_with_context_provided(self):
92
+ """Test getting user ID when context is provided."""
93
+ mock_ctx = Mock()
94
+ mock_request = Mock()
95
+ mock_request.headers.get.return_value = "CTX-USER-456"
96
+ mock_ctx.get_http_request.return_value = mock_request
97
+
98
+ result = get_user_id_from_request(mock_ctx)
99
+
100
+ self.assertEqual(result, "ctx-user-456") # Should be lowercase
101
+ mock_ctx.get_http_request.assert_called_once()
102
+ mock_request.headers.get.assert_called_once_with("user-id")
103
+
104
+ @patch('aixtools.server.utils.dependencies')
105
+ def test_get_user_id_header_not_found(self, mock_dependencies):
106
+ """Test getting user ID when header is not found."""
107
+ mock_request = Mock()
108
+ mock_request.headers.get.return_value = None
109
+ mock_dependencies.get_http_request.return_value = mock_request
110
+
111
+ result = get_user_id_from_request(None)
112
+
113
+ self.assertIsNone(result)
114
+
115
+ @patch('aixtools.server.utils.dependencies')
116
+ def test_get_user_id_empty_string(self, mock_dependencies):
117
+ """Test getting user ID when header is empty string."""
118
+ mock_request = Mock()
119
+ mock_request.headers.get.return_value = ""
120
+ mock_dependencies.get_http_request.return_value = mock_request
121
+
122
+ result = get_user_id_from_request(None)
123
+
124
+ self.assertIsNone(result)
125
+
126
+ @patch('aixtools.server.utils.dependencies')
127
+ def test_get_user_id_value_error(self, mock_dependencies):
128
+ """Test getting user ID when ValueError is raised."""
129
+ mock_dependencies.get_http_request.side_effect = ValueError("Request error")
130
+
131
+ result = get_user_id_from_request(None)
132
+
133
+ self.assertIsNone(result)
134
+
135
+ @patch('aixtools.server.utils.dependencies')
136
+ def test_get_user_id_runtime_error(self, mock_dependencies):
137
+ """Test getting user ID when RuntimeError is raised."""
138
+ mock_dependencies.get_http_request.side_effect = RuntimeError("Runtime error")
139
+
140
+ result = get_user_id_from_request(None)
141
+
142
+ self.assertIsNone(result)
143
+
144
+ @patch('aixtools.server.utils.dependencies')
145
+ def test_get_user_id_attribute_error(self, mock_dependencies):
146
+ """Test getting user ID when AttributeError is raised."""
147
+ mock_dependencies.get_http_request.side_effect = AttributeError("Attribute error")
148
+
149
+ result = get_user_id_from_request(None)
150
+
151
+ self.assertIsNone(result)
152
+
153
+ @patch('aixtools.server.utils.dependencies')
154
+ def test_get_user_id_case_variations(self, mock_dependencies):
155
+ """Test that user ID is always returned in lowercase."""
156
+ test_cases = [
157
+ ("UPPERCASE", "uppercase"),
158
+ ("MixedCase", "mixedcase"),
159
+ ("lowercase", "lowercase"),
160
+ ("CamelCase", "camelcase"),
161
+ ]
162
+
163
+ for input_user_id, expected_output in test_cases:
164
+ with self.subTest(input_user_id=input_user_id):
165
+ mock_request = Mock()
166
+ mock_request.headers.get.return_value = input_user_id
167
+ mock_dependencies.get_http_request.return_value = mock_request
168
+
169
+ result = get_user_id_from_request(None)
170
+
171
+ self.assertEqual(result, expected_output)
172
+
173
+
174
+ class TestGetSessionIdTuple(unittest.TestCase):
175
+ """Test cases for get_session_id_tuple function."""
176
+
177
+ @patch('aixtools.server.utils.get_session_id_from_request')
178
+ @patch('aixtools.server.utils.get_user_id_from_request')
179
+ @patch('aixtools.server.utils.session_id_var')
180
+ @patch('aixtools.server.utils.user_id_var')
181
+ def test_get_session_id_tuple_with_headers(self, mock_user_var, mock_session_var,
182
+ mock_get_user, mock_get_session):
183
+ """Test getting session ID tuple when headers are available."""
184
+ mock_get_user.return_value = "header-user"
185
+ mock_get_session.return_value = "header-session"
186
+
187
+ result = get_session_id_tuple(None)
188
+
189
+ self.assertEqual(result, ("header-user", "header-session"))
190
+ mock_get_user.assert_called_once_with(None)
191
+ mock_get_session.assert_called_once_with(None)
192
+
193
+ @patch('aixtools.server.utils.get_session_id_from_request')
194
+ @patch('aixtools.server.utils.get_user_id_from_request')
195
+ @patch('aixtools.server.utils.session_id_var')
196
+ @patch('aixtools.server.utils.user_id_var')
197
+ def test_get_session_id_tuple_with_fallback(self, mock_user_var, mock_session_var,
198
+ mock_get_user, mock_get_session):
199
+ """Test getting session ID tuple with fallback to context variables."""
200
+ mock_get_user.return_value = None
201
+ mock_get_session.return_value = None
202
+ mock_user_var.get.return_value = "context-user"
203
+ mock_session_var.get.return_value = "context-session"
204
+
205
+ result = get_session_id_tuple(None)
206
+
207
+ self.assertEqual(result, ("context-user", "context-session"))
208
+ mock_user_var.get.assert_called_once_with("default_user")
209
+ mock_session_var.get.assert_called_once_with("default_session")
210
+
211
+ @patch('aixtools.server.utils.get_session_id_from_request')
212
+ @patch('aixtools.server.utils.get_user_id_from_request')
213
+ @patch('aixtools.server.utils.session_id_var')
214
+ @patch('aixtools.server.utils.user_id_var')
215
+ def test_get_session_id_tuple_mixed_sources(self, mock_user_var, mock_session_var,
216
+ mock_get_user, mock_get_session):
217
+ """Test getting session ID tuple with mixed sources."""
218
+ mock_get_user.return_value = "header-user"
219
+ mock_get_session.return_value = None
220
+ mock_session_var.get.return_value = "context-session"
221
+
222
+ result = get_session_id_tuple(None)
223
+
224
+ self.assertEqual(result, ("header-user", "context-session"))
225
+
226
+ def test_get_session_id_tuple_with_context(self):
227
+ """Test getting session ID tuple with provided context."""
228
+ mock_ctx = Mock()
229
+
230
+ with patch('aixtools.server.utils.get_user_id_from_request') as mock_get_user, \
231
+ patch('aixtools.server.utils.get_session_id_from_request') as mock_get_session:
232
+
233
+ mock_get_user.return_value = "ctx-user"
234
+ mock_get_session.return_value = "ctx-session"
235
+
236
+ result = get_session_id_tuple(mock_ctx)
237
+
238
+ self.assertEqual(result, ("ctx-user", "ctx-session"))
239
+ mock_get_user.assert_called_once_with(mock_ctx)
240
+ mock_get_session.assert_called_once_with(mock_ctx)
241
+
242
+
243
+ class TestGetSessionIdStr(unittest.TestCase):
244
+ """Test cases for get_session_id_str function."""
245
+
246
+ @patch('aixtools.server.utils.get_session_id_tuple')
247
+ def test_get_session_id_str(self, mock_get_tuple):
248
+ """Test getting session ID string."""
249
+ mock_get_tuple.return_value = ("test-user", "test-session")
250
+
251
+ result = get_session_id_str(None)
252
+
253
+ self.assertEqual(result, "test-user:test-session")
254
+ mock_get_tuple.assert_called_once_with(None)
255
+
256
+ @patch('aixtools.server.utils.get_session_id_tuple')
257
+ def test_get_session_id_str_with_context(self, mock_get_tuple):
258
+ """Test getting session ID string with context."""
259
+ mock_ctx = Mock()
260
+ mock_get_tuple.return_value = ("ctx-user", "ctx-session")
261
+
262
+ result = get_session_id_str(mock_ctx)
263
+
264
+ self.assertEqual(result, "ctx-user:ctx-session")
265
+ mock_get_tuple.assert_called_once_with(mock_ctx)
266
+
267
+ @patch('aixtools.server.utils.get_session_id_tuple')
268
+ def test_get_session_id_str_special_characters(self, mock_get_tuple):
269
+ """Test getting session ID string with special characters."""
270
+ mock_get_tuple.return_value = ("user@domain.com", "session-123-abc")
271
+
272
+ result = get_session_id_str(None)
273
+
274
+ self.assertEqual(result, "user@domain.com:session-123-abc")
275
+
276
+
277
+ class TestRunInThread(unittest.IsolatedAsyncioTestCase):
278
+ """Test cases for run_in_thread decorator."""
279
+
280
+ async def test_run_in_thread_basic_function(self):
281
+ """Test run_in_thread decorator with basic function."""
282
+ @run_in_thread
283
+ def sync_function(x, y):
284
+ return x + y
285
+
286
+ result = await sync_function(5, 3) # type: ignore
287
+
288
+ self.assertEqual(result, 8)
289
+
290
+ async def test_run_in_thread_with_kwargs(self):
291
+ """Test run_in_thread decorator with keyword arguments."""
292
+ @run_in_thread
293
+ def sync_function(x, y, multiplier=1):
294
+ return (x + y) * multiplier
295
+
296
+ result = await sync_function(5, 3, multiplier=2) # type: ignore
297
+
298
+ self.assertEqual(result, 16)
299
+
300
+ async def test_run_in_thread_with_exception(self):
301
+ """Test run_in_thread decorator when function raises exception."""
302
+ @run_in_thread
303
+ def failing_function():
304
+ raise ValueError("Test error")
305
+
306
+ with self.assertRaises(ValueError) as context:
307
+ await failing_function() # type: ignore
308
+
309
+ self.assertEqual(str(context.exception), "Test error")
310
+
311
+ async def test_run_in_thread_preserves_function_metadata(self):
312
+ """Test that run_in_thread preserves function metadata."""
313
+ @run_in_thread
314
+ def documented_function(x):
315
+ """This is a test function."""
316
+ return x * 2
317
+
318
+ self.assertEqual(documented_function.__name__, "documented_function")
319
+ self.assertEqual(documented_function.__doc__, "This is a test function.")
320
+
321
+ async def test_run_in_thread_with_no_args(self):
322
+ """Test run_in_thread decorator with function that takes no arguments."""
323
+ @run_in_thread
324
+ def no_args_function():
325
+ return "success"
326
+
327
+ result = await no_args_function() # type: ignore
328
+
329
+ self.assertEqual(result, "success")
330
+
331
+ async def test_run_in_thread_with_complex_return_type(self):
332
+ """Test run_in_thread decorator with complex return type."""
333
+ @run_in_thread
334
+ def complex_function():
335
+ return {"key": "value", "list": [1, 2, 3], "nested": {"inner": True}}
336
+
337
+ result = await complex_function() # type: ignore
338
+
339
+ expected = {"key": "value", "list": [1, 2, 3], "nested": {"inner": True}}
340
+ self.assertEqual(result, expected)
341
+
342
+ @patch('asyncio.to_thread')
343
+ async def test_run_in_thread_calls_asyncio_to_thread(self, mock_to_thread):
344
+ """Test that run_in_thread actually calls asyncio.to_thread."""
345
+ mock_to_thread.return_value = "mocked_result"
346
+
347
+ @run_in_thread
348
+ def test_function(arg1, arg2, kwarg1=None):
349
+ return f"{arg1}-{arg2}-{kwarg1}"
350
+
351
+ result = await test_function("a", "b", kwarg1="c") # type: ignore
352
+
353
+ self.assertEqual(result, "mocked_result")
354
+ mock_to_thread.assert_called_once()
355
+ # Verify the original function and arguments were passed
356
+ args, kwargs = mock_to_thread.call_args
357
+ self.assertEqual(args[1:], ("a", "b")) # Skip the function itself
358
+ self.assertEqual(kwargs, {"kwarg1": "c"})
359
+
360
+
361
+ if __name__ == '__main__':
362
+ unittest.main()
File without changes
@@ -0,0 +1,146 @@
1
+ """Unit tests for aixtools.utils.files module."""
2
+
3
+ import unittest
4
+
5
+ from aixtools.utils.files import is_text_content
6
+
7
+
8
+ class TestIsTextContent(unittest.TestCase):
9
+ """Test cases for is_text_content function."""
10
+
11
+ def test_text_mime_types_return_true(self):
12
+ """Test that text mime types return True."""
13
+ text_mime_types = [
14
+ "text/plain",
15
+ "text/html",
16
+ "text/css",
17
+ "text/javascript",
18
+ "text/csv",
19
+ "text/xml",
20
+ "text/markdown",
21
+ ]
22
+
23
+ for mime_type in text_mime_types:
24
+ with self.subTest(mime_type=mime_type):
25
+ result = is_text_content(b"some content", mime_type)
26
+ self.assertTrue(result, f"MIME type {mime_type} should be detected as text")
27
+
28
+ def test_application_text_mime_types_return_true(self):
29
+ """Test that application text-like mime types return True."""
30
+ app_text_mime_types = [
31
+ "application/json",
32
+ "application/xml",
33
+ "application/javascript",
34
+ ]
35
+
36
+ for mime_type in app_text_mime_types:
37
+ with self.subTest(mime_type=mime_type):
38
+ result = is_text_content(b"some content", mime_type)
39
+ self.assertTrue(result, f"MIME type {mime_type} should be detected as text")
40
+
41
+ def test_binary_mime_types_with_valid_utf8_return_true(self):
42
+ """Test that binary mime types with valid UTF-8 content return True."""
43
+ binary_mime_types = [
44
+ "application/octet-stream",
45
+ "image/png",
46
+ "video/mp4",
47
+ "application/pdf",
48
+ ]
49
+
50
+ utf8_content = "Hello, world! 🌍".encode("utf-8")
51
+
52
+ for mime_type in binary_mime_types:
53
+ with self.subTest(mime_type=mime_type):
54
+ result = is_text_content(utf8_content, mime_type)
55
+ self.assertTrue(result, f"Valid UTF-8 content should be detected as text even with {mime_type}")
56
+
57
+ def test_binary_mime_types_with_invalid_utf8_return_false(self):
58
+ """Test that binary mime types with invalid UTF-8 content return False."""
59
+ binary_mime_types = [
60
+ "application/octet-stream",
61
+ "image/png",
62
+ "video/mp4",
63
+ "application/pdf",
64
+ ]
65
+
66
+ # Create invalid UTF-8 bytes
67
+ invalid_utf8_content = b'\x80\x81\x82\x83'
68
+
69
+ for mime_type in binary_mime_types:
70
+ with self.subTest(mime_type=mime_type):
71
+ result = is_text_content(invalid_utf8_content, mime_type)
72
+ self.assertFalse(result, f"Invalid UTF-8 content should not be detected as text with {mime_type}")
73
+
74
+ def test_empty_mime_type_with_valid_utf8_return_true(self):
75
+ """Test that empty mime type with valid UTF-8 content returns True."""
76
+ utf8_content = "Hello, world!".encode("utf-8")
77
+
78
+ result = is_text_content(utf8_content, "")
79
+ self.assertTrue(result)
80
+
81
+ def test_empty_mime_type_with_invalid_utf8_return_false(self):
82
+ """Test that empty mime type with invalid UTF-8 content returns False."""
83
+ invalid_utf8_content = b'\x80\x81\x82\x83'
84
+
85
+ result = is_text_content(invalid_utf8_content, "")
86
+ self.assertFalse(result)
87
+
88
+ def test_none_mime_type_with_valid_utf8_return_true(self):
89
+ """Test that None mime type with valid UTF-8 content returns True."""
90
+ utf8_content = "Hello, world!".encode("utf-8")
91
+
92
+ result = is_text_content(utf8_content, None) # type: ignore
93
+ self.assertTrue(result)
94
+
95
+ def test_none_mime_type_with_invalid_utf8_return_false(self):
96
+ """Test that None mime type with invalid UTF-8 content returns False."""
97
+ invalid_utf8_content = b'\x80\x81\x82\x83'
98
+
99
+ result = is_text_content(invalid_utf8_content, None) # type: ignore
100
+ self.assertFalse(result)
101
+
102
+ def test_empty_content_with_text_mime_type_return_true(self):
103
+ """Test that empty content with text mime type returns True."""
104
+ result = is_text_content(b"", "text/plain")
105
+ self.assertTrue(result)
106
+
107
+ def test_empty_content_with_binary_mime_type_return_true(self):
108
+ """Test that empty content with binary mime type returns True (empty is valid UTF-8)."""
109
+ result = is_text_content(b"", "application/octet-stream")
110
+ self.assertTrue(result)
111
+
112
+ def test_unicode_content_return_true(self):
113
+ """Test that Unicode content is properly detected as text."""
114
+ unicode_strings = [
115
+ "Hello, 世界!",
116
+ "Café ☕",
117
+ "🚀 Rocket",
118
+ "Здравствуй мир",
119
+ "مرحبا بالعالم",
120
+ ]
121
+
122
+ for unicode_str in unicode_strings:
123
+ with self.subTest(content=unicode_str):
124
+ utf8_content = unicode_str.encode("utf-8")
125
+ result = is_text_content(utf8_content, "application/octet-stream")
126
+ self.assertTrue(result, f"Unicode string '{unicode_str}' should be detected as text")
127
+
128
+ def test_binary_image_data_return_false(self):
129
+ """Test that actual binary image data returns False."""
130
+ # PNG file header
131
+ png_header = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR'
132
+
133
+ result = is_text_content(png_header, "image/png")
134
+ self.assertFalse(result)
135
+
136
+ def test_binary_executable_data_return_false(self):
137
+ """Test that binary executable data returns False."""
138
+ # Binary data with invalid UTF-8 sequences
139
+ binary_data = b'\x7f\x80\x81\x82\x83\x84\x85\x86'
140
+
141
+ result = is_text_content(binary_data, "application/octet-stream")
142
+ self.assertFalse(result)
143
+
144
+
145
+ if __name__ == '__main__':
146
+ unittest.main()
aixtools/a2a/__init__.py DELETED
@@ -1,5 +0,0 @@
1
- """A2A (Agent-to-Agent) communication utilities."""
2
-
3
- from .utils import fetch_agent_card, task, text_message, tool2skill
4
-
5
- __all__ = ["fetch_agent_card", "task", "text_message", "tool2skill"]