gohumanloop 0.0.2__py3-none-any.whl → 0.0.4__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.
- gohumanloop/adapters/langgraph_adapter.py +65 -52
- gohumanloop/core/interface.py +342 -21
- gohumanloop/core/manager.py +302 -39
- gohumanloop/manager/ghl_manager.py +24 -24
- gohumanloop/providers/api_provider.py +50 -24
- gohumanloop/providers/base.py +170 -9
- gohumanloop/providers/email_provider.py +66 -22
- gohumanloop/providers/terminal_provider.py +95 -23
- gohumanloop/utils/utils.py +33 -3
- {gohumanloop-0.0.2.dist-info → gohumanloop-0.0.4.dist-info}/METADATA +1 -1
- {gohumanloop-0.0.2.dist-info → gohumanloop-0.0.4.dist-info}/RECORD +15 -15
- {gohumanloop-0.0.2.dist-info → gohumanloop-0.0.4.dist-info}/WHEEL +1 -1
- {gohumanloop-0.0.2.dist-info → gohumanloop-0.0.4.dist-info}/entry_points.txt +0 -0
- {gohumanloop-0.0.2.dist-info → gohumanloop-0.0.4.dist-info}/licenses/LICENSE +0 -0
- {gohumanloop-0.0.2.dist-info → gohumanloop-0.0.4.dist-info}/top_level.txt +0 -0
@@ -98,22 +98,22 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
98
98
|
if auto_start_sync:
|
99
99
|
# 判断是否处在异步环境
|
100
100
|
if asyncio.get_event_loop().is_running():
|
101
|
-
asyncio.create_task(self.
|
101
|
+
asyncio.create_task(self.async_start_sync_task())
|
102
102
|
else:
|
103
103
|
self.start_sync_task()
|
104
104
|
|
105
105
|
|
106
|
-
async def
|
106
|
+
async def async_get_ghl_provider(self) -> GoHumanLoopProvider:
|
107
107
|
"""
|
108
108
|
获取 GoHumanLoop 提供者实例
|
109
109
|
|
110
110
|
Returns:
|
111
111
|
GoHumanLoopProvider: GoHumanLoop 提供者实例
|
112
112
|
"""
|
113
|
-
provider = await self.
|
113
|
+
provider = await self.async_get_provider(self.default_provider_id)
|
114
114
|
return provider
|
115
115
|
|
116
|
-
async def
|
116
|
+
async def async_start_sync_task(self):
|
117
117
|
"""启动数据同步任务"""
|
118
118
|
if self._sync_task is None or self._sync_task.done():
|
119
119
|
self._sync_task = asyncio.create_task(self._async_data_periodically())
|
@@ -176,7 +176,7 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
176
176
|
# 对每个任务进行数据同步
|
177
177
|
for task_id in task_ids:
|
178
178
|
# 获取任务相关的所有对话
|
179
|
-
conversations = await self.
|
179
|
+
conversations = await self.async_get_task_conversations(task_id)
|
180
180
|
|
181
181
|
# 收集任务数据
|
182
182
|
task_data = {
|
@@ -188,7 +188,7 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
188
188
|
# 收集每个对话的数据
|
189
189
|
for conversation_id in conversations:
|
190
190
|
# 获取对话中的所有请求
|
191
|
-
request_ids = await self.
|
191
|
+
request_ids = await self.async_get_conversation_requests(conversation_id)
|
192
192
|
|
193
193
|
conversation_data = {
|
194
194
|
"conversation_id": conversation_id,
|
@@ -198,7 +198,7 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
198
198
|
|
199
199
|
# 收集每个请求的数据
|
200
200
|
for request_id in request_ids:
|
201
|
-
result = await self.
|
201
|
+
result = await self._async_get_request_status(conversation_id, request_id)
|
202
202
|
|
203
203
|
# 添加请求数据
|
204
204
|
conversation_data["requests"].append({
|
@@ -227,7 +227,7 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
227
227
|
|
228
228
|
# 添加此对话中的已取消请求
|
229
229
|
for request_id in cancel_info.get("request_ids", []):
|
230
|
-
result = await self.
|
230
|
+
result = await self._async_get_request_status(conv_id, request_id, cancel_info.get("provider_id"))
|
231
231
|
|
232
232
|
# 添加请求数据
|
233
233
|
cancelled_conv_data["requests"].append({
|
@@ -245,7 +245,7 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
245
245
|
task_data["conversations"].append(cancelled_conv_data)
|
246
246
|
|
247
247
|
# 发送数据到平台
|
248
|
-
await self.
|
248
|
+
await self._async_send_task_data_to_platform(task_data)
|
249
249
|
|
250
250
|
# 更新最后同步时间
|
251
251
|
self._last_sync_time = current_time
|
@@ -288,7 +288,7 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
288
288
|
|
289
289
|
# 收集每个请求的数据
|
290
290
|
for request_id in request_ids:
|
291
|
-
result = loop.run_until_complete(self.
|
291
|
+
result = loop.run_until_complete(self._async_get_request_status(conversation_id, request_id))
|
292
292
|
|
293
293
|
# 添加请求数据
|
294
294
|
conversation_data["requests"].append({
|
@@ -318,7 +318,7 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
318
318
|
# 添加此对话中的已取消请求
|
319
319
|
for request_id in cancel_info.get("request_ids", []):
|
320
320
|
result = loop.run_until_complete(
|
321
|
-
self.
|
321
|
+
self._async_get_request_status(conv_id, request_id, cancel_info.get("provider_id"))
|
322
322
|
)
|
323
323
|
|
324
324
|
# 添加请求数据
|
@@ -337,13 +337,13 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
337
337
|
task_data["conversations"].append(cancelled_conv_data)
|
338
338
|
|
339
339
|
# 发送数据到平台
|
340
|
-
loop.run_until_complete(self.
|
340
|
+
loop.run_until_complete(self._async_send_task_data_to_platform(task_data))
|
341
341
|
loop.close()
|
342
342
|
|
343
343
|
# 更新最后同步时间
|
344
344
|
self._last_sync_time = current_time
|
345
345
|
|
346
|
-
async def
|
346
|
+
async def _async_send_task_data_to_platform(self, task_data: Dict[str, Any]):
|
347
347
|
"""发送任务数据到 GoHumanLoop 平台"""
|
348
348
|
try:
|
349
349
|
# 构建 API 请求 URL
|
@@ -390,7 +390,7 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
390
390
|
print(f"发送任务数据到平台异常: {str(e)}")
|
391
391
|
|
392
392
|
|
393
|
-
async def
|
393
|
+
async def async_cancel_conversation(
|
394
394
|
self,
|
395
395
|
conversation_id: str,
|
396
396
|
provider_id: Optional[str] = None
|
@@ -411,13 +411,13 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
411
411
|
}
|
412
412
|
|
413
413
|
# 调用父类方法执行实际取消操作
|
414
|
-
return await super().
|
414
|
+
return await super().async_cancel_conversation(conversation_id, provider_id)
|
415
415
|
|
416
416
|
def __str__(self) -> str:
|
417
417
|
"""返回此实例的字符串描述"""
|
418
418
|
return f"GoHumanLoop(default_provider={self.default_provider_id}, providers={len(self.providers)})"
|
419
419
|
|
420
|
-
async def
|
420
|
+
async def _async_get_request_status(
|
421
421
|
self,
|
422
422
|
conversation_id: str,
|
423
423
|
request_id: str,
|
@@ -434,7 +434,7 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
434
434
|
Returns:
|
435
435
|
HumanLoopResult: 请求状态结果
|
436
436
|
"""
|
437
|
-
#
|
437
|
+
# check_request_status
|
438
438
|
if provider_id is None:
|
439
439
|
provider_id = self._conversation_provider.get(conversation_id)
|
440
440
|
|
@@ -442,9 +442,9 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
442
442
|
raise ValueError(f"Provider '{provider_id}' not found")
|
443
443
|
|
444
444
|
provider = self.providers[provider_id]
|
445
|
-
return await provider.
|
445
|
+
return await provider.async_check_request_status(conversation_id, request_id)
|
446
446
|
|
447
|
-
async def
|
447
|
+
async def async_check_request_status(
|
448
448
|
self,
|
449
449
|
conversation_id: str,
|
450
450
|
request_id: str,
|
@@ -462,7 +462,7 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
462
462
|
raise ValueError(f"Provider '{provider_id}' not found")
|
463
463
|
|
464
464
|
provider = self.providers[provider_id]
|
465
|
-
result = await provider.
|
465
|
+
result = await provider.async_check_request_status(conversation_id, request_id)
|
466
466
|
|
467
467
|
# 如果有回调且状态不是等待或进行中
|
468
468
|
if result.status not in [HumanLoopStatus.PENDING]:
|
@@ -470,7 +470,7 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
470
470
|
await self.async_data_to_platform()
|
471
471
|
# 触发状态更新回调
|
472
472
|
if (conversation_id, request_id) in self._callbacks:
|
473
|
-
await self.
|
473
|
+
await self._async_trigger_update_callback(conversation_id, request_id, provider, result)
|
474
474
|
|
475
475
|
return result
|
476
476
|
|
@@ -492,7 +492,7 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
492
492
|
except Exception as e:
|
493
493
|
print(f"最终同步数据同步失败: {str(e)}")
|
494
494
|
|
495
|
-
async def
|
495
|
+
async def async_shutdown(self):
|
496
496
|
"""
|
497
497
|
关闭管理器并确保数据同步(异步版本)
|
498
498
|
|
@@ -514,12 +514,12 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
514
514
|
|
515
515
|
async def __aenter__(self):
|
516
516
|
"""实现异步上下文管理器协议的进入方法"""
|
517
|
-
await self.
|
517
|
+
await self.async_start_sync_task()
|
518
518
|
return self
|
519
519
|
|
520
520
|
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
521
521
|
"""实现异步上下文管理器协议的退出方法"""
|
522
|
-
await self.
|
522
|
+
await self.async_shutdown()
|
523
523
|
|
524
524
|
def __enter__(self):
|
525
525
|
"""实现同步上下文管理器协议的进入方法"""
|
@@ -4,7 +4,7 @@ from typing import Dict, Any, Optional
|
|
4
4
|
|
5
5
|
import aiohttp
|
6
6
|
from pydantic import SecretStr
|
7
|
-
|
7
|
+
from concurrent.futures import ThreadPoolExecutor
|
8
8
|
from gohumanloop.core.interface import (
|
9
9
|
HumanLoopResult, HumanLoopStatus, HumanLoopType
|
10
10
|
)
|
@@ -56,6 +56,18 @@ class APIProvider(BaseProvider):
|
|
56
56
|
|
57
57
|
# Store the currently running polling tasks.
|
58
58
|
self._poll_tasks = {}
|
59
|
+
# Create thread pool for background service execution
|
60
|
+
self._executor = ThreadPoolExecutor(max_workers=10)
|
61
|
+
|
62
|
+
|
63
|
+
def __del__(self):
|
64
|
+
"""析构函数,确保线程池被正确关闭"""
|
65
|
+
self._executor.shutdown(wait=False)
|
66
|
+
|
67
|
+
# 取消所有邮件检查任务
|
68
|
+
for task_key, future in list(self._poll_tasks.items()):
|
69
|
+
future.cancel()
|
70
|
+
self._poll_tasks.clear()
|
59
71
|
|
60
72
|
def __str__(self) -> str:
|
61
73
|
"""Returns a string description of this instance"""
|
@@ -65,7 +77,7 @@ class APIProvider(BaseProvider):
|
|
65
77
|
api_info += f" Default Platform: {self.default_platform}\n"
|
66
78
|
return f"{api_info}{base_str}"
|
67
79
|
|
68
|
-
async def
|
80
|
+
async def _async_make_api_request(
|
69
81
|
self,
|
70
82
|
endpoint: str,
|
71
83
|
method: str = "POST",
|
@@ -146,7 +158,7 @@ class APIProvider(BaseProvider):
|
|
146
158
|
continue
|
147
159
|
raise
|
148
160
|
|
149
|
-
async def
|
161
|
+
async def async_request_humanloop(
|
150
162
|
self,
|
151
163
|
task_id: str,
|
152
164
|
conversation_id: str,
|
@@ -208,7 +220,7 @@ class APIProvider(BaseProvider):
|
|
208
220
|
|
209
221
|
try:
|
210
222
|
# Send API request
|
211
|
-
response = await self.
|
223
|
+
response = await self._async_make_api_request(
|
212
224
|
endpoint="v1/humanloop/request",
|
213
225
|
method="POST",
|
214
226
|
data=request_data
|
@@ -230,14 +242,13 @@ class APIProvider(BaseProvider):
|
|
230
242
|
)
|
231
243
|
|
232
244
|
# Create polling task
|
233
|
-
|
234
|
-
|
245
|
+
self._poll_tasks[(conversation_id, request_id)] = self._executor.submit(
|
246
|
+
self._run_async_poll_request_status, conversation_id, request_id, platform
|
235
247
|
)
|
236
|
-
self._poll_tasks[(conversation_id, request_id)] = poll_task
|
237
248
|
|
238
249
|
# Create timeout task if timeout is set
|
239
250
|
if timeout:
|
240
|
-
|
251
|
+
await self._async_create_timeout_task(conversation_id, request_id, timeout)
|
241
252
|
|
242
253
|
return HumanLoopResult(
|
243
254
|
conversation_id=conversation_id,
|
@@ -258,7 +269,23 @@ class APIProvider(BaseProvider):
|
|
258
269
|
status=HumanLoopStatus.ERROR,
|
259
270
|
error=str(e)
|
260
271
|
)
|
261
|
-
|
272
|
+
|
273
|
+
def _run_async_poll_request_status(self, conversation_id: str, request_id: str, platform: str):
|
274
|
+
"""Run asynchronous API interaction in a separate thread"""
|
275
|
+
# Create new event loop
|
276
|
+
loop = asyncio.new_event_loop()
|
277
|
+
asyncio.set_event_loop(loop)
|
278
|
+
|
279
|
+
try:
|
280
|
+
# Run interaction processing in the new event loop
|
281
|
+
loop.run_until_complete(self._async_poll_request_status(conversation_id, request_id, platform))
|
282
|
+
finally:
|
283
|
+
loop.close()
|
284
|
+
# Remove from task dictionary
|
285
|
+
if (conversation_id, request_id) in self._poll_tasks:
|
286
|
+
del self._poll_tasks[(conversation_id, request_id)]
|
287
|
+
|
288
|
+
async def async_check_request_status(
|
262
289
|
self,
|
263
290
|
conversation_id: str,
|
264
291
|
request_id: str
|
@@ -297,7 +324,7 @@ class APIProvider(BaseProvider):
|
|
297
324
|
return result
|
298
325
|
|
299
326
|
|
300
|
-
async def
|
327
|
+
async def async_cancel_request(
|
301
328
|
self,
|
302
329
|
conversation_id: str,
|
303
330
|
request_id: str
|
@@ -312,7 +339,7 @@ class APIProvider(BaseProvider):
|
|
312
339
|
bool: Whether cancellation was successful, True for success, False for failure
|
313
340
|
"""
|
314
341
|
# First call parent method to update local state
|
315
|
-
result = await super().
|
342
|
+
result = await super().async_cancel_request(conversation_id, request_id)
|
316
343
|
if not result:
|
317
344
|
return False
|
318
345
|
|
@@ -335,7 +362,7 @@ class APIProvider(BaseProvider):
|
|
335
362
|
platform=platform
|
336
363
|
).model_dump()
|
337
364
|
|
338
|
-
response = await self.
|
365
|
+
response = await self._async_make_api_request(
|
339
366
|
endpoint="v1/humanloop/cancel",
|
340
367
|
method="POST",
|
341
368
|
data=cancel_data
|
@@ -359,7 +386,7 @@ class APIProvider(BaseProvider):
|
|
359
386
|
logger.error(f"Cancel request failed: {str(e)}")
|
360
387
|
return False
|
361
388
|
|
362
|
-
async def
|
389
|
+
async def async_cancel_conversation(
|
363
390
|
self,
|
364
391
|
conversation_id: str
|
365
392
|
) -> bool:
|
@@ -372,7 +399,7 @@ class APIProvider(BaseProvider):
|
|
372
399
|
bool: Whether cancellation was successful
|
373
400
|
"""
|
374
401
|
# First call parent method to update local state
|
375
|
-
result = await super().
|
402
|
+
result = await super().async_cancel_conversation(conversation_id)
|
376
403
|
if not result:
|
377
404
|
return False
|
378
405
|
|
@@ -398,7 +425,7 @@ class APIProvider(BaseProvider):
|
|
398
425
|
platform=platform
|
399
426
|
).model_dump()
|
400
427
|
|
401
|
-
response = await self.
|
428
|
+
response = await self._async_make_api_request(
|
402
429
|
endpoint="v1/humanloop/cancel_conversation",
|
403
430
|
method="POST",
|
404
431
|
data=cancel_data
|
@@ -424,7 +451,7 @@ class APIProvider(BaseProvider):
|
|
424
451
|
return False
|
425
452
|
|
426
453
|
|
427
|
-
async def
|
454
|
+
async def async_continue_humanloop(
|
428
455
|
self,
|
429
456
|
conversation_id: str,
|
430
457
|
context: Dict[str, Any],
|
@@ -496,7 +523,7 @@ class APIProvider(BaseProvider):
|
|
496
523
|
|
497
524
|
try:
|
498
525
|
# Send API request
|
499
|
-
response = await self.
|
526
|
+
response = await self._async_make_api_request(
|
500
527
|
endpoint="v1/humanloop/continue",
|
501
528
|
method="POST",
|
502
529
|
data=continue_data
|
@@ -516,15 +543,14 @@ class APIProvider(BaseProvider):
|
|
516
543
|
error=error_msg
|
517
544
|
)
|
518
545
|
|
519
|
-
|
520
|
-
|
521
|
-
|
546
|
+
# Create polling task
|
547
|
+
self._poll_tasks[(conversation_id, request_id)] = self._executor.submit(
|
548
|
+
self._run_async_poll_request_status, conversation_id, request_id, platform
|
522
549
|
)
|
523
|
-
self._poll_tasks[(conversation_id, request_id)] = poll_task
|
524
550
|
|
525
551
|
# Create timeout task if timeout is set
|
526
552
|
if timeout:
|
527
|
-
self.
|
553
|
+
await self._async_create_timeout_task(conversation_id, request_id, timeout)
|
528
554
|
|
529
555
|
return HumanLoopResult(
|
530
556
|
conversation_id=conversation_id,
|
@@ -546,7 +572,7 @@ class APIProvider(BaseProvider):
|
|
546
572
|
error=str(e)
|
547
573
|
)
|
548
574
|
|
549
|
-
async def
|
575
|
+
async def _async_poll_request_status(
|
550
576
|
self,
|
551
577
|
conversation_id: str,
|
552
578
|
request_id: str,
|
@@ -579,7 +605,7 @@ class APIProvider(BaseProvider):
|
|
579
605
|
platform=platform
|
580
606
|
).model_dump()
|
581
607
|
|
582
|
-
response = await self.
|
608
|
+
response = await self._async_make_api_request(
|
583
609
|
endpoint="v1/humanloop/status",
|
584
610
|
method="GET",
|
585
611
|
params=params
|
gohumanloop/providers/base.py
CHANGED
@@ -7,6 +7,7 @@ import uuid
|
|
7
7
|
from datetime import datetime
|
8
8
|
from collections import defaultdict
|
9
9
|
from gohumanloop.utils.threadsafedict import ThreadSafeDict
|
10
|
+
from gohumanloop.utils import run_async_safely
|
10
11
|
|
11
12
|
from gohumanloop.core.interface import (
|
12
13
|
HumanLoopProvider, HumanLoopResult, HumanLoopStatus, HumanLoopType
|
@@ -109,7 +110,7 @@ class BaseProvider(HumanLoopProvider, ABC):
|
|
109
110
|
"""Get all request IDs in the conversation"""
|
110
111
|
return self._conversation_requests.get(conversation_id, [])
|
111
112
|
|
112
|
-
async def
|
113
|
+
async def async_request_humanloop(
|
113
114
|
self,
|
114
115
|
task_id: str,
|
115
116
|
conversation_id: str,
|
@@ -134,8 +135,42 @@ class BaseProvider(HumanLoopProvider, ABC):
|
|
134
135
|
# Subclasses must implement this method
|
135
136
|
raise NotImplementedError("Subclasses must implement request_humanloop")
|
136
137
|
|
138
|
+
def request_humanloop(
|
139
|
+
self,
|
140
|
+
task_id: str,
|
141
|
+
conversation_id: str,
|
142
|
+
loop_type: HumanLoopType,
|
143
|
+
context: Dict[str, Any],
|
144
|
+
metadata: Optional[Dict[str, Any]] = None,
|
145
|
+
timeout: Optional[int] = None
|
146
|
+
) -> HumanLoopResult:
|
147
|
+
"""Request human-in-the-loop interaction (synchronous version)
|
137
148
|
|
138
|
-
|
149
|
+
Args:
|
150
|
+
task_id: Task identifier
|
151
|
+
conversation_id: Conversation ID for multi-turn dialogues
|
152
|
+
loop_type: Type of human loop interaction
|
153
|
+
context: Context information provided to human
|
154
|
+
metadata: Additional metadata
|
155
|
+
timeout: Request timeout in seconds
|
156
|
+
|
157
|
+
Returns:
|
158
|
+
HumanLoopResult: Result object containing request ID and initial status
|
159
|
+
"""
|
160
|
+
|
161
|
+
return run_async_safely(
|
162
|
+
self.async_request_humanloop(
|
163
|
+
task_id=task_id,
|
164
|
+
conversation_id=conversation_id,
|
165
|
+
loop_type=loop_type,
|
166
|
+
context=context,
|
167
|
+
metadata=metadata,
|
168
|
+
timeout=timeout
|
169
|
+
)
|
170
|
+
)
|
171
|
+
|
172
|
+
|
173
|
+
async def async_check_request_status(
|
139
174
|
self,
|
140
175
|
conversation_id: str,
|
141
176
|
request_id: str
|
@@ -163,7 +198,28 @@ class BaseProvider(HumanLoopProvider, ABC):
|
|
163
198
|
raise NotImplementedError("Subclasses must implement check_request_status")
|
164
199
|
|
165
200
|
|
166
|
-
|
201
|
+
def check_request_status(
|
202
|
+
self,
|
203
|
+
conversation_id: str,
|
204
|
+
request_id: str
|
205
|
+
) -> HumanLoopResult:
|
206
|
+
"""Check conversation status (synchronous version)
|
207
|
+
|
208
|
+
Args:
|
209
|
+
conversation_id: Conversation identifier
|
210
|
+
|
211
|
+
Returns:
|
212
|
+
HumanLoopResult: Result containing the status of the latest request in the conversation
|
213
|
+
"""
|
214
|
+
|
215
|
+
return run_async_safely(
|
216
|
+
self.async_check_request_status(
|
217
|
+
conversation_id=conversation_id,
|
218
|
+
request_id=request_id
|
219
|
+
)
|
220
|
+
)
|
221
|
+
|
222
|
+
async def async_check_conversation_status(
|
167
223
|
self,
|
168
224
|
conversation_id: str
|
169
225
|
) -> HumanLoopResult:
|
@@ -195,9 +251,29 @@ class BaseProvider(HumanLoopProvider, ABC):
|
|
195
251
|
error=f"No requests found in conversation '{conversation_id}'"
|
196
252
|
)
|
197
253
|
|
198
|
-
return await self.
|
254
|
+
return await self.async_check_request_status(conversation_id, latest_request_id)
|
255
|
+
|
256
|
+
|
257
|
+
def check_conversation_status(
|
258
|
+
self,
|
259
|
+
conversation_id: str
|
260
|
+
) -> HumanLoopResult:
|
261
|
+
"""Check conversation status (synchronous version)
|
199
262
|
|
200
|
-
|
263
|
+
Args:
|
264
|
+
conversation_id: Conversation identifier
|
265
|
+
|
266
|
+
Returns:
|
267
|
+
HumanLoopResult: Result containing the status of the latest request in the conversation
|
268
|
+
"""
|
269
|
+
|
270
|
+
return run_async_safely(
|
271
|
+
self.async_check_conversation_status(
|
272
|
+
conversation_id=conversation_id
|
273
|
+
)
|
274
|
+
)
|
275
|
+
|
276
|
+
async def async_cancel_request(
|
201
277
|
self,
|
202
278
|
conversation_id: str,
|
203
279
|
request_id: str
|
@@ -224,7 +300,29 @@ class BaseProvider(HumanLoopProvider, ABC):
|
|
224
300
|
return True
|
225
301
|
return False
|
226
302
|
|
227
|
-
|
303
|
+
def cancel_request(
|
304
|
+
self,
|
305
|
+
conversation_id: str,
|
306
|
+
request_id: str
|
307
|
+
) -> bool:
|
308
|
+
"""Cancel human-in-the-loop request (synchronous version)
|
309
|
+
|
310
|
+
Args:
|
311
|
+
conversation_id: Conversation identifier for multi-turn dialogues
|
312
|
+
request_id: Request identifier for specific interaction request
|
313
|
+
|
314
|
+
Returns:
|
315
|
+
bool: Whether cancellation was successful, True indicates success, False indicates failure
|
316
|
+
"""
|
317
|
+
|
318
|
+
return run_async_safely(
|
319
|
+
self.async_cancel_request(
|
320
|
+
conversation_id=conversation_id,
|
321
|
+
request_id=request_id
|
322
|
+
)
|
323
|
+
)
|
324
|
+
|
325
|
+
async def async_cancel_conversation(
|
228
326
|
self,
|
229
327
|
conversation_id: str
|
230
328
|
) -> bool:
|
@@ -258,7 +356,27 @@ class BaseProvider(HumanLoopProvider, ABC):
|
|
258
356
|
|
259
357
|
return success
|
260
358
|
|
261
|
-
|
359
|
+
|
360
|
+
def cancel_conversation(
|
361
|
+
self,
|
362
|
+
conversation_id: str
|
363
|
+
) -> bool:
|
364
|
+
"""Cancel the entire conversation (synchronous version)
|
365
|
+
|
366
|
+
Args:
|
367
|
+
conversation_id: Conversation identifier
|
368
|
+
|
369
|
+
Returns:
|
370
|
+
bool: Whether the cancellation was successful
|
371
|
+
"""
|
372
|
+
|
373
|
+
return run_async_safely(
|
374
|
+
self.async_cancel_conversation(
|
375
|
+
conversation_id=conversation_id
|
376
|
+
)
|
377
|
+
)
|
378
|
+
|
379
|
+
async def async_continue_humanloop(
|
262
380
|
self,
|
263
381
|
conversation_id: str,
|
264
382
|
context: Dict[str, Any],
|
@@ -290,7 +408,36 @@ class BaseProvider(HumanLoopProvider, ABC):
|
|
290
408
|
# Subclasses need to implement specific continuation logic
|
291
409
|
raise NotImplementedError("Subclasses must implement continue_humanloop")
|
292
410
|
|
293
|
-
|
411
|
+
|
412
|
+
def continue_humanloop(
|
413
|
+
self,
|
414
|
+
conversation_id: str,
|
415
|
+
context: Dict[str, Any],
|
416
|
+
metadata: Optional[Dict[str, Any]] = None,
|
417
|
+
timeout: Optional[int] = None,
|
418
|
+
) -> HumanLoopResult:
|
419
|
+
"""Continue human-in-the-loop interaction (synchronous version)
|
420
|
+
|
421
|
+
Args:
|
422
|
+
conversation_id: Conversation ID for multi-turn dialogues
|
423
|
+
context: Context information provided to human
|
424
|
+
metadata: Additional metadata
|
425
|
+
timeout: Request timeout in seconds
|
426
|
+
|
427
|
+
Returns:
|
428
|
+
HumanLoopResult: Result object containing request ID and status
|
429
|
+
"""
|
430
|
+
|
431
|
+
return run_async_safely(
|
432
|
+
self.async_continue_humanloop(
|
433
|
+
conversation_id=conversation_id,
|
434
|
+
context=context,
|
435
|
+
metadata=metadata,
|
436
|
+
timeout=timeout
|
437
|
+
)
|
438
|
+
)
|
439
|
+
|
440
|
+
def async_get_conversation_history(self, conversation_id: str) -> List[Dict[str, Any]]:
|
294
441
|
"""Get complete history for the specified conversation
|
295
442
|
|
296
443
|
Args:
|
@@ -315,8 +462,22 @@ class BaseProvider(HumanLoopProvider, ABC):
|
|
315
462
|
})
|
316
463
|
return conversation_history
|
317
464
|
|
465
|
+
def get_conversation_history(self, conversation_id: str) -> List[Dict[str, Any]]:
|
466
|
+
"""Get complete history for the specified conversation (synchronous version)
|
467
|
+
|
468
|
+
Args:
|
469
|
+
conversation_id: Conversation identifier
|
470
|
+
|
471
|
+
Returns:
|
472
|
+
List[Dict[str, Any]]: List of conversation history records, each containing request ID,
|
473
|
+
status, context, response and other information
|
474
|
+
"""
|
475
|
+
|
476
|
+
return run_async_safely(
|
477
|
+
self.async_get_conversation_history(conversation_id=conversation_id)
|
478
|
+
)
|
318
479
|
|
319
|
-
def
|
480
|
+
async def _async_create_timeout_task(
|
320
481
|
self,
|
321
482
|
conversation_id: str,
|
322
483
|
request_id: str,
|