gohumanloop 0.0.2__py3-none-any.whl → 0.0.3__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.
@@ -132,7 +132,7 @@ class EmailProvider(BaseProvider):
132
132
  "powered_by": "Powered by GoHumanLoop"
133
133
  }
134
134
 
135
- async def _send_email(
135
+ async def _async_send_email(
136
136
  self,
137
137
  to_email: str,
138
138
  subject: str,
@@ -195,7 +195,7 @@ class EmailProvider(BaseProvider):
195
195
  logger.exception(f"Unknown error occurred while sending email: {str(e)}")
196
196
  raise
197
197
 
198
- async def _check_emails(self, conversation_id: str, request_id: str, recipient_email: str, subject: str):
198
+ async def _async_check_emails(self, conversation_id: str, request_id: str, recipient_email: str, subject: str):
199
199
  """Check email replies
200
200
 
201
201
  Args:
@@ -603,7 +603,7 @@ class EmailProvider(BaseProvider):
603
603
 
604
604
  return text_body, "\n".join(html_body)
605
605
 
606
- async def request_humanloop(
606
+ async def async_request_humanloop(
607
607
  self,
608
608
  task_id: str,
609
609
  conversation_id: str,
@@ -678,7 +678,7 @@ class EmailProvider(BaseProvider):
678
678
 
679
679
 
680
680
  # 发送邮件
681
- success = await self._send_email(
681
+ success = await self._async_send_email(
682
682
  to_email=recipient_email,
683
683
  subject=subject,
684
684
  body=body,
@@ -701,13 +701,13 @@ class EmailProvider(BaseProvider):
701
701
 
702
702
  # 创建邮件检查任务
703
703
  check_task = asyncio.create_task(
704
- self._check_emails(conversation_id, request_id, recipient_email, subject)
704
+ self._async_check_emails(conversation_id, request_id, recipient_email, subject)
705
705
  )
706
706
  self._mail_check_tasks[(conversation_id, request_id)] = check_task
707
707
 
708
708
  # 如果设置了超时,创建超时任务
709
709
  if timeout:
710
- self._create_timeout_task(conversation_id, request_id, timeout)
710
+ await self._async_create_timeout_task(conversation_id, request_id, timeout)
711
711
 
712
712
  return HumanLoopResult(
713
713
  conversation_id=conversation_id,
@@ -716,7 +716,7 @@ class EmailProvider(BaseProvider):
716
716
  status=HumanLoopStatus.PENDING
717
717
  )
718
718
 
719
- async def check_request_status(
719
+ async def async_check_request_status(
720
720
  self,
721
721
  conversation_id: str,
722
722
  request_id: str
@@ -755,7 +755,7 @@ class EmailProvider(BaseProvider):
755
755
 
756
756
  return result
757
757
 
758
- async def continue_humanloop(
758
+ async def async_continue_humanloop(
759
759
  self,
760
760
  conversation_id: str,
761
761
  context: Dict[str, Any],
@@ -855,7 +855,7 @@ class EmailProvider(BaseProvider):
855
855
  body, html_body = self._format_email_body(prompt, HumanLoopType.CONVERSATION, subject)
856
856
 
857
857
  # 发送邮件
858
- success = await self._send_email(
858
+ success = await self._async_send_email(
859
859
  to_email=recipient_email,
860
860
  subject=subject,
861
861
  body=body,
@@ -879,13 +879,13 @@ class EmailProvider(BaseProvider):
879
879
 
880
880
  # 创建邮件检查任务
881
881
  check_task = asyncio.create_task(
882
- self._check_emails(conversation_id, request_id, recipient_email, subject)
882
+ self._async_check_emails(conversation_id, request_id, recipient_email, subject)
883
883
  )
884
884
  self._mail_check_tasks[(conversation_id, request_id)] = check_task
885
885
 
886
886
  # 如果设置了超时,创建超时任务
887
887
  if timeout:
888
- self._create_timeout_task(conversation_id, request_id, timeout)
888
+ await self._async_create_timeout_task(conversation_id, request_id, timeout)
889
889
 
890
890
  return HumanLoopResult(
891
891
  conversation_id=conversation_id,
@@ -894,7 +894,7 @@ class EmailProvider(BaseProvider):
894
894
  status=HumanLoopStatus.PENDING
895
895
  )
896
896
 
897
- async def cancel_request(
897
+ async def async_cancel_request(
898
898
  self,
899
899
  conversation_id: str,
900
900
  request_id: str
@@ -916,9 +916,9 @@ class EmailProvider(BaseProvider):
916
916
  del self._mail_check_tasks[request_key]
917
917
 
918
918
  # 调用父类方法取消请求
919
- return await super().cancel_request(conversation_id, request_id)
919
+ return await super().async_cancel_request(conversation_id, request_id)
920
920
 
921
- async def cancel_conversation(
921
+ async def async_cancel_conversation(
922
922
  self,
923
923
  conversation_id: str
924
924
  ) -> bool:
@@ -938,7 +938,7 @@ class EmailProvider(BaseProvider):
938
938
  del self._mail_check_tasks[request_key]
939
939
 
940
940
  # 调用父类方法取消对话
941
- return await super().cancel_conversation(conversation_id)
941
+ return await super().async_cancel_conversation(conversation_id)
942
942
 
943
943
  def _extract_user_reply_content(self, body: str) -> str:
944
944
  """Extract the actual reply content from the email, excluding quoted original email content
@@ -28,7 +28,7 @@ class TerminalProvider(BaseProvider):
28
28
  terminal_info = f"- Terminal Provider: Terminal-based human-in-the-loop implementation\n"
29
29
  return f"{terminal_info}{base_str}"
30
30
 
31
- async def request_humanloop(
31
+ async def async_request_humanloop(
32
32
  self,
33
33
  task_id: str,
34
34
  conversation_id: str,
@@ -77,11 +77,11 @@ class TerminalProvider(BaseProvider):
77
77
 
78
78
  # Create timeout task if timeout is specified
79
79
  if timeout:
80
- self._create_timeout_task(conversation_id, request_id, timeout)
80
+ await self._async_create_timeout_task(conversation_id, request_id, timeout)
81
81
 
82
82
  return result
83
83
 
84
- async def check_request_status(
84
+ async def async_check_request_status(
85
85
  self,
86
86
  conversation_id: str,
87
87
  request_id: str
@@ -120,7 +120,7 @@ class TerminalProvider(BaseProvider):
120
120
 
121
121
  return result
122
122
 
123
- async def continue_humanloop(
123
+ async def async_continue_humanloop(
124
124
  self,
125
125
  conversation_id: str,
126
126
  context: Dict[str, Any],
@@ -179,7 +179,7 @@ class TerminalProvider(BaseProvider):
179
179
 
180
180
  # Create timeout task if timeout is specified
181
181
  if timeout:
182
- self._create_timeout_task(conversation_id, request_id, timeout)
182
+ await self._async_create_timeout_task(conversation_id, request_id, timeout)
183
183
 
184
184
  return result
185
185
 
@@ -205,14 +205,14 @@ class TerminalProvider(BaseProvider):
205
205
 
206
206
  # Handle different interaction types based on loop type
207
207
  if loop_type == HumanLoopType.APPROVAL:
208
- await self._handle_approval_interaction(conversation_id, request_id, request_info)
208
+ await self._async_handle_approval_interaction(conversation_id, request_id, request_info)
209
209
  elif loop_type == HumanLoopType.INFORMATION:
210
- await self._handle_information_interaction(conversation_id, request_id, request_info)
210
+ await self._async_handle_information_interaction(conversation_id, request_id, request_info)
211
211
  else: # HumanLoopType.CONVERSATION
212
- await self._handle_conversation_interaction(conversation_id, request_id, request_info)
212
+ await self._async_handle_conversation_interaction(conversation_id, request_id, request_info)
213
213
 
214
214
 
215
- async def _handle_approval_interaction(self, conversation_id: str, request_id: str, request_info: Dict[str, Any]):
215
+ async def _async_handle_approval_interaction(self, conversation_id: str, request_id: str, request_info: Dict[str, Any]):
216
216
  """Handle approval type interaction
217
217
 
218
218
  Args:
@@ -225,7 +225,6 @@ class TerminalProvider(BaseProvider):
225
225
  # Execute blocking input() call in thread pool using run_in_executor
226
226
  loop = asyncio.get_event_loop()
227
227
  response = await loop.run_in_executor(None, input)
228
-
229
228
  # Process response
230
229
  response = response.strip().lower()
231
230
  if response in ["approve", "yes", "y", "同意", "批准"]:
@@ -239,7 +238,7 @@ class TerminalProvider(BaseProvider):
239
238
  else:
240
239
  print("\nInvalid input, please enter 'approve' or 'reject'")
241
240
  # Recursively handle approval interaction
242
- await self._handle_approval_interaction(conversation_id, request_id, request_info)
241
+ await self._async_handle_approval_interaction(conversation_id, request_id, request_info)
243
242
  return
244
243
 
245
244
  # Update request information
@@ -250,7 +249,7 @@ class TerminalProvider(BaseProvider):
250
249
 
251
250
  print(f"\nYour decision has been recorded: {status.value}")
252
251
 
253
- async def _handle_information_interaction(self, conversation_id: str, request_id: str, request_info: Dict[str, Any]):
252
+ async def _async_handle_information_interaction(self, conversation_id: str, request_id: str, request_info: Dict[str, Any]):
254
253
  """Handle information collection type interaction
255
254
 
256
255
  Args:
@@ -272,7 +271,7 @@ class TerminalProvider(BaseProvider):
272
271
 
273
272
  print("\nYour information has been recorded")
274
273
 
275
- async def _handle_conversation_interaction(self, conversation_id: str, request_id: str, request_info: Dict[str, Any]):
274
+ async def _async_handle_conversation_interaction(self, conversation_id: str, request_id: str, request_info: Dict[str, Any]):
276
275
  """Handle conversation type interaction
277
276
 
278
277
  Args:
@@ -2,16 +2,43 @@ import asyncio
2
2
  import os
3
3
  from typing import Optional, Union
4
4
  from pydantic import SecretStr
5
+ import warnings
6
+
5
7
  def run_async_safely(coro):
6
- """同步环境下安全地运行异步协程,避免事件循环冲突"""
8
+ """
9
+ Safely run async coroutines in synchronous environment
10
+ Will raise RuntimeError if called in async environment
11
+ """
12
+ try:
13
+ loop = asyncio.get_running_loop()
14
+ except RuntimeError: # No running event loop
15
+ loop = None
16
+
17
+ if loop is not None:
18
+ raise RuntimeError(
19
+ "Detected running event loop! "
20
+ "You should use 'await' directly instead of run_async_safely(). "
21
+ "If you really need to call sync code from async context, "
22
+ "consider using asyncio.to_thread() or other proper methods."
23
+ )
24
+
25
+ # Handle synchronous environment
7
26
  try:
8
27
  loop = asyncio.get_event_loop()
28
+ print("Using existing event loop.")
9
29
  except RuntimeError:
10
- # 如果没有事件循环,创建一个新的
11
30
  loop = asyncio.new_event_loop()
12
31
  asyncio.set_event_loop(loop)
32
+ own_loop = True
33
+ print("Created new event loop.")
34
+ else:
35
+ own_loop = False
13
36
 
14
- return loop.run_until_complete(coro)
37
+ try:
38
+ return loop.run_until_complete(coro)
39
+ finally:
40
+ if own_loop and not loop.is_closed():
41
+ loop.close()
15
42
 
16
43
 
17
44
  def get_secret_from_env(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gohumanloop
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: Perfecting AI workflows with human intelligence
5
5
  Author-email: gohumanloop authors <baird0917@163.com>
6
6
  Project-URL: repository, https://github.com/ptonlix/gohumanloop
@@ -1,30 +1,30 @@
1
1
  gohumanloop/__init__.py,sha256=7_AkUtiG-_iozObldORElQS9mufxjZx_WfxuX0E5Af0,1845
2
2
  gohumanloop/__main__.py,sha256=zdGKN92H9SgwZfL4xLqPkE1YaiRcHhVg_GqC-H1VurA,75
3
3
  gohumanloop/adapters/__init__.py,sha256=alRiJPahmH5vIbiw7l6o3eFvEADVTkfWYIsXy5uPGSo,391
4
- gohumanloop/adapters/langgraph_adapter.py,sha256=W-Uu9KYzLX69pm3UgkK57lsbONb9DllQwRBdau_voZc,34058
4
+ gohumanloop/adapters/langgraph_adapter.py,sha256=7w3ek8Yzr1r0tfJ4A5UNb_pcFRTfNVDc5gWNVq56IH0,34099
5
5
  gohumanloop/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  gohumanloop/cli/main.py,sha256=54-0nwjaAeRH2WhbyO6pN-XADPQwk4_EUUvVWDWruLc,744
7
7
  gohumanloop/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- gohumanloop/core/interface.py,sha256=WOWxlwsj3FSjLiZp_CW36AN_AQYc89PgdA9GZX1Irwc,13361
9
- gohumanloop/core/manager.py,sha256=QTpSa0GJEpmEd-f-FevqEsPQL9F8e8f0YLB5fPeLMio,23923
8
+ gohumanloop/core/interface.py,sha256=UjeEBKGS_JjwIsT5sBzyq6_IhUkDFrUvBXqpkxkFrAA,22696
9
+ gohumanloop/core/manager.py,sha256=MAgT5Sx1aLRBIb1mWxp-XJkQxEoibut8-TVtze8bWXQ,33068
10
10
  gohumanloop/manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- gohumanloop/manager/ghl_manager.py,sha256=0FEV3brYz3jerkljDL2C0pt3_tAFsB019MWhyPiNDis,21909
11
+ gohumanloop/manager/ghl_manager.py,sha256=m7KVdjd5bpxPNm2Sxk4LySzx_Ll4OfpJygxrfFhToDA,22026
12
12
  gohumanloop/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  gohumanloop/models/api_model.py,sha256=cNTXTlfI7yrTk_87Qf6ms0VtRXO2fYFJFLPTLy2dmQk,2853
14
14
  gohumanloop/models/glh_model.py,sha256=Ht93iCdLfVYz_nW-uW4bE5s0UoyKG3VEx9q-Gg8_tiY,870
15
15
  gohumanloop/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- gohumanloop/providers/api_provider.py,sha256=WJ7z1dUkQ6xcURx0sAOt_sLFPSGaz2yttSvmNGhvI-c,24398
17
- gohumanloop/providers/base.py,sha256=ke9HUKCrr24U71UUdLKoKyTRujCG0cOGEevKDDcd5Nc,16863
18
- gohumanloop/providers/email_provider.py,sha256=U1dAXx3T-unDNQ4Kn7Q4xLnGiUfTIz6iw5YKRn4A2h0,42460
16
+ gohumanloop/providers/api_provider.py,sha256=ooZQfi4Zu27U8kyTJ9rssAVzAVoyga71xT8nUjdQJmE,24517
17
+ gohumanloop/providers/base.py,sha256=Eq2y4fqJXdDfbA4xkyHBBH7opGeOg8PAte5vAbx2lwI,24623
18
+ gohumanloop/providers/email_provider.py,sha256=G04557UxdyBnmCx4WTXiakElELRv1fHDYTYNbvzDtqw,42562
19
19
  gohumanloop/providers/ghl_provider.py,sha256=YdxTpRzitFhTXTbhUcMhQlPUs3kwEBd4wyXEcGK8Svk,2524
20
- gohumanloop/providers/terminal_provider.py,sha256=obe1Mjj3dlyIPlyViMj3bi4R9HhKXmGjingnfoyHY1I,11637
20
+ gohumanloop/providers/terminal_provider.py,sha256=HBR6fLftaDRydueI5wxKtVOrgYF5RcPxzIhmLPrNVzo,11720
21
21
  gohumanloop/utils/__init__.py,sha256=idlE5ZNCELVNF9WIiyhtyzG9HJuQQCOlKeTr2aHJ2-Q,56
22
22
  gohumanloop/utils/context_formatter.py,sha256=v4vdgKNJCHjnTtIMq83AkyXwltL14vx-D4KahwcZhIQ,2171
23
23
  gohumanloop/utils/threadsafedict.py,sha256=0-Pmre2-lqHkUPal9wSaqh3fLaEtbo-OnJ3Wbi_knWE,9601
24
- gohumanloop/utils/utils.py,sha256=NU-qA5eGuuBjp2SJ49F2V8Gt8Rm1uV3AKM79LUeIcFY,1347
25
- gohumanloop-0.0.2.dist-info/licenses/LICENSE,sha256=-U5tuCcSpndQwSKWtZbFbazb-_AtZcZL2kQgHbSLg-M,1064
26
- gohumanloop-0.0.2.dist-info/METADATA,sha256=dG9y3LZsTdc3pTonB1fXwx5XZjY1Cedfk3O8bAiHbFA,1557
27
- gohumanloop-0.0.2.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
28
- gohumanloop-0.0.2.dist-info/entry_points.txt,sha256=wM6jqRRD8bQXkvIduRVCuAJIlbyWg_F5EDXo5OZ_PwY,88
29
- gohumanloop-0.0.2.dist-info/top_level.txt,sha256=LvOXBqS6Mspmcuqp81uz0Vjx_m_YI0w06DOPCiI1BfY,12
30
- gohumanloop-0.0.2.dist-info/RECORD,,
24
+ gohumanloop/utils/utils.py,sha256=iwfIAYuuKSyuEpOUv4ftf7zRDqSvJ6ALgqceHaZNeO4,2102
25
+ gohumanloop-0.0.3.dist-info/licenses/LICENSE,sha256=-U5tuCcSpndQwSKWtZbFbazb-_AtZcZL2kQgHbSLg-M,1064
26
+ gohumanloop-0.0.3.dist-info/METADATA,sha256=e7exfCd8QVCiMbcAjFwgnAbqoziS1WMUnYh7GL7eZPc,1557
27
+ gohumanloop-0.0.3.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
28
+ gohumanloop-0.0.3.dist-info/entry_points.txt,sha256=wM6jqRRD8bQXkvIduRVCuAJIlbyWg_F5EDXo5OZ_PwY,88
29
+ gohumanloop-0.0.3.dist-info/top_level.txt,sha256=LvOXBqS6Mspmcuqp81uz0Vjx_m_YI0w06DOPCiI1BfY,12
30
+ gohumanloop-0.0.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.4.0)
2
+ Generator: setuptools (80.7.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5