aidev-bkplugin 2.2.0.post3__tar.gz → 2.2.0.post4__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.
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/PKG-INFO +2 -2
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/services/agent_bkplugin.py +17 -1
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/views/chat.py +3 -1
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/pyproject.toml +2 -2
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/services/test_bkplugin.py +38 -11
- aidev_bkplugin-2.2.0.post4/tests/views/test_chat_stream_status.py +40 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/__init__.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/apps.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/constants.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/enums.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/management/__init__.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/management/commands/__init__.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/management/commands/upgrade_sessions.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/migrations/0001_initial.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/migrations/__init__.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/models.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/openapi/__init__.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/openapi/urls.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/openapi/views.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/packages/__init__.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/packages/apigw/__init__.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/packages/apigw/permissions.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/packages/checkpoint/__init__.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/packages/checkpoint/bk_django_saver.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/packages/drf/__init__.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/packages/drf/authentication.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/packages/drf/decorators.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/packages/drf/exception.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/packages/drf/renderers.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/permissions.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/private/__init__.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/private/permissions.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/private/urls.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/private/views.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/serializers/__init__.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/serializers/agent.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/serializers/chat_completion.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/serializers/user_operation.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/services/__init__.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/services/agent_builder.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/services/agent_config.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/services/agent_execution.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/services/agent_helpers.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/services/agent_session.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/services/approval_resume.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/services/user_operation.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/settings.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/tasks.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/urls.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/utils.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/views/__init__.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/views/agent.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/views/base.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/views/chat_group.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/views/flow_agent.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/views/session.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/views/user_operation.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/readme.md +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/__init__.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/conftest.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/packages/__init__.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/packages/test_bk_django_saver.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/private/__init__.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/private/test_private_views.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/services/__init__.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/services/agent/__init__.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/services/agent/conftest.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/services/agent/test_agent_config_fetcher.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/services/agent/test_builder.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/services/agent/test_session_manager.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/services/test_agent_completion.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/services/test_agui_handler.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/services/test_thread_chat_completion.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/services/test_user_operation.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/settings.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/test_constants.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/test_utils_otel.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/views/__init__.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/views/test_chat_completion_serializer.py +0 -0
- {aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/views/test_chat_flow_agent.py +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: aidev-bkplugin
|
|
3
|
-
Version: 2.2.0.
|
|
3
|
+
Version: 2.2.0.post4
|
|
4
4
|
Summary: AiDev Agent Bkplugin builtin functions
|
|
5
5
|
Requires-Python: <3.12,>=3.11
|
|
6
|
-
Requires-Dist: aidev-agent>=2.2.
|
|
6
|
+
Requires-Dist: aidev-agent>=2.2.0post4
|
|
7
7
|
Requires-Dist: blueapps<5.0,>=4.15.1
|
|
8
8
|
Requires-Dist: django<5.0,>=4.2.28
|
|
9
9
|
Description-Content-Type: text/markdown
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/services/agent_bkplugin.py
RENAMED
|
@@ -28,6 +28,7 @@ from aidev_agent.pydantic_models import ExecuteKwargs
|
|
|
28
28
|
from aidev_agent.services.agent import AgentInstanceFactory
|
|
29
29
|
from aidev_agent.services.common_agent import common_agent_factory
|
|
30
30
|
from aidev_agent.services.event_handlers.agui_writer import AGUISessionWriter
|
|
31
|
+
from aidev_agent.services.messages_handler import RetryableHeartbeatTimeoutError
|
|
31
32
|
from aidev_agent.utils.local import request_local
|
|
32
33
|
from django.contrib.auth import get_user_model
|
|
33
34
|
|
|
@@ -173,6 +174,13 @@ class BkpluginAgentRunner(ABC):
|
|
|
173
174
|
"""同步执行 Agent,返回最终 AI 回复字符串;异常时写回失败状态 (D-01)。"""
|
|
174
175
|
try:
|
|
175
176
|
return self._do_execute()
|
|
177
|
+
except RetryableHeartbeatTimeoutError:
|
|
178
|
+
logger.warning(
|
|
179
|
+
"[Bkplugin] skip session terminal update for retryable consumer heartbeat timeout session_code=%s",
|
|
180
|
+
self.session_code or "",
|
|
181
|
+
exc_info=True,
|
|
182
|
+
)
|
|
183
|
+
raise
|
|
176
184
|
except Exception as e:
|
|
177
185
|
logger.exception("[Bkplugin] execute error: %s", e)
|
|
178
186
|
session_code = self.session_code or ""
|
|
@@ -212,7 +220,7 @@ class BkpluginAgentRunner(ABC):
|
|
|
212
220
|
*,
|
|
213
221
|
chat_context: list[dict] | None = None,
|
|
214
222
|
) -> None:
|
|
215
|
-
"""Celery worker
|
|
223
|
+
"""Celery worker 入口:业务异常写失败;可重试消费异常保持 session 原状态。"""
|
|
216
224
|
logger.info(
|
|
217
225
|
"[Bkplugin] run_worker enter session_code=%s turn_id=%s thread=%s",
|
|
218
226
|
session_code,
|
|
@@ -221,6 +229,14 @@ class BkpluginAgentRunner(ABC):
|
|
|
221
229
|
)
|
|
222
230
|
try:
|
|
223
231
|
self.invoke_agent(session_code, execute_payload, chat_context=chat_context or [])
|
|
232
|
+
except RetryableHeartbeatTimeoutError:
|
|
233
|
+
logger.warning(
|
|
234
|
+
"[Bkplugin] skip session terminal update for retryable consumer heartbeat timeout "
|
|
235
|
+
"session_code=%s turn_id=%s",
|
|
236
|
+
session_code,
|
|
237
|
+
execute_payload.get("turn_id") or "",
|
|
238
|
+
exc_info=True,
|
|
239
|
+
)
|
|
224
240
|
except Exception as e:
|
|
225
241
|
logger.exception("[Bkplugin] worker error session_code=%s", session_code)
|
|
226
242
|
manager = SessionManager(self.username or "")
|
|
@@ -397,9 +397,11 @@ class ChatCompletionViewSet(PluginViewSet):
|
|
|
397
397
|
_preempted = False
|
|
398
398
|
_client_disconnected = False
|
|
399
399
|
_cancelled = False
|
|
400
|
+
_stream_completed = False
|
|
400
401
|
try:
|
|
401
402
|
for chunk in generator:
|
|
402
403
|
yield chunk
|
|
404
|
+
_stream_completed = True
|
|
403
405
|
except GeneratorExit:
|
|
404
406
|
_client_disconnected = True
|
|
405
407
|
logger.info(f"[WRAP_STATUS] Client disconnected (GeneratorExit): session_code={session_code}")
|
|
@@ -421,7 +423,7 @@ class ChatCompletionViewSet(PluginViewSet):
|
|
|
421
423
|
if GeneratorStreamingHelper.is_cancelled(session_code):
|
|
422
424
|
_cancelled = True
|
|
423
425
|
logger.info(f"[WRAP_STATUS] Generator结束后检测到取消标志: session_code={session_code}")
|
|
424
|
-
if not _preempted and not _client_disconnected and not _cancelled:
|
|
426
|
+
if _stream_completed and not _preempted and not _client_disconnected and not _cancelled:
|
|
425
427
|
logger.info(f"[WRAP_STATUS] 流正常结束, 调用 set_streaming_finished: session_code={session_code}")
|
|
426
428
|
event_handler.set_streaming_finished()
|
|
427
429
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "aidev-bkplugin"
|
|
3
|
-
version = "2.2.
|
|
3
|
+
version = "2.2.0post4"
|
|
4
4
|
description = "AiDev Agent Bkplugin builtin functions"
|
|
5
5
|
readme = "readme.md"
|
|
6
6
|
requires-python = "<3.12,>=3.11"
|
|
7
7
|
dependencies = [
|
|
8
|
-
"aidev-agent>=2.2.
|
|
8
|
+
"aidev-agent>=2.2.0post4",
|
|
9
9
|
"blueapps>=4.15.1, <5.0",
|
|
10
10
|
"django>=4.2.28,<5.0",
|
|
11
11
|
]
|
|
@@ -23,6 +23,7 @@ sys.modules.setdefault("bk_plugin_framework.kit", _bk_plugin_framework.kit)
|
|
|
23
23
|
sys.modules.setdefault("bk_plugin_framework.kit.decorators", _bk_plugin_framework.kit.decorators)
|
|
24
24
|
|
|
25
25
|
from aidev_agent.enums import AgentType, ChatContentStatus, PromptRole, SessionsStatus # noqa: E402
|
|
26
|
+
from aidev_agent.services.messages_handler import RetryableHeartbeatTimeoutError # noqa: E402
|
|
26
27
|
from aidev_bkplugin.enums import PluginPollTaskState # noqa: E402
|
|
27
28
|
from aidev_bkplugin.services.agent_session import SessionManager # noqa: E402
|
|
28
29
|
|
|
@@ -272,14 +273,10 @@ class TestBkpluginExecution:
|
|
|
272
273
|
from aidev_bkplugin.services.agent_bkplugin import BkpluginChat
|
|
273
274
|
|
|
274
275
|
agent = BkpluginChat(chat_history=[], execute_kwargs={}, username="alice")
|
|
275
|
-
monkeypatch.setattr(
|
|
276
|
-
agent, "invoke_agent", MagicMock(side_effect=RuntimeError("生产者心跳超时"))
|
|
277
|
-
)
|
|
276
|
+
monkeypatch.setattr(agent, "invoke_agent", MagicMock(side_effect=RuntimeError("生产者心跳超时")))
|
|
278
277
|
mock_sm = MagicMock()
|
|
279
278
|
mock_sm.retrieve_session.return_value = {"status": SessionsStatus.FINISHED.value}
|
|
280
|
-
monkeypatch.setattr(
|
|
281
|
-
"aidev_bkplugin.services.agent_bkplugin.SessionManager", lambda username: mock_sm
|
|
282
|
-
)
|
|
279
|
+
monkeypatch.setattr("aidev_bkplugin.services.agent_bkplugin.SessionManager", lambda username: mock_sm)
|
|
283
280
|
|
|
284
281
|
agent.run_worker("sess-1", {"turn_id": "t1"})
|
|
285
282
|
|
|
@@ -291,16 +288,46 @@ class TestBkpluginExecution:
|
|
|
291
288
|
from aidev_bkplugin.services.agent_bkplugin import BkpluginChat
|
|
292
289
|
|
|
293
290
|
agent = BkpluginChat(chat_history=[], execute_kwargs={}, username="alice")
|
|
294
|
-
monkeypatch.setattr(
|
|
295
|
-
agent, "invoke_agent", MagicMock(side_effect=RuntimeError("生产者心跳超时"))
|
|
296
|
-
)
|
|
291
|
+
monkeypatch.setattr(agent, "invoke_agent", MagicMock(side_effect=RuntimeError("producer crashed")))
|
|
297
292
|
mock_sm = MagicMock()
|
|
298
293
|
mock_sm.retrieve_session.return_value = {"status": SessionsStatus.RUNNING.value}
|
|
294
|
+
monkeypatch.setattr("aidev_bkplugin.services.agent_bkplugin.SessionManager", lambda username: mock_sm)
|
|
295
|
+
|
|
296
|
+
agent.run_worker("sess-1", {"turn_id": "t1"})
|
|
297
|
+
|
|
298
|
+
mock_sm.save_stream_failure.assert_called_once_with("sess-1", ANY, turn_id="t1")
|
|
299
|
+
|
|
300
|
+
def test_run_worker_skips_session_update_for_retryable_heartbeat_timeout(self, monkeypatch):
|
|
301
|
+
"""消费者心跳超时可重试,不应更新 session 终态。"""
|
|
302
|
+
from aidev_bkplugin.services.agent_bkplugin import BkpluginChat
|
|
303
|
+
|
|
304
|
+
agent = BkpluginChat(chat_history=[], execute_kwargs={}, username="alice")
|
|
299
305
|
monkeypatch.setattr(
|
|
300
|
-
|
|
306
|
+
agent,
|
|
307
|
+
"invoke_agent",
|
|
308
|
+
MagicMock(side_effect=RetryableHeartbeatTimeoutError("生产者心跳超时")),
|
|
301
309
|
)
|
|
310
|
+
manager_factory = MagicMock()
|
|
311
|
+
monkeypatch.setattr("aidev_bkplugin.services.agent_bkplugin.SessionManager", manager_factory)
|
|
302
312
|
|
|
303
313
|
agent.run_worker("sess-1", {"turn_id": "t1"})
|
|
304
314
|
|
|
305
|
-
|
|
315
|
+
manager_factory.assert_not_called()
|
|
316
|
+
|
|
317
|
+
def test_execute_skips_session_update_for_retryable_heartbeat_timeout(self, monkeypatch):
|
|
318
|
+
"""同步消费遇到可重试心跳超时,也不应覆盖 session 状态。"""
|
|
319
|
+
from aidev_bkplugin.services.agent_bkplugin import BkpluginChat
|
|
320
|
+
|
|
321
|
+
agent = BkpluginChat(chat_history=[], execute_kwargs={"session_code": "sess-1"}, username="alice")
|
|
322
|
+
monkeypatch.setattr(
|
|
323
|
+
agent,
|
|
324
|
+
"_do_execute",
|
|
325
|
+
MagicMock(side_effect=RetryableHeartbeatTimeoutError("生产者心跳超时")),
|
|
326
|
+
)
|
|
327
|
+
manager_factory = MagicMock()
|
|
328
|
+
monkeypatch.setattr("aidev_bkplugin.services.agent_bkplugin.SessionManager", manager_factory)
|
|
329
|
+
|
|
330
|
+
with pytest.raises(RetryableHeartbeatTimeoutError):
|
|
331
|
+
agent.execute()
|
|
306
332
|
|
|
333
|
+
manager_factory.assert_not_called()
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""Chat SSE 异常时的会话终态回归测试。"""
|
|
3
|
+
|
|
4
|
+
from unittest.mock import MagicMock
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@pytest.mark.parametrize("error", [RuntimeError("生产者心跳超时"), SystemExit("worker abort")])
|
|
10
|
+
def test_unexpected_stream_error_does_not_mark_session_finished(monkeypatch, error):
|
|
11
|
+
from aidev_agent.services.messages_handler.streaming_helper import GeneratorStreamingHelper
|
|
12
|
+
from aidev_bkplugin.views.chat import ChatCompletionViewSet
|
|
13
|
+
|
|
14
|
+
def failing_stream():
|
|
15
|
+
yield "chunk"
|
|
16
|
+
raise error
|
|
17
|
+
|
|
18
|
+
monkeypatch.setattr(GeneratorStreamingHelper, "is_cancelled", lambda _session_code: False)
|
|
19
|
+
event_handler = MagicMock()
|
|
20
|
+
stream = ChatCompletionViewSet()._wrap_streaming_with_status(
|
|
21
|
+
failing_stream(), event_handler, session_code="session-1"
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
assert next(stream) == "chunk"
|
|
25
|
+
with pytest.raises(type(error)):
|
|
26
|
+
next(stream)
|
|
27
|
+
event_handler.set_streaming_finished.assert_not_called()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_normal_stream_marks_session_finished(monkeypatch):
|
|
31
|
+
from aidev_agent.services.messages_handler.streaming_helper import GeneratorStreamingHelper
|
|
32
|
+
from aidev_bkplugin.views.chat import ChatCompletionViewSet
|
|
33
|
+
|
|
34
|
+
monkeypatch.setattr(GeneratorStreamingHelper, "is_cancelled", lambda _session_code: False)
|
|
35
|
+
event_handler = MagicMock()
|
|
36
|
+
|
|
37
|
+
assert list(
|
|
38
|
+
ChatCompletionViewSet()._wrap_streaming_with_status(iter(["chunk"]), event_handler, session_code="session-1")
|
|
39
|
+
) == ["chunk"]
|
|
40
|
+
event_handler.set_streaming_finished.assert_called_once_with()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/management/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/migrations/0001_initial.py
RENAMED
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/migrations/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/openapi/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/packages/__init__.py
RENAMED
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/packages/apigw/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/packages/drf/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/packages/drf/decorators.py
RENAMED
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/packages/drf/exception.py
RENAMED
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/packages/drf/renderers.py
RENAMED
|
File without changes
|
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/private/__init__.py
RENAMED
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/private/permissions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/serializers/__init__.py
RENAMED
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/serializers/agent.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/services/__init__.py
RENAMED
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/services/agent_builder.py
RENAMED
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/services/agent_config.py
RENAMED
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/services/agent_execution.py
RENAMED
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/services/agent_helpers.py
RENAMED
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/services/agent_session.py
RENAMED
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/services/approval_resume.py
RENAMED
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/services/user_operation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/views/chat_group.py
RENAMED
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/views/flow_agent.py
RENAMED
|
File without changes
|
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/aidev_bkplugin/views/user_operation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/packages/test_bk_django_saver.py
RENAMED
|
File without changes
|
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/private/test_private_views.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/services/agent/test_builder.py
RENAMED
|
File without changes
|
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/services/test_agent_completion.py
RENAMED
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/services/test_agui_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/services/test_user_operation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aidev_bkplugin-2.2.0.post3 → aidev_bkplugin-2.2.0.post4}/tests/views/test_chat_flow_agent.py
RENAMED
|
File without changes
|