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.
@@ -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.astart_sync_task())
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 get_ghl_provider(self) -> GoHumanLoopProvider:
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.get_provider(self.default_provider_id)
113
+ provider = await self.async_get_provider(self.default_provider_id)
114
114
  return provider
115
115
 
116
- async def astart_sync_task(self):
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.aget_task_conversations(task_id)
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.aget_conversation_requests(conversation_id)
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._aget_request_status(conversation_id, request_id)
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._aget_request_status(conv_id, request_id, cancel_info.get("provider_id"))
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._asend_task_data_to_platform(task_data)
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._aget_request_status(conversation_id, request_id))
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._aget_request_status(conv_id, request_id, cancel_info.get("provider_id"))
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._asend_task_data_to_platform(task_data))
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 _asend_task_data_to_platform(self, task_data: Dict[str, Any]):
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 cancel_conversation(
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().cancel_conversation(conversation_id, provider_id)
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 _aget_request_status(
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
- # 如果没有指定provider_id,从存储的映射中获取
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.check_request_status(conversation_id, request_id)
445
+ return await provider.async_check_request_status(conversation_id, request_id)
446
446
 
447
- async def check_request_status(
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.check_request_status(conversation_id, request_id)
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._trigger_update_callback(conversation_id, request_id, provider, result)
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 ashutdown(self):
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.astart_sync_task()
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.ashutdown()
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 _make_api_request(
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 request_humanloop(
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._make_api_request(
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
- poll_task = asyncio.create_task(
234
- self._poll_request_status(conversation_id, request_id, platform)
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
- self._create_timeout_task(conversation_id, request_id, timeout)
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
- async def check_request_status(
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 cancel_request(
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().cancel_request(conversation_id, request_id)
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._make_api_request(
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 cancel_conversation(
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().cancel_conversation(conversation_id)
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._make_api_request(
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 continue_humanloop(
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._make_api_request(
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
- # Create polling task
520
- poll_task = asyncio.create_task(
521
- self._poll_request_status(conversation_id, request_id, platform)
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._create_timeout_task(conversation_id, request_id, timeout)
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 _poll_request_status(
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._make_api_request(
608
+ response = await self._async_make_api_request(
583
609
  endpoint="v1/humanloop/status",
584
610
  method="GET",
585
611
  params=params
@@ -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 request_humanloop(
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
- async def check_request_status(
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
- async def check_conversation_status(
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.check_request_status(conversation_id, latest_request_id)
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
- async def cancel_request(
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
- async def cancel_conversation(
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
- async def continue_humanloop(
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
- def get_conversation_history(self, conversation_id: str) -> List[Dict[str, Any]]:
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 _create_timeout_task(
480
+ async def _async_create_timeout_task(
320
481
  self,
321
482
  conversation_id: str,
322
483
  request_id: str,