pygeai 0.6.0b14__py3-none-any.whl → 0.6.1__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.
- pygeai/__init__.py +1 -2
- pygeai/_docs/source/content/api_reference/project.rst +392 -0
- pygeai/_docs/source/content/authentication.rst +130 -1
- pygeai/_docs/source/content/debugger.rst +327 -157
- pygeai/_docs/source/pygeai.core.common.rst +8 -0
- pygeai/_docs/source/pygeai.tests.auth.rst +56 -0
- pygeai/_docs/source/pygeai.tests.cli.rst +8 -0
- pygeai/admin/clients.py +1 -3
- pygeai/analytics/clients.py +1 -1
- pygeai/assistant/clients.py +2 -7
- pygeai/assistant/data/clients.py +0 -8
- pygeai/assistant/data_analyst/clients.py +0 -2
- pygeai/assistant/managers.py +1 -1
- pygeai/assistant/rag/clients.py +0 -2
- pygeai/assistant/rag/mappers.py +9 -11
- pygeai/auth/clients.py +26 -7
- pygeai/auth/endpoints.py +2 -1
- pygeai/chat/clients.py +2 -2
- pygeai/chat/managers.py +1 -1
- pygeai/cli/commands/admin.py +13 -25
- pygeai/cli/commands/analytics.py +31 -71
- pygeai/cli/commands/assistant.py +84 -138
- pygeai/cli/commands/auth.py +23 -46
- pygeai/cli/commands/base.py +0 -1
- pygeai/cli/commands/chat.py +218 -209
- pygeai/cli/commands/common.py +5 -5
- pygeai/cli/commands/configuration.py +79 -29
- pygeai/cli/commands/docs.py +3 -4
- pygeai/cli/commands/embeddings.py +13 -19
- pygeai/cli/commands/evaluation.py +133 -344
- pygeai/cli/commands/feedback.py +7 -15
- pygeai/cli/commands/files.py +26 -53
- pygeai/cli/commands/gam.py +28 -69
- pygeai/cli/commands/lab/ai_lab.py +96 -142
- pygeai/cli/commands/lab/common.py +1 -1
- pygeai/cli/commands/lab/spec.py +12 -32
- pygeai/cli/commands/llm.py +9 -18
- pygeai/cli/commands/migrate.py +43 -99
- pygeai/cli/commands/organization.py +223 -196
- pygeai/cli/commands/rag.py +35 -58
- pygeai/cli/commands/rerank.py +21 -25
- pygeai/cli/commands/secrets.py +39 -67
- pygeai/cli/commands/usage_limits.py +50 -136
- pygeai/cli/commands/validators.py +1 -1
- pygeai/cli/geai.py +32 -3
- pygeai/cli/geai_proxy.py +6 -2
- pygeai/cli/install_man.py +1 -1
- pygeai/cli/parsers.py +1 -1
- pygeai/core/base/clients.py +90 -21
- pygeai/core/base/mappers.py +39 -55
- pygeai/core/base/session.py +129 -18
- pygeai/core/common/config.py +50 -13
- pygeai/core/common/constants.py +8 -0
- pygeai/core/common/exceptions.py +6 -0
- pygeai/core/embeddings/clients.py +0 -1
- pygeai/core/embeddings/managers.py +0 -1
- pygeai/core/feedback/clients.py +0 -2
- pygeai/core/feedback/models.py +1 -1
- pygeai/core/files/clients.py +0 -3
- pygeai/core/files/managers.py +1 -1
- pygeai/core/files/mappers.py +4 -5
- pygeai/core/llm/clients.py +0 -1
- pygeai/core/models.py +4 -4
- pygeai/core/plugins/clients.py +0 -3
- pygeai/core/plugins/models.py +2 -2
- pygeai/core/rerank/clients.py +0 -2
- pygeai/core/secrets/clients.py +0 -2
- pygeai/core/services/rest.py +80 -14
- pygeai/core/singleton.py +24 -0
- pygeai/dbg/__init__.py +2 -2
- pygeai/dbg/debugger.py +276 -38
- pygeai/evaluation/clients.py +2 -4
- pygeai/evaluation/dataset/clients.py +0 -1
- pygeai/evaluation/plan/clients.py +0 -2
- pygeai/evaluation/result/clients.py +0 -2
- pygeai/gam/clients.py +1 -3
- pygeai/health/clients.py +1 -3
- pygeai/lab/clients.py +0 -1
- pygeai/lab/managers.py +0 -1
- pygeai/lab/models.py +0 -1
- pygeai/lab/strategies/clients.py +1 -2
- pygeai/lab/tools/clients.py +2 -2
- pygeai/lab/tools/mappers.py +1 -1
- pygeai/migration/strategies.py +5 -6
- pygeai/migration/tools.py +1 -1
- pygeai/organization/clients.py +118 -12
- pygeai/organization/endpoints.py +1 -0
- pygeai/organization/limits/clients.py +4 -6
- pygeai/organization/limits/managers.py +1 -4
- pygeai/organization/managers.py +2 -2
- pygeai/proxy/config.py +1 -0
- pygeai/proxy/managers.py +6 -5
- pygeai/tests/admin/test_clients.py +11 -11
- pygeai/tests/assistants/rag/test_clients.py +1 -1
- pygeai/tests/assistants/rag/test_models.py +1 -2
- pygeai/tests/assistants/test_clients.py +1 -1
- pygeai/tests/assistants/test_managers.py +1 -3
- pygeai/tests/auth/test_cli_configuration.py +252 -0
- pygeai/tests/auth/test_client_initialization.py +411 -0
- pygeai/tests/auth/test_clients.py +29 -27
- pygeai/tests/auth/test_config_manager.py +305 -0
- pygeai/tests/auth/test_header_injection.py +294 -0
- pygeai/tests/auth/test_oauth.py +3 -1
- pygeai/tests/auth/test_session_logging.py +119 -0
- pygeai/tests/auth/test_session_validation.py +408 -0
- pygeai/tests/auth/test_singleton_reset.py +201 -0
- pygeai/tests/chat/test_clients.py +1 -1
- pygeai/tests/chat/test_iris.py +1 -1
- pygeai/tests/chat/test_ui.py +0 -2
- pygeai/tests/cli/commands/lab/test_ai_lab.py +1 -3
- pygeai/tests/cli/commands/lab/test_common.py +0 -1
- pygeai/tests/cli/commands/test_chat.py +1 -1
- pygeai/tests/cli/commands/test_common.py +0 -1
- pygeai/tests/cli/commands/test_embeddings.py +2 -2
- pygeai/tests/cli/commands/test_evaluation.py +1 -9
- pygeai/tests/cli/commands/test_llm.py +1 -1
- pygeai/tests/cli/commands/test_migrate.py +1 -1
- pygeai/tests/cli/commands/test_rerank.py +0 -1
- pygeai/tests/cli/commands/test_secrets.py +1 -1
- pygeai/tests/cli/commands/test_show_help.py +0 -1
- pygeai/tests/cli/commands/test_validators.py +0 -1
- pygeai/tests/cli/test_credentials_flag.py +312 -0
- pygeai/tests/cli/test_error_handler.py +0 -1
- pygeai/tests/core/base/test_mappers.py +2 -2
- pygeai/tests/core/base/test_models.py +4 -4
- pygeai/tests/core/common/test_config.py +2 -7
- pygeai/tests/core/common/test_decorators.py +0 -1
- pygeai/tests/core/embeddings/test_managers.py +1 -1
- pygeai/tests/core/feedback/test_clients.py +2 -2
- pygeai/tests/core/files/test_clients.py +6 -6
- pygeai/tests/core/files/test_models.py +0 -1
- pygeai/tests/core/files/test_responses.py +0 -1
- pygeai/tests/core/llm/test_clients.py +1 -1
- pygeai/tests/core/plugins/test_clients.py +4 -4
- pygeai/tests/core/rerank/test_mappers.py +1 -3
- pygeai/tests/core/secrets/test_clients.py +2 -3
- pygeai/tests/core/services/test_rest.py +10 -10
- pygeai/tests/core/utils/test_console.py +0 -1
- pygeai/tests/dbg/test_debugger.py +95 -8
- pygeai/tests/evaluation/dataset/test_clients.py +24 -27
- pygeai/tests/evaluation/plan/test_clients.py +16 -18
- pygeai/tests/evaluation/result/test_clients.py +4 -5
- pygeai/tests/health/test_clients.py +2 -2
- pygeai/tests/integration/lab/agents/test_create_agent.py +1 -3
- pygeai/tests/integration/lab/agents/test_get_agent.py +1 -1
- pygeai/tests/integration/lab/processes/test_create_process.py +2 -2
- pygeai/tests/integration/lab/processes/test_create_task.py +2 -3
- pygeai/tests/integration/lab/processes/test_delete_process.py +0 -1
- pygeai/tests/integration/lab/processes/test_get_process.py +2 -4
- pygeai/tests/integration/lab/processes/test_list_process_instances.py +1 -3
- pygeai/tests/integration/lab/processes/test_update_process.py +3 -9
- pygeai/tests/integration/lab/reasoning_strategies/test_update_reasoning_strategy.py +1 -2
- pygeai/tests/integration/lab/tools/test_delete_tool.py +1 -1
- pygeai/tests/integration/lab/tools/test_list_tools.py +1 -1
- pygeai/tests/integration/lab/tools/test_update_tool.py +1 -1
- pygeai/tests/lab/agents/test_clients.py +17 -17
- pygeai/tests/lab/processes/test_clients.py +67 -67
- pygeai/tests/lab/processes/test_mappers.py +23 -23
- pygeai/tests/lab/spec/test_loader.py +0 -2
- pygeai/tests/lab/spec/test_parsers.py +1 -2
- pygeai/tests/lab/strategies/test_clients.py +10 -10
- pygeai/tests/lab/test_managers.py +3 -5
- pygeai/tests/lab/test_mappers.py +1 -4
- pygeai/tests/lab/tools/test_clients.py +21 -21
- pygeai/tests/lab/tools/test_mappers.py +0 -1
- pygeai/tests/organization/limits/test_clients.py +33 -33
- pygeai/tests/organization/limits/test_managers.py +7 -7
- pygeai/tests/organization/test_clients.py +78 -60
- pygeai/tests/proxy/test_clients.py +1 -1
- pygeai/tests/proxy/test_integration.py +1 -4
- pygeai/tests/proxy/test_managers.py +1 -2
- pygeai/tests/proxy/test_servers.py +1 -2
- pygeai/tests/snippets/assistants/rag/delete_rag_assistant.py +0 -1
- pygeai/tests/snippets/assistants/rag/get_documents.py +0 -1
- pygeai/tests/snippets/assistants/rag/get_rag_assistant_data.py +0 -1
- pygeai/tests/snippets/chat/get_request_status.py +0 -1
- pygeai/tests/snippets/dbg/file_debugging.py +72 -0
- pygeai/tests/snippets/dbg/module_debugging.py +60 -0
- pygeai/tests/snippets/embeddings/cohere_example.py +2 -2
- pygeai/tests/snippets/embeddings/openai_base64_example.py +1 -1
- pygeai/tests/snippets/evaluation/dataset/complete_workflow_example.py +8 -8
- pygeai/tests/snippets/evaluation/plan/complete_workflow_example.py +5 -5
- pygeai/tests/snippets/evaluation/result/complete_workflow_example.py +3 -3
- pygeai/tests/snippets/lab/agentic_flow_example_1.py +1 -1
- pygeai/tests/snippets/lab/agentic_flow_example_2.py +3 -4
- pygeai/tests/snippets/lab/agents/create_agent_with_permissions.py +2 -2
- pygeai/tests/snippets/lab/agents/delete_agent.py +1 -2
- pygeai/tests/snippets/lab/agents/get_agent.py +1 -1
- pygeai/tests/snippets/lab/agents/get_agent_with_new_fields.py +10 -10
- pygeai/tests/snippets/lab/agents/get_sharing_link.py +0 -1
- pygeai/tests/snippets/lab/agents/list_agents.py +1 -1
- pygeai/tests/snippets/lab/agents/publish_agent_revision.py +0 -1
- pygeai/tests/snippets/lab/agents/update_agent_properties.py +1 -1
- pygeai/tests/snippets/lab/crud_ui.py +3 -5
- pygeai/tests/snippets/lab/processes/kbs/get_kb.py +0 -1
- pygeai/tests/snippets/lab/processes/kbs/list_kbs.py +0 -1
- pygeai/tests/snippets/lab/processes/list_processes.py +1 -1
- pygeai/tests/snippets/lab/samples/summarize_files.py +0 -3
- pygeai/tests/snippets/lab/strategies/get_reasoning_strategy.py +0 -1
- pygeai/tests/snippets/lab/strategies/list_reasoning_strategies.py +1 -1
- pygeai/tests/snippets/lab/tools/get_tool.py +1 -1
- pygeai/tests/snippets/lab/tools/publish_tool_revision.py +0 -1
- pygeai/tests/snippets/lab/tools/set_parameters.py +1 -2
- pygeai/tests/snippets/lab/use_cases/c_code_fixer_agent_flow.py +2 -3
- pygeai/tests/snippets/lab/use_cases/file_summarizer_example_2.py +1 -1
- pygeai/tests/snippets/lab/use_cases/update_cli_expert.py +0 -1
- pygeai/tests/snippets/lab/use_cases/update_lab_expert.py +0 -1
- pygeai/tests/snippets/lab/use_cases/update_web_designer.py +0 -1
- pygeai/tests/snippets/lab/use_cases/update_web_reader.py +0 -1
- pygeai/tests/snippets/migrate/orchestrator_examples.py +1 -1
- {pygeai-0.6.0b14.dist-info → pygeai-0.6.1.dist-info}/METADATA +32 -7
- {pygeai-0.6.0b14.dist-info → pygeai-0.6.1.dist-info}/RECORD +216 -205
- {pygeai-0.6.0b14.dist-info → pygeai-0.6.1.dist-info}/WHEEL +0 -0
- {pygeai-0.6.0b14.dist-info → pygeai-0.6.1.dist-info}/entry_points.txt +0 -0
- {pygeai-0.6.0b14.dist-info → pygeai-0.6.1.dist-info}/licenses/LICENSE +0 -0
- {pygeai-0.6.0b14.dist-info → pygeai-0.6.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import warnings
|
|
3
|
+
import logging
|
|
4
|
+
import io
|
|
5
|
+
import tempfile
|
|
6
|
+
import os
|
|
7
|
+
|
|
8
|
+
from pygeai.core.base.session import Session, get_session, reset_session, _validate_alias
|
|
9
|
+
from pygeai.core.common.config import reset_settings, get_settings
|
|
10
|
+
from pygeai.core.common.constants import AuthType
|
|
11
|
+
from pygeai.core.common.exceptions import MissingRequirementException, MixedAuthenticationException
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TestSessionValidation(unittest.TestCase):
|
|
15
|
+
"""
|
|
16
|
+
Tests for Session validation, warnings, and error handling.
|
|
17
|
+
|
|
18
|
+
python -m unittest pygeai.tests.auth.test_session_validation.TestSessionValidation
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def setUp(self):
|
|
22
|
+
"""Set up test fixtures"""
|
|
23
|
+
reset_session()
|
|
24
|
+
reset_settings()
|
|
25
|
+
|
|
26
|
+
self.log_capture = io.StringIO()
|
|
27
|
+
self.handler = logging.StreamHandler(self.log_capture)
|
|
28
|
+
self.handler.setLevel(logging.WARNING)
|
|
29
|
+
|
|
30
|
+
self.geai_logger = logging.getLogger('geai')
|
|
31
|
+
self._original_handlers = self.geai_logger.handlers.copy()
|
|
32
|
+
self._original_level = self.geai_logger.level
|
|
33
|
+
|
|
34
|
+
self.geai_logger.handlers = []
|
|
35
|
+
self.geai_logger.addHandler(self.handler)
|
|
36
|
+
self.geai_logger.setLevel(logging.WARNING)
|
|
37
|
+
self.geai_logger.propagate = False
|
|
38
|
+
|
|
39
|
+
def tearDown(self):
|
|
40
|
+
"""Clean up test fixtures"""
|
|
41
|
+
self.geai_logger.handlers = self._original_handlers
|
|
42
|
+
self.geai_logger.level = self._original_level
|
|
43
|
+
reset_session()
|
|
44
|
+
reset_settings()
|
|
45
|
+
|
|
46
|
+
def test_oauth_requires_project_id(self):
|
|
47
|
+
"""Test that OAuth access_token requires project_id"""
|
|
48
|
+
with self.assertRaises(MissingRequirementException) as context:
|
|
49
|
+
Session(
|
|
50
|
+
base_url="https://api.test.com",
|
|
51
|
+
access_token="oauth_token_123"
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
self.assertIn("project_id", str(context.exception).lower())
|
|
55
|
+
|
|
56
|
+
def test_project_id_without_access_token_warns(self):
|
|
57
|
+
"""Test that project_id without access_token issues UserWarning"""
|
|
58
|
+
with warnings.catch_warnings(record=True) as w:
|
|
59
|
+
warnings.simplefilter("always")
|
|
60
|
+
|
|
61
|
+
session = Session(
|
|
62
|
+
api_key="api_key_123",
|
|
63
|
+
base_url="https://api.test.com",
|
|
64
|
+
project_id="project-123"
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
self.assertEqual(len(w), 1)
|
|
68
|
+
self.assertTrue(issubclass(w[0].category, UserWarning))
|
|
69
|
+
self.assertIn("project_id provided without access_token", str(w[0].message))
|
|
70
|
+
|
|
71
|
+
def test_mixed_auth_without_allow_raises_error(self):
|
|
72
|
+
"""Test that both api_key and access_token without allow_mixed_auth raises MixedAuthenticationException"""
|
|
73
|
+
with self.assertRaises(MixedAuthenticationException) as context:
|
|
74
|
+
Session(
|
|
75
|
+
api_key="api_key_123",
|
|
76
|
+
base_url="https://api.test.com",
|
|
77
|
+
access_token="oauth_token_123",
|
|
78
|
+
project_id="project-456",
|
|
79
|
+
allow_mixed_auth=False
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
self.assertIn("Cannot specify both", str(context.exception))
|
|
83
|
+
|
|
84
|
+
def test_mixed_auth_with_allow_succeeds(self):
|
|
85
|
+
"""Test that mixed auth works when allow_mixed_auth=True"""
|
|
86
|
+
session = Session(
|
|
87
|
+
api_key="api_key_123",
|
|
88
|
+
base_url="https://api.test.com",
|
|
89
|
+
access_token="oauth_token_123",
|
|
90
|
+
project_id="project-456",
|
|
91
|
+
allow_mixed_auth=True
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
self.assertEqual(session.api_key, "api_key_123")
|
|
95
|
+
self.assertEqual(session.access_token, "oauth_token_123")
|
|
96
|
+
self.assertEqual(session.project_id, "project-456")
|
|
97
|
+
self.assertEqual(session.auth_type, AuthType.OAUTH_TOKEN)
|
|
98
|
+
|
|
99
|
+
def test_no_authentication_logs_warning(self):
|
|
100
|
+
"""Test that no authentication method logs warning"""
|
|
101
|
+
Session(base_url="https://api.test.com")
|
|
102
|
+
|
|
103
|
+
log_output = self.log_capture.getvalue()
|
|
104
|
+
self.assertIn("No authentication method configured", log_output)
|
|
105
|
+
|
|
106
|
+
def test_no_base_url_logs_warning(self):
|
|
107
|
+
"""Test that missing base_url logs warning"""
|
|
108
|
+
Session(api_key="api_key_123")
|
|
109
|
+
|
|
110
|
+
log_output = self.log_capture.getvalue()
|
|
111
|
+
self.assertIn("Cannot instantiate session without base_url", log_output)
|
|
112
|
+
|
|
113
|
+
def test_auth_type_api_key_only(self):
|
|
114
|
+
"""Test auth type is API_KEY when only api_key is provided"""
|
|
115
|
+
session = Session(
|
|
116
|
+
api_key="api_key_123",
|
|
117
|
+
base_url="https://api.test.com"
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
self.assertEqual(session.auth_type, AuthType.API_KEY)
|
|
121
|
+
self.assertTrue(session.is_api_key())
|
|
122
|
+
self.assertFalse(session.is_oauth())
|
|
123
|
+
|
|
124
|
+
def test_auth_type_oauth_only(self):
|
|
125
|
+
"""Test auth type is OAUTH_TOKEN when OAuth credentials are provided"""
|
|
126
|
+
session = Session(
|
|
127
|
+
base_url="https://api.test.com",
|
|
128
|
+
access_token="oauth_token_123",
|
|
129
|
+
project_id="project-456"
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
self.assertEqual(session.auth_type, AuthType.OAUTH_TOKEN)
|
|
133
|
+
self.assertTrue(session.is_oauth())
|
|
134
|
+
self.assertFalse(session.is_api_key())
|
|
135
|
+
|
|
136
|
+
def test_auth_type_none(self):
|
|
137
|
+
"""Test auth type is NONE when no credentials are provided"""
|
|
138
|
+
session = Session(base_url="https://api.test.com")
|
|
139
|
+
|
|
140
|
+
self.assertEqual(session.auth_type, AuthType.NONE)
|
|
141
|
+
self.assertFalse(session.is_oauth())
|
|
142
|
+
self.assertFalse(session.is_api_key())
|
|
143
|
+
|
|
144
|
+
def test_auth_type_oauth_takes_precedence(self):
|
|
145
|
+
"""Test that OAuth takes precedence over API key when both are present"""
|
|
146
|
+
session = Session(
|
|
147
|
+
api_key="api_key_123",
|
|
148
|
+
base_url="https://api.test.com",
|
|
149
|
+
access_token="oauth_token_123",
|
|
150
|
+
project_id="project-456",
|
|
151
|
+
allow_mixed_auth=True
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
self.assertEqual(session.auth_type, AuthType.OAUTH_TOKEN)
|
|
155
|
+
|
|
156
|
+
def test_get_active_token_api_key(self):
|
|
157
|
+
"""Test get_active_token returns api_key when using API key auth"""
|
|
158
|
+
session = Session(
|
|
159
|
+
api_key="api_key_123",
|
|
160
|
+
base_url="https://api.test.com"
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
self.assertEqual(session.get_active_token(), "api_key_123")
|
|
164
|
+
|
|
165
|
+
def test_get_active_token_oauth(self):
|
|
166
|
+
"""Test get_active_token returns access_token when using OAuth"""
|
|
167
|
+
session = Session(
|
|
168
|
+
base_url="https://api.test.com",
|
|
169
|
+
access_token="oauth_token_123",
|
|
170
|
+
project_id="project-456"
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
self.assertEqual(session.get_active_token(), "oauth_token_123")
|
|
174
|
+
|
|
175
|
+
def test_get_active_token_none(self):
|
|
176
|
+
"""Test get_active_token returns None when no auth is configured"""
|
|
177
|
+
session = Session(base_url="https://api.test.com")
|
|
178
|
+
|
|
179
|
+
self.assertIsNone(session.get_active_token())
|
|
180
|
+
|
|
181
|
+
def test_setter_updates_auth_type_api_key(self):
|
|
182
|
+
"""Test that setting api_key updates auth type"""
|
|
183
|
+
session = Session(base_url="https://api.test.com")
|
|
184
|
+
self.assertEqual(session.auth_type, AuthType.NONE)
|
|
185
|
+
|
|
186
|
+
session.api_key = "new_api_key"
|
|
187
|
+
self.assertEqual(session.auth_type, AuthType.API_KEY)
|
|
188
|
+
|
|
189
|
+
def test_setter_updates_auth_type_oauth(self):
|
|
190
|
+
"""Test that setting OAuth properties updates auth type"""
|
|
191
|
+
session = Session(
|
|
192
|
+
api_key="api_key_123",
|
|
193
|
+
base_url="https://api.test.com"
|
|
194
|
+
)
|
|
195
|
+
self.assertEqual(session.auth_type, AuthType.API_KEY)
|
|
196
|
+
|
|
197
|
+
session.access_token = "oauth_token_123"
|
|
198
|
+
session.project_id = "project-456"
|
|
199
|
+
self.assertEqual(session.auth_type, AuthType.OAUTH_TOKEN)
|
|
200
|
+
|
|
201
|
+
def test_alias_defaults_to_default(self):
|
|
202
|
+
"""Test that alias defaults to 'default' when not provided"""
|
|
203
|
+
session = Session(
|
|
204
|
+
api_key="api_key_123",
|
|
205
|
+
base_url="https://api.test.com"
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
self.assertEqual(session.alias, "default")
|
|
209
|
+
|
|
210
|
+
def test_alias_can_be_set(self):
|
|
211
|
+
"""Test that custom alias can be set"""
|
|
212
|
+
session = Session(
|
|
213
|
+
api_key="api_key_123",
|
|
214
|
+
base_url="https://api.test.com",
|
|
215
|
+
alias="production"
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
self.assertEqual(session.alias, "production")
|
|
219
|
+
|
|
220
|
+
def test_organization_id_can_be_set(self):
|
|
221
|
+
"""Test that organization_id can be set and retrieved"""
|
|
222
|
+
session = Session(
|
|
223
|
+
base_url="https://api.test.com",
|
|
224
|
+
access_token="oauth_token_123",
|
|
225
|
+
project_id="project-456",
|
|
226
|
+
organization_id="org-789"
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
self.assertEqual(session.organization_id, "org-789")
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
class TestGetSession(unittest.TestCase):
|
|
233
|
+
"""
|
|
234
|
+
Tests for get_session function and singleton behavior.
|
|
235
|
+
|
|
236
|
+
python -m unittest pygeai.tests.auth.test_session_validation.TestGetSession
|
|
237
|
+
"""
|
|
238
|
+
|
|
239
|
+
def setUp(self):
|
|
240
|
+
"""Set up test fixtures"""
|
|
241
|
+
reset_session()
|
|
242
|
+
reset_settings()
|
|
243
|
+
|
|
244
|
+
self.log_capture = io.StringIO()
|
|
245
|
+
self.handler = logging.StreamHandler(self.log_capture)
|
|
246
|
+
self.handler.setLevel(logging.WARNING)
|
|
247
|
+
|
|
248
|
+
self.geai_logger = logging.getLogger('geai')
|
|
249
|
+
self._original_handlers = self.geai_logger.handlers.copy()
|
|
250
|
+
self._original_level = self.geai_logger.level
|
|
251
|
+
|
|
252
|
+
self.geai_logger.handlers = []
|
|
253
|
+
self.geai_logger.addHandler(self.handler)
|
|
254
|
+
self.geai_logger.setLevel(logging.WARNING)
|
|
255
|
+
self.geai_logger.propagate = False
|
|
256
|
+
|
|
257
|
+
def tearDown(self):
|
|
258
|
+
"""Clean up test fixtures"""
|
|
259
|
+
self.geai_logger.handlers = self._original_handlers
|
|
260
|
+
self.geai_logger.level = self._original_level
|
|
261
|
+
reset_session()
|
|
262
|
+
reset_settings()
|
|
263
|
+
|
|
264
|
+
def test_get_session_is_singleton(self):
|
|
265
|
+
"""Test that get_session returns the same instance"""
|
|
266
|
+
with tempfile.NamedTemporaryFile(mode='w', suffix='_credentials', delete=False) as f:
|
|
267
|
+
creds_file = f.name
|
|
268
|
+
f.write('[default]\n')
|
|
269
|
+
f.write('GEAI_API_KEY = test_key\n')
|
|
270
|
+
f.write('GEAI_API_BASE_URL = https://test.example.com\n')
|
|
271
|
+
|
|
272
|
+
try:
|
|
273
|
+
reset_settings()
|
|
274
|
+
get_settings(credentials_file=creds_file)
|
|
275
|
+
|
|
276
|
+
session1 = get_session()
|
|
277
|
+
session2 = get_session()
|
|
278
|
+
|
|
279
|
+
self.assertIs(session1, session2)
|
|
280
|
+
finally:
|
|
281
|
+
os.unlink(creds_file)
|
|
282
|
+
|
|
283
|
+
def test_get_session_loads_from_config(self):
|
|
284
|
+
"""Test that get_session loads credentials from config file"""
|
|
285
|
+
with tempfile.NamedTemporaryFile(mode='w', suffix='_credentials', delete=False) as f:
|
|
286
|
+
creds_file = f.name
|
|
287
|
+
f.write('[default]\n')
|
|
288
|
+
f.write('GEAI_API_KEY = config_key_123\n')
|
|
289
|
+
f.write('GEAI_API_BASE_URL = https://config.example.com\n')
|
|
290
|
+
|
|
291
|
+
try:
|
|
292
|
+
reset_settings()
|
|
293
|
+
get_settings(credentials_file=creds_file)
|
|
294
|
+
|
|
295
|
+
session = get_session()
|
|
296
|
+
|
|
297
|
+
self.assertEqual(session.api_key, "config_key_123")
|
|
298
|
+
self.assertEqual(session.base_url, "https://config.example.com")
|
|
299
|
+
finally:
|
|
300
|
+
os.unlink(creds_file)
|
|
301
|
+
|
|
302
|
+
def test_get_session_loads_oauth_from_config(self):
|
|
303
|
+
"""Test that get_session loads OAuth credentials from config"""
|
|
304
|
+
with tempfile.NamedTemporaryFile(mode='w', suffix='_credentials', delete=False) as f:
|
|
305
|
+
creds_file = f.name
|
|
306
|
+
f.write('[default]\n')
|
|
307
|
+
f.write('GEAI_OAUTH_ACCESS_TOKEN = oauth_token_123\n')
|
|
308
|
+
f.write('GEAI_PROJECT_ID = project-456\n')
|
|
309
|
+
f.write('GEAI_API_BASE_URL = https://oauth.example.com\n')
|
|
310
|
+
|
|
311
|
+
try:
|
|
312
|
+
reset_settings()
|
|
313
|
+
get_settings(credentials_file=creds_file)
|
|
314
|
+
|
|
315
|
+
session = get_session()
|
|
316
|
+
|
|
317
|
+
self.assertEqual(session.access_token, "oauth_token_123")
|
|
318
|
+
self.assertEqual(session.project_id, "project-456")
|
|
319
|
+
self.assertEqual(session.auth_type, AuthType.OAUTH_TOKEN)
|
|
320
|
+
finally:
|
|
321
|
+
os.unlink(creds_file)
|
|
322
|
+
|
|
323
|
+
def test_get_session_warns_about_mixed_auth(self):
|
|
324
|
+
"""Test that get_session warns when both API key and OAuth are configured"""
|
|
325
|
+
with tempfile.NamedTemporaryFile(mode='w', suffix='_credentials', delete=False) as f:
|
|
326
|
+
creds_file = f.name
|
|
327
|
+
f.write('[default]\n')
|
|
328
|
+
f.write('GEAI_API_KEY = api_key_123\n')
|
|
329
|
+
f.write('GEAI_OAUTH_ACCESS_TOKEN = oauth_token_123\n')
|
|
330
|
+
f.write('GEAI_PROJECT_ID = project-456\n')
|
|
331
|
+
f.write('GEAI_API_BASE_URL = https://mixed.example.com\n')
|
|
332
|
+
|
|
333
|
+
try:
|
|
334
|
+
reset_settings()
|
|
335
|
+
get_settings(credentials_file=creds_file)
|
|
336
|
+
|
|
337
|
+
session = get_session()
|
|
338
|
+
|
|
339
|
+
log_output = self.log_capture.getvalue()
|
|
340
|
+
self.assertIn("Both API key and OAuth token configured", log_output)
|
|
341
|
+
self.assertIn("OAuth token will take precedence", log_output)
|
|
342
|
+
finally:
|
|
343
|
+
os.unlink(creds_file)
|
|
344
|
+
|
|
345
|
+
def test_get_session_updates_existing_with_alias(self):
|
|
346
|
+
"""Test that get_session with alias updates existing session"""
|
|
347
|
+
with tempfile.NamedTemporaryFile(mode='w', suffix='_credentials', delete=False) as f:
|
|
348
|
+
creds_file = f.name
|
|
349
|
+
f.write('[default]\n')
|
|
350
|
+
f.write('GEAI_API_KEY = default_key\n')
|
|
351
|
+
f.write('GEAI_API_BASE_URL = https://default.example.com\n')
|
|
352
|
+
f.write('\n')
|
|
353
|
+
f.write('[staging]\n')
|
|
354
|
+
f.write('GEAI_API_KEY = staging_key\n')
|
|
355
|
+
f.write('GEAI_API_BASE_URL = https://staging.example.com\n')
|
|
356
|
+
|
|
357
|
+
try:
|
|
358
|
+
reset_settings()
|
|
359
|
+
get_settings(credentials_file=creds_file)
|
|
360
|
+
|
|
361
|
+
session1 = get_session('default')
|
|
362
|
+
self.assertEqual(session1.api_key, "default_key")
|
|
363
|
+
|
|
364
|
+
session2 = get_session('staging')
|
|
365
|
+
self.assertEqual(session2.api_key, "staging_key")
|
|
366
|
+
|
|
367
|
+
self.assertIs(session1, session2)
|
|
368
|
+
finally:
|
|
369
|
+
os.unlink(creds_file)
|
|
370
|
+
|
|
371
|
+
def test_validate_alias_raises_for_missing(self):
|
|
372
|
+
"""Test that _validate_alias raises exception for non-existent alias"""
|
|
373
|
+
with tempfile.NamedTemporaryFile(mode='w', suffix='_credentials', delete=False) as f:
|
|
374
|
+
creds_file = f.name
|
|
375
|
+
f.write('[default]\n')
|
|
376
|
+
f.write('GEAI_API_KEY = test_key\n')
|
|
377
|
+
f.write('GEAI_API_BASE_URL = https://test.example.com\n')
|
|
378
|
+
|
|
379
|
+
try:
|
|
380
|
+
reset_settings()
|
|
381
|
+
get_settings(credentials_file=creds_file)
|
|
382
|
+
|
|
383
|
+
with self.assertRaises(MissingRequirementException) as context:
|
|
384
|
+
_validate_alias('nonexistent', allow_missing_default=False)
|
|
385
|
+
|
|
386
|
+
self.assertIn("doesn't exist", str(context.exception))
|
|
387
|
+
finally:
|
|
388
|
+
os.unlink(creds_file)
|
|
389
|
+
|
|
390
|
+
def test_validate_alias_allows_missing_default(self):
|
|
391
|
+
"""Test that _validate_alias allows missing 'default' when flag is set"""
|
|
392
|
+
with tempfile.NamedTemporaryFile(mode='w', suffix='_credentials', delete=False) as f:
|
|
393
|
+
creds_file = f.name
|
|
394
|
+
f.write('[production]\n')
|
|
395
|
+
f.write('GEAI_API_KEY = prod_key\n')
|
|
396
|
+
f.write('GEAI_API_BASE_URL = https://prod.example.com\n')
|
|
397
|
+
|
|
398
|
+
try:
|
|
399
|
+
reset_settings()
|
|
400
|
+
get_settings(credentials_file=creds_file)
|
|
401
|
+
|
|
402
|
+
_validate_alias('default', allow_missing_default=True)
|
|
403
|
+
finally:
|
|
404
|
+
os.unlink(creds_file)
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
if __name__ == '__main__':
|
|
408
|
+
unittest.main()
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
|
|
3
|
+
from pygeai.core.singleton import Singleton
|
|
4
|
+
from pygeai.core.base.session import Session, reset_session
|
|
5
|
+
from pygeai.core.common.constants import AuthType
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestSingletonReset(unittest.TestCase):
|
|
9
|
+
"""
|
|
10
|
+
Tests for Singleton reset functionality to ensure proper test isolation.
|
|
11
|
+
|
|
12
|
+
python -m unittest pygeai.tests.auth.test_singleton_reset.TestSingletonReset
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def setUp(self):
|
|
16
|
+
"""Set up test fixtures"""
|
|
17
|
+
reset_session()
|
|
18
|
+
|
|
19
|
+
def tearDown(self):
|
|
20
|
+
"""Clean up test fixtures"""
|
|
21
|
+
reset_session()
|
|
22
|
+
|
|
23
|
+
def test_singleton_returns_same_instance(self):
|
|
24
|
+
"""Test that Singleton returns the same instance without reset"""
|
|
25
|
+
s1 = Session(api_key="key1", base_url="https://test1.com")
|
|
26
|
+
s2 = Session(api_key="key2", base_url="https://test2.com")
|
|
27
|
+
|
|
28
|
+
self.assertIs(s1, s2)
|
|
29
|
+
self.assertEqual(s1.api_key, "key1")
|
|
30
|
+
self.assertEqual(s2.api_key, "key1")
|
|
31
|
+
|
|
32
|
+
def test_reset_instance_clears_singleton_cache(self):
|
|
33
|
+
"""Test that Singleton.reset_instance clears the cache for specific class"""
|
|
34
|
+
s1 = Session(api_key="key1", base_url="https://test1.com")
|
|
35
|
+
self.assertEqual(s1.api_key, "key1")
|
|
36
|
+
|
|
37
|
+
Singleton.reset_instance(Session)
|
|
38
|
+
|
|
39
|
+
s2 = Session(api_key="key2", base_url="https://test2.com")
|
|
40
|
+
|
|
41
|
+
self.assertIsNot(s1, s2)
|
|
42
|
+
self.assertEqual(s2.api_key, "key2")
|
|
43
|
+
|
|
44
|
+
def test_reset_session_clears_singleton_cache(self):
|
|
45
|
+
"""Test that reset_session() clears both global variable and singleton cache"""
|
|
46
|
+
s1 = Session(api_key="key1", base_url="https://test1.com")
|
|
47
|
+
self.assertEqual(s1.api_key, "key1")
|
|
48
|
+
self.assertEqual(s1.auth_type, AuthType.API_KEY)
|
|
49
|
+
|
|
50
|
+
reset_session()
|
|
51
|
+
|
|
52
|
+
s2 = Session(
|
|
53
|
+
base_url="https://test2.com",
|
|
54
|
+
access_token="token2",
|
|
55
|
+
project_id="project2"
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
self.assertIsNot(s1, s2)
|
|
59
|
+
self.assertEqual(s2.access_token, "token2")
|
|
60
|
+
self.assertEqual(s2.auth_type, AuthType.OAUTH_TOKEN)
|
|
61
|
+
self.assertIsNone(s2.api_key)
|
|
62
|
+
|
|
63
|
+
def test_reset_allows_different_auth_types(self):
|
|
64
|
+
"""Test that reset allows switching between auth types"""
|
|
65
|
+
s1 = Session(api_key="api_key", base_url="https://test.com")
|
|
66
|
+
self.assertEqual(s1.auth_type, AuthType.API_KEY)
|
|
67
|
+
|
|
68
|
+
reset_session()
|
|
69
|
+
|
|
70
|
+
s2 = Session(
|
|
71
|
+
base_url="https://test.com",
|
|
72
|
+
access_token="oauth_token",
|
|
73
|
+
project_id="project_id"
|
|
74
|
+
)
|
|
75
|
+
self.assertEqual(s2.auth_type, AuthType.OAUTH_TOKEN)
|
|
76
|
+
|
|
77
|
+
reset_session()
|
|
78
|
+
|
|
79
|
+
s3 = Session(base_url="https://test.com")
|
|
80
|
+
self.assertEqual(s3.auth_type, AuthType.NONE)
|
|
81
|
+
|
|
82
|
+
def test_reset_session_allows_clean_state(self):
|
|
83
|
+
"""Test that reset_session creates truly independent instances"""
|
|
84
|
+
s1 = Session(
|
|
85
|
+
api_key="key1",
|
|
86
|
+
base_url="https://test1.com",
|
|
87
|
+
access_token="token1",
|
|
88
|
+
project_id="project1",
|
|
89
|
+
organization_id="org1",
|
|
90
|
+
allow_mixed_auth=True
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
self.assertEqual(s1.api_key, "key1")
|
|
94
|
+
self.assertEqual(s1.access_token, "token1")
|
|
95
|
+
self.assertEqual(s1.project_id, "project1")
|
|
96
|
+
self.assertEqual(s1.organization_id, "org1")
|
|
97
|
+
|
|
98
|
+
reset_session()
|
|
99
|
+
|
|
100
|
+
s2 = Session(base_url="https://test2.com")
|
|
101
|
+
|
|
102
|
+
self.assertIsNot(s1, s2)
|
|
103
|
+
self.assertIsNone(s2.api_key)
|
|
104
|
+
self.assertIsNone(s2.access_token)
|
|
105
|
+
self.assertIsNone(s2.project_id)
|
|
106
|
+
self.assertIsNone(s2.organization_id)
|
|
107
|
+
self.assertEqual(s2.auth_type, AuthType.NONE)
|
|
108
|
+
|
|
109
|
+
def test_reset_all_instances_clears_everything(self):
|
|
110
|
+
"""Test that reset_all_instances clears all singleton caches"""
|
|
111
|
+
s1 = Session(api_key="key1", base_url="https://test1.com")
|
|
112
|
+
|
|
113
|
+
Singleton.reset_all_instances()
|
|
114
|
+
|
|
115
|
+
s2 = Session(api_key="key2", base_url="https://test2.com")
|
|
116
|
+
|
|
117
|
+
self.assertIsNot(s1, s2)
|
|
118
|
+
self.assertEqual(s2.api_key, "key2")
|
|
119
|
+
|
|
120
|
+
def test_singleton_cache_persists_without_reset(self):
|
|
121
|
+
"""Test that without reset, singleton cache persists"""
|
|
122
|
+
s1 = Session(api_key="persistent_key", base_url="https://test.com")
|
|
123
|
+
|
|
124
|
+
s2 = Session(api_key="ignored_key", base_url="https://ignored.com")
|
|
125
|
+
|
|
126
|
+
self.assertIs(s1, s2)
|
|
127
|
+
self.assertEqual(s2.api_key, "persistent_key")
|
|
128
|
+
self.assertEqual(s2.base_url, "https://test.com")
|
|
129
|
+
|
|
130
|
+
def test_reset_does_not_affect_other_sessions(self):
|
|
131
|
+
"""Test that reset only affects Session class singleton"""
|
|
132
|
+
s1 = Session(api_key="key1", base_url="https://test1.com")
|
|
133
|
+
|
|
134
|
+
reset_session()
|
|
135
|
+
|
|
136
|
+
s2 = Session(api_key="key2", base_url="https://test2.com")
|
|
137
|
+
|
|
138
|
+
self.assertIsNot(s1, s2)
|
|
139
|
+
self.assertNotEqual(s1.api_key, s2.api_key)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class TestSingletonResetSequence(unittest.TestCase):
|
|
143
|
+
"""
|
|
144
|
+
Tests that simulate the sequence of tests running to verify isolation.
|
|
145
|
+
|
|
146
|
+
python -m unittest pygeai.tests.auth.test_singleton_reset.TestSingletonResetSequence
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
def setUp(self):
|
|
150
|
+
"""Set up test fixtures"""
|
|
151
|
+
reset_session()
|
|
152
|
+
|
|
153
|
+
def tearDown(self):
|
|
154
|
+
"""Clean up test fixtures"""
|
|
155
|
+
reset_session()
|
|
156
|
+
|
|
157
|
+
def test_sequence_1_oauth_session(self):
|
|
158
|
+
"""Simulates a test creating OAuth session"""
|
|
159
|
+
session = Session(
|
|
160
|
+
base_url="https://test.com",
|
|
161
|
+
access_token="oauth_token",
|
|
162
|
+
project_id="project_id"
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
self.assertEqual(session.auth_type, AuthType.OAUTH_TOKEN)
|
|
166
|
+
self.assertEqual(session.access_token, "oauth_token")
|
|
167
|
+
|
|
168
|
+
def test_sequence_2_api_key_session(self):
|
|
169
|
+
"""Simulates next test creating API key session - should not see OAuth"""
|
|
170
|
+
session = Session(
|
|
171
|
+
api_key="api_key",
|
|
172
|
+
base_url="https://test.com"
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
self.assertEqual(session.auth_type, AuthType.API_KEY)
|
|
176
|
+
self.assertEqual(session.api_key, "api_key")
|
|
177
|
+
self.assertIsNone(session.access_token)
|
|
178
|
+
|
|
179
|
+
def test_sequence_3_no_auth_session(self):
|
|
180
|
+
"""Simulates test creating session with no auth - should not see previous auth"""
|
|
181
|
+
session = Session(base_url="https://test.com")
|
|
182
|
+
|
|
183
|
+
self.assertEqual(session.auth_type, AuthType.NONE)
|
|
184
|
+
self.assertIsNone(session.api_key)
|
|
185
|
+
self.assertIsNone(session.access_token)
|
|
186
|
+
|
|
187
|
+
def test_sequence_4_different_oauth_session(self):
|
|
188
|
+
"""Simulates test creating different OAuth session - should not see previous"""
|
|
189
|
+
session = Session(
|
|
190
|
+
base_url="https://test.com",
|
|
191
|
+
access_token="different_token",
|
|
192
|
+
project_id="different_project"
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
self.assertEqual(session.auth_type, AuthType.OAUTH_TOKEN)
|
|
196
|
+
self.assertEqual(session.access_token, "different_token")
|
|
197
|
+
self.assertEqual(session.project_id, "different_project")
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
if __name__ == '__main__':
|
|
201
|
+
unittest.main()
|
pygeai/tests/chat/test_iris.py
CHANGED
pygeai/tests/chat/test_ui.py
CHANGED
|
@@ -3,7 +3,6 @@ import os
|
|
|
3
3
|
import json
|
|
4
4
|
from datetime import datetime
|
|
5
5
|
from unittest.mock import patch, MagicMock
|
|
6
|
-
import streamlit as st
|
|
7
6
|
from pygeai.chat.ui import (
|
|
8
7
|
parse_args,
|
|
9
8
|
save_session_to_file,
|
|
@@ -17,7 +16,6 @@ from pygeai.chat.ui import (
|
|
|
17
16
|
save_recent_agents,
|
|
18
17
|
load_recent_agents
|
|
19
18
|
)
|
|
20
|
-
from pygeai.lab.models import AgentList, Agent
|
|
21
19
|
|
|
22
20
|
|
|
23
21
|
class TestStreamlitChat(unittest.TestCase):
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import unittest
|
|
2
2
|
from unittest.mock import patch, MagicMock
|
|
3
|
-
import json
|
|
4
3
|
from pygeai.cli.commands.lab.ai_lab import (
|
|
5
4
|
show_help,
|
|
6
5
|
list_agents,
|
|
@@ -38,7 +37,6 @@ from pygeai.cli.commands.lab.ai_lab import (
|
|
|
38
37
|
start_instance,
|
|
39
38
|
abort_instance,
|
|
40
39
|
get_instance,
|
|
41
|
-
get_instance_history,
|
|
42
40
|
get_thread_information,
|
|
43
41
|
send_user_signal,
|
|
44
42
|
create_kb,
|
|
@@ -91,7 +89,7 @@ class TestAILab(unittest.TestCase):
|
|
|
91
89
|
option_list = [(Option("project_id", ["--project-id"], "", True), "proj123")]
|
|
92
90
|
with self.assertRaises(MissingRequirementException) as cm:
|
|
93
91
|
create_agent(option_list)
|
|
94
|
-
self.assertEqual(str(cm.exception), "Cannot create assistant without specifying name
|
|
92
|
+
self.assertEqual(str(cm.exception), "Cannot create assistant without specifying name.")
|
|
95
93
|
|
|
96
94
|
def test_create_agent_invalid_input_json(self):
|
|
97
95
|
option_list = [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import unittest
|
|
2
2
|
from unittest.mock import patch, MagicMock
|
|
3
|
-
from pygeai.cli.commands.chat import
|
|
3
|
+
from pygeai.cli.commands.chat import get_chat_completion, chat_with_iris, chat_with_agent
|
|
4
4
|
from pygeai.core.common.exceptions import MissingRequirementException, WrongArgumentError
|
|
5
5
|
from pygeai.cli.commands import Option
|
|
6
6
|
|