sunholo 0.60.9__tar.gz → 0.61.0__tar.gz

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.
Files changed (113) hide show
  1. {sunholo-0.60.9 → sunholo-0.61.0}/PKG-INFO +2 -2
  2. {sunholo-0.60.9 → sunholo-0.61.0}/setup.py +1 -1
  3. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo.egg-info/PKG-INFO +2 -2
  4. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo.egg-info/SOURCES.txt +3 -2
  5. sunholo-0.61.0/tests/test_chat_history.py +50 -0
  6. sunholo-0.61.0/tests/test_config.py +40 -0
  7. sunholo-0.60.9/sunholo/agents/test_chat_history.py +0 -119
  8. {sunholo-0.60.9 → sunholo-0.61.0}/LICENSE.txt +0 -0
  9. {sunholo-0.60.9 → sunholo-0.61.0}/MANIFEST.in +0 -0
  10. {sunholo-0.60.9 → sunholo-0.61.0}/README.md +0 -0
  11. {sunholo-0.60.9 → sunholo-0.61.0}/setup.cfg +0 -0
  12. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/__init__.py +0 -0
  13. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/agents/__init__.py +0 -0
  14. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/agents/chat_history.py +0 -0
  15. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/agents/dispatch_to_qa.py +0 -0
  16. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/agents/fastapi/__init__.py +0 -0
  17. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/agents/fastapi/base.py +0 -0
  18. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/agents/fastapi/qna_routes.py +0 -0
  19. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/agents/flask/__init__.py +0 -0
  20. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/agents/flask/base.py +0 -0
  21. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/agents/flask/qna_routes.py +0 -0
  22. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/agents/langserve.py +0 -0
  23. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/agents/pubsub.py +0 -0
  24. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/agents/route.py +0 -0
  25. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/agents/special_commands.py +0 -0
  26. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/archive/__init__.py +0 -0
  27. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/archive/archive.py +0 -0
  28. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/auth/__init__.py +0 -0
  29. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/auth/run.py +0 -0
  30. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/bots/__init__.py +0 -0
  31. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/bots/discord.py +0 -0
  32. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/bots/github_webhook.py +0 -0
  33. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/bots/webapp.py +0 -0
  34. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/chunker/__init__.py +0 -0
  35. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/chunker/data_to_embed_pubsub.py +0 -0
  36. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/chunker/doc_handling.py +0 -0
  37. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/chunker/images.py +0 -0
  38. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/chunker/loaders.py +0 -0
  39. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/chunker/message_data.py +0 -0
  40. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/chunker/pdfs.py +0 -0
  41. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/chunker/publish.py +0 -0
  42. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/chunker/splitter.py +0 -0
  43. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/cli/__init__.py +0 -0
  44. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/cli/chat_vac.py +0 -0
  45. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/cli/cli.py +0 -0
  46. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/cli/cli_init.py +0 -0
  47. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/cli/configs.py +0 -0
  48. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/cli/deploy.py +0 -0
  49. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/cli/merge_texts.py +0 -0
  50. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/cli/run_proxy.py +0 -0
  51. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/cli/sun_rich.py +0 -0
  52. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/components/__init__.py +0 -0
  53. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/components/llm.py +0 -0
  54. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/components/prompt.py +0 -0
  55. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/components/retriever.py +0 -0
  56. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/components/vectorstore.py +0 -0
  57. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/database/__init__.py +0 -0
  58. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/database/alloydb.py +0 -0
  59. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/database/database.py +0 -0
  60. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/database/lancedb.py +0 -0
  61. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/database/sql/sb/create_function.sql +0 -0
  62. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/database/sql/sb/create_function_time.sql +0 -0
  63. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/database/sql/sb/create_table.sql +0 -0
  64. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/database/sql/sb/delete_source_row.sql +0 -0
  65. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/database/sql/sb/return_sources.sql +0 -0
  66. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/database/sql/sb/setup.sql +0 -0
  67. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/database/static_dbs.py +0 -0
  68. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/database/uuid.py +0 -0
  69. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/embedder/__init__.py +0 -0
  70. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/embedder/embed_chunk.py +0 -0
  71. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/gcs/__init__.py +0 -0
  72. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/gcs/add_file.py +0 -0
  73. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/gcs/download_url.py +0 -0
  74. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/gcs/metadata.py +0 -0
  75. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/langfuse/__init__.py +0 -0
  76. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/langfuse/callback.py +0 -0
  77. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/langfuse/prompts.py +0 -0
  78. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/llamaindex/__init__.py +0 -0
  79. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/llamaindex/generate.py +0 -0
  80. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/llamaindex/import_files.py +0 -0
  81. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/logging.py +0 -0
  82. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/lookup/__init__.py +0 -0
  83. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/lookup/model_lookup.yaml +0 -0
  84. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/patches/__init__.py +0 -0
  85. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/patches/langchain/__init__.py +0 -0
  86. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/patches/langchain/lancedb.py +0 -0
  87. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/patches/langchain/vertexai.py +0 -0
  88. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/pubsub/__init__.py +0 -0
  89. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/pubsub/process_pubsub.py +0 -0
  90. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/pubsub/pubsub_manager.py +0 -0
  91. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/qna/__init__.py +0 -0
  92. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/qna/parsers.py +0 -0
  93. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/qna/retry.py +0 -0
  94. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/streaming/__init__.py +0 -0
  95. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/streaming/content_buffer.py +0 -0
  96. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/streaming/langserve.py +0 -0
  97. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/streaming/streaming.py +0 -0
  98. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/summarise/__init__.py +0 -0
  99. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/summarise/summarise.py +0 -0
  100. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/utils/__init__.py +0 -0
  101. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/utils/big_context.py +0 -0
  102. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/utils/config.py +0 -0
  103. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/utils/config_schema.py +0 -0
  104. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/utils/gcp.py +0 -0
  105. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/utils/parsers.py +0 -0
  106. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/utils/user_ids.py +0 -0
  107. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/vertex/__init__.py +0 -0
  108. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo/vertex/init_vertex.py +0 -0
  109. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo.egg-info/dependency_links.txt +0 -0
  110. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo.egg-info/entry_points.txt +0 -0
  111. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo.egg-info/requires.txt +0 -0
  112. {sunholo-0.60.9 → sunholo-0.61.0}/sunholo.egg-info/top_level.txt +0 -0
  113. {sunholo-0.60.9 → sunholo-0.61.0}/test/test_dispatch_to_qa.py +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sunholo
3
- Version: 0.60.9
3
+ Version: 0.61.0
4
4
  Summary: Large Language Model DevOps - a package to help deploy LLMs to the Cloud.
5
5
  Home-page: https://github.com/sunholo-data/sunholo-py
6
- Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.60.9.tar.gz
6
+ Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.61.0.tar.gz
7
7
  Author: Holosun ApS
8
8
  Author-email: multivac@sunholo.com
9
9
  License: Apache License, Version 2.0
@@ -1,7 +1,7 @@
1
1
  from setuptools import setup, find_packages
2
2
 
3
3
  # Define your base version
4
- version = '0.60.9'
4
+ version = '0.61.0'
5
5
 
6
6
  setup(
7
7
  name='sunholo',
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sunholo
3
- Version: 0.60.9
3
+ Version: 0.61.0
4
4
  Summary: Large Language Model DevOps - a package to help deploy LLMs to the Cloud.
5
5
  Home-page: https://github.com/sunholo-data/sunholo-py
6
- Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.60.9.tar.gz
6
+ Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.61.0.tar.gz
7
7
  Author: Holosun ApS
8
8
  Author-email: multivac@sunholo.com
9
9
  License: Apache License, Version 2.0
@@ -18,7 +18,6 @@ sunholo/agents/langserve.py
18
18
  sunholo/agents/pubsub.py
19
19
  sunholo/agents/route.py
20
20
  sunholo/agents/special_commands.py
21
- sunholo/agents/test_chat_history.py
22
21
  sunholo/agents/fastapi/__init__.py
23
22
  sunholo/agents/fastapi/base.py
24
23
  sunholo/agents/fastapi/qna_routes.py
@@ -107,4 +106,6 @@ sunholo/utils/parsers.py
107
106
  sunholo/utils/user_ids.py
108
107
  sunholo/vertex/__init__.py
109
108
  sunholo/vertex/init_vertex.py
110
- test/test_dispatch_to_qa.py
109
+ test/test_dispatch_to_qa.py
110
+ tests/test_chat_history.py
111
+ tests/test_config.py
@@ -0,0 +1,50 @@
1
+ import pytest
2
+ from sunholo.agents.chat_history import extract_chat_history, embeds_to_json, create_message_element, is_human, is_bot, is_ai
3
+
4
+ # Test cases for extract_chat_history function
5
+ @pytest.mark.parametrize("chat_history,expected", [
6
+ ([], []),
7
+ ([{"name": "Human", "text": "Hello, AI!"}, {"name": "AI", "text": "Hello, Human! How can I help you today?"}], [("Hello, AI!", "Hello, Human! How can I help you today?")])
8
+ ])
9
+ def test_extract_chat_history(chat_history, expected):
10
+ assert extract_chat_history(chat_history) == expected
11
+
12
+ # Test cases for embeds_to_json function
13
+ @pytest.mark.parametrize("message,expected", [
14
+ ({"embeds": []}, ""),
15
+ ({"embeds": [{"type": "image", "url": "https://example.com/image.png"}]}, '[{"type": "image", "url": "https://example.com/image.png"}]')
16
+ ])
17
+ def test_embeds_to_json(message, expected):
18
+ assert embeds_to_json(message) == expected
19
+
20
+ # Test cases for create_message_element function
21
+ @pytest.mark.parametrize("message,expected", [
22
+ ({"text": "Hello, AI!"}, "Hello, AI!"),
23
+ ({"content": "Hello, AI!"}, "Hello, AI!")
24
+ ])
25
+ def test_create_message_element(message, expected):
26
+ assert create_message_element(message) == expected
27
+
28
+ # Test cases for is_human function
29
+ @pytest.mark.parametrize("message,expected", [
30
+ ({"name": "Human"}, True),
31
+ ({"name": "AI"}, False)
32
+ ])
33
+ def test_is_human(message, expected):
34
+ assert is_human(message) == expected
35
+
36
+ # Test cases for is_bot function
37
+ @pytest.mark.parametrize("message,expected", [
38
+ ({"name": "AI"}, True),
39
+ ({"name": "Human"}, False)
40
+ ])
41
+ def test_is_bot(message, expected):
42
+ assert is_bot(message) == expected
43
+
44
+ # Test cases for is_ai function
45
+ @pytest.mark.parametrize("message,expected", [
46
+ ({"name": "AI"}, True),
47
+ ({"name": "Human"}, False)
48
+ ])
49
+ def test_is_ai(message, expected):
50
+ assert is_ai(message) == expected
@@ -0,0 +1,40 @@
1
+ import pytest
2
+ from sunholo.utils import config
3
+
4
+ # Test for the `load_config` function
5
+ def test_load_config():
6
+ # Assuming the function is supposed to load a configuration from a file
7
+ # and return a dictionary with the configuration data
8
+ expected_config = {"key": "value"}
9
+ with pytest.raises(FileNotFoundError):
10
+ config.load_config("non_existent_file")
11
+ with pytest.mock.patch("builtins.open", pytest.mock.mock_open(read_data="key: value"), create=True):
12
+ assert config.load_config("mock_file.yaml") == expected_config
13
+
14
+ # Test for the `load_config_key` function
15
+ def test_load_config_key():
16
+ # Assuming the function is supposed to load a specific key from the configuration
17
+ expected_value = "value"
18
+ with pytest.raises(KeyError):
19
+ config.load_config_key("non_existent_key", "mock_vector_name")
20
+ with pytest.mock.patch("sunholo.utils.config.load_all_configs", return_value={"mock_vector_name": {"key": "value"}}):
21
+ assert config.load_config_key("key", "mock_vector_name") == expected_value
22
+
23
+ # Test for the `get_module_filepath` function
24
+ def test_get_module_filepath():
25
+ # Assuming the function is supposed to return the absolute path of a module file
26
+ expected_path = "/absolute/path/to/module/file"
27
+ with pytest.mock.patch("os.path.dirname", return_value="/absolute/path/to"):
28
+ assert config.get_module_filepath("module/file") == expected_path
29
+
30
+ # Test for the `fetch_config` function
31
+ def test_fetch_config():
32
+ # Assuming the function is supposed to fetch configuration from a cloud storage bucket
33
+ expected_update_time = "2022-01-01T00:00:00Z"
34
+ with pytest.mock.patch("google.cloud.storage.Client") as mock_client:
35
+ mock_bucket = mock_client.return_value.get_bucket.return_value
36
+ mock_blob = mock_bucket.get_blob.return_value
37
+ mock_blob.updated = expected_update_time
38
+ assert config.fetch_config("bucket_name", "blob_name") == expected_update_time
39
+ mock_bucket.get_blob.return_value = None
40
+ assert config.fetch_config("bucket_name", "blob_name") is None
@@ -1,119 +0,0 @@
1
- import pytest
2
- from .chat_history import *
3
-
4
-
5
- def test_extract_chat_history_null_input():
6
- assert extract_chat_history(None) == [], 'Expected empty list for null input'
7
-
8
-
9
- def test_extract_chat_history_no_chat():
10
- assert extract_chat_history([]) == [], 'Expected empty list for no chat history'
11
-
12
-
13
- def test_extract_chat_history_with_chat():
14
- chat_history = [('User', 'Hello'), ('Bot', 'Hi'), ('User', 'How are you?'), ('Bot', 'I am fine.')]
15
- expected_output = [('User', 'Hello'), ('Bot', 'Hi'), ('User', 'How are you?'), ('Bot', 'I am fine.')]
16
- assert extract_chat_history(chat_history) == expected_output, 'Expected list of paired messages for chat history'
17
-
18
-
19
- # Test cases for embeds_to_json function
20
-
21
- def test_embeds_to_json_no_embeds():
22
- message = 'Hello, world!'
23
- assert embeds_to_json(message) == '', 'Expected empty string for message with no embeds'
24
-
25
-
26
- def test_embeds_to_json_one_embed():
27
- message = 'Hello, world! [embed]'
28
- expected_output = '{"embeds": ["embed"]}'
29
- assert embeds_to_json(message) == expected_output, 'Expected JSON string with one embed for message with one embed'
30
-
31
-
32
- def test_embeds_to_json_multiple_embeds():
33
- message = 'Hello, world! [embed1] [embed2]'
34
- expected_output = '{"embeds": ["embed1", "embed2"]}'
35
- assert embeds_to_json(message) == expected_output, 'Expected JSON string with multiple embeds for message with multiple embeds'
36
-
37
-
38
- # Test cases for create_message_element function
39
-
40
- def test_create_message_element_text():
41
- message = {'text': 'Hello, world!'}
42
- assert create_message_element(message) == 'Hello, world!', 'Expected text element for message with text'
43
-
44
-
45
- def test_create_message_element_content():
46
- message = {'content': 'Hello, world!'}
47
- assert create_message_element(message) == 'Hello, world!', 'Expected content element for message with content'
48
-
49
-
50
- def test_create_message_element_no_text_or_content():
51
- message = {}
52
- with pytest.raises(KeyError):
53
- create_message_element(message)
54
-
55
-
56
- # Test cases for is_human function
57
-
58
- def test_is_human_name_human():
59
- message = {'name': 'Human'}
60
- assert is_human(message) == True, 'Expected True for message with name Human'
61
-
62
-
63
- def test_is_human_sender_type_human():
64
- message = {'sender': {'type': 'HUMAN'}}
65
- assert is_human(message) == True, 'Expected True for message with sender type HUMAN'
66
-
67
-
68
- def test_is_human_user_no_bot_id():
69
- message = {'user': 'User1', 'bot_id': None}
70
- assert is_human(message) == True, 'Expected True for message with user field and no bot_id field'
71
-
72
-
73
- def test_is_human_not_human():
74
- message = {'name': 'Bot'}
75
- assert is_human(message) == False, 'Expected False for message not from a human'
76
-
77
-
78
- # Test cases for is_bot function
79
-
80
- def test_is_bot_name_bot():
81
- message = {'name': 'Bot'}
82
- assert is_bot(message) == True, 'Expected True for message with name Bot'
83
-
84
-
85
- def test_is_bot_sender_type_bot():
86
- message = {'sender': {'type': 'BOT'}}
87
- assert is_bot(message) == True, 'Expected True for message with sender type BOT'
88
-
89
-
90
- def test_is_bot_with_bot_id():
91
- message = {'bot_id': 'bot1'}
92
- assert is_bot(message) == True, 'Expected True for message with bot_id field'
93
-
94
-
95
- def test_is_bot_not_bot():
96
- message = {'name': 'Human'}
97
- assert is_bot(message) == False, 'Expected False for message not from a bot'
98
-
99
-
100
- # Test cases for is_ai function
101
-
102
- def test_is_ai_name_ai():
103
- message = {'name': 'AI'}
104
- assert is_ai(message) == True, 'Expected True for message with name AI'
105
-
106
-
107
- def test_is_ai_sender_type_bot():
108
- message = {'sender': {'type': 'BOT'}}
109
- assert is_ai(message) == True, 'Expected True for message with sender type BOT'
110
-
111
-
112
- def test_is_ai_with_bot_id():
113
- message = {'bot_id': 'bot1'}
114
- assert is_ai(message) == True, 'Expected True for message with bot_id field'
115
-
116
-
117
- def test_is_ai_not_ai():
118
- message = {'name': 'Human'}
119
- assert is_ai(message) == False, 'Expected False for message not from an AI'
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes